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