]> Dogcows Code - chaz/homebank/blob - src/rep-stats.c
import homebank-5.2.6
[chaz/homebank] / src / rep-stats.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20
21 #include "homebank.h"
22
23 #include "rep-stats.h"
24
25 #include "list-operation.h"
26 #include "gtk-chart.h"
27 #include "gtk-dateentry.h"
28
29 #include "dsp-mainwindow.h"
30 #include "ui-account.h"
31 #include "ui-payee.h"
32 #include "ui-category.h"
33 #include "ui-filter.h"
34 #include "ui-transaction.h"
35
36 /****************************************************************************/
37 /* Debug macros */
38 /****************************************************************************/
39 #define MYDEBUG 0
40
41 #if MYDEBUG
42 #define DB(x) (x);
43 #else
44 #define DB(x);
45 #endif
46
47 /* our global datas */
48 extern struct HomeBank *GLOBALS;
49 extern struct Preferences *PREFS;
50
51
52 /* prototypes */
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
62
63 static GtkRadioActionEntry radio_entries[] = {
64 { "List" , ICONNAME_HB_VIEW_LIST , N_("List") , NULL, N_("View results as list"), 0 },
65 { "Column" , ICONNAME_HB_VIEW_COLUMN , N_("Column") , NULL, N_("View results as column"), 1 },
66 { "Donut" , ICONNAME_HB_VIEW_DONUT , N_("Donut") , NULL, N_("View results as donut"), 2 },
67 };
68 static guint n_radio_entries = G_N_ELEMENTS (radio_entries);
69
70
71 static GtkActionEntry entries[] = {
72 { "Filter" , ICONNAME_HB_FILTER , N_("Filter") , NULL, N_("Edit filter"), G_CALLBACK (ui_repdist_action_filter) },
73 { "Refresh" , ICONNAME_HB_REFRESH , N_("Refresh"), NULL, N_("Refresh results"), G_CALLBACK (ui_repdist_action_refresh) },
74
75 //{ "Export" , ICONNAME_HB_FILE_EXPORT , N_("Export") , NULL, N_("Export as CSV"), G_CALLBACK (ui_repdist_action_export) },
76 };
77 static guint n_entries = G_N_ELEMENTS (entries);
78
79
80 static GtkToggleActionEntry toggle_entries[] = {
81 { "Detail", ICONNAME_HB_OPE_SHOW, /* name, icon-name */
82 N_("Detail"), NULL, /* label, accelerator */
83 N_("Toggle detail"), /* tooltip */
84 G_CALLBACK (ui_repdist_action_detail),
85 FALSE }, /* is_active */
86
87 { "Legend", ICONNAME_HB_SHOW_LEGEND, /* name, icon-name */
88 N_("Legend"), NULL, /* label, accelerator */
89 N_("Toggle legend"), /* tooltip */
90 G_CALLBACK (ui_repdist_action_legend),
91 TRUE }, /* is_active */
92
93 { "Rate", ICONNAME_HB_SHOW_RATE, /* name, icon-name */
94 N_("Rate"), NULL, /* label, accelerator */
95 N_("Toggle rate"), /* tooltip */
96 G_CALLBACK (ui_repdist_action_rate),
97 FALSE }, /* is_active */
98
99 };
100 static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);
101
102
103
104 static const gchar *ui_info =
105 "<ui>"
106 " <toolbar name='ToolBar'>"
107 " <toolitem action='List'/>"
108 " <toolitem action='Column'/>"
109 " <toolitem action='Donut'/>"
110 " <separator/>"
111 " <toolitem action='Detail'/>"
112 " <toolitem action='Legend'/>"
113 " <toolitem action='Rate'/>"
114 " <separator/>"
115 " <toolitem action='Filter'/>"
116 " <toolitem action='Refresh'/>"
117 " <separator/>"
118 //" <toolitem action='Export'/>"
119 // replaced by a menubutton
120 " </toolbar>"
121 "</ui>";
122
123
124
125 static void ui_repdist_date_change(GtkWidget *widget, gpointer user_data);
126 static void ui_repdist_range_change(GtkWidget *widget, gpointer user_data);
127 static void ui_repdist_detail(GtkWidget *widget, gpointer user_data);
128 static void ui_repdist_update(GtkWidget *widget, gpointer user_data);
129 static void ui_repdist_update_total(GtkWidget *widget, gpointer user_data);
130 static void ui_repdist_compute(GtkWidget *widget, gpointer user_data);
131 static void ui_repdist_sensitive(GtkWidget *widget, gpointer user_data);
132 static void ui_repdist_toggle_detail(GtkWidget *widget, gpointer user_data);
133 static void ui_repdist_toggle_legend(GtkWidget *widget, gpointer user_data);
134 static void ui_repdist_toggle_minor(GtkWidget *widget, gpointer user_data);
135 static void ui_repdist_toggle_rate(GtkWidget *widget, gpointer user_data);
136 static GtkWidget *ui_list_repdist_create(void);
137 static void ui_repdist_update_daterange(GtkWidget *widget, gpointer user_data);
138 static void ui_repdist_update_date_widget(GtkWidget *widget, gpointer user_data);
139
140 static GString *ui_list_repdist_to_string(GtkTreeView *treeview, gboolean clipboard);
141 static gint ui_list_repdist_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata);
142
143
144
145 HbKvData CYA_REPORT_SRC[] = {
146 { REPORT_SRC_CATEGORY, N_("Category") },
147 { REPORT_SRC_SUBCATEGORY, N_("Subcategory") },
148 { REPORT_SRC_PAYEE, N_("Payee") },
149 { REPORT_SRC_ACCOUNT, N_("Account") },
150 { REPORT_SRC_TAG, N_("Tag") },
151 { REPORT_SRC_MONTH, N_("Month") },
152 { REPORT_SRC_YEAR, N_("Year") },
153 { 0, NULL }
154 };
155
156
157 HbKvData CYA_REPORT_TYPE[] = {
158 { REPORT_TYPE_ALL, N_("Exp. & Inc.") },
159 { REPORT_TYPE_EXPENSE, N_("Expense") },
160 { REPORT_TYPE_INCOME, N_("Income") },
161 { REPORT_TYPE_BALANCE, N_("Balance")} ,
162 { 0, NULL }
163 };
164
165 extern gchar *CYA_REPORT_MODE[];
166 extern HbKvData CYA_REPORT_INTVL[];
167
168 extern gchar *CYA_ABMONTHS[];
169
170 /* action functions -------------------- */
171
172 static void ui_repdist_action_viewlist(GtkAction *action, gpointer user_data)
173 {
174 struct ui_repdist_data *data = user_data;
175
176 gtk_notebook_set_current_page(GTK_NOTEBOOK(data->GR_result), 0);
177 ui_repdist_sensitive(data->window, NULL);
178 }
179
180 static void ui_repdist_action_viewbar(GtkAction *action, gpointer user_data)
181 {
182 struct ui_repdist_data *data = user_data;
183
184 gtk_notebook_set_current_page(GTK_NOTEBOOK(data->GR_result), 1);
185 gtk_chart_set_type (GTK_CHART(data->RE_chart), CHART_TYPE_COL);
186 ui_repdist_sensitive(data->window, NULL);
187 }
188
189
190 static void ui_repdist_action_viewpie(GtkAction *action, gpointer user_data)
191 {
192 struct ui_repdist_data *data = user_data;
193 gint tmpview;
194
195 gtk_notebook_set_current_page(GTK_NOTEBOOK(data->GR_result), 1);
196
197 gtk_chart_set_type (GTK_CHART(data->RE_chart), CHART_TYPE_PIE);
198 ui_repdist_sensitive(data->window, NULL);
199
200 tmpview = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_type));
201
202 // ensure not exp & inc for piechart
203 if( tmpview == REPORT_TYPE_ALL )
204 {
205 //g_signal_handler_block(data->CY_type, data->handler_id[HID_REPDIST_VIEW]);
206 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_type), REPORT_TYPE_EXPENSE);
207 //g_signal_handler_unblock(data->CY_type, data->handler_id[HID_REPDIST_VIEW]);
208 }
209
210 }
211
212
213 static void ui_repdist_action_mode (GtkRadioAction *action, GtkRadioAction *current, gpointer user_data)
214 {
215 gint value;
216
217 value = gtk_radio_action_get_current_value(GTK_RADIO_ACTION(action));
218 switch( value )
219 {
220 case 0:
221 ui_repdist_action_viewlist(GTK_ACTION(action), user_data);
222 break;
223 case 1:
224 ui_repdist_action_viewbar(GTK_ACTION(action), user_data);
225 break;
226 case 2:
227 ui_repdist_action_viewpie(GTK_ACTION(action), user_data);
228 break;
229 }
230 }
231
232
233 static void ui_repdist_action_detail(GtkAction *action, gpointer user_data)
234 {
235 struct ui_repdist_data *data = user_data;
236
237 ui_repdist_toggle_detail(data->window, NULL);
238 }
239
240 static void ui_repdist_action_legend(GtkAction *action, gpointer user_data)
241 {
242 struct ui_repdist_data *data = user_data;
243
244 ui_repdist_toggle_legend(data->window, NULL);
245 }
246
247 static void ui_repdist_action_rate(GtkAction *action, gpointer user_data)
248 {
249 struct ui_repdist_data *data = user_data;
250
251 ui_repdist_toggle_rate(data->window, NULL);
252 }
253
254 static void ui_repdist_action_filter(GtkAction *action, gpointer user_data)
255 {
256 struct ui_repdist_data *data = user_data;
257
258 //debug
259 //create_deffilter_window(data->filter, TRUE);
260
261 if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, TRUE, FALSE) != GTK_RESPONSE_REJECT)
262 {
263 ui_repdist_compute(data->window, NULL);
264 ui_repdist_update_date_widget(data->window, NULL);
265 ui_repdist_update_daterange(data->window, NULL);
266
267 g_signal_handler_block(data->CY_range, data->handler_id[HID_REPDIST_RANGE]);
268 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), FLT_RANGE_OTHER);
269 g_signal_handler_unblock(data->CY_range, data->handler_id[HID_REPDIST_RANGE]);
270
271 }
272 }
273
274 static void ui_repdist_action_refresh(GtkAction *action, gpointer user_data)
275 {
276 struct ui_repdist_data *data = user_data;
277
278 ui_repdist_compute(data->window, NULL);
279 }
280
281 /*static void ui_repdist_action_export(GtkAction *action, gpointer user_data)
282 {
283 struct ui_repdist_data *data = user_data;
284
285 ui_repdist_export_csv(data->window, NULL);
286 }*/
287
288
289
290 /* ======================== */
291
292
293
294 /*
295 ** ============================================================================
296 */
297
298
299 static void ui_repdist_date_change(GtkWidget *widget, gpointer user_data)
300 {
301 struct ui_repdist_data *data;
302
303 DB( g_print("\n[repdist] date change\n") );
304
305 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
306
307 data->filter->mindate = gtk_date_entry_get_date(GTK_DATE_ENTRY(data->PO_mindate));
308 data->filter->maxdate = gtk_date_entry_get_date(GTK_DATE_ENTRY(data->PO_maxdate));
309
310 // set min/max date for both widget
311 gtk_date_entry_set_maxdate(GTK_DATE_ENTRY(data->PO_mindate), data->filter->maxdate);
312 gtk_date_entry_set_mindate(GTK_DATE_ENTRY(data->PO_maxdate), data->filter->mindate);
313
314 g_signal_handler_block(data->CY_range, data->handler_id[HID_REPDIST_RANGE]);
315 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), FLT_RANGE_OTHER);
316 g_signal_handler_unblock(data->CY_range, data->handler_id[HID_REPDIST_RANGE]);
317
318 ui_repdist_compute(widget, NULL);
319 ui_repdist_update_daterange(widget, NULL);
320
321 }
322
323
324 static void ui_repdist_range_change(GtkWidget *widget, gpointer user_data)
325 {
326 struct ui_repdist_data *data;
327 gint range;
328
329 DB( g_print("\n[repdist] range change\n") );
330
331 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
332
333 range = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_range));
334
335 if(range != FLT_RANGE_OTHER)
336 {
337 filter_preset_daterange_set(data->filter, range, 0);
338
339 ui_repdist_update_date_widget(data->window, NULL);
340
341 ui_repdist_compute(data->window, NULL);
342 ui_repdist_update_daterange(data->window, NULL);
343 }
344 else
345 {
346 if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, TRUE, FALSE) != GTK_RESPONSE_REJECT)
347 {
348 ui_repdist_update_date_widget(data->window, NULL);
349 ui_repdist_compute(data->window, NULL);
350 ui_repdist_update_daterange(data->window, NULL);
351 }
352 }
353 }
354
355
356 static void ui_repdist_update(GtkWidget *widget, gpointer user_data)
357 {
358 struct ui_repdist_data *data;
359 gboolean byamount;
360 GtkTreeModel *model;
361 gint page, tmpsrc, tmptype, column;
362 gboolean xval;
363 gchar *title;
364
365 DB( g_print("\n[repdist] update\n") );
366
367 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
368
369
370 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_report));
371 byamount = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_byamount));
372 tmptype = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_type));
373 //tmpsrc = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_src));
374 tmpsrc = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_src));
375
376 //debug option
377 DB( g_print(" option: byamount=%d tmptype=%d '%s' tmpsrc=%d '%s'\n\n", byamount, tmptype, hbtk_get_label(CYA_REPORT_TYPE,tmptype), tmpsrc, hbtk_get_label(CYA_REPORT_SRC,tmpsrc)) );
378
379 // ensure not exp & inc for piechart
380 page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->GR_result));
381
382 if( page == 2 && tmptype == REPORT_TYPE_ALL )
383 {
384 g_signal_handler_block(data->CY_type, data->handler_id[HID_REPDIST_VIEW]);
385 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_type), 1);
386 g_signal_handler_unblock(data->CY_type, data->handler_id[HID_REPDIST_VIEW]);
387 tmptype = REPORT_TYPE_EXPENSE;
388 }
389
390 // define view/sort column
391 column = LST_REPDIST_POS;
392
393 if( byamount )
394 {
395 switch( tmptype )
396 {
397 case REPORT_TYPE_ALL: //Inc & Exp
398 case REPORT_TYPE_BALANCE:
399 column = LST_REPDIST_BALANCE;
400 break;
401 case REPORT_TYPE_EXPENSE:
402 column = LST_REPDIST_EXPENSE;
403 break;
404 case REPORT_TYPE_INCOME:
405 column = LST_REPDIST_INCOME;
406 break;
407 }
408 }
409
410 DB( g_print(" sort on column %d\n\n", column) );
411
412 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), column, GTK_SORT_DESCENDING);
413
414 gtk_chart_set_color_scheme(GTK_CHART(data->RE_chart), PREFS->report_color_scheme);
415
416 //TRANSLATORS: example 'Expense by Category'
417 title = g_strdup_printf(_("%s by %s"), hbtk_get_label(CYA_REPORT_TYPE,tmptype), hbtk_get_label(CYA_REPORT_SRC, tmpsrc) );
418
419 /* update absolute or not */
420 gboolean abs = (tmptype == REPORT_TYPE_EXPENSE || tmptype == REPORT_TYPE_INCOME) ? TRUE : FALSE;
421 gtk_chart_set_absolute(GTK_CHART(data->RE_chart), abs);
422
423 /* show xval for month/year and no by amount display */
424 xval = FALSE;
425
426 if( !byamount && (tmpsrc == REPORT_SRC_MONTH || tmpsrc == REPORT_SRC_YEAR) )
427 {
428 xval = TRUE;
429 /*switch( tmpsrc)
430 {
431 case REPORT_SRC_MONTH:
432 gtk_chart_set_every_xval(GTK_CHART(data->RE_chart), 4);
433 break;
434 case REPORT_SRC_YEAR:
435 gtk_chart_set_every_xval(GTK_CHART(data->RE_chart), 2);
436 break;
437 }*/
438 }
439
440 gtk_chart_show_xval(GTK_CHART(data->RE_chart), xval);
441
442
443 /* update bar chart */
444 if( tmptype == REPORT_TYPE_ALL ) //dual exp/inc
445 {
446 DB( g_print(" set bar to dual exp %d/inc %d\n\n", LST_REPDIST_EXPENSE, LST_REPDIST_INCOME) );
447 gtk_chart_set_dualdatas(GTK_CHART(data->RE_chart), model, LST_REPDIST_EXPENSE, LST_REPDIST_INCOME, title, NULL);
448 }
449 else
450 {
451 // /!\ hazardous here
452 column = LST_REPDIST_EXPENSE+(tmptype-1)*2;
453 DB( g_print(" set bar to %d\n\n", column) );
454 gtk_chart_set_datas(GTK_CHART(data->RE_chart), model, column, title, NULL);
455 }
456
457
458 g_free(title);
459
460 }
461
462
463 static void ui_repdist_update_date_widget(GtkWidget *widget, gpointer user_data)
464 {
465 struct ui_repdist_data *data;
466
467 DB( g_print("\n[repdist] update date widget\n") );
468
469 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
470
471 g_signal_handler_block(data->PO_mindate, data->handler_id[HID_REPDIST_MINDATE]);
472 g_signal_handler_block(data->PO_maxdate, data->handler_id[HID_REPDIST_MAXDATE]);
473
474 gtk_date_entry_set_date(GTK_DATE_ENTRY(data->PO_mindate), data->filter->mindate);
475 gtk_date_entry_set_date(GTK_DATE_ENTRY(data->PO_maxdate), data->filter->maxdate);
476
477 g_signal_handler_unblock(data->PO_mindate, data->handler_id[HID_REPDIST_MINDATE]);
478 g_signal_handler_unblock(data->PO_maxdate, data->handler_id[HID_REPDIST_MAXDATE]);
479
480 }
481
482
483 static void ui_repdist_update_daterange(GtkWidget *widget, gpointer user_data)
484 {
485 struct ui_repdist_data *data;
486 gchar *daterange;
487
488 DB( g_print("\n[repdist] update daterange\n") );
489
490 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
491
492 daterange = filter_daterange_text_get(data->filter);
493 gtk_label_set_markup(GTK_LABEL(data->TX_daterange), daterange);
494 g_free(daterange);
495 }
496
497 static void ui_repdist_update_total(GtkWidget *widget, gpointer user_data)
498 {
499 struct ui_repdist_data *data;
500 //gboolean minor;
501
502 DB( g_print("\n[repdist] update total\n") );
503
504 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
505
506 //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
507
508 hb_label_set_colvalue(GTK_LABEL(data->TX_total[0]), data->total_expense, GLOBALS->kcur, GLOBALS->minor);
509 hb_label_set_colvalue(GTK_LABEL(data->TX_total[1]), data->total_income, GLOBALS->kcur, GLOBALS->minor);
510 hb_label_set_colvalue(GTK_LABEL(data->TX_total[2]), data->total_expense + data->total_income, GLOBALS->kcur, GLOBALS->minor);
511
512
513 }
514
515
516 static void ui_repdist_export_result_clipboard(GtkWidget *widget, gpointer user_data)
517 {
518 struct ui_repdist_data *data;
519 GtkClipboard *clipboard;
520 GString *node;
521
522 DB( g_print("\n[repdist] export result clipboard\n") );
523
524 data = user_data;
525 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
526
527 node = ui_list_repdist_to_string(GTK_TREE_VIEW(data->LV_report), TRUE);
528
529 clipboard = gtk_clipboard_get_default(gdk_display_get_default());
530 gtk_clipboard_set_text(clipboard, node->str, node->len);
531
532 g_string_free(node, TRUE);
533 }
534
535
536 static void ui_repdist_export_result_csv(GtkWidget *widget, gpointer user_data)
537 {
538 struct ui_repdist_data *data;
539 gchar *filename = NULL;
540 GString *node;
541 GIOChannel *io;
542 gchar *name;
543 gint tmpsrc;
544
545 DB( g_print("\n[repdist] export result csv\n") );
546
547 data = user_data;
548 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
549
550 //tmpsrc = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_src));
551 tmpsrc = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_src));
552
553 name = g_strdup_printf("hb-repstat_%s.csv", hbtk_get_label(CYA_REPORT_SRC,tmpsrc));
554
555 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, name) == TRUE )
556 {
557 DB( g_print(" + filename is %s\n", filename) );
558 io = g_io_channel_new_file(filename, "w", NULL);
559 if(io != NULL)
560 {
561 node = ui_list_repdist_to_string(GTK_TREE_VIEW(data->LV_report), FALSE);
562 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
563 g_io_channel_unref (io);
564 g_string_free(node, TRUE);
565 }
566 g_free( filename );
567 }
568 g_free(name);
569 }
570
571
572 static void ui_repdist_export_detail_clipboard(GtkWidget *widget, gpointer user_data)
573 {
574 struct ui_repdist_data *data;
575 GtkClipboard *clipboard;
576 GString *node;
577
578 DB( g_print("\n[repdist] export detail clipboard\n") );
579
580 data = user_data;
581 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
582
583 node = list_txn_to_string(GTK_TREE_VIEW(data->LV_detail), TRUE);
584
585 clipboard = gtk_clipboard_get_default(gdk_display_get_default());
586 gtk_clipboard_set_text(clipboard, node->str, node->len);
587
588 g_string_free(node, TRUE);
589 }
590
591
592 static void ui_repdist_export_detail_csv(GtkWidget *widget, gpointer user_data)
593 {
594 struct ui_repdist_data *data;
595 gchar *filename = NULL;
596 GString *node;
597 GIOChannel *io;
598 gchar *name;
599 gint tmpsrc;
600
601 DB( g_print("\n[repdist] export detail csv\n") );
602
603 data = user_data;
604 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
605
606 //tmpsrc = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_src));
607 tmpsrc = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_src));
608 name = g_strdup_printf("hb-repstat-detail_%s.csv", hbtk_get_label(CYA_REPORT_SRC,tmpsrc));
609
610 if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, name) == TRUE )
611 {
612 DB( g_print(" + filename is %s\n", filename) );
613
614 io = g_io_channel_new_file(filename, "w", NULL);
615 if(io != NULL)
616 {
617 node = list_txn_to_string(GTK_TREE_VIEW(data->LV_detail), FALSE);
618 g_io_channel_write_chars(io, node->str, -1, NULL, NULL);
619
620 g_io_channel_unref (io);
621 g_string_free(node, TRUE);
622 }
623
624 g_free( filename );
625 }
626
627 g_free(name);
628 }
629
630
631 static void ui_repdist_detail(GtkWidget *widget, gpointer user_data)
632 {
633 struct ui_repdist_data *data;
634 guint active = GPOINTER_TO_INT(user_data);
635 guint tmpsrc;
636 GList *list;
637 GtkTreeModel *model;
638 GtkTreeIter iter;
639
640 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
641
642 DB( g_print("\n[repdist] detail\n") );
643
644 /* clear and detach our model */
645 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_detail));
646 gtk_list_store_clear (GTK_LIST_STORE(model));
647
648 if(data->detail)
649 {
650 //tmpsrc = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_src));
651 tmpsrc = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_src));
652
653 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
654 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_detail), NULL); /* Detach model from view */
655
656 /* fill in the model */
657 list = g_queue_peek_head_link(data->txn_queue);
658 while (list != NULL)
659 {
660 Transaction *ope = list->data;
661 gdouble dtlamt = ope->amount;
662
663 if(filter_txn_match(data->filter, ope) == 1)
664 {
665 gboolean match = FALSE;
666 guint i, pos = 0;
667
668 if( tmpsrc != REPORT_SRC_TAG )
669 {
670 if( (tmpsrc == REPORT_SRC_CATEGORY || tmpsrc == REPORT_SRC_SUBCATEGORY) && ope->flags & OF_SPLIT )
671 {
672 guint nbsplit = da_splits_length(ope->splits);
673 Split *split;
674
675 dtlamt = 0.0;
676 for(i=0;i<nbsplit;i++)
677 {
678 split = da_splits_get(ope->splits, i);
679 pos = category_report_id(split->kcat, (tmpsrc == REPORT_SRC_SUBCATEGORY) ? TRUE : FALSE);
680 if( pos == active )
681 {
682 match = TRUE;
683 dtlamt += split->amount;
684 // no more break here as we need to compute split 4 cat
685 //break;
686 }
687 }
688 }
689 else
690 {
691 pos = report_items_get_pos(tmpsrc, data->filter->mindate, ope);
692 if( pos == active )
693 {
694 match = TRUE;
695 }
696 }
697 }
698 else
699 /* the TAG process is particular */
700 {
701 if(ope->tags != NULL)
702 {
703 guint32 *tptr = ope->tags;
704
705 while(*tptr)
706 {
707 pos = *tptr - 1;
708
709 DB( g_print(" -> storing tag %d %.2f\n", pos, ope->amount) );
710
711 if( pos == active )
712 {
713 match = TRUE;
714 break;
715 }
716 tptr++;
717 }
718 }
719 }
720
721 if( match == TRUE )
722 {
723 gtk_list_store_insert_with_values (GTK_LIST_STORE(model), &iter, -1,
724 MODEL_TXN_POINTER, ope,
725 MODEL_TXN_SPLITAMT, dtlamt,
726 -1);
727 }
728 }
729
730 list = g_list_next(list);
731 }
732
733 /* Re-attach model to view */
734 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_detail), model);
735 g_object_unref(model);
736
737 gtk_tree_view_columns_autosize( GTK_TREE_VIEW(data->LV_detail) );
738
739 }
740
741 }
742
743
744 static void ui_repdist_compute(GtkWidget *widget, gpointer user_data)
745 {
746 struct ui_repdist_data *data;
747 gint tmpsrc, tmptype;
748 guint32 from, to;
749 GtkTreeModel *model;
750 GtkTreeIter iter;
751 GList *list, *tmplist = NULL;
752 guint n_result, sortid;
753 guint i;
754 gdouble *tmp_income, *tmp_expense;
755 gdouble exprate, incrate, balrate;
756
757 DB( g_print("\n[repdist] compute\n") );
758
759 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
760
761 //tmpsrc = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_src));
762 tmpsrc = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_src));
763 tmptype = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_type));
764
765
766 DB( g_print(" for=%d,type=%d\n", tmpsrc, tmptype) );
767
768 //get our min max date
769 from = data->filter->mindate;
770 to = data->filter->maxdate;
771 if(to < from) return;
772
773
774 g_queue_free (data->txn_queue);
775 data->txn_queue = hbfile_transaction_get_partial(data->filter->mindate, data->filter->maxdate);
776
777 DB( g_print(" nb-txn=%d\n", g_queue_get_length (data->txn_queue) ) );
778
779 //todo: remove this later on
780 n_result = report_items_count(tmpsrc, data->filter->mindate, data->filter->maxdate);
781
782 switch(tmpsrc)
783 {
784 case REPORT_SRC_CATEGORY:
785 case REPORT_SRC_SUBCATEGORY:
786 tmplist = category_glist_sorted(1);
787 break;
788 case REPORT_SRC_PAYEE:
789 tmplist = payee_glist_sorted(1);
790 break;
791 case REPORT_SRC_ACCOUNT:
792 tmplist = account_glist_sorted(1);
793 break;
794 case REPORT_SRC_TAG:
795 tmplist = tag_glist_sorted(1);
796 break;
797 }
798
799 DB( g_print(" %s :: n_result=%d\n", hbtk_get_label(CYA_REPORT_SRC,tmpsrc), n_result) );
800
801 /* allocate some memory */
802 tmp_expense = g_malloc0((n_result+2) * sizeof(gdouble));
803 tmp_income = g_malloc0((n_result+2) * sizeof(gdouble));
804
805 data->total_expense = 0.0;
806 data->total_income = 0.0;
807
808 if(tmp_expense && tmp_income)
809 {
810
811 DB( g_print(" - ok memory\n") );
812
813 /* compute the results */
814 list = g_queue_peek_head_link(data->txn_queue);
815 while (list != NULL)
816 {
817 Transaction *ope = list->data;
818
819 DB( g_print("** testing '%s', cat=%d==> %d\n", ope->memo, ope->kcat, filter_txn_match(data->filter, ope)) );
820
821 if( (filter_txn_match(data->filter, ope) == 1) )
822 {
823 guint32 pos = 0;
824 gdouble trn_amount;
825
826 DB( g_print(" - should insert\n") );
827
828 //trn_amount = ope->amount;
829 trn_amount = hb_amount_base(ope->amount, ope->kcur);
830
831 //#1562372 in case of a split we need to take amount for filter categories only
832 if( ope->flags & OF_SPLIT )
833 {
834 guint nbsplit = da_splits_length(ope->splits);
835 Split *split;
836 Category *catentry;
837 gint sinsert;
838
839 trn_amount = 0.0;
840
841 for(i=0;i<nbsplit;i++)
842 {
843 split = da_splits_get(ope->splits, i);
844 catentry = da_cat_get(split->kcat);
845 if(catentry == NULL) continue;
846 sinsert = ( catentry->flt_select == TRUE ) ? 1 : 0;
847 if(data->filter->option[FILTER_CATEGORY] == 2) sinsert ^= 1;
848
849 DB( g_print(" split '%s' insert=%d\n",catentry->name, sinsert) );
850
851 if( (data->filter->option[FILTER_CATEGORY] == 0) || sinsert)
852 {
853 trn_amount += hb_amount_base(split->amount, ope->kcur);
854 }
855 }
856
857 }
858
859
860 if( tmpsrc != REPORT_SRC_TAG )
861 {
862 if( (tmpsrc == REPORT_SRC_CATEGORY || tmpsrc == REPORT_SRC_SUBCATEGORY) && ope->flags & OF_SPLIT )
863 {
864 guint nbsplit = da_splits_length(ope->splits);
865 Split *split;
866 Category *catentry;
867 gint sinsert;
868
869 for(i=0;i<nbsplit;i++)
870 {
871 split = da_splits_get(ope->splits, i);
872 catentry = da_cat_get(split->kcat);
873 if(catentry == NULL) continue;
874 sinsert = ( catentry->flt_select == TRUE ) ? 1 : 0;
875 if(data->filter->option[FILTER_CATEGORY] == 2) sinsert ^= 1;
876
877 DB( g_print(" split '%s' insert=%d\n",catentry->name, sinsert) );
878
879 if( (data->filter->option[FILTER_CATEGORY] == 0) || sinsert)
880 {
881 switch(tmpsrc)
882 {
883 case REPORT_SRC_CATEGORY:
884 {
885 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
886 }
887 break;
888 case REPORT_SRC_SUBCATEGORY:
889 pos = split->kcat;
890 break;
891 }
892
893 trn_amount = hb_amount_base(split->amount, ope->kcur);
894 //trn_amount = split->amount;
895
896 if(trn_amount > 0.0)
897 {
898 tmp_income[pos] += trn_amount;
899 data->total_income += trn_amount;
900 }
901 else
902 {
903 tmp_expense[pos] += trn_amount;
904 data->total_expense += trn_amount;
905 }
906
907 }
908 // end insert
909
910 }
911 }
912 else
913 {
914 pos = report_items_get_pos(tmpsrc, from, ope);
915 if(trn_amount > 0.0)
916 {
917 tmp_income[pos] += trn_amount;
918 data->total_income += trn_amount;
919 }
920 else
921 {
922 tmp_expense[pos] += trn_amount;
923 data->total_expense += trn_amount;
924 }
925 }
926 }
927 else
928 /* the TAG process is particularly */
929 {
930 if(ope->tags != NULL)
931 {
932 guint32 *tptr = ope->tags;
933
934 while(*tptr)
935 {
936 pos = *tptr - 1;
937
938 DB( g_print(" -> storing tag %d %s %.2f\n", pos, da_tag_get(*tptr)->name, trn_amount) );
939
940 if(trn_amount > 0.0)
941 {
942 tmp_income[pos] += trn_amount;
943 data->total_income += trn_amount;
944 }
945 else
946 {
947 tmp_expense[pos] += trn_amount;
948 data->total_expense += trn_amount;
949 }
950 tptr++;
951 }
952 }
953 }
954
955 // fix total according to selection
956 //if(tmpkind==0 && !tmp_expense[pos]) { data->total_income -= ope->amount; }
957 //if(tmpkind==1 && !tmp_income[pos] ) { data->total_expense -= ope->amount; }
958
959
960 }
961
962 list = g_list_next(list);
963 }
964
965 /* clear and detach our model */
966 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_report));
967 gtk_list_store_clear (GTK_LIST_STORE(model));
968 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
969 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_report), NULL); /* Detach model from view */
970
971 /* insert into the treeview */
972 for(i=0, sortid=0; i<n_result; i++)
973 {
974 gchar *name, *fullcatname;
975 gchar buffer[64];
976 GDate *date;
977
978 name = NULL;
979 fullcatname = NULL;
980
981 DB( g_print("try to insert item %d - %.2f %.2f\n", i, tmp_expense[i], tmp_income[i]) );
982
983
984 /* filter empty results */
985 // 1829630 crash _cairo_arc_in_direction (account was missing here)
986
987 if( !(tmpsrc == REPORT_SRC_MONTH || tmpsrc == REPORT_SRC_YEAR) )
988 {
989 if( tmptype == 1 && !tmp_expense[i] ) continue;
990 if( tmptype == 2 && !tmp_income[i] ) continue;
991 if( !tmp_expense[i] && !tmp_income[i] ) continue;
992 }
993
994 /* get the result name */
995 switch(tmpsrc)
996 {
997 case REPORT_SRC_CATEGORY:
998 {
999 Category *entry = da_cat_get(i);
1000 if(entry != NULL)
1001 {
1002 name = entry->key == 0 ? _("(no category)") : entry->name;
1003
1004 sortid = g_list_index(tmplist, entry);
1005 }
1006 }
1007 break;
1008
1009 case REPORT_SRC_SUBCATEGORY:
1010 {
1011 Category *entry = da_cat_get(i);
1012 if(entry != NULL)
1013 {
1014 if(entry->flags & GF_SUB)
1015 {
1016 Category *parent = da_cat_get(entry->parent);
1017
1018 fullcatname = g_strdup_printf("%s : %s", parent->name, entry->name);
1019 name = fullcatname;
1020 }
1021 else
1022 name = entry->key == 0 ? _("(no category)") : entry->name;
1023
1024 sortid = g_list_index(tmplist, entry);
1025 }
1026 }
1027 break;
1028
1029 case REPORT_SRC_PAYEE:
1030 {
1031 Payee *entry = da_pay_get(i);
1032 if(entry != NULL)
1033 {
1034 name = entry->key == 0 ? _("(no payee)") : entry->name;
1035 sortid = g_list_index(tmplist, entry);
1036 }
1037 }
1038 break;
1039
1040 case REPORT_SRC_ACCOUNT:
1041 {
1042 Account *entry = da_acc_get(i);
1043 if(entry != NULL)
1044 {
1045 name = entry->name;
1046 sortid = g_list_index(tmplist, entry);
1047 }
1048 }
1049 break;
1050
1051 case REPORT_SRC_TAG:
1052 {
1053 Tag *entry = da_tag_get(i+1);
1054 name = entry->name;
1055 sortid = g_list_index(tmplist, entry);
1056 }
1057 break;
1058
1059 case REPORT_SRC_MONTH:
1060 date = g_date_new_julian(from);
1061 g_date_add_months(date, i);
1062 //g_snprintf(buffer, 63, "%d-%02d", g_date_get_year(date), g_date_get_month(date));
1063 g_snprintf(buffer, 63, "%d-%s", g_date_get_year(date), _(CYA_ABMONTHS[g_date_get_month(date)]));
1064 g_date_free(date);
1065 name = buffer;
1066 break;
1067
1068 case REPORT_SRC_YEAR:
1069 date = g_date_new_julian(from);
1070 g_date_add_years(date, i);
1071 g_snprintf(buffer, 63, "%d", g_date_get_year(date));
1072 g_date_free(date);
1073 name = buffer;
1074 break;
1075 }
1076
1077 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]) );
1078
1079 //compute rate
1080 exprate = 0.0;
1081 incrate = 0.0;
1082 balrate = 0.0;
1083
1084 if( data->total_expense )
1085 exprate = ABS((tmp_expense[i] * 100 / data->total_expense));
1086
1087 if( data->total_income )
1088 incrate = (tmp_income[i] * 100 / data->total_income);
1089
1090 data->total_balance = ABS(data->total_expense) + data->total_income;
1091 if( data->total_balance )
1092 balrate = (ABS(tmp_expense[i]) + tmp_income[i]) * 100 / data->total_balance;
1093
1094 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1095 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1096 LST_REPDIST_POS, sortid++,
1097 LST_REPDIST_KEY, i,
1098 LST_REPDIST_NAME, name,
1099 LST_REPDIST_EXPENSE, tmp_expense[i],
1100 LST_REPDIST_INCOME , tmp_income[i],
1101 LST_REPDIST_BALANCE, tmp_expense[i] + tmp_income[i],
1102 LST_REPDIST_EXPRATE, exprate,
1103 LST_REPDIST_INCRATE, incrate,
1104 LST_REPDIST_BALRATE, balrate,
1105 -1);
1106
1107 g_free(fullcatname);
1108 }
1109
1110 /* update column 0 title */
1111 GtkTreeViewColumn *column = gtk_tree_view_get_column( GTK_TREE_VIEW(data->LV_report), 0);
1112 gtk_tree_view_column_set_title(column, hbtk_get_label(CYA_REPORT_SRC,tmpsrc));
1113
1114 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_report));
1115
1116 /* Re-attach model to view */
1117 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_report), model);
1118 g_object_unref(model);
1119 }
1120
1121 /* free our memory */
1122 g_free(tmp_expense);
1123 g_free(tmp_income);
1124
1125 /* free tmplist (sort cat/pay) */
1126 g_list_free(tmplist);
1127
1128 ui_repdist_update_total(widget,NULL);
1129
1130 ui_repdist_update(widget, user_data);
1131
1132 }
1133
1134
1135 /*
1136 ** update sensitivity
1137 */
1138 static void ui_repdist_sensitive(GtkWidget *widget, gpointer user_data)
1139 {
1140 struct ui_repdist_data *data;
1141 GtkAction *action;
1142 gboolean visible, sensitive;
1143 gint page;
1144
1145 DB( g_print("\n[repdist] sensitive\n") );
1146
1147 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1148
1149 page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->GR_result));
1150
1151 visible = page == 0 ? TRUE : FALSE;
1152 action = gtk_ui_manager_get_action(data->ui, "/ToolBar/Detail");
1153 gtk_action_set_visible (action, visible);
1154 //sensitive = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), NULL, NULL);
1155 //gtk_action_set_sensitive(action, sensitive);
1156 //action = gtk_ui_manager_get_action(data->ui, "/ToolBar/Export");
1157 //gtk_action_set_visible (action, visible);
1158 hb_widget_visible (data->BT_export, visible);
1159
1160
1161 visible = page == 0 ? FALSE : TRUE;
1162 //todo: don't display for pie chart (get the type form chart)
1163
1164 hb_widget_visible(data->LB_zoomx, visible);
1165 hb_widget_visible(data->RG_zoomx, visible);
1166
1167 visible = page == 0 ? FALSE : TRUE;
1168 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/ToolBar/Legend"), visible);
1169
1170 visible = page == 0 ? TRUE : FALSE;
1171 gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/ToolBar/Rate"), visible);
1172
1173 sensitive = gtk_tree_model_iter_n_children(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_detail)), NULL) > 0 ? TRUE : FALSE;
1174 gtk_widget_set_sensitive(data->MI_detailtoclip, sensitive);
1175 gtk_widget_set_sensitive(data->MI_detailtocsv, sensitive);
1176 }
1177
1178
1179 static void ui_repdist_detail_onRowActivated (GtkTreeView *treeview,
1180 GtkTreePath *path,
1181 GtkTreeViewColumn *col,
1182 gpointer userdata)
1183 {
1184 struct ui_repdist_data *data;
1185 Transaction *active_txn;
1186 gboolean result;
1187
1188 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data");
1189
1190 DB( g_print ("\n[repdist] A detail row has been double-clicked!\n") );
1191
1192 active_txn = list_txn_get_active_transaction(GTK_TREE_VIEW(data->LV_detail));
1193 if(active_txn)
1194 {
1195 Transaction *old_txn, *new_txn;
1196
1197 old_txn = da_transaction_clone (active_txn);
1198 new_txn = active_txn;
1199 result = deftransaction_external_edit(GTK_WINDOW(data->window), old_txn, new_txn);
1200
1201 if(result == GTK_RESPONSE_ACCEPT)
1202 {
1203 //#1640885
1204 GLOBALS->changes_count++;
1205 ui_repdist_compute(data->window, NULL);
1206 }
1207
1208 da_transaction_free (old_txn);
1209 }
1210 }
1211
1212
1213 static void ui_repdist_update_detail(GtkWidget *widget, gpointer user_data)
1214 {
1215 struct ui_repdist_data *data;
1216
1217 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1218
1219 if(GTK_IS_TREE_VIEW(data->LV_report))
1220 {
1221 if(data->detail)
1222 {
1223 GtkTreeSelection *treeselection;
1224 GtkTreeModel *model;
1225 GtkTreeIter iter;
1226 guint key;
1227
1228 treeselection = gtk_tree_view_get_selection (GTK_TREE_VIEW(data->LV_report));
1229
1230 if (gtk_tree_selection_get_selected(treeselection, &model, &iter))
1231 {
1232 gtk_tree_model_get(model, &iter, LST_REPDIST_KEY, &key, -1);
1233
1234 DB( g_print(" - active is %d\n", key) );
1235
1236 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(key));
1237 }
1238
1239
1240
1241 gtk_widget_show(data->GR_detail);
1242 }
1243 else
1244 gtk_widget_hide(data->GR_detail);
1245
1246 }
1247 }
1248
1249
1250
1251
1252 static void ui_repdist_toggle_detail(GtkWidget *widget, gpointer user_data)
1253 {
1254 struct ui_repdist_data *data;
1255
1256 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1257
1258 data->detail ^= 1;
1259
1260 DB( g_print("\n[repdist] toggledetail to %d\n", data->detail) );
1261
1262 ui_repdist_update_detail(widget, user_data);
1263
1264 }
1265
1266 /*
1267 ** change the chart legend visibility
1268 */
1269 static void ui_repdist_toggle_legend(GtkWidget *widget, gpointer user_data)
1270 {
1271 struct ui_repdist_data *data;
1272 //gint active;
1273
1274 DB( g_print("\n[repdist] toggle legend\n") );
1275
1276 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1277
1278 data->legend ^= 1;
1279
1280 gtk_chart_show_legend(GTK_CHART(data->RE_chart), data->legend, FALSE);
1281
1282 }
1283
1284 static void ui_repdist_zoomx_callback(GtkWidget *widget, gpointer user_data)
1285 {
1286 struct ui_repdist_data *data;
1287 gdouble value;
1288
1289 DB( g_print("\n[repdist] zoomx\n") );
1290
1291 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1292
1293 value = gtk_range_get_value(GTK_RANGE(data->RG_zoomx));
1294
1295 DB( g_print(" + scale is %.2f\n", value) );
1296
1297 gtk_chart_set_barw(GTK_CHART(data->RE_chart), value);
1298
1299 }
1300
1301
1302 /*
1303 ** change the chart rate columns visibility
1304 */
1305 static void ui_repdist_toggle_rate(GtkWidget *widget, gpointer user_data)
1306 {
1307 struct ui_repdist_data *data;
1308 GtkTreeViewColumn *column;
1309
1310 DB( g_print("\n[repdist] toggle rate\n") );
1311
1312 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1313
1314 data->rate ^= 1;
1315
1316 if(GTK_IS_TREE_VIEW(data->LV_report))
1317 {
1318
1319 column = gtk_tree_view_get_column (GTK_TREE_VIEW(data->LV_report), 2);
1320 gtk_tree_view_column_set_visible(column, data->rate);
1321
1322 column = gtk_tree_view_get_column (GTK_TREE_VIEW(data->LV_report), 4);
1323 gtk_tree_view_column_set_visible(column, data->rate);
1324
1325 column = gtk_tree_view_get_column (GTK_TREE_VIEW(data->LV_report), 6);
1326 gtk_tree_view_column_set_visible(column, data->rate);
1327 }
1328
1329 }
1330
1331 static void ui_repdist_toggle_minor(GtkWidget *widget, gpointer user_data)
1332 {
1333 struct ui_repdist_data *data;
1334
1335 DB( g_print("\n[repdist] toggle minor\n") );
1336
1337 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1338
1339 GLOBALS->minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
1340
1341 ui_repdist_update_total(widget,NULL);
1342
1343 //hbfile_update(data->LV_acc, (gpointer)4);
1344 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_report));
1345 gtk_chart_show_minor(GTK_CHART(data->RE_chart), GLOBALS->minor);
1346
1347 }
1348
1349
1350 /*
1351 **
1352 */
1353 static void ui_repdist_setup(struct ui_repdist_data *data)
1354 {
1355 DB( g_print("\n[repdist] setup\n") );
1356
1357 data->txn_queue = g_queue_new ();
1358
1359 data->filter = da_flt_malloc();
1360 filter_reset(data->filter);
1361
1362
1363 data->detail = PREFS->stat_showdetail;
1364 data->legend = 1;
1365 data->rate = PREFS->stat_showrate^1;
1366
1367
1368 ui_repdist_toggle_rate(data->window, NULL);
1369
1370
1371
1372 /* 3.4 : make int transfer out of stats */
1373 data->filter->option[FILTER_PAYMODE] = 1;
1374 data->filter->paymode[PAYMODE_INTXFER] = FALSE;
1375
1376 filter_preset_daterange_set(data->filter, PREFS->date_range_rep, 0);
1377
1378 ui_repdist_update_date_widget(data->window, NULL);
1379
1380 }
1381
1382
1383
1384 static void ui_repdist_selection(GtkTreeSelection *treeselection, gpointer user_data)
1385 {
1386 GtkTreeModel *model;
1387 GtkTreeIter iter;
1388 guint key = -1;
1389
1390 DB( g_print("\n[repdist] selection\n") );
1391
1392 if (gtk_tree_selection_get_selected(treeselection, &model, &iter))
1393 {
1394 gtk_tree_model_get(model, &iter, LST_REPDIST_KEY, &key, -1);
1395 }
1396
1397 DB( g_print(" - active is %d\n", key) );
1398
1399 ui_repdist_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(key));
1400 ui_repdist_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
1401 }
1402
1403
1404 /*
1405 **
1406 */
1407 static gboolean ui_repdist_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1408 {
1409 struct ui_repdist_data *data = user_data;
1410 struct WinGeometry *wg;
1411
1412 DB( g_print("\n[repdist] dispose\n") );
1413
1414 g_queue_free (data->txn_queue);
1415
1416 da_flt_free(data->filter);
1417
1418 g_free(data);
1419
1420 //store position and size
1421 wg = &PREFS->sta_wg;
1422 gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t);
1423 gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h);
1424
1425 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg->l, wg->t, wg->w, wg->h) );
1426
1427
1428
1429 //enable define windows
1430 GLOBALS->define_off--;
1431 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
1432
1433 return FALSE;
1434 }
1435
1436
1437 // the window creation
1438 GtkWidget *ui_repdist_window_new(void)
1439 {
1440 struct ui_repdist_data *data;
1441 struct WinGeometry *wg;
1442 GtkWidget *window, *mainvbox, *hbox, *vbox, *notebook, *treeview, *vpaned, *sw;
1443 GtkWidget *label, *widget, *table, *entry;
1444 gint row;
1445 GtkUIManager *ui;
1446 GtkActionGroup *actions;
1447 GtkAction *action;
1448 GError *error = NULL;
1449
1450 DB( g_print("\n[repdist] new\n") );
1451
1452
1453 data = g_malloc0(sizeof(struct ui_repdist_data));
1454 if(!data) return NULL;
1455
1456 //disable define windows
1457 GLOBALS->define_off++;
1458 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
1459
1460 /* create window, etc */
1461 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1462 data->window = window;
1463
1464 //store our window private data
1465 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data);
1466 DB( g_print(" - new window=%p, inst_data=%p\n", window, data) );
1467
1468 gtk_window_set_title (GTK_WINDOW (window), _("Statistics Report"));
1469 gtk_window_set_icon_name(GTK_WINDOW (window), ICONNAME_HB_REP_STATS);
1470
1471
1472 //window contents
1473 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1474 gtk_container_add (GTK_CONTAINER (window), mainvbox);
1475
1476 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1477 gtk_box_pack_start (GTK_BOX (mainvbox), hbox, TRUE, TRUE, 0);
1478
1479 //control part
1480 table = gtk_grid_new ();
1481 gtk_widget_set_hexpand (GTK_WIDGET(table), FALSE);
1482 gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
1483
1484 gtk_container_set_border_width (GTK_CONTAINER (table), SPACING_SMALL);
1485 gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL);
1486 gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM);
1487
1488 row = 0;
1489 label = make_label_group(_("Display"));
1490 gtk_grid_attach (GTK_GRID (table), label, 0, row, 3, 1);
1491
1492 row++;
1493 label = make_label_widget(_("_View by:"));
1494 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1495 //widget = make_cycle(label, CYA_REPORT_SRC);
1496 widget = hbtk_combo_box_new_with_data(label, CYA_REPORT_SRC);
1497 data->CY_src = widget;
1498 gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1);
1499
1500 row++;
1501 label = make_label_widget(_("_Type:"));
1502 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1503 //widget = make_cycle(label, CYA_REPORT_TXN_TYPE);
1504 widget = hbtk_combo_box_new_with_data(label, CYA_REPORT_TYPE);
1505 data->CY_type = widget;
1506 gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1);
1507
1508
1509 row++;
1510 widget = gtk_check_button_new_with_mnemonic (_("By _amount"));
1511 data->CM_byamount = widget;
1512 gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1);
1513
1514 row++;
1515 widget = gtk_check_button_new_with_mnemonic (_("Euro _minor"));
1516 data->CM_minor = widget;
1517 gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1);
1518
1519
1520 row++;
1521 label = make_label_widget(_("_Zoom X:"));
1522 data->LB_zoomx = label;
1523 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1524 widget = make_scale(label);
1525 data->RG_zoomx = widget;
1526 gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1);
1527
1528 /*
1529 row++;
1530 widget = gtk_check_button_new_with_mnemonic ("Legend");
1531 data->CM_legend = widget;
1532 gtk_grid_attach (GTK_GRID (table), widget, 1, 2, row, row+1);
1533 */
1534 row++;
1535 widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
1536 gtk_grid_attach (GTK_GRID (table), widget, 0, row, 3, 1);
1537
1538 row++;
1539 label = make_label_group(_("Date filter"));
1540 gtk_grid_attach (GTK_GRID (table), label, 0, row, 3, 1);
1541
1542 row++;
1543 label = make_label_widget(_("_Range:"));
1544 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1545 data->CY_range = make_daterange(label, DATE_RANGE_CUSTOM_DISABLE);
1546 gtk_grid_attach (GTK_GRID (table), data->CY_range, 2, row, 1, 1);
1547
1548 row++;
1549 label = make_label_widget(_("_From:"));
1550 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1551 data->PO_mindate = gtk_date_entry_new();
1552 gtk_grid_attach (GTK_GRID (table), data->PO_mindate, 2, row, 1, 1);
1553
1554 row++;
1555 label = make_label_widget(_("_To:"));
1556 gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1);
1557 data->PO_maxdate = gtk_date_entry_new();
1558 gtk_grid_attach (GTK_GRID (table), data->PO_maxdate, 2, row, 1, 1);
1559
1560 //part: info + report
1561 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1562 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
1563
1564 //ui manager
1565 actions = gtk_action_group_new ("default");
1566
1567 //as we use gettext
1568 gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
1569
1570 // data to action callbacks is set here (data)
1571 gtk_action_group_add_radio_actions (actions, radio_entries, n_radio_entries, 0, G_CALLBACK(ui_repdist_action_mode), data);
1572
1573 gtk_action_group_add_actions (actions, entries, n_entries, data);
1574
1575 gtk_action_group_add_toggle_actions (actions,
1576 toggle_entries, n_toggle_entries,
1577 data);
1578
1579
1580 /* set which action should have priority in the toolbar */
1581 //action = gtk_action_group_get_action(actions, "List");
1582 //g_object_set(action, "is_important", TRUE, NULL);
1583
1584 //action = gtk_action_group_get_action(actions, "Column");
1585 //g_object_set(action, "is_important", TRUE, NULL);
1586
1587 //action = gtk_action_group_get_action(actions, "Donut");
1588 //g_object_set(action, "is_important", TRUE, NULL);
1589
1590 action = gtk_action_group_get_action(actions, "Detail");
1591 //g_object_set(action, "is_important", TRUE, NULL);
1592 g_object_set(action, "active", PREFS->stat_showdetail, NULL);
1593
1594 action = gtk_action_group_get_action(actions, "Rate");
1595 g_object_set(action, "active", PREFS->stat_showrate, NULL);
1596
1597 //action = gtk_action_group_get_action(actions, "Filter");
1598 //g_object_set(action, "is_important", TRUE, NULL);
1599
1600 //action = gtk_action_group_get_action(actions, "Refresh");
1601 //g_object_set(action, "is_important", TRUE, NULL);
1602
1603
1604 ui = gtk_ui_manager_new ();
1605 gtk_ui_manager_insert_action_group (ui, actions, 0);
1606 gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui));
1607
1608 if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
1609 {
1610 g_message ("building UI failed: %s", error->message);
1611 g_error_free (error);
1612 }
1613
1614 data->ui = ui;
1615 data->actions = actions;
1616
1617 //toolbar
1618 data->TB_bar = gtk_ui_manager_get_widget (ui, "/ToolBar");
1619 gtk_box_pack_start (GTK_BOX (vbox), data->TB_bar, FALSE, FALSE, 0);
1620
1621 //add export menu button
1622 GtkToolItem *toolitem;
1623 GtkWidget *menu, *menuitem, *image;
1624
1625 menu = gtk_menu_new ();
1626 //gtk_widget_set_halign (menu, GTK_ALIGN_END);
1627
1628 menuitem = gtk_menu_item_new_with_mnemonic (_("_Result to clipboard"));
1629 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1630 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_repdist_export_result_clipboard), data);
1631
1632 menuitem = gtk_menu_item_new_with_mnemonic (_("_Result to CSV"));
1633 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1634 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_repdist_export_result_csv), data);
1635
1636 menuitem = gtk_menu_item_new_with_mnemonic (_("_Detail to clipboard"));
1637 data->MI_detailtoclip = menuitem;
1638 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1639 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_repdist_export_detail_clipboard), data);
1640
1641 menuitem = gtk_menu_item_new_with_mnemonic (_("_Detail to CSV"));
1642 data->MI_detailtocsv = menuitem;
1643 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
1644 g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_repdist_export_detail_csv), data);
1645
1646 gtk_widget_show_all (menu);
1647
1648 widget = gtk_menu_button_new();
1649 data->BT_export = widget;
1650 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_FLAT);
1651
1652 //gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_DOWN);
1653 //gtk_widget_set_halign (widget, GTK_ALIGN_END);
1654 image = gtk_image_new_from_icon_name (ICONNAME_HB_FILE_EXPORT, GTK_ICON_SIZE_LARGE_TOOLBAR);
1655 g_object_set (widget, "image", image, "popup", GTK_MENU(menu), NULL);
1656
1657 toolitem = gtk_tool_item_new();
1658 gtk_container_add (GTK_CONTAINER(toolitem), widget);
1659 gtk_toolbar_insert(GTK_TOOLBAR(data->TB_bar), GTK_TOOL_ITEM(toolitem), -1);
1660
1661
1662 //infos + balance
1663 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
1664 gtk_container_set_border_width (GTK_CONTAINER(hbox), SPACING_SMALL);
1665 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1666
1667 widget = make_label(NULL, 0.5, 0.5);
1668 gimp_label_set_attributes (GTK_LABEL (widget), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
1669 data->TX_daterange = widget;
1670 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
1671
1672 entry = gtk_label_new(NULL);
1673 data->TX_total[2] = entry;
1674 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1675 label = gtk_label_new(_("Balance:"));
1676 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1677
1678 entry = gtk_label_new(NULL);
1679 data->TX_total[1] = entry;
1680 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1681 label = gtk_label_new(_("Income:"));
1682 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1683
1684
1685 entry = gtk_label_new(NULL);
1686 data->TX_total[0] = entry;
1687 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1688 label = gtk_label_new(_("Expense:"));
1689 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1690
1691
1692 /* report area */
1693 notebook = gtk_notebook_new();
1694 data->GR_result = notebook;
1695 gtk_widget_show(notebook);
1696 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
1697 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
1698 gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
1699
1700 // page list/detail
1701 vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
1702 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vpaned, NULL);
1703
1704 // list
1705 sw = gtk_scrolled_window_new (NULL, NULL);
1706 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
1707 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1708 treeview = ui_list_repdist_create();
1709 data->LV_report = treeview;
1710 gtk_container_add (GTK_CONTAINER(sw), treeview);
1711 gtk_paned_pack1 (GTK_PANED(vpaned), sw, TRUE, TRUE);
1712
1713 //detail
1714 sw = gtk_scrolled_window_new (NULL, NULL);
1715 data->GR_detail = sw;
1716 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (sw), GTK_CORNER_TOP_RIGHT);
1717 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
1718 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1719 treeview = create_list_transaction(LIST_TXN_TYPE_DETAIL, PREFS->lst_ope_columns);
1720 data->LV_detail = treeview;
1721 gtk_container_add (GTK_CONTAINER(sw), treeview);
1722 gtk_paned_pack2 (GTK_PANED(vpaned), sw, TRUE, TRUE);
1723
1724 //page: 2d bar /pie
1725 widget = gtk_chart_new(CHART_TYPE_COL);
1726 data->RE_chart = widget;
1727 gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.symbol);
1728 gtk_chart_set_currency(GTK_CHART(widget), GLOBALS->kcur);
1729 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL);
1730
1731 //todo: setup should move this
1732 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_minor), GLOBALS->minor);
1733 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_byamount), PREFS->stat_byamount);
1734
1735 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_type), REPORT_TYPE_EXPENSE);
1736
1737 /* attach our minor to treeview */
1738 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_report))), "minor", (gpointer)data->CM_minor);
1739 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_detail))), "minor", (gpointer)data->CM_minor);
1740
1741 /* signal connect */
1742 g_signal_connect (window, "delete-event", G_CALLBACK (ui_repdist_dispose), (gpointer)data);
1743
1744 g_signal_connect (data->CM_minor, "toggled", G_CALLBACK (ui_repdist_toggle_minor), NULL);
1745
1746 data->handler_id[HID_REPDIST_MINDATE] = g_signal_connect (data->PO_mindate, "changed", G_CALLBACK (ui_repdist_date_change), (gpointer)data);
1747 data->handler_id[HID_REPDIST_MAXDATE] = g_signal_connect (data->PO_maxdate, "changed", G_CALLBACK (ui_repdist_date_change), (gpointer)data);
1748
1749 data->handler_id[HID_REPDIST_RANGE] = g_signal_connect (data->CY_range, "changed", G_CALLBACK (ui_repdist_range_change), NULL);
1750
1751 g_signal_connect (data->CY_src, "changed", G_CALLBACK (ui_repdist_compute), (gpointer)data);
1752
1753 data->handler_id[HID_REPDIST_VIEW] = g_signal_connect (data->CY_type, "changed", G_CALLBACK (ui_repdist_compute), (gpointer)data);
1754
1755 g_signal_connect (data->RG_zoomx, "value-changed", G_CALLBACK (ui_repdist_zoomx_callback), NULL);
1756
1757
1758 g_signal_connect (data->CM_byamount, "toggled", G_CALLBACK (ui_repdist_update), NULL);
1759
1760 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), "changed", G_CALLBACK (ui_repdist_selection), NULL);
1761
1762 g_signal_connect (GTK_TREE_VIEW(data->LV_detail), "row-activated", G_CALLBACK (ui_repdist_detail_onRowActivated), NULL);
1763
1764 //setup, init and show window
1765 ui_repdist_setup(data);
1766
1767 /* toolbar */
1768 if(PREFS->toolbar_style == 0)
1769 gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar));
1770 else
1771 gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1);
1772
1773
1774 //setup, init and show window
1775 wg = &PREFS->sta_wg;
1776 gtk_window_move(GTK_WINDOW(window), wg->l, wg->t);
1777 gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h);
1778
1779 gtk_widget_show_all (window);
1780
1781
1782
1783 //minor ?
1784 if( PREFS->euro_active )
1785 gtk_widget_show(data->CM_minor);
1786 else
1787 gtk_widget_hide(data->CM_minor);
1788
1789 //gtk_widget_hide(data->GR_detail);
1790
1791
1792
1793 ui_repdist_sensitive(window, NULL);
1794 ui_repdist_update_detail(window, NULL);
1795
1796 DB( g_print("range: %d\n", PREFS->date_range_rep) );
1797
1798 if( PREFS->date_range_rep != 0)
1799 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), PREFS->date_range_rep);
1800 else
1801 ui_repdist_compute(window, NULL);
1802
1803
1804 return window;
1805 }
1806
1807 /*
1808 ** ============================================================================
1809 */
1810
1811
1812 static GString *ui_list_repdist_to_string(GtkTreeView *treeview, gboolean clipboard)
1813 {
1814 GString *node;
1815 GtkTreeModel *model;
1816 GtkTreeIter iter;
1817 gboolean valid;
1818 const gchar *format;
1819
1820 node = g_string_new(NULL);
1821
1822 // header
1823 format = (clipboard == TRUE) ? "%s\t%s\t%s\t%s\n" : "%s;%s;%s;%s\n";
1824 g_string_append_printf(node, format, _("Result"), _("Expense"), _("Income"), _("Balance"));
1825
1826 model = gtk_tree_view_get_model(treeview);
1827 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
1828 while (valid)
1829 {
1830 gchar *name;
1831 gdouble exp, inc, bal;
1832
1833 gtk_tree_model_get (model, &iter,
1834 //LST_REPDIST_KEY, i,
1835 LST_REPDIST_NAME , &name,
1836 LST_REPDIST_EXPENSE, &exp,
1837 LST_REPDIST_INCOME , &inc,
1838 LST_REPDIST_BALANCE, &bal,
1839 -1);
1840
1841 format = (clipboard == TRUE) ? "%s\t%.2f\t%.2f\t%.2f\n" : "%s;%.2f;%.2f;%.2f\n";
1842 g_string_append_printf(node, format, name, exp, inc, bal);
1843
1844 //leak
1845 g_free(name);
1846
1847 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
1848 }
1849
1850 //DB( g_print("text is:\n%s", node->str) );
1851
1852 return node;
1853 }
1854
1855
1856
1857
1858 static void ui_list_repdist_rate_cell_data_function (GtkTreeViewColumn *col,
1859 GtkCellRenderer *renderer,
1860 GtkTreeModel *model,
1861 GtkTreeIter *iter,
1862 gpointer user_data)
1863 {
1864 //GtkWidget *widget;
1865
1866 //widget = g_object_get_data(G_OBJECT(model), "minor");
1867
1868 //todo g_assert here and null test
1869
1870 gdouble tmp;
1871 gchar buf[128];
1872
1873 gtk_tree_model_get(model, iter, GPOINTER_TO_INT(user_data), &tmp, -1);
1874
1875 if(tmp != 0.0)
1876 {
1877 g_snprintf(buf, sizeof(buf), "%.2f %%", tmp);
1878 g_object_set(renderer, "text", buf, NULL);
1879 }
1880 else
1881 g_object_set(renderer, "text", "", NULL);
1882
1883 }
1884
1885
1886 static void ui_list_repdist_amount_cell_data_function (GtkTreeViewColumn *col,
1887 GtkCellRenderer *renderer,
1888 GtkTreeModel *model,
1889 GtkTreeIter *iter,
1890 gpointer user_data)
1891 {
1892 gdouble value;
1893 gchar *color;
1894 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
1895
1896 gtk_tree_model_get(model, iter, GPOINTER_TO_INT(user_data), &value, -1);
1897
1898 if( value )
1899 {
1900 hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, GLOBALS->kcur, GLOBALS->minor);
1901
1902 color = get_normal_color_amount(value);
1903
1904 g_object_set(renderer,
1905 "foreground", color,
1906 "text", buf,
1907 NULL); }
1908 else
1909 {
1910 g_object_set(renderer, "text", "", NULL);
1911 }
1912 }
1913
1914
1915 static GtkTreeViewColumn *ui_list_repdist_amount_column(gchar *name, gint id)
1916 {
1917 GtkTreeViewColumn *column;
1918 GtkCellRenderer *renderer;
1919
1920 column = gtk_tree_view_column_new();
1921 gtk_tree_view_column_set_title(column, name);
1922 renderer = gtk_cell_renderer_text_new ();
1923 g_object_set(renderer, "xalign", 1.0, NULL);
1924 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1925 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_list_repdist_amount_cell_data_function, GINT_TO_POINTER(id), NULL);
1926 gtk_tree_view_column_set_alignment (column, 0.5);
1927 //gtk_tree_view_column_set_sort_column_id (column, id);
1928 return column;
1929 }
1930
1931 static GtkTreeViewColumn *ui_list_repdist_rate_column(gint id)
1932 {
1933 GtkTreeViewColumn *column;
1934 GtkCellRenderer *renderer;
1935
1936 column = gtk_tree_view_column_new();
1937 gtk_tree_view_column_set_title(column, "%");
1938 renderer = gtk_cell_renderer_text_new ();
1939 g_object_set(renderer, "xalign", 1.0, "yalign", 1.0, "scale", 0.8, "scale-set", TRUE, NULL);
1940
1941 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1942 //gtk_tree_view_column_add_attribute(column, renderer, "text", id);
1943 gtk_tree_view_column_set_cell_data_func(column, renderer, ui_list_repdist_rate_cell_data_function, GINT_TO_POINTER(id), NULL);
1944 gtk_tree_view_column_set_alignment (column, 0.5);
1945 //gtk_tree_view_column_set_sort_column_id (column, id);
1946
1947 //gtk_tree_view_column_set_visible(column, FALSE);
1948
1949 return column;
1950 }
1951
1952 /*
1953 ** create our statistic list
1954 */
1955 static GtkWidget *ui_list_repdist_create(void)
1956 {
1957 GtkListStore *store;
1958 GtkWidget *view;
1959 GtkCellRenderer *renderer;
1960 GtkTreeViewColumn *column;
1961
1962 /* create list store */
1963 store = gtk_list_store_new(
1964 NUM_LST_REPDIST,
1965 G_TYPE_INT, //keep for compatibility with chart
1966 G_TYPE_INT,
1967 G_TYPE_STRING,
1968 G_TYPE_DOUBLE,
1969 G_TYPE_DOUBLE,
1970 G_TYPE_DOUBLE,
1971 G_TYPE_DOUBLE,
1972 G_TYPE_DOUBLE,
1973 G_TYPE_DOUBLE
1974 );
1975
1976 //treeview
1977 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1978 g_object_unref(store);
1979
1980 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), PREFS->grid_lines);
1981
1982 /* column: Name */
1983 column = gtk_tree_view_column_new();
1984 gtk_tree_view_column_set_title(column, _("Result"));
1985 renderer = gtk_cell_renderer_text_new ();
1986 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1987 //gtk_tree_view_column_set_cell_data_func(column, renderer, ope_result_cell_data_function, NULL, NULL);
1988 gtk_tree_view_column_add_attribute(column, renderer, "text", LST_REPDIST_NAME);
1989 //gtk_tree_view_column_set_sort_column_id (column, LST_REPDIST_NAME);
1990 gtk_tree_view_column_set_resizable(column, TRUE);
1991 gtk_tree_view_column_set_alignment (column, 0.5);
1992 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1993
1994 /* column: Expense */
1995 column = ui_list_repdist_amount_column(_("Expense"), LST_REPDIST_EXPENSE);
1996 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1997 column = ui_list_repdist_rate_column(LST_REPDIST_EXPRATE);
1998 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1999
2000 /* column: Income */
2001 column = ui_list_repdist_amount_column(_("Income"), LST_REPDIST_INCOME);
2002 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
2003 column = ui_list_repdist_rate_column(LST_REPDIST_INCRATE);
2004 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
2005
2006 /* column: Balance */
2007 column = ui_list_repdist_amount_column(_("Balance"), LST_REPDIST_BALANCE);
2008 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
2009 column = ui_list_repdist_rate_column(LST_REPDIST_BALRATE);
2010 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
2011
2012 /* column last: empty */
2013 column = gtk_tree_view_column_new();
2014 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
2015
2016 /* sort */
2017 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);
2018 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);
2019 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);
2020 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);
2021
2022
2023 return(view);
2024 }
2025
2026 static gint ui_list_repdist_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
2027 {
2028 gint sortcol = GPOINTER_TO_INT(userdata);
2029 gint retval = 0;
2030 gint pos1, pos2;
2031 gdouble val1, val2;
2032
2033 gtk_tree_model_get(model, a,
2034 LST_REPDIST_POS, &pos1,
2035 sortcol, &val1,
2036 -1);
2037 gtk_tree_model_get(model, b,
2038 LST_REPDIST_POS, &pos2,
2039 sortcol, &val2,
2040 -1);
2041
2042 switch(sortcol)
2043 {
2044 case LST_REPDIST_POS:
2045 retval = pos2 - pos1;
2046 break;
2047 default:
2048 retval = (ABS(val1) - ABS(val2)) > 0 ? 1 : -1;
2049 break;
2050 }
2051
2052 //DB( g_print(" sort %d=%d or %.2f=%.2f :: %d\n", pos1,pos2, val1, val2, ret) );
2053
2054 return retval;
2055 }
2056
This page took 0.126318 seconds and 4 git commands to generate.