1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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"
35 /****************************************************************************/
37 /****************************************************************************/
46 /* our global datas */
47 extern struct HomeBank
*GLOBALS
;
48 extern struct Preferences
*PREFS
;
52 static void ui_repdist_action_viewlist(GtkAction
*action
, gpointer user_data
);
53 static void ui_repdist_action_viewbar(GtkAction
*action
, gpointer user_data
);
54 static void ui_repdist_action_viewpie(GtkAction
*action
, gpointer user_data
);
55 static void ui_repdist_action_detail(GtkAction
*action
, gpointer user_data
);
56 static void ui_repdist_action_legend(GtkAction
*action
, gpointer user_data
);
57 static void ui_repdist_action_rate(GtkAction
*action
, gpointer user_data
);
58 static void ui_repdist_action_filter(GtkAction
*action
, gpointer user_data
);
59 static void ui_repdist_action_refresh(GtkAction
*action
, gpointer user_data
);
60 static void ui_repdist_action_export(GtkAction
*action
, gpointer user_data
);
63 static GtkActionEntry entries
[] = {
64 { "List" , "hb-view-list" , N_("List") , NULL
, N_("View results as list"), G_CALLBACK (ui_repdist_action_viewlist
) },
65 { "Bar" , "hb-view-bar" , N_("Bar") , NULL
, N_("View results as bars"), G_CALLBACK (ui_repdist_action_viewbar
) },
66 { "Pie" , "hb-view-pie" , N_("Pie") , NULL
, N_("View results as pies"), G_CALLBACK (ui_repdist_action_viewpie
) },
68 { "Filter" , "hb-filter" , N_("Filter") , NULL
, N_("Edit the filter"), G_CALLBACK (ui_repdist_action_filter
) },
69 { "Refresh" , GTK_STOCK_REFRESH
, N_("Refresh"), NULL
, N_("Refresh results"), G_CALLBACK (ui_repdist_action_refresh
) },
71 { "Export" , "hb-file-export", N_("Export") , NULL
, N_("Export as CSV"), G_CALLBACK (ui_repdist_action_export
) },
73 static guint n_entries
= G_N_ELEMENTS (entries
);
76 static GtkToggleActionEntry toggle_entries
[] = {
77 { "Detail", "hb-ope-show", /* name, stock id */
78 N_("Detail"), NULL
, /* label, accelerator */
79 N_("Toggle detail"), /* tooltip */
80 G_CALLBACK (ui_repdist_action_detail
),
81 FALSE
}, /* is_active */
83 { "Legend", "hb-legend", /* name, stock id */
84 N_("Legend"), NULL
, /* label, accelerator */
85 N_("Toggle legend"), /* tooltip */
86 G_CALLBACK (ui_repdist_action_legend
),
87 TRUE
}, /* is_active */
89 { "Rate", "hb-rate", /* name, stock id */
90 N_("Rate"), NULL
, /* label, accelerator */
91 N_("Toggle rate"), /* tooltip */
92 G_CALLBACK (ui_repdist_action_rate
),
93 FALSE
}, /* is_active */
96 static guint n_toggle_entries
= G_N_ELEMENTS (toggle_entries
);
100 static const gchar
*ui_info
=
102 " <toolbar name='ToolBar'>"
103 " <toolitem action='List'/>"
104 " <toolitem action='Bar'/>"
105 " <toolitem action='Pie'/>"
107 " <toolitem action='Detail'/>"
108 " <toolitem action='Legend'/>"
109 " <toolitem action='Rate'/>"
111 " <toolitem action='Filter'/>"
112 " <toolitem action='Refresh'/>"
114 " <toolitem action='Export'/>"
120 static void ui_repdist_date_change(GtkWidget
*widget
, gpointer user_data
);
121 static void ui_repdist_range_change(GtkWidget
*widget
, gpointer user_data
);
122 static void ui_repdist_detail(GtkWidget
*widget
, gpointer user_data
);
123 static void ui_repdist_update(GtkWidget
*widget
, gpointer user_data
);
124 static void ui_repdist_update_total(GtkWidget
*widget
, gpointer user_data
);
125 static void ui_repdist_export_csv(GtkWidget
*widget
, gpointer user_data
);
126 static void ui_repdist_compute(GtkWidget
*widget
, gpointer user_data
);
127 static void ui_repdist_sensitive(GtkWidget
*widget
, gpointer user_data
);
128 static void ui_repdist_toggle_detail(GtkWidget
*widget
, gpointer user_data
);
129 static void ui_repdist_toggle_legend(GtkWidget
*widget
, gpointer user_data
);
130 static void ui_repdist_toggle_minor(GtkWidget
*widget
, gpointer user_data
);
131 static void ui_repdist_toggle_rate(GtkWidget
*widget
, gpointer user_data
);
132 static GtkWidget
*ui_list_repdist_create(void);
133 static void ui_repdist_update_daterange(GtkWidget
*widget
, gpointer user_data
);
135 static gint
ui_list_repdist_compare_func (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
);
139 gchar
*CYA_STATSELECT
[] = {
149 gchar
*CYA_KIND2
[] = {
158 //extern gchar *CYA_FLT_SELECT[];
160 gchar
*CYA_MONTHS
[] =
177 /* action functions -------------------- */
179 static void ui_repdist_action_viewlist(GtkAction
*action
, gpointer user_data
)
181 struct ui_repdist_data
*data
= user_data
;
183 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 0);
184 ui_repdist_sensitive(data
->window
, NULL
);
187 static void ui_repdist_action_viewbar(GtkAction
*action
, gpointer user_data
)
189 struct ui_repdist_data
*data
= user_data
;
191 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
192 gtk_chart_set_type (GTK_CHART(data
->RE_chart
), CHART_TYPE_COL
);
193 ui_repdist_sensitive(data
->window
, NULL
);
196 static void ui_repdist_action_viewpie(GtkAction
*action
, gpointer user_data
)
198 struct ui_repdist_data
*data
= user_data
;
201 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
203 gtk_chart_set_type (GTK_CHART(data
->RE_chart
), CHART_TYPE_PIE
);
204 ui_repdist_sensitive(data
->window
, NULL
);
206 tmpview
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
208 // ensure not exp & inc for piechart
211 //g_signal_handler_block(data->CY_view, data->handler_id[HID_REPDIST_VIEW]);
212 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
213 //g_signal_handler_unblock(data->CY_view, data->handler_id[HID_REPDIST_VIEW]);
218 static void ui_repdist_action_detail(GtkAction
*action
, gpointer user_data
)
220 struct ui_repdist_data
*data
= user_data
;
222 ui_repdist_toggle_detail(data
->window
, NULL
);
225 static void ui_repdist_action_legend(GtkAction
*action
, gpointer user_data
)
227 struct ui_repdist_data
*data
= user_data
;
229 ui_repdist_toggle_legend(data
->window
, NULL
);
232 static void ui_repdist_action_rate(GtkAction
*action
, gpointer user_data
)
234 struct ui_repdist_data
*data
= user_data
;
236 ui_repdist_toggle_rate(data
->window
, NULL
);
239 static void ui_repdist_action_filter(GtkAction
*action
, gpointer user_data
)
241 struct ui_repdist_data
*data
= user_data
;
244 //create_deffilter_window(data->filter, TRUE);
246 if(ui_flt_manage_dialog_new(data
->filter
, TRUE
) != GTK_RESPONSE_REJECT
)
248 ui_repdist_compute(data
->window
, NULL
);
249 ui_repdist_update_daterange(data
->window
, NULL
);
253 static void ui_repdist_action_refresh(GtkAction
*action
, gpointer user_data
)
255 struct ui_repdist_data
*data
= user_data
;
257 ui_repdist_compute(data
->window
, NULL
);
260 static void ui_repdist_action_export(GtkAction
*action
, gpointer user_data
)
262 struct ui_repdist_data
*data
= user_data
;
264 ui_repdist_export_csv(data
->window
, NULL
);
269 /* ======================== */
274 ** ============================================================================
281 ** return the month list position correponding to the passed date
283 static gint
DateInPer(guint32 from
, guint32 opedate
)
285 GDate
*date1
, *date2
;
289 // this return sometimes -1, -2 which is wrong
291 date1
= g_date_new_julian(from
);
292 date2
= g_date_new_julian(opedate
);
294 pos
= ((g_date_get_year(date2
) - g_date_get_year(date1
)) * 12) + g_date_get_month(date2
) - g_date_get_month(date1
);
296 //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);
305 ** return the year list position correponding to the passed date
307 static gint
DateInYear(guint32 from
, guint32 opedate
)
310 gint year_from
, year_ope
, pos
;
312 date
= g_date_new_julian(from
);
313 year_from
= g_date_get_year(date
);
314 g_date_set_julian(date
, opedate
);
315 year_ope
= g_date_get_year(date
);
318 pos
= year_ope
- year_from
;
320 //g_print(" from=%d ope=%d => %d\n", year_from, year_ope, pos);
325 static void ui_repdist_date_change(GtkWidget
*widget
, gpointer user_data
)
327 struct ui_repdist_data
*data
;
329 DB( g_print("\n[repdist] date change\n") );
331 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
333 data
->filter
->mindate
= gtk_dateentry_get_date(GTK_DATE_ENTRY(data
->PO_mindate
));
334 data
->filter
->maxdate
= gtk_dateentry_get_date(GTK_DATE_ENTRY(data
->PO_maxdate
));
336 // set min/max date for both widget
337 gtk_dateentry_set_maxdate(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->maxdate
);
338 gtk_dateentry_set_mindate(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->mindate
);
340 g_signal_handler_block(data
->CY_range
, data
->handler_id
[HID_REPDIST_RANGE
]);
341 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), FLT_RANGE_OTHER
);
342 g_signal_handler_unblock(data
->CY_range
, data
->handler_id
[HID_REPDIST_RANGE
]);
345 ui_repdist_compute(widget
, NULL
);
346 ui_repdist_update_daterange(widget
, NULL
);
352 static void ui_repdist_range_change(GtkWidget
*widget
, gpointer user_data
)
354 struct ui_repdist_data
*data
;
357 DB( g_print("\n[repdist] range change\n") );
359 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
361 range
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_range
));
363 if(range
!= FLT_RANGE_OTHER
)
365 filter_preset_daterange_set(data
->filter
, range
);
367 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
368 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
370 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
371 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
373 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
374 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
376 ui_repdist_compute(widget
, NULL
);
377 ui_repdist_update_daterange(widget
, NULL
);
381 if(ui_flt_manage_dialog_new(data
->filter
, TRUE
) != GTK_RESPONSE_REJECT
)
383 ui_repdist_compute(data
->window
, NULL
);
384 ui_repdist_update_daterange(widget
, NULL
);
391 static gint
ui_repdist_result_get_pos(gint tmpfor
, guint from
, Transaction
*ope
)
397 case BY_REPDIST_CATEGORY
:
399 Category
*catentry
= da_cat_get(ope
->kcat
);
401 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
404 case BY_REPDIST_SUBCATEGORY
:
407 case BY_REPDIST_PAYEE
:
410 case BY_REPDIST_MONTH
:
411 pos
= DateInPer(from
, ope
->date
);
413 case BY_REPDIST_YEAR
:
414 pos
= DateInYear(from
, ope
->date
);
423 static void ui_repdist_detail(GtkWidget
*widget
, gpointer user_data
)
425 struct ui_repdist_data
*data
;
426 guint active
= GPOINTER_TO_INT(user_data
);
432 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
434 DB( g_print("\n[repdist] detail\n") );
436 /* clear and detach our model */
437 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
));
438 gtk_list_store_clear (GTK_LIST_STORE(model
));
442 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
444 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
445 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), NULL
); /* Detach model from view */
447 /* fill in the model */
448 list
= g_list_first(GLOBALS
->ope_list
);
451 Transaction
*ope
= list
->data
;
454 //DB( g_print(" get %s\n", ope->ope_Word) );
456 acc
= da_acc_get(ope
->kacc
);
457 if(acc
== NULL
) goto next1
;
458 if((acc
->flags
& (AF_CLOSED
|AF_NOREPORT
))) goto next1
;
461 if( !(ope
->flags
& OF_REMIND
) )
463 if(filter_test(data
->filter
, ope
) == 1)
467 if( tmpfor
!= BY_REPDIST_TAG
)
469 if( (tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
) && ope
->flags
& OF_SPLIT
)
471 guint nbsplit
= da_transaction_splits_count(ope
);
474 for(i
=0;i
<nbsplit
;i
++)
476 split
= ope
->splits
[i
];
479 case BY_REPDIST_CATEGORY
:
481 Category
*catentry
= da_cat_get(split
->kcat
);
483 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
486 case BY_REPDIST_SUBCATEGORY
:
494 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
495 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
496 LST_DSPOPE_DATAS
, ope
,
506 pos
= ui_repdist_result_get_pos(tmpfor
, data
->filter
->mindate
, ope
);
510 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
511 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
512 LST_DSPOPE_DATAS
, ope
,
520 /* the TAG process is particular */
522 if(ope
->tags
!= NULL
)
524 guint32
*tptr
= ope
->tags
;
530 DB( g_print(" -> storing tag %d %.2f\n", pos
, ope
->amount
) );
534 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
535 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
536 LST_DSPOPE_DATAS
, ope
,
552 list
= g_list_next(list
);
555 /* Re-attach model to view */
556 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), model
);
557 g_object_unref(model
);
564 static void ui_repdist_update(GtkWidget
*widget
, gpointer user_data
)
566 struct ui_repdist_data
*data
;
569 gint page
, tmpfor
, tmpkind
, column
;
573 DB( g_print("\n[repdist] update\n") );
575 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
578 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
579 byamount
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_byamount
));
580 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
581 tmpkind
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
583 // ensure not exp & inc for piechart
584 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
586 if( page
== 2 && tmpkind
== 0 )
588 g_signal_handler_block(data
->CY_view
, data
->handler_id
[HID_REPDIST_VIEW
]);
589 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
590 g_signal_handler_unblock(data
->CY_view
, data
->handler_id
[HID_REPDIST_VIEW
]);
595 DB( g_print(" tmpkind %d\n\n", tmpkind
) );
598 column
= byamount
? LST_REPDIST_EXPENSE
+(tmpkind
-1)*2 : LST_REPDIST_POS
;
600 //#833614 sort category/payee by name
601 //if(!byamount && tmpkind <= BY_REPDIST_PAYEE)
602 // column = LST_REPDIST_NAME;
604 DB( g_print(" sort on column %d\n\n", column
) );
606 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model
), column
, GTK_SORT_DESCENDING
);
608 column
= LST_REPDIST_EXPENSE
+(tmpkind
-1)*2;
610 /* set chart color scheme */
611 gtk_chart_set_color_scheme(GTK_CHART(data
->RE_chart
), PREFS
->report_color_scheme
);
613 /* set chart title */
614 ////TRANSLATORS: example 'Expense by Category'
615 title
= g_strdup_printf(_("%s by %s"), _(CYA_KIND2
[tmpkind
]), _(CYA_STATSELECT
[tmpfor
]) );
617 /* update absolute or not */
618 gboolean abs
= (tmpkind
== 1 || tmpkind
== 2) ? TRUE
: FALSE
;
619 gtk_chart_set_absolute(GTK_CHART(data
->RE_chart
), abs
);
622 /* update bar chart */
623 DB( g_print(" set bar to %d %s\n\n", column
, _(CYA_KIND2
[tmpkind
])) );
625 gtk_chart_set_dualdatas(GTK_CHART(data
->RE_chart
), model
, LST_REPDIST_EXPENSE
, LST_REPDIST_INCOME
, title
);
627 gtk_chart_set_datas(GTK_CHART(data
->RE_chart
), model
, column
, title
);
630 /* show xval for month/year and no by amount display */
634 if( !byamount
&& (tmpfor
== BY_REPDIST_MONTH
|| tmpfor
== BY_REPDIST_YEAR
) )
639 case BY_REPDIST_MONTH
:
640 gtk_chart_set_every_xval(GTK_CHART(data
->RE_chart
), 4);
642 case BY_REPDIST_YEAR
:
643 gtk_chart_set_every_xval(GTK_CHART(data
->RE_chart
), 2);
648 gtk_chart_show_xval(GTK_CHART(data
->RE_chart
), xval
);
654 static void ui_repdist_update_daterange(GtkWidget
*widget
, gpointer user_data
)
656 struct ui_repdist_data
*data
;
659 DB( g_print("\n[repdist] update daterange\n") );
661 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
663 daterange
= filter_daterange_text_get(data
->filter
);
664 gtk_label_set_markup(GTK_LABEL(data
->TX_daterange
), daterange
);
668 static void ui_repdist_update_total(GtkWidget
*widget
, gpointer user_data
)
670 struct ui_repdist_data
*data
;
673 DB( g_print("\n[repdist] update total\n") );
675 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
677 //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
680 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[0]), data->total_expense, GLOBALS->kcur);
681 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[1]), data->total_income, GLOBALS->kcur);
682 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[2]), data->total_expense + data->total_income, GLOBALS->kcur);
685 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[0]), data
->total_expense
, GLOBALS
->minor
);
686 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[1]), data
->total_income
, GLOBALS
->minor
);
687 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[2]), data
->total_expense
+ data
->total_income
, GLOBALS
->minor
);
692 static void ui_repdist_export_csv(GtkWidget
*widget
, gpointer user_data
)
694 struct ui_repdist_data
*data
;
698 gchar
*filename
= NULL
;
700 gchar
*outstr
, *name
;
703 DB( g_print("\n[repdist] export csv\n") );
705 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
707 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
709 name
= g_strdup_printf("hb-stat_%s.csv", CYA_STATSELECT
[tmpfor
]);
711 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, name
) == TRUE
)
713 DB( g_print(" + filename is %s\n", filename
) );
715 io
= g_io_channel_new_file(filename
, "w", NULL
);
719 outstr
= g_strdup_printf("%s;%s;%s;%s\n", _("Result"), _("expense"), _("Income"), _("Balance"));
720 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
722 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
723 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
727 gdouble exp
, inc
, bal
;
729 gtk_tree_model_get (model
, &iter
,
730 //LST_REPDIST_KEY, i,
731 LST_REPDIST_NAME
, &name
,
732 LST_REPDIST_EXPENSE
, &exp
,
733 LST_REPDIST_INCOME
, &inc
,
734 LST_REPDIST_BALANCE
, &bal
,
737 outstr
= g_strdup_printf("%s;%.2f;%.2f;%.2f\n", name
, exp
, inc
, bal
);
738 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
740 DB( g_print("%s", outstr
) );
744 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
747 g_io_channel_unref (io
);
759 static void ui_repdist_compute(GtkWidget
*widget
, gpointer user_data
)
761 struct ui_repdist_data
*data
;
762 gint tmpfor
, tmpkind
;
766 GList
*list
, *tmplist
= NULL
;
767 guint n_result
, sortid
;
769 GDate
*date1
, *date2
;
770 gdouble
*tmp_income
, *tmp_expense
;
771 gdouble exprate
, incrate
, balrate
;
773 DB( g_print("\n[repdist] compute\n") );
775 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
777 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_by
));
778 tmpkind
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_view
));
781 DB( g_print(" for=%d,kind=%d\n", tmpfor
, tmpkind
) );
785 /* do nothing if no transaction */
786 if(g_list_length(GLOBALS
->ope_list
) == 0) return;
788 //get our min max date
789 from
= data
->filter
->mindate
;
790 to
= data
->filter
->maxdate
;
791 if(to
< from
) return;
793 /* count number or results */
796 case BY_REPDIST_CATEGORY
:
797 case BY_REPDIST_SUBCATEGORY
:
798 n_result
= da_cat_get_max_key() + 1;
799 tmplist
= category_glist_sorted(1);
801 case BY_REPDIST_PAYEE
:
802 n_result
= da_pay_get_max_key() + 1;
803 tmplist
= payee_glist_sorted(1);
806 n_result
= da_tag_length();
807 tmplist
= tag_glist_sorted(1);
809 case BY_REPDIST_MONTH
:
810 date1
= g_date_new_julian(from
);
811 date2
= g_date_new_julian(to
);
812 n_result
= ((g_date_get_year(date2
) - g_date_get_year(date1
)) * 12) + g_date_get_month(date2
) - g_date_get_month(date1
) + 1;
816 case BY_REPDIST_YEAR
:
817 date1
= g_date_new_julian(from
);
818 date2
= g_date_new_julian(to
);
819 n_result
= g_date_get_year(date2
) - g_date_get_year(date1
) + 1;
827 DB( g_print(" %s :: n_result=%d\n", CYA_STATSELECT
[tmpfor
], n_result
) );
829 /* allocate some memory */
830 tmp_expense
= g_malloc0((n_result
+2) * sizeof(gdouble
));
831 tmp_income
= g_malloc0((n_result
+2) * sizeof(gdouble
));
833 data
->total_expense
= 0.0;
834 data
->total_income
= 0.0;
836 if(tmp_expense
&& tmp_income
)
838 /* compute the results */
839 list
= g_list_first(GLOBALS
->ope_list
);
842 Transaction
*ope
= list
->data
;
845 //DB( g_print("** testing '%s', cat=%d==> %d\n", ope->wording, ope->category, filter_test(data->filter, ope)) );
846 acc
= da_acc_get(ope
->kacc
);
847 if(acc
== NULL
) goto next1
;
848 if((acc
->flags
& (AF_CLOSED
|AF_NOREPORT
))) goto next1
;
850 if( !(ope
->flags
& OF_REMIND
) )
852 if( (filter_test(data
->filter
, ope
) == 1) )
857 //trn_amount = to_base_amount(ope->amount, acc->kcur);
858 trn_amount
= ope
->amount
;
860 if( tmpfor
!= BY_REPDIST_TAG
)
862 if( (tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
) && ope
->flags
& OF_SPLIT
)
864 guint nbsplit
= da_transaction_splits_count(ope
);
869 for(i
=0;i
<nbsplit
;i
++)
871 split
= ope
->splits
[i
];
872 catentry
= da_cat_get(split
->kcat
);
873 if(!catentry
) continue;
874 sinsert
= ( catentry
->filter
== TRUE
) ? 1 : 0;
875 if(data
->filter
->option
[FILTER_CATEGORY
] == 2) sinsert
^= 1;
877 DB( g_print(" split '%s' insert=%d\n",catentry
->name
, sinsert
) );
879 if( (data
->filter
->option
[FILTER_CATEGORY
] == 0) || sinsert
)
883 case BY_REPDIST_CATEGORY
:
886 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
889 case BY_REPDIST_SUBCATEGORY
:
894 //trn_amount = to_base_amount(split->amount, acc->kcur);
895 trn_amount
= split
->amount
;
899 tmp_income
[pos
] += trn_amount
;
900 data
->total_income
+= trn_amount
;
904 tmp_expense
[pos
] += trn_amount
;
905 data
->total_expense
+= trn_amount
;
915 pos
= ui_repdist_result_get_pos(tmpfor
, from
, ope
);
918 tmp_income
[pos
] += trn_amount
;
919 data
->total_income
+= trn_amount
;
923 tmp_expense
[pos
] += trn_amount
;
924 data
->total_expense
+= trn_amount
;
929 /* the TAG process is particular */
931 if(ope
->tags
!= NULL
)
933 guint32
*tptr
= ope
->tags
;
939 DB( g_print(" -> storing tag %d %s %.2f\n", pos
, da_tag_get(*tptr
)->name
, trn_amount
) );
943 tmp_income
[pos
] += trn_amount
;
947 tmp_expense
[pos
] += trn_amount
;
955 data
->total_income
+= trn_amount
;
959 data
->total_expense
+= trn_amount
;
965 // fix total according to selection
966 //if(tmpkind==0 && !tmp_expense[pos]) { data->total_income -= ope->amount; }
967 //if(tmpkind==1 && !tmp_income[pos] ) { data->total_expense -= ope->amount; }
973 list
= g_list_next(list
);
976 /* clear and detach our model */
977 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
978 gtk_list_store_clear (GTK_LIST_STORE(model
));
979 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
980 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), NULL
); /* Detach model from view */
982 /* insert into the treeview */
983 for(i
=0, sortid
=0; i
<n_result
; i
++)
985 gchar
*name
, *fullcatname
;
992 DB( g_print("try to insert item %d\n", i
) );
995 /* filter empty results */
996 if(tmpfor
== BY_REPDIST_CATEGORY
|| tmpfor
== BY_REPDIST_SUBCATEGORY
|| tmpfor
== BY_REPDIST_PAYEE
|| tmpfor
== BY_REPDIST_TAG
)
998 if( tmpkind
== 1 && !tmp_expense
[i
] ) continue;
999 if( tmpkind
== 2 && !tmp_income
[i
] ) continue;
1000 if( !tmp_expense
[i
] && !tmp_income
[i
] ) continue;
1003 /* get the result name */
1006 case BY_REPDIST_CATEGORY
:
1008 Category
*entry
= da_cat_get(i
);
1012 name
= entry
->key
== 0 ? _("(no category)") : entry
->name
;
1014 sortid
= g_list_index(tmplist
, entry
);
1019 case BY_REPDIST_SUBCATEGORY
:
1021 Category
*entry
= da_cat_get(i
);
1024 if(entry
->flags
& GF_SUB
)
1026 Category
*parent
= da_cat_get(entry
->parent
);
1028 fullcatname
= g_strdup_printf("%s : %s", parent
->name
, entry
->name
);
1032 name
= entry
->key
== 0 ? _("(no category)") : entry
->name
;
1034 sortid
= g_list_index(tmplist
, entry
);
1039 case BY_REPDIST_PAYEE
:
1041 Payee
*entry
= da_pay_get(i
);
1044 name
= entry
->key
== 0 ? _("(no payee)") : entry
->name
;
1045 sortid
= g_list_index(tmplist
, entry
);
1050 case BY_REPDIST_TAG
:
1052 Tag
*entry
= da_tag_get(i
+1);
1054 sortid
= g_list_index(tmplist
, entry
);
1058 case BY_REPDIST_MONTH
:
1059 date
= g_date_new_julian(from
);
1060 g_date_add_months(date
, i
);
1061 //g_snprintf(buffer, 63, "%d-%02d", g_date_get_year(date), g_date_get_month(date));
1062 g_snprintf(buffer
, 63, "%d-%s", g_date_get_year(date
), _(CYA_MONTHS
[g_date_get_month(date
)-1]));
1067 case BY_REPDIST_YEAR
:
1068 date
= g_date_new_julian(from
);
1069 g_date_add_years(date
, i
);
1070 g_snprintf(buffer
, 63, "%d", g_date_get_year(date
));
1076 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
]) );
1083 if( data
->total_expense
)
1084 exprate
= ABS((tmp_expense
[i
] * 100 / data
->total_expense
));
1086 if( data
->total_income
)
1087 incrate
= (tmp_income
[i
] * 100 / data
->total_income
);
1089 data
->total_balance
= ABS(data
->total_expense
) + data
->total_income
;
1090 if( data
->total_balance
)
1091 balrate
= (ABS(tmp_expense
[i
]) + tmp_income
[i
]) * 100 / data
->total_balance
;
1093 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
1094 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
1095 LST_REPDIST_POS
, sortid
++,
1097 LST_REPDIST_NAME
, name
,
1098 LST_REPDIST_EXPENSE
, tmp_expense
[i
],
1099 LST_REPDIST_INCOME
, tmp_income
[i
],
1100 LST_REPDIST_BALANCE
, tmp_expense
[i
] + tmp_income
[i
],
1101 LST_REPDIST_EXPRATE
, exprate
,
1102 LST_REPDIST_INCRATE
, incrate
,
1103 LST_REPDIST_BALRATE
, balrate
,
1106 g_free(fullcatname
);
1109 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
1111 /* Re-attach model to view */
1112 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), model
);
1113 g_object_unref(model
);
1116 /* free our memory */
1117 g_free(tmp_expense
);
1120 /* free tmplist (sort cat/pay) */
1121 g_list_free(tmplist
);
1123 ui_repdist_update_total(widget
,NULL
);
1125 ui_repdist_update(widget
, user_data
);
1134 ** update sensitivity
1136 static void ui_repdist_sensitive(GtkWidget
*widget
, gpointer user_data
)
1138 struct ui_repdist_data
*data
;
1143 DB( g_print("\n[repdist] sensitive\n") );
1145 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1147 active
= gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), NULL
, NULL
);
1149 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
1151 sensitive
= page
== 0 ? active
: FALSE
;
1152 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_DETAIL], sensitive);
1153 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Detail"), sensitive
);
1155 //view = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_view));
1159 sensitive
= page
== 0 ? FALSE
: TRUE
;
1160 gtk_widget_set_sensitive(data
->RG_zoomx
, sensitive
);
1161 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_LEGEND], sensitive);
1162 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Legend"), sensitive
);
1164 sensitive
= page
== 0 ? TRUE
: FALSE
;
1165 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Rate"), sensitive
);
1170 static void ui_repdist_update_detail(GtkWidget
*widget
, gpointer user_data
)
1172 struct ui_repdist_data
*data
;
1174 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1176 if(GTK_IS_TREE_VIEW(data
->LV_report
))
1180 GtkTreeSelection
*treeselection
;
1181 GtkTreeModel
*model
;
1185 treeselection
= gtk_tree_view_get_selection (GTK_TREE_VIEW(data
->LV_report
));
1187 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
1189 gtk_tree_model_get(model
, &iter
, LST_REPDIST_KEY
, &key
, -1);
1191 DB( g_print(" - active is %d\n", key
) );
1193 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
1198 gtk_widget_show(data
->GR_detail
);
1201 gtk_widget_hide(data
->GR_detail
);
1209 static void ui_repdist_toggle_detail(GtkWidget
*widget
, gpointer user_data
)
1211 struct ui_repdist_data
*data
;
1213 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1217 DB( printf("\n[repdist] toggledetail to %d\n", data
->detail
) );
1219 ui_repdist_update_detail(widget
, user_data
);
1224 ** change the chart legend visibility
1226 static void ui_repdist_toggle_legend(GtkWidget
*widget
, gpointer user_data
)
1228 struct ui_repdist_data
*data
;
1231 DB( g_print("\n[repdist] toggle legend\n") );
1233 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1237 gtk_chart_show_legend(GTK_CHART(data
->RE_chart
), data
->legend
, FALSE
);
1241 static void ui_repdist_zoomx_callback(GtkWidget
*widget
, gpointer user_data
)
1243 struct ui_repdist_data
*data
;
1246 DB( g_print("\n[repdist] zoomx\n") );
1248 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1250 value
= gtk_range_get_value(GTK_RANGE(data
->RG_zoomx
));
1252 DB( g_print(" + scale is %.2f\n", value
) );
1254 gtk_chart_set_barw(GTK_CHART(data
->RE_chart
), value
);
1260 ** change the chart rate columns visibility
1262 static void ui_repdist_toggle_rate(GtkWidget
*widget
, gpointer user_data
)
1264 struct ui_repdist_data
*data
;
1265 GtkTreeViewColumn
*column
;
1267 DB( g_print("\n[repdist] toggle rate\n") );
1269 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1273 if(GTK_IS_TREE_VIEW(data
->LV_report
))
1276 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 2);
1277 gtk_tree_view_column_set_visible(column
, data
->rate
);
1279 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 4);
1280 gtk_tree_view_column_set_visible(column
, data
->rate
);
1282 column
= gtk_tree_view_get_column (GTK_TREE_VIEW(data
->LV_report
), 6);
1283 gtk_tree_view_column_set_visible(column
, data
->rate
);
1288 static void ui_repdist_toggle_minor(GtkWidget
*widget
, gpointer user_data
)
1290 struct ui_repdist_data
*data
;
1292 DB( g_print("\n[repdist] toggle minor\n") );
1294 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1296 GLOBALS
->minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
1298 ui_repdist_update_total(widget
,NULL
);
1300 //hbfile_update(data->LV_acc, (gpointer)4);
1301 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
1302 gtk_chart_show_minor(GTK_CHART(data
->RE_chart
), GLOBALS
->minor
);
1310 static void ui_repdist_setup(struct ui_repdist_data
*data
)
1312 DB( g_print("\n[repdist] setup\n") );
1314 data
->detail
= PREFS
->stat_showdetail
;
1316 data
->rate
= PREFS
->stat_showrate
^1;
1319 ui_repdist_toggle_rate(data
->window
, NULL
);
1322 data
->filter
= da_filter_malloc();
1323 filter_default_all_set(data
->filter
);
1325 /* 3.4 : make int transfer out of stats */
1326 data
->filter
->option
[FILTER_PAYMODE
] = 1;
1327 data
->filter
->paymode
[PAYMODE_INTXFER
] = FALSE
;
1329 filter_preset_daterange_set(data
->filter
, PREFS
->date_range_rep
);
1331 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
1332 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
1334 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
1335 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
1337 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPDIST_MINDATE
]);
1338 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPDIST_MAXDATE
]);
1344 static void ui_repdist_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
1346 GtkTreeModel
*model
;
1350 DB( g_print("\n[repdist] selection\n") );
1352 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
1354 gtk_tree_model_get(model
, &iter
, LST_REPDIST_KEY
, &key
, -1);
1358 DB( g_print(" - active is %d\n", key
) );
1360 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
1361 ui_repdist_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
1368 static gboolean
ui_repdist_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1370 struct ui_repdist_data
*data
= user_data
;
1371 struct WinGeometry
*wg
;
1373 DB( g_print("\n[repdist] dispose\n") );
1375 da_filter_free(data
->filter
);
1379 //store position and size
1380 wg
= &PREFS
->sta_wg
;
1381 gtk_window_get_position(GTK_WINDOW(widget
), &wg
->l
, &wg
->t
);
1382 gtk_window_get_size(GTK_WINDOW(widget
), &wg
->w
, &wg
->h
);
1384 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg
->l
, wg
->t
, wg
->w
, wg
->h
) );
1388 //enable define windows
1389 GLOBALS
->define_off
--;
1390 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
1395 // the window creation
1396 GtkWidget
*ui_repdist_window_new(void)
1398 struct ui_repdist_data
*data
;
1399 struct WinGeometry
*wg
;
1400 GtkWidget
*window
, *mainvbox
, *hbox
, *vbox
, *notebook
, *treeview
;
1401 GtkWidget
*label
, *widget
, *table
, *alignment
, *entry
;
1404 GtkActionGroup
*actions
;
1406 GError
*error
= NULL
;
1408 DB( g_print("\n[repdist] new\n") );
1411 data
= g_malloc0(sizeof(struct ui_repdist_data
));
1412 if(!data
) return NULL
;
1414 //disable define windows
1415 GLOBALS
->define_off
++;
1416 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(2));
1418 /* create window, etc */
1419 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1420 data
->window
= window
;
1422 //store our window private data
1423 g_object_set_data(G_OBJECT(window
), "inst_data", (gpointer
)data
);
1425 gtk_window_set_title (GTK_WINDOW (window
), _("Statistics Report"));
1427 //set the window icon
1428 //homebank_window_set_icon_from_file(GTK_WINDOW (window), "report_stats.svg");
1429 gtk_window_set_icon_name(GTK_WINDOW (window
), HB_STOCK_REP_STATS
);
1433 mainvbox
= gtk_vbox_new (FALSE
, 0);
1434 gtk_container_add (GTK_CONTAINER (window
), mainvbox
);
1436 hbox
= gtk_hbox_new(FALSE
, 0);
1437 gtk_box_pack_start (GTK_BOX (mainvbox
), hbox
, TRUE
, TRUE
, 0);
1440 table
= gtk_table_new (6, 3, FALSE
);
1441 // gtk_alignment_new(xalign, yalign, xscale, yscale)
1442 alignment
= gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
1443 gtk_container_add(GTK_CONTAINER(alignment
), table
);
1444 gtk_box_pack_start (GTK_BOX (hbox
), alignment
, FALSE
, FALSE
, 0);
1446 gtk_container_set_border_width (GTK_CONTAINER (table
), HB_BOX_SPACING
);
1447 gtk_table_set_row_spacings (GTK_TABLE (table
), HB_TABROW_SPACING
);
1448 gtk_table_set_col_spacings (GTK_TABLE (table
), HB_TABCOL_SPACING
);
1451 label
= make_label(_("Display"), 0.0, 0.5);
1452 gimp_label_set_attributes(GTK_LABEL(label
), PANGO_ATTR_WEIGHT
, PANGO_WEIGHT_BOLD
, -1);
1453 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 3, row
, row
+1);
1456 label
= make_label(_("_View:"), 0, 0.5);
1457 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1458 widget
= make_cycle(label
, CYA_KIND2
);
1459 data
->CY_view
= widget
;
1460 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 2, 3, row
, row
+1);
1463 label
= make_label(_("_By:"), 0, 0.5);
1464 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1465 widget
= make_cycle(label
, CYA_STATSELECT
);
1466 data
->CY_by
= widget
;
1467 gtk_table_attach_defaults (GTK_TABLE (table
), data
->CY_by
, 2, 3, row
, row
+1);
1470 widget
= gtk_check_button_new_with_mnemonic (_("By _amount"));
1471 data
->CM_byamount
= widget
;
1472 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 1, 3, row
, row
+1);
1475 widget
= gtk_check_button_new_with_mnemonic (_("_Minor currency"));
1476 data
->CM_minor
= widget
;
1477 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 1, 3, row
, row
+1);
1481 label
= make_label(_("_Zoom X:"), 0, 0.5);
1482 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1483 widget
= make_scale(label
);
1484 data
->RG_zoomx
= widget
;
1485 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 2, 3, row
, row
+1);
1490 widget = gtk_check_button_new_with_mnemonic ("Legend");
1491 data->CM_legend = widget;
1492 gtk_table_attach_defaults (GTK_TABLE (table), widget, 1, 2, row, row+1);
1495 widget
= gtk_hseparator_new();
1496 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 0, 3, row
, row
+1);
1499 label
= make_label(_("Date filter"), 0.0, 0.5);
1500 gimp_label_set_attributes(GTK_LABEL(label
), PANGO_ATTR_WEIGHT
, PANGO_WEIGHT_BOLD
, -1);
1501 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 3, row
, row
+1);
1504 label
= make_label(_("_Range:"), 0, 0.5);
1505 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1506 data
->CY_range
= make_daterange(label
, TRUE
);
1507 gtk_table_attach_defaults (GTK_TABLE (table
), data
->CY_range
, 2, 3, row
, row
+1);
1510 label
= make_label(_("_From:"), 0, 0.5);
1511 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1512 data
->PO_mindate
= gtk_dateentry_new();
1513 gtk_table_attach_defaults (GTK_TABLE (table
), data
->PO_mindate
, 2, 3, row
, row
+1);
1516 label
= make_label(_("_To:"), 0, 0.5);
1517 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
1518 data
->PO_maxdate
= gtk_dateentry_new();
1519 gtk_table_attach_defaults (GTK_TABLE (table
), data
->PO_maxdate
, 2, 3, row
, row
+1);
1521 //part: info + report
1522 vbox
= gtk_vbox_new (FALSE
, 0);
1523 gtk_box_pack_start (GTK_BOX (hbox
), vbox
, TRUE
, TRUE
, 0);
1526 actions
= gtk_action_group_new ("Account");
1529 gtk_action_group_set_translation_domain(actions
, GETTEXT_PACKAGE
);
1531 // data to action callbacks is set here (data)
1532 gtk_action_group_add_actions (actions
, entries
, n_entries
, data
);
1534 gtk_action_group_add_toggle_actions (actions
,
1535 toggle_entries
, n_toggle_entries
,
1539 /* set which action should have priority in the toolbar */
1540 action
= gtk_action_group_get_action(actions
, "List");
1541 g_object_set(action
, "is_important", TRUE
, NULL
);
1543 action
= gtk_action_group_get_action(actions
, "Bar");
1544 g_object_set(action
, "is_important", TRUE
, NULL
);
1546 action
= gtk_action_group_get_action(actions
, "Pie");
1547 g_object_set(action
, "is_important", TRUE
, NULL
);
1549 action
= gtk_action_group_get_action(actions
, "Detail");
1550 g_object_set(action
, "is_important", TRUE
, NULL
);
1551 g_object_set(action
, "active", PREFS
->stat_showdetail
, NULL
);
1553 action
= gtk_action_group_get_action(actions
, "Rate");
1554 g_object_set(action
, "active", PREFS
->stat_showrate
, NULL
);
1556 action
= gtk_action_group_get_action(actions
, "Filter");
1557 g_object_set(action
, "is_important", TRUE
, NULL
);
1559 action
= gtk_action_group_get_action(actions
, "Refresh");
1560 g_object_set(action
, "is_important", TRUE
, NULL
);
1563 ui
= gtk_ui_manager_new ();
1564 gtk_ui_manager_insert_action_group (ui
, actions
, 0);
1565 gtk_window_add_accel_group (GTK_WINDOW (window
), gtk_ui_manager_get_accel_group (ui
));
1567 if (!gtk_ui_manager_add_ui_from_string (ui
, ui_info
, -1, &error
))
1569 g_message ("building UI failed: %s", error
->message
);
1570 g_error_free (error
);
1574 data
->actions
= actions
;
1577 data
->TB_bar
= gtk_ui_manager_get_widget (ui
, "/ToolBar");
1578 gtk_box_pack_start (GTK_BOX (vbox
), data
->TB_bar
, FALSE
, FALSE
, 0);
1581 hbox
= gtk_hbox_new (FALSE
, HB_BOX_SPACING
);
1582 gtk_container_set_border_width (GTK_CONTAINER(hbox
), HB_BOX_SPACING
);
1583 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1585 widget
= make_label(NULL
, 0.5, 0.5);
1586 gimp_label_set_attributes (GTK_LABEL (widget
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
1587 data
->TX_daterange
= widget
;
1588 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1590 entry
= gtk_label_new(NULL
);
1591 data
->TX_total
[2] = entry
;
1592 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1593 label
= gtk_label_new(_("Balance:"));
1594 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1596 entry
= gtk_label_new(NULL
);
1597 data
->TX_total
[1] = entry
;
1598 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1599 label
= gtk_label_new(_("Income:"));
1600 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1603 entry
= gtk_label_new(NULL
);
1604 data
->TX_total
[0] = entry
;
1605 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1606 label
= gtk_label_new(_("Expense:"));
1607 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1611 notebook
= gtk_notebook_new();
1612 data
->GR_result
= notebook
;
1613 gtk_widget_show(notebook
);
1614 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
1615 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
1616 gtk_box_pack_start (GTK_BOX (vbox
), notebook
, TRUE
, TRUE
, 0);
1619 vbox
= gtk_vbox_new (FALSE
, 0);
1620 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vbox
, NULL
);
1622 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1623 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (widget), GTK_CORNER_TOP_RIGHT);
1624 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1625 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1626 treeview
= ui_list_repdist_create();
1627 data
->LV_report
= treeview
;
1628 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1629 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1632 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1633 data
->GR_detail
= widget
;
1634 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (widget), GTK_CORNER_TOP_RIGHT);
1635 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1636 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1637 treeview
= create_list_transaction(TRN_LIST_TYPE_DETAIL
, PREFS
->lst_ope_columns
);
1638 data
->LV_detail
= treeview
;
1639 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1641 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1645 widget
= gtk_chart_new(CHART_TYPE_COL
);
1646 data
->RE_chart
= widget
;
1647 gtk_chart_set_minor_prefs(GTK_CHART(widget
), PREFS
->euro_value
, PREFS
->minor_cur
.symbol
);
1648 //gtk_chart_set_currency(GTK_CHART(widget), GLOBALS->kcur);
1649 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), widget
, NULL
);
1651 //todo: setup should move this
1652 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_minor
), GLOBALS
->minor
);
1653 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_byamount
), PREFS
->stat_byamount
);
1655 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_view
), 1);
1657 /* attach our minor to treeview */
1658 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
))), "minor", (gpointer
)data
->CM_minor
);
1659 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
))), "minor", (gpointer
)data
->CM_minor
);
1661 /* signal connect */
1662 g_signal_connect (window
, "delete-event", G_CALLBACK (ui_repdist_dispose
), (gpointer
)data
);
1664 g_signal_connect (data
->CM_minor
, "toggled", G_CALLBACK (ui_repdist_toggle_minor
), NULL
);
1666 data
->handler_id
[HID_REPDIST_MINDATE
] = g_signal_connect (data
->PO_mindate
, "changed", G_CALLBACK (ui_repdist_date_change
), (gpointer
)data
);
1667 data
->handler_id
[HID_REPDIST_MAXDATE
] = g_signal_connect (data
->PO_maxdate
, "changed", G_CALLBACK (ui_repdist_date_change
), (gpointer
)data
);
1669 data
->handler_id
[HID_REPDIST_RANGE
] = g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (ui_repdist_range_change
), NULL
);
1671 g_signal_connect (data
->CY_by
, "changed", G_CALLBACK (ui_repdist_compute
), (gpointer
)data
);
1672 data
->handler_id
[HID_REPDIST_VIEW
] = g_signal_connect (data
->CY_view
, "changed", G_CALLBACK (ui_repdist_compute
), (gpointer
)data
);
1674 g_signal_connect (data
->RG_zoomx
, "value-changed", G_CALLBACK (ui_repdist_zoomx_callback
), NULL
);
1677 g_signal_connect (data
->CM_byamount
, "toggled", G_CALLBACK (ui_repdist_update
), NULL
);
1679 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), "changed", G_CALLBACK (ui_repdist_selection
), NULL
);
1682 //setup, init and show window
1683 ui_repdist_setup(data
);
1686 if(PREFS
->toolbar_style
== 0)
1687 gtk_toolbar_unset_style(GTK_TOOLBAR(data
->TB_bar
));
1689 gtk_toolbar_set_style(GTK_TOOLBAR(data
->TB_bar
), PREFS
->toolbar_style
-1);
1692 //setup, init and show window
1693 wg
= &PREFS
->sta_wg
;
1694 gtk_window_move(GTK_WINDOW(window
), wg
->l
, wg
->t
);
1695 gtk_window_resize(GTK_WINDOW(window
), wg
->w
, wg
->h
);
1697 gtk_widget_show_all (window
);
1702 if( PREFS
->euro_active
)
1703 gtk_widget_show(data
->CM_minor
);
1705 gtk_widget_hide(data
->CM_minor
);
1707 //gtk_widget_hide(data->GR_detail);
1711 ui_repdist_sensitive(window
, NULL
);
1712 ui_repdist_update_detail(window
, NULL
);
1714 DB( g_print("range: %d\n", PREFS
->date_range_rep
) );
1716 if( PREFS
->date_range_rep
!= 0)
1717 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), PREFS
->date_range_rep
);
1719 ui_repdist_compute(window
, NULL
);
1726 ** ============================================================================
1729 static void ui_list_repdist_rate_cell_data_function (GtkTreeViewColumn
*col
,
1730 GtkCellRenderer
*renderer
,
1731 GtkTreeModel
*model
,
1735 //GtkWidget *widget;
1737 //widget = g_object_get_data(G_OBJECT(model), "minor");
1739 //todo g_assert here and null test
1744 gtk_tree_model_get(model
, iter
, GPOINTER_TO_INT(user_data
), &tmp
, -1);
1748 g_snprintf(buf
, sizeof(buf
), "%.2f %%", tmp
);
1749 g_object_set(renderer
, "text", buf
, NULL
);
1752 g_object_set(renderer
, "text", "", NULL
);
1757 static void ui_list_repdist_amount_cell_data_function (GtkTreeViewColumn
*col
,
1758 GtkCellRenderer
*renderer
,
1759 GtkTreeModel
*model
,
1765 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1767 gtk_tree_model_get(model
, iter
, GPOINTER_TO_INT(user_data
), &value
, -1);
1771 mystrfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, GLOBALS
->minor
);
1772 //hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, GLOBALS->kcur);
1774 color
= get_normal_color_amount(value
);
1776 g_object_set(renderer
,
1777 "foreground", color
,
1782 g_object_set(renderer
, "text", "", NULL
);
1787 static GtkTreeViewColumn
*ui_list_repdist_amount_column(gchar
*name
, gint id
)
1789 GtkTreeViewColumn
*column
;
1790 GtkCellRenderer
*renderer
;
1792 column
= gtk_tree_view_column_new();
1793 gtk_tree_view_column_set_title(column
, name
);
1794 renderer
= gtk_cell_renderer_text_new ();
1795 g_object_set(renderer
, "xalign", 1.0, NULL
);
1796 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1797 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_list_repdist_amount_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1798 gtk_tree_view_column_set_alignment (column
, 0.5);
1799 //gtk_tree_view_column_set_sort_column_id (column, id);
1803 static GtkTreeViewColumn
*ui_list_repdist_rate_column(gint id
)
1805 GtkTreeViewColumn
*column
;
1806 GtkCellRenderer
*renderer
;
1808 column
= gtk_tree_view_column_new();
1809 gtk_tree_view_column_set_title(column
, "%");
1810 renderer
= gtk_cell_renderer_text_new ();
1811 g_object_set(renderer
, "xalign", 1.0, "yalign", 1.0, "scale", 0.8, "scale-set", TRUE
, NULL
);
1813 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1814 //gtk_tree_view_column_add_attribute(column, renderer, "text", id);
1815 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_list_repdist_rate_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1816 gtk_tree_view_column_set_alignment (column
, 0.5);
1817 //gtk_tree_view_column_set_sort_column_id (column, id);
1819 //gtk_tree_view_column_set_visible(column, FALSE);
1825 ** create our statistic list
1827 static GtkWidget
*ui_list_repdist_create(void)
1829 GtkListStore
*store
;
1831 GtkCellRenderer
*renderer
;
1832 GtkTreeViewColumn
*column
;
1834 /* create list store */
1835 store
= gtk_list_store_new(
1849 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1850 g_object_unref(store
);
1852 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view
), PREFS
->rules_hint
);
1855 column
= gtk_tree_view_column_new();
1856 gtk_tree_view_column_set_title(column
, _("Result"));
1857 renderer
= gtk_cell_renderer_text_new ();
1858 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1859 //gtk_tree_view_column_set_cell_data_func(column, renderer, ope_result_cell_data_function, NULL, NULL);
1860 gtk_tree_view_column_add_attribute(column
, renderer
, "text", LST_REPDIST_NAME
);
1861 //gtk_tree_view_column_set_sort_column_id (column, LST_REPDIST_NAME);
1862 gtk_tree_view_column_set_resizable(column
, TRUE
);
1863 gtk_tree_view_column_set_alignment (column
, 0.5);
1864 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1866 /* column: Expense */
1867 column
= ui_list_repdist_amount_column(_("Expense"), LST_REPDIST_EXPENSE
);
1868 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1869 column
= ui_list_repdist_rate_column(LST_REPDIST_EXPRATE
);
1870 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1872 /* column: Income */
1873 column
= ui_list_repdist_amount_column(_("Income"), LST_REPDIST_INCOME
);
1874 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1875 column
= ui_list_repdist_rate_column(LST_REPDIST_INCRATE
);
1876 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1878 /* column: Balance */
1879 column
= ui_list_repdist_amount_column(_("Balance"), LST_REPDIST_BALANCE
);
1880 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1881 column
= ui_list_repdist_rate_column(LST_REPDIST_BALRATE
);
1882 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1884 /* column last: empty */
1885 column
= gtk_tree_view_column_new();
1886 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1889 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
);
1890 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
);
1891 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
);
1892 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
);
1898 static gint
ui_list_repdist_compare_func (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
)
1900 gint sortcol
= GPOINTER_TO_INT(userdata
);
1905 gtk_tree_model_get(model
, a
,
1906 LST_REPDIST_POS
, &pos1
,
1909 gtk_tree_model_get(model
, b
,
1910 LST_REPDIST_POS
, &pos2
,
1916 case LST_REPDIST_POS
:
1917 retval
= pos2
- pos1
;
1920 retval
= (ABS(val1
) - ABS(val2
)) > 0 ? 1 : -1;
1924 //DB( g_print(" sort %d=%d or %.2f=%.2f :: %d\n", pos1,pos2, val1, val2, ret) );