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