add gitignore
[chaz/homebank] / src / rep_budget.c
1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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_budget.h"
24
25 #include "list_operation.h"
26 #include "gtk-chart.h"
27 #include "gtk-dateentry.h"
28
29 #include "dsp_mainwindow.h"
30
31
32
33 /****************************************************************************/
34 /* Debug macros */
35 /****************************************************************************/
36 #define MYDEBUG 0
37
38 #if MYDEBUG
39 #define DB(x) (x);
40 #else
41 #define DB(x);
42 #endif
43
44 enum {
45 HID_MINDATE,
46 HID_MAXDATE,
47 HID_RANGE,
48 MAX_HID
49 };
50
51 /* our global datas */
52 extern struct HomeBank *GLOBALS;
53 extern struct Preferences *PREFS;
54
55
56 struct repbudget_data
57 {
58 GtkWidget *window;
59 GtkUIManager *ui;
60
61 GtkWidget *TB_bar;
62
63 GtkWidget *TX_info;
64 GtkWidget *TX_daterange;
65 GtkWidget *CM_minor;
66 GtkWidget *CY_for;
67 GtkWidget *CY_kind;
68 GtkWidget *CY_view;
69 GtkWidget *RG_zoomx;
70 GtkWidget *LV_report;
71
72 GtkWidget *PO_mindate, *PO_maxdate;
73
74 GtkWidget *CY_range;
75 GtkWidget *GR_result;
76
77 GtkWidget *TX_total[3];
78
79 GtkWidget *RE_bar;
80 GtkWidget *RE_pie;
81
82 GtkWidget *GR_detail;
83 GtkWidget *LV_detail;
84
85 Filter *filter;
86
87 gdouble total_spent;
88 gdouble total_budget;
89
90 gboolean detail;
91 gboolean legend;
92
93 gulong handler_id[MAX_HID];
94 };
95
96 /* prototypes */
97 static void repbudget_action_viewlist(GtkAction *action, gpointer user_data);
98 static void repbudget_action_viewbar(GtkAction *action, gpointer user_data);
99 static void repbudget_action_detail(GtkAction *action, gpointer user_data);
100 static void repbudget_action_legend(GtkAction *action, gpointer user_data);
101 static void repbudget_action_refresh(GtkAction *action, gpointer user_data);
102
103 enum
104 {
105 BUDG_CATEGORY,
106 BUDG_SUBCATEGORY,
107 };
108
109 gchar *CYA_BUDGSELECT[] = { N_("Category"), N_("Subcategory"), NULL };
110
111 gchar *CYA_KIND[] = { N_("Exp. & Inc."), N_("Expense"), N_("Income"), NULL };
112
113 gchar *CYA_BUDGETSELECT[] = { N_("Spent & Budget"), N_("Spent"), N_("Budget"), N_("Result"), NULL };
114
115
116 //extern gchar *CYA_FLT_SELECT[];
117
118 static GtkActionEntry entries[] = {
119 { "List" , "hb-view-list" , N_("List") , NULL, N_("View results as list"), G_CALLBACK (repbudget_action_viewlist) },
120 { "Bar" , "hb-view-bar" , N_("Bar") , NULL, N_("View results as bars"), G_CALLBACK (repbudget_action_viewbar) },
121 { "Refresh" , GTK_STOCK_REFRESH, N_("Refresh"), NULL, N_("Refresh results"), G_CALLBACK (repbudget_action_refresh) },
122 };
123 static guint n_entries = G_N_ELEMENTS (entries);
124
125
126 static GtkToggleActionEntry toggle_entries[] = {
127 { "Detail", "hb-ope-show", /* name, stock id */
128 N_("Detail"), NULL, /* label, accelerator */
129 N_("Toggle detail"), /* tooltip */
130 G_CALLBACK (repbudget_action_detail),
131 FALSE }, /* is_active */
132
133 { "Legend", "hb-legend", /* name, stock id */
134 N_("Legend"), NULL, /* label, accelerator */
135 N_("Toggle legend"), /* tooltip */
136 G_CALLBACK (repbudget_action_legend),
137 TRUE }, /* is_active */
138
139 };
140 static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);
141
142
143 static const gchar *ui_info =
144 "<ui>"
145 " <toolbar name='ToolBar'>"
146 " <toolitem action='List'/>"
147 " <toolitem action='Bar'/>"
148 " <separator/>"
149 " <toolitem action='Detail'/>"
150 " <toolitem action='Legend'/>"
151 " <separator/>"
152 " <toolitem action='Refresh'/>"
153 " </toolbar>"
154 "</ui>";
155
156 /* list stat */
157 enum
158 {
159 LST_BUDGET_POS,
160 LST_BUDGET_KEY,
161 LST_BUDGET_NAME,
162 LST_BUDGET_SPENT,
163 LST_BUDGET_BUDGET,
164 LST_BUDGET_RESULT,
165 NUM_LST_BUDGET
166 };
167
168 /* prototypes */
169
170 static void repbudget_date_change(GtkWidget *widget, gpointer user_data);
171 static void repbudget_range_change(GtkWidget *widget, gpointer user_data);
172 static void repbudget_toggle_detail(GtkWidget *widget, gpointer user_data);
173 static void repbudget_detail(GtkWidget *widget, gpointer user_data);
174 static void repbudget_compute(GtkWidget *widget, gpointer user_data);
175 static void repbudget_update_total(GtkWidget *widget, gpointer user_data);
176 static void repbudget_sensitive(GtkWidget *widget, gpointer user_data);
177 static void repbudget_toggle_legend(GtkWidget *widget, gpointer user_data);
178 static void repbudget_toggle(GtkWidget *widget, gpointer user_data);
179 static GtkWidget *create_list_budget(void);
180 static void repbudget_update_detail(GtkWidget *widget, gpointer user_data);
181 static void repbudget_update_daterange(GtkWidget *widget, gpointer user_data);
182
183 /* action functions -------------------- */
184 static void repbudget_action_viewlist(GtkAction *action, gpointer user_data)
185 {
186 struct repbudget_data *data = user_data;
187
188 gtk_notebook_set_current_page(GTK_NOTEBOOK(data->GR_result), 0);
189 repbudget_sensitive(data->window, NULL);
190 }
191
192 static void repbudget_action_viewbar(GtkAction *action, gpointer user_data)
193 {
194 struct repbudget_data *data = user_data;
195
196 gtk_notebook_set_current_page(GTK_NOTEBOOK(data->GR_result), 1);
197 repbudget_sensitive(data->window, NULL);
198 }
199
200 static void repbudget_action_detail(GtkAction *action, gpointer user_data)
201 {
202 struct repbudget_data *data = user_data;
203
204 repbudget_toggle_detail(data->window, NULL);
205 }
206
207 static void repbudget_action_legend(GtkAction *action, gpointer user_data)
208 {
209 struct repbudget_data *data = user_data;
210
211 repbudget_toggle_legend(data->window, NULL);
212 }
213
214 static void repbudget_action_refresh(GtkAction *action, gpointer user_data)
215 {
216 struct repbudget_data *data = user_data;
217
218 repbudget_compute(data->window, NULL);
219 }
220
221
222
223 /* ======================== */
224
225
226 static gint getmonth(guint date)
227 {
228 GDate *date1;
229 gint month;
230
231 date1 = g_date_new_julian(date);
232 month = g_date_get_month(date1);
233
234 #if MYDEBUG == 1
235 gchar buffer1[128];
236 g_date_strftime (buffer1, 128-1, "%x", date1);
237 g_print(" date is '%s'\n", buffer1);
238
239 g_print(" month is %d\n", month);
240
241 #endif
242
243 g_date_free(date1);
244
245 return(month);
246 }
247
248 static gint countmonth(guint32 mindate, guint32 maxdate)
249 {
250 GDate *date1, *date2;
251 gint nbmonth;
252
253 date1 = g_date_new_julian(mindate);
254 date2 = g_date_new_julian(maxdate);
255
256 nbmonth = 0;
257 while(g_date_compare(date1, date2) < 0)
258 {
259 nbmonth++;
260 g_date_add_months(date1, 1);
261 }
262
263 g_date_free(date2);
264 g_date_free(date1);
265
266 return(nbmonth);
267 }
268
269 static gdouble budget_compute_result(gdouble budget, gdouble spent)
270 {
271 gdouble retval;
272
273 //original formula
274 //result = ABS(budget) - ABS(spent);
275
276 retval = spent - budget;
277
278 return retval;
279 }
280
281
282
283
284
285 static void repbudget_date_change(GtkWidget *widget, gpointer user_data)
286 {
287 struct repbudget_data *data;
288
289 DB( g_print("(repbudget) date change\n") );
290
291 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
292
293 data->filter->mindate = gtk_dateentry_get_date(GTK_DATE_ENTRY(data->PO_mindate));
294 data->filter->maxdate = gtk_dateentry_get_date(GTK_DATE_ENTRY(data->PO_maxdate));
295
296 // set min/max date for both widget
297 gtk_dateentry_set_maxdate(GTK_DATE_ENTRY(data->PO_mindate), data->filter->maxdate);
298 gtk_dateentry_set_mindate(GTK_DATE_ENTRY(data->PO_maxdate), data->filter->mindate);
299
300 g_signal_handler_block(data->CY_range, data->handler_id[HID_RANGE]);
301 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), FLT_RANGE_OTHER);
302 g_signal_handler_unblock(data->CY_range, data->handler_id[HID_RANGE]);
303
304
305 repbudget_compute(widget, NULL);
306 repbudget_update_daterange(widget, NULL);
307
308 }
309
310
311 static void repbudget_range_change(GtkWidget *widget, gpointer user_data)
312 {
313 struct repbudget_data *data;
314 gint range;
315
316 DB( g_print("(repbudget) range change\n") );
317
318 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
319
320 range = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_range));
321
322
323 if(range != FLT_RANGE_OTHER)
324 {
325 filter_preset_daterange_set(data->filter, range);
326
327 g_signal_handler_block(data->PO_mindate, data->handler_id[HID_MINDATE]);
328 g_signal_handler_block(data->PO_maxdate, data->handler_id[HID_MAXDATE]);
329
330 gtk_dateentry_set_date(GTK_DATE_ENTRY(data->PO_mindate), data->filter->mindate);
331 gtk_dateentry_set_date(GTK_DATE_ENTRY(data->PO_maxdate), data->filter->maxdate);
332
333 g_signal_handler_unblock(data->PO_mindate, data->handler_id[HID_MINDATE]);
334 g_signal_handler_unblock(data->PO_maxdate, data->handler_id[HID_MAXDATE]);
335
336 repbudget_compute(widget, NULL);
337 repbudget_update_daterange(widget, NULL);
338 }
339 }
340
341
342 static void repbudget_update_daterange(GtkWidget *widget, gpointer user_data)
343 {
344 struct repbudget_data *data;
345 gchar *daterange;
346
347 DB( g_print("(repbudget) update daterange\n") );
348
349 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
350
351 daterange = filter_daterange_text_get(data->filter);
352 gtk_label_set_markup(GTK_LABEL(data->TX_daterange), daterange);
353 g_free(daterange);
354 }
355
356
357 static void repbudget_toggle_detail(GtkWidget *widget, gpointer user_data)
358 {
359 struct repbudget_data *data;
360
361 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
362
363 DB( g_print("(repbudget) toggle detail\n") );
364
365 data->detail ^= 1;
366
367 repbudget_update_detail(widget, user_data);
368
369 }
370
371 static void repbudget_update_detail(GtkWidget *widget, gpointer user_data)
372 {
373 struct repbudget_data *data;
374
375 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
376
377 DB( g_print("(repbudget) update detail\n") );
378
379 if(GTK_IS_TREE_VIEW(data->LV_report))
380 {
381 if(data->detail)
382 {
383 GtkTreeSelection *treeselection;
384 GtkTreeModel *model;
385 GtkTreeIter iter;
386 guint key;
387
388 treeselection = gtk_tree_view_get_selection (GTK_TREE_VIEW(data->LV_report));
389
390 if (gtk_tree_selection_get_selected(treeselection, &model, &iter))
391 {
392 gtk_tree_model_get(model, &iter, LST_BUDGET_KEY, &key, -1);
393
394 //DB( g_print(" - active is %d\n", pos) );
395
396 repbudget_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(key));
397 }
398
399
400 gtk_widget_show(data->GR_detail);
401 }
402 else
403 gtk_widget_hide(data->GR_detail);
404
405
406 }
407 }
408
409 static void repbudget_detail(GtkWidget *widget, gpointer user_data)
410 {
411 struct repbudget_data *data;
412 guint active = GPOINTER_TO_INT(user_data);
413 GList *list;
414 guint tmpfor;
415 GtkTreeModel *model;
416 GtkTreeIter iter;
417
418 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
419
420 DB( g_print("(repbudget) detail\n") );
421
422 if(data->detail)
423 {
424 /* clear and detach our model */
425 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_detail));
426 gtk_list_store_clear (GTK_LIST_STORE(model));
427 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
428 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_detail), NULL); /* Detach model from view */
429
430 tmpfor = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_for));
431
432 /* fill in the model */
433 list = g_list_first(GLOBALS->ope_list);
434 while (list != NULL)
435 {
436 Account *acc;
437 Transaction *ope = list->data;
438
439 //DB( g_print(" get %s\n", ope->ope_Word) );
440
441 acc = da_acc_get(ope->kacc);
442 if(acc != NULL)
443 {
444 if((acc->flags & AF_CLOSED)) goto next1;
445 if((acc->flags & AF_NOBUDGET)) goto next1;
446 }
447
448 //filter here
449 if( !(ope->flags & OF_REMIND) && (ope->date >= data->filter->mindate) && (ope->date <= data->filter->maxdate))
450 {
451 guint pos = 0;
452 gboolean insert = FALSE;
453
454 if( ope->flags & OF_SPLIT )
455 {
456 guint nbsplit = da_transaction_splits_count(ope);
457 Split *split;
458 guint i;
459
460 for(i=0;i<nbsplit;i++)
461 {
462 split = ope->splits[i];
463 switch(tmpfor)
464 {
465 case BUDG_CATEGORY:
466 {
467 Category *catentry = da_cat_get(split->kcat);
468 if(catentry)
469 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
470 }
471 break;
472 case BUDG_SUBCATEGORY:
473 pos = split->kcat;
474 break;
475 }
476
477 if( pos == active )
478 { insert = TRUE; break; }
479 }
480 }
481 else
482 {
483 switch(tmpfor)
484 {
485 case BUDG_CATEGORY:
486 {
487 Category *catentry = da_cat_get(ope->kcat);
488 if(catentry)
489 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
490 }
491 break;
492 case BUDG_SUBCATEGORY:
493 pos = ope->kcat;
494 break;
495 }
496
497 if( pos == active )
498 insert = TRUE;
499 }
500
501 //insert
502 if( insert == TRUE )
503 {
504
505 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
506 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
507 LST_DSPOPE_DATAS, ope,
508 -1);
509 }
510
511 }
512 next1:
513 list = g_list_next(list);
514 }
515
516 /* Re-attach model to view */
517 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_detail), model);
518 g_object_unref(model);
519
520 }
521
522 }
523
524
525 static void repbudget_compute(GtkWidget *widget, gpointer user_data)
526 {
527 struct repbudget_data *data;
528
529 gint tmpfor, tmpkind, tmpview;
530 guint32 mindate, maxdate;
531
532 GtkTreeModel *model;
533 GtkTreeIter iter;
534 GList *list;
535 guint n_result, id, column;
536 gdouble *tmp_spent, *tmp_budget, *tmp_hasbudget;
537 gint nbmonth = 1;
538
539 DB( g_print("(repbudget) compute\n") );
540
541 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
542
543 tmpfor = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_for));
544 tmpkind = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_kind));
545 tmpview = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_view));
546
547 mindate = data->filter->mindate;
548 maxdate = data->filter->maxdate;
549 if(maxdate < mindate) return;
550
551 DB( g_print(" kind=%d,view=%d\n", tmpkind, tmpview) );
552
553
554 /* do nothing if no transaction */
555 if(g_list_length(GLOBALS->ope_list) == 0) return;
556
557 nbmonth = countmonth(mindate, maxdate);
558 DB( g_print(" date: min=%d max=%d nbmonth=%d\n", mindate, maxdate, nbmonth) );
559
560 n_result = da_cat_get_max_key();
561 DB( g_print(" nbcat=%d\n", n_result) );
562
563 /* allocate some memory */
564 tmp_spent = g_malloc0((n_result+1) * sizeof(gdouble));
565 tmp_budget = g_malloc0((n_result+1) * sizeof(gdouble));
566 tmp_hasbudget = g_malloc0((n_result+1) * sizeof(gdouble));
567
568 if(tmp_spent && tmp_budget && tmp_hasbudget)
569 {
570 guint i = 0;
571 /* compute the results */
572 data->total_spent = 0.0;
573 data->total_budget = 0.0;
574
575
576 /* compute budget for each category */
577 //fixed #328034: here <=n_result
578 for(i=0, id=0; i<=n_result; i++)
579 {
580 Category *entry;
581 //gchar buffer[128];
582 gint pos;
583
584 entry = da_cat_get(i);
585 if( entry == NULL)
586 continue;
587
588 //debug
589 #if MYDEBUG == 1
590
591 gint k;
592
593 g_print("--------\n");
594
595 g_print("+ %s", entry->name);
596 for(k=0;k<13;k++)
597 g_print( "%d[%.2f] ", k, entry->budget[k]);
598 g_print("\n");
599
600 #endif
601
602 pos = 0;
603 switch(tmpfor)
604 {
605 case BUDG_CATEGORY:
606 {
607 Category *catentry = da_cat_get(i);
608 if(catentry)
609 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
610 }
611 break;
612 case BUDG_SUBCATEGORY:
613 pos = i;
614 break;
615 }
616
617 DB( g_print(" ** budget for %d '%s'\n", entry->key, entry->name) );
618
619 // same value each month ?
620 if(!(entry->flags & GF_CUSTOM))
621 {
622 //DB( g_print(" cat %s -> monthly %.2f\n", entry->name, entry->budget[0]) );
623 tmp_budget[pos] += entry->budget[0]*nbmonth;
624 tmp_hasbudget[i] += entry->budget[0]*nbmonth;
625 }
626 //otherwise sum each month from mindate month
627 else
628 {
629 gint month = getmonth(mindate);
630 gint j;
631
632 for(j=0;j<nbmonth;j++)
633 {
634 DB( g_print(" %d, cat %s -> custom : month=%d budg=%.2f\n", j, entry->name, month, entry->budget[month]) );
635
636 tmp_budget[pos] += entry->budget[month];
637 tmp_hasbudget[i] += entry->budget[month];
638 month++;
639 if(month > 12) month = 1;
640 }
641 }
642
643 //debug
644 #if MYDEBUG == 1
645 if( tmp_budget[pos] )
646 {
647 g_print(" -> cat %d %s, budg[%d]=%.2f hasbudg[%d]=%.2f\n",
648 entry->key, entry->name, pos, tmp_budget[pos], i, tmp_hasbudget[i]);
649 }
650
651 #endif
652
653
654
655 }
656
657
658 // compute spent for each transaction */
659 DB( g_print(" ** compute spent for each categories\n") );
660
661
662 list = g_list_first(GLOBALS->ope_list);
663 while (list != NULL)
664 {
665 Transaction *ope = list->data;
666 Account *acc;
667
668 //DB( g_print("%d, get ope: %s :: acc=%d, cat=%d, mnt=%.2f\n", i, ope->wording, ope->account, ope->category, ope->amount) );
669
670 acc = da_acc_get(ope->kacc);
671
672 if(acc == NULL) goto next1;
673 if((acc->flags & (AF_CLOSED|AF_NOREPORT))) goto next1;
674 if((acc->flags & AF_NOBUDGET)) goto next1;
675
676 if( !(ope->flags & OF_REMIND) && ope->date >= mindate && ope->date <= maxdate)
677 {
678 gint pos = 0;
679 gdouble trn_amount;
680
681 if( ope->flags & OF_SPLIT )
682 {
683 guint nbsplit = da_transaction_splits_count(ope);
684 Split *split;
685
686 for(i=0;i<nbsplit;i++)
687 {
688 split = ope->splits[i];
689 switch(tmpfor)
690 {
691 case BUDG_CATEGORY:
692 {
693 Category *catentry = da_cat_get(split->kcat);
694 if(catentry)
695 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
696 }
697 break;
698 case BUDG_SUBCATEGORY:
699 pos = split->kcat;
700 break;
701 }
702
703 //trn_amount = to_base_amount(split->amount, acc->kcur);
704 trn_amount = split->amount;
705
706
707 DB( g_print(" -> affecting split %.2f to cat %d\n", trn_amount, pos) );
708
709 tmp_spent[pos] += trn_amount;
710
711 }
712 }
713 else
714 {
715 switch(tmpfor)
716 {
717 case BUDG_CATEGORY:
718 {
719 Category *catentry = da_cat_get(ope->kcat);
720 if(catentry)
721 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
722 }
723 break;
724 case BUDG_SUBCATEGORY:
725 pos = ope->kcat;
726 break;
727 }
728
729 //trn_amount = to_base_amount(ope->amount, acc->kcur);
730 trn_amount = ope->amount;
731
732 DB( g_print(" -> affecting %.2f to cat %d\n", trn_amount, pos) );
733
734 tmp_spent[pos] += trn_amount;
735
736 }
737
738
739 }
740
741
742 next1:
743 list = g_list_next(list);
744 i++;
745 }
746
747
748
749
750
751 DB( g_print("clear and detach model\n") );
752
753 /* clear and detach our model */
754 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_report));
755 gtk_list_store_clear (GTK_LIST_STORE(model));
756 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
757 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_report), NULL); /* Detach model from view */
758
759
760 /* insert into the treeview */
761 for(i=0, id=0; i<=n_result; i++)
762 {
763 gchar *name, *fullcatname;
764 Category *entry;
765
766 fullcatname = NULL;
767
768
769 entry = da_cat_get(i);
770 if( entry == NULL)
771 continue;
772
773 if(entry->flags & GF_SUB)
774 {
775 Category *parent = da_cat_get( entry->parent);
776
777 fullcatname = g_strdup_printf("%s:%s", parent->name, entry->name);
778 name = fullcatname;
779 }
780 else
781 name = entry->name;
782
783 if(name == NULL) name = "(None)";
784
785 if( (tmpfor == BUDG_CATEGORY && !(entry->flags & GF_SUB)) || (tmpfor == BUDG_SUBCATEGORY) )
786 {
787 guint pos;
788
789
790
791 pos = 0;
792 switch(tmpfor)
793 {
794 case BUDG_CATEGORY:
795 {
796 Category *catentry = da_cat_get(i);
797 if(catentry)
798 pos = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
799 }
800 break;
801 case BUDG_SUBCATEGORY:
802 pos = i;
803 break;
804 }
805
806 // display expense or income (filter on amount and not category hupothetical flag
807 //if( tmpkind != (entry->flags & GF_INCOME)) continue;
808 if( tmpkind == 1 && tmp_budget[pos] > 0)
809 continue;
810
811 if( tmpkind == 2 && tmp_budget[pos] < 0)
812 continue;
813
814
815 if(tmp_budget[pos] || entry->flags & GF_FORCED /*|| tmp_spent[pos]*/)
816 {
817 gdouble result;
818
819 result = budget_compute_result(tmp_budget[pos], tmp_spent[pos]);
820
821 DB( g_print(" inserting %i, %s, %.2f %.2f %.2f\n", i, name, tmp_spent[pos], tmp_budget[pos], result) );
822
823 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
824 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
825 LST_BUDGET_POS, id++,
826 LST_BUDGET_KEY, pos,
827 LST_BUDGET_NAME, name,
828 LST_BUDGET_SPENT, tmp_spent[pos],
829 LST_BUDGET_BUDGET, tmp_budget[pos],
830 LST_BUDGET_RESULT, result,
831 -1);
832
833 data->total_spent += tmp_spent[pos];
834 data->total_budget += tmp_budget[pos];
835 }
836 }
837
838 g_free(fullcatname);
839
840
841 }
842
843
844 /* Re-attach model to view */
845 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_report), model);
846 g_object_unref(model);
847
848
849
850 repbudget_update_total(widget, NULL);
851
852 column = LST_BUDGET_SPENT+tmpview-1;
853
854 /* update bar chart */
855 DB( g_print(" set bar to %d\n\n", column) );
856
857 //gtk_chart_set_currency(GTK_CHART(data->RE_bar), GLOBALS->kcur);
858
859 /* set chart color scheme */
860 gtk_chart_set_color_scheme(GTK_CHART(data->RE_bar), PREFS->report_color_scheme);
861
862 if( tmpview == 0 )
863 gtk_chart_set_dualdatas(GTK_CHART(data->RE_bar), model, LST_BUDGET_SPENT, LST_BUDGET_BUDGET, _(CYA_BUDGETSELECT[tmpview]));
864 else
865 gtk_chart_set_datas(GTK_CHART(data->RE_bar), model, column, _(CYA_BUDGETSELECT[tmpview]));
866
867 }
868
869
870 //DB( g_print(" inserting %i, %f %f\n", i, total_expense, total_income) );
871
872 /* free our memory */
873 g_free(tmp_spent);
874 g_free(tmp_budget);
875 g_free(tmp_hasbudget);
876
877
878 }
879
880
881 static void repbudget_update_total(GtkWidget *widget, gpointer user_data)
882 {
883 struct repbudget_data *data;
884
885 DB( g_print("(repbudget) update total\n") );
886
887 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
888
889 GLOBALS->minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
890
891 /*
892 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[0]), data->total_spent, GLOBALS->kcur);
893 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[1]), data->total_budget, GLOBALS->kcur);
894 hb_label_set_colvaluecurr(GTK_LABEL(data->TX_total[2]), budget_compute_result(data->total_budget, data->total_spent), GLOBALS->kcur);
895 */
896 hb_label_set_colvalue(GTK_LABEL(data->TX_total[0]), data->total_spent, GLOBALS->minor);
897 hb_label_set_colvalue(GTK_LABEL(data->TX_total[1]), data->total_budget, GLOBALS->minor);
898 hb_label_set_colvalue(GTK_LABEL(data->TX_total[2]), budget_compute_result(data->total_budget, data->total_spent), GLOBALS->minor);
899
900
901 }
902
903
904 /*
905 ** update sensitivity
906 */
907 static void repbudget_sensitive(GtkWidget *widget, gpointer user_data)
908 {
909 struct repbudget_data *data;
910 gboolean active;
911 gboolean sensitive;
912 gint page;
913
914 DB( g_print("(repbudget) sensitive\n") );
915
916 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
917
918 active = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), NULL, NULL);
919
920 page = gtk_notebook_get_current_page(GTK_NOTEBOOK(data->GR_result));
921
922 sensitive = page == 0 ? active : FALSE;
923 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_DETAIL], sensitive);
924 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/ToolBar/Detail"), sensitive);
925
926 sensitive = page == 0 ? FALSE : TRUE;
927 gtk_widget_set_sensitive(data->CY_view, sensitive);
928 gtk_widget_set_sensitive(data->RG_zoomx, sensitive);
929 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_LEGEND], sensitive);
930 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/ToolBar/Legend"), sensitive);
931
932 }
933
934
935
936 /*
937 ** change the chart legend visibility
938 */
939 static void repbudget_toggle_legend(GtkWidget *widget, gpointer user_data)
940 {
941 struct repbudget_data *data;
942
943 DB( g_print("(repbudget) legend\n") );
944
945 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
946
947 //active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_legend));
948 data->legend ^= 1;
949
950 gtk_chart_show_legend(GTK_CHART(data->RE_bar), data->legend, FALSE);
951
952 }
953
954 static void repbudget_zoomx_callback(GtkWidget *widget, gpointer user_data)
955 {
956 struct repbudget_data *data;
957 gdouble value;
958
959 DB( g_print("(repbudget) zoomx\n") );
960
961 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
962
963 value = gtk_range_get_value(GTK_RANGE(data->RG_zoomx));
964
965 DB( g_print(" + scale is %.2f\n", value) );
966
967 gtk_chart_set_barw(GTK_CHART(data->RE_bar), value);
968
969 }
970
971 static void repbudget_toggle(GtkWidget *widget, gpointer user_data)
972 {
973 struct repbudget_data *data;
974 gboolean minor;
975
976 DB( g_print("(repbudget) toggle\n") );
977
978 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
979
980 repbudget_update_total(widget, NULL);
981
982 //hbfile_update(data->LV_acc, (gpointer)4);
983 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_report));
984
985 minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
986 gtk_chart_show_minor(GTK_CHART(data->RE_bar), minor);
987
988 }
989
990 static void repbudget_setup(struct repbudget_data *data)
991 {
992 DB( g_print("(repbudget) setup\n") );
993
994 data->detail = PREFS->budg_showdetail;
995 data->legend = 1;
996
997
998 data->filter = da_filter_malloc();
999 filter_default_all_set(data->filter);
1000
1001 /* 3.4 : make int transfer out of stats */
1002 data->filter->option[FILTER_PAYMODE] = 1;
1003 data->filter->paymode[PAYMODE_INTXFER] = FALSE;
1004
1005 filter_preset_daterange_set(data->filter, PREFS->date_range_rep);
1006
1007 g_signal_handler_block(data->PO_mindate, data->handler_id[HID_MINDATE]);
1008 g_signal_handler_block(data->PO_maxdate, data->handler_id[HID_MAXDATE]);
1009
1010 gtk_dateentry_set_date(GTK_DATE_ENTRY(data->PO_mindate), data->filter->mindate);
1011 gtk_dateentry_set_date(GTK_DATE_ENTRY(data->PO_maxdate), data->filter->maxdate);
1012
1013 g_signal_handler_unblock(data->PO_mindate, data->handler_id[HID_MINDATE]);
1014 g_signal_handler_unblock(data->PO_maxdate, data->handler_id[HID_MAXDATE]);
1015
1016 }
1017
1018
1019 static void repbudget_selection(GtkTreeSelection *treeselection, gpointer user_data)
1020 {
1021 GtkTreeModel *model;
1022 GtkTreeIter iter;
1023 guint key;
1024
1025 DB( g_print("(repbudget) selection\n") );
1026
1027 if (gtk_tree_selection_get_selected(treeselection, &model, &iter))
1028 {
1029 gtk_tree_model_get(model, &iter, LST_BUDGET_KEY, &key, -1);
1030
1031 DB( g_print(" - active is %d\n", key) );
1032
1033 repbudget_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(key));
1034 }
1035
1036 repbudget_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), NULL);
1037 }
1038 /*
1039 **
1040 */
1041 static gboolean repbudget_window_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1042 {
1043 struct repbudget_data *data = user_data;
1044 struct WinGeometry *wg;
1045
1046 DB( g_print("(repbudget) start dispose\n") );
1047
1048 da_filter_free(data->filter);
1049
1050 g_free(data);
1051
1052 //store position and size
1053 wg = &PREFS->bud_wg;
1054 gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t);
1055 gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h);
1056
1057 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg->l, wg->t, wg->w, wg->h) );
1058
1059 //enable define windows
1060 GLOBALS->define_off--;
1061 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
1062
1063 DB( g_print("(repbudget) end dispose\n") );
1064
1065 return FALSE;
1066 }
1067
1068
1069 // the window creation
1070 GtkWidget *repbudget_window_new(void)
1071 {
1072 struct repbudget_data *data;
1073 struct WinGeometry *wg;
1074 GtkWidget *window, *mainvbox, *hbox, *vbox, *notebook, *treeview;
1075 GtkWidget *label, *widget, *table, *alignment, *entry;
1076 gint row;
1077 GtkUIManager *ui;
1078 GtkActionGroup *actions;
1079 GtkAction *action;
1080 GError *error = NULL;
1081
1082 data = g_malloc0(sizeof(struct repbudget_data));
1083 if(!data) return NULL;
1084
1085 DB( g_print("(repbudget) new\n") );
1086
1087 //disable define windows
1088 GLOBALS->define_off++;
1089 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(2));
1090
1091 /* create window, etc */
1092 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1093 data->window = window;
1094
1095 //store our window private data
1096 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data);
1097
1098 gtk_window_set_title (GTK_WINDOW (window), _("Budget report"));
1099
1100 //set the window icon
1101 //homebank_window_set_icon_from_file(GTK_WINDOW (window), "report_budget.svg");
1102 gtk_window_set_icon_name(GTK_WINDOW (window), HB_STOCK_REP_BUDGET);
1103
1104
1105 //window contents
1106 mainvbox = gtk_vbox_new (FALSE, 0);
1107 gtk_container_add (GTK_CONTAINER (window), mainvbox);
1108
1109 hbox = gtk_hbox_new(FALSE, 0);
1110 gtk_box_pack_start (GTK_BOX (mainvbox), hbox, TRUE, TRUE, 0);
1111
1112 //control part
1113 table = gtk_table_new (9, 3, FALSE);
1114 // gtk_alignment_new(xalign, yalign, xscale, yscale)
1115 alignment = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
1116 gtk_container_add(GTK_CONTAINER(alignment), table);
1117 gtk_box_pack_start (GTK_BOX (hbox), alignment, FALSE, FALSE, 0);
1118
1119 gtk_container_set_border_width (GTK_CONTAINER (table), HB_BOX_SPACING);
1120 gtk_table_set_row_spacings (GTK_TABLE (table), HB_TABROW_SPACING);
1121 gtk_table_set_col_spacings (GTK_TABLE (table), HB_TABCOL_SPACING);
1122
1123 row = 0;
1124 label = make_label(_("Display"), 0.0, 0.5);
1125 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
1126 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 3, row, row+1);
1127
1128 row++;
1129 label = make_label(_("_For:"), 0, 0.5);
1130 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1131 widget = make_cycle(label, CYA_BUDGSELECT);
1132 data->CY_for = widget;
1133 gtk_table_attach_defaults (GTK_TABLE (table), data->CY_for, 2, 3, row, row+1);
1134
1135
1136 row++;
1137 label = make_label(_("_Kind:"), 0, 0.5);
1138 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1139 widget = make_cycle(label, CYA_KIND);
1140 data->CY_kind = widget;
1141 gtk_table_attach_defaults (GTK_TABLE (table), data->CY_kind, 2, 3, row, row+1);
1142
1143 row++;
1144 label = make_label(_("_View:"), 0, 0.5);
1145 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1146 widget = make_cycle(label, CYA_BUDGETSELECT);
1147 data->CY_view = widget;
1148 gtk_table_attach_defaults (GTK_TABLE (table), data->CY_view, 2, 3, row, row+1);
1149
1150 row++;
1151 widget = gtk_check_button_new_with_mnemonic (_("_Minor currency"));
1152 data->CM_minor = widget;
1153 gtk_table_attach_defaults (GTK_TABLE (table), widget, 1, 3, row, row+1);
1154
1155 row++;
1156 label = make_label(_("_Zoom X:"), 0, 0.5);
1157 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1158 widget = make_scale(label);
1159 data->RG_zoomx = widget;
1160 gtk_table_attach_defaults (GTK_TABLE (table), widget, 2, 3, row, row+1);
1161
1162 row++;
1163 widget = gtk_hseparator_new();
1164 gtk_table_attach_defaults (GTK_TABLE (table), widget, 0, 3, row, row+1);
1165
1166 row++;
1167 label = make_label(_("Date filter"), 0.0, 0.5);
1168 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
1169 gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 3, row, row+1);
1170
1171 row++;
1172 label = make_label(_("_Range:"), 0, 0.5);
1173 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1174 data->CY_range = make_daterange(label, FALSE);
1175 gtk_table_attach_defaults (GTK_TABLE (table), data->CY_range, 2, 3, row, row+1);
1176
1177 row++;
1178 label = make_label(_("_From:"), 0, 0.5);
1179 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1180 data->PO_mindate = gtk_dateentry_new();
1181 gtk_table_attach_defaults (GTK_TABLE (table), data->PO_mindate, 2, 3, row, row+1);
1182
1183 row++;
1184 label = make_label(_("_To:"), 0, 0.5);
1185 gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
1186 data->PO_maxdate = gtk_dateentry_new();
1187 gtk_table_attach_defaults (GTK_TABLE (table), data->PO_maxdate, 2, 3, row, row+1);
1188
1189
1190 //part: info + report
1191 vbox = gtk_vbox_new (FALSE, 0);
1192 gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
1193
1194 //ui manager
1195 actions = gtk_action_group_new ("Account");
1196
1197 //as we use gettext
1198 gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
1199
1200 // data to action callbacks is set here (data)
1201 gtk_action_group_add_actions (actions, entries, n_entries, data);
1202
1203 gtk_action_group_add_toggle_actions (actions,
1204 toggle_entries, n_toggle_entries,
1205 data);
1206
1207
1208 /* set which action should have priority in the toolbar */
1209 action = gtk_action_group_get_action(actions, "List");
1210 g_object_set(action, "is_important", TRUE, NULL);
1211
1212 action = gtk_action_group_get_action(actions, "Bar");
1213 g_object_set(action, "is_important", TRUE, NULL);
1214
1215 action = gtk_action_group_get_action(actions, "Detail");
1216 g_object_set(action, "is_important", TRUE, NULL);
1217 g_object_set(action, "active", PREFS->budg_showdetail, NULL);
1218
1219 action = gtk_action_group_get_action(actions, "Refresh");
1220 g_object_set(action, "is_important", TRUE, NULL);
1221
1222
1223 ui = gtk_ui_manager_new ();
1224 gtk_ui_manager_insert_action_group (ui, actions, 0);
1225 gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (ui));
1226
1227 if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error))
1228 {
1229 g_message ("building UI failed: %s", error->message);
1230 g_error_free (error);
1231 }
1232
1233 data->ui = ui;
1234
1235 //toolbar
1236 data->TB_bar = gtk_ui_manager_get_widget (ui, "/ToolBar");
1237 gtk_box_pack_start (GTK_BOX (vbox), data->TB_bar, FALSE, FALSE, 0);
1238
1239 //infos
1240 hbox = gtk_hbox_new (FALSE, HB_BOX_SPACING);
1241 gtk_container_set_border_width (GTK_CONTAINER(hbox), HB_BOX_SPACING);
1242 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1243
1244 widget = make_label(NULL, 0.5, 0.5);
1245 gimp_label_set_attributes (GTK_LABEL (widget), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
1246 data->TX_daterange = widget;
1247 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
1248
1249
1250 entry = gtk_label_new(NULL);
1251 data->TX_total[2] = entry;
1252 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1253 label = gtk_label_new(_("Result:"));
1254 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1255
1256 entry = gtk_label_new(NULL);
1257 data->TX_total[1] = entry;
1258 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1259 label = gtk_label_new(_("Budget:"));
1260 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1261
1262 entry = gtk_label_new(NULL);
1263 data->TX_total[0] = entry;
1264 gtk_box_pack_end (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
1265 label = gtk_label_new(_("Spent:"));
1266 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1267
1268
1269 notebook = gtk_notebook_new();
1270 data->GR_result = notebook;
1271 gtk_widget_show(notebook);
1272 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
1273 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
1274
1275 gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
1276
1277 //page: list
1278
1279 vbox = gtk_vbox_new (FALSE, 0);
1280 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, NULL);
1281
1282 widget = gtk_scrolled_window_new (NULL, NULL);
1283 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_ETCHED_IN);
1284 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1285 treeview = create_list_budget();
1286 data->LV_report = treeview;
1287 gtk_container_add (GTK_CONTAINER(widget), treeview);
1288 gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
1289
1290 //detail
1291 widget = gtk_scrolled_window_new (NULL, NULL);
1292 data->GR_detail = widget;
1293 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_ETCHED_IN);
1294 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1295 treeview = create_list_transaction(TRN_LIST_TYPE_DETAIL, PREFS->lst_ope_columns);
1296 data->LV_detail = treeview;
1297 gtk_container_add (GTK_CONTAINER(widget), treeview);
1298
1299 gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
1300
1301 //page: 2d bar
1302 widget = gtk_chart_new(CHART_TYPE_COL);
1303 data->RE_bar = widget;
1304 //gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.suffix_symbol);
1305 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL);
1306
1307 //todo:should move this
1308 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_minor),GLOBALS->minor);
1309
1310
1311 /* attach our minor to treeview */
1312 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_report))), "minor", (gpointer)data->CM_minor);
1313 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_detail))), "minor", (gpointer)data->CM_minor);
1314
1315 /* signal connect */
1316 g_signal_connect (window, "delete-event", G_CALLBACK (repbudget_window_dispose), (gpointer)data);
1317
1318 g_signal_connect (data->CM_minor, "toggled", G_CALLBACK (repbudget_toggle), NULL);
1319
1320
1321 data->handler_id[HID_RANGE] = g_signal_connect (data->CY_range, "changed", G_CALLBACK (repbudget_range_change), NULL);
1322
1323 g_signal_connect (data->CY_for , "changed", G_CALLBACK (repbudget_compute), (gpointer)data);
1324 g_signal_connect (data->CY_kind, "changed", G_CALLBACK (repbudget_compute), (gpointer)data);
1325 g_signal_connect (data->CY_view, "changed", G_CALLBACK (repbudget_compute), (gpointer)data);
1326
1327 g_signal_connect (data->RG_zoomx, "value-changed", G_CALLBACK (repbudget_zoomx_callback), NULL);
1328
1329 data->handler_id[HID_MINDATE] = g_signal_connect (data->PO_mindate, "changed", G_CALLBACK (repbudget_date_change), (gpointer)data);
1330 data->handler_id[HID_MAXDATE] = g_signal_connect (data->PO_maxdate, "changed", G_CALLBACK (repbudget_date_change), (gpointer)data);
1331
1332 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), "changed", G_CALLBACK (repbudget_selection), NULL);
1333
1334 //setup, init and show window
1335 repbudget_setup(data);
1336
1337
1338 /* toolbar */
1339 if(PREFS->toolbar_style == 0)
1340 gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar));
1341 else
1342 gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1);
1343
1344
1345 //setup, init and show window
1346 wg = &PREFS->bud_wg;
1347 gtk_window_move(GTK_WINDOW(window), wg->l, wg->t);
1348 gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h);
1349
1350
1351
1352 gtk_widget_show_all (window);
1353
1354
1355 //minor ?
1356 if( PREFS->euro_active )
1357 gtk_widget_show(data->CM_minor);
1358 else
1359 gtk_widget_hide(data->CM_minor);
1360
1361 //check for any account included into the budget or warn
1362 {
1363 guint count =0;
1364 GList *lacc, *list;
1365
1366 lacc = list = g_hash_table_get_values(GLOBALS->h_acc);
1367
1368 while (list != NULL)
1369 {
1370 Account *acc;
1371 acc = list->data;
1372 if((acc->flags & (AF_CLOSED|AF_NOREPORT))) goto next1;
1373 if(!(acc->flags & AF_NOBUDGET))
1374 count++;
1375 next1:
1376 list = g_list_next(list);
1377 }
1378 g_list_free(lacc);
1379
1380 if(count <= 0)
1381 {
1382 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_WARNING,
1383 _("No account is defined to be part of the budget."),
1384 _("You should include some accounts from the account dialog.")
1385 );
1386 }
1387
1388
1389
1390 }
1391
1392
1393
1394 //gtk_widget_hide(data->GR_detail);
1395
1396 repbudget_sensitive(window, NULL);
1397 repbudget_update_detail(window, NULL);
1398
1399 if( PREFS->date_range_rep != 0)
1400 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_rep);
1401 else
1402 repbudget_compute(window, NULL);
1403
1404 return(window);
1405 }
1406
1407 /*
1408 ** ============================================================================
1409 */
1410 static void budget_amount_cell_data_function (GtkTreeViewColumn *col,
1411 GtkCellRenderer *renderer,
1412 GtkTreeModel *model,
1413 GtkTreeIter *iter,
1414 gpointer user_data)
1415 {
1416 gdouble value;
1417 gchar *color;
1418 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
1419 gint column_id = GPOINTER_TO_INT(user_data);
1420
1421 gtk_tree_model_get(model, iter, column_id, &value, -1);
1422
1423 if( value )
1424 {
1425 mystrfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, GLOBALS->minor);
1426 //hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, GLOBALS->kcur);
1427
1428 if( column_id == LST_BUDGET_RESULT)
1429 color = get_minimum_color_amount (value, 0.0);
1430 else
1431 color = get_normal_color_amount(value);
1432
1433 g_object_set(renderer,
1434 "foreground", color,
1435 "text", buf,
1436 NULL);
1437 }
1438 else
1439 {
1440 g_object_set(renderer, "text", "", NULL);
1441 }
1442 }
1443
1444
1445 static GtkTreeViewColumn *amount_list_budget_column(gchar *name, gint id)
1446 {
1447 GtkTreeViewColumn *column;
1448 GtkCellRenderer *renderer;
1449
1450 column = gtk_tree_view_column_new();
1451 gtk_tree_view_column_set_title(column, name);
1452 renderer = gtk_cell_renderer_text_new ();
1453 g_object_set(renderer, "xalign", 1.0, NULL);
1454 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1455 gtk_tree_view_column_set_cell_data_func(column, renderer, budget_amount_cell_data_function, GINT_TO_POINTER(id), NULL);
1456 gtk_tree_view_column_set_alignment (column, 0.5);
1457 //gtk_tree_view_column_set_sort_column_id (column, id);
1458 return column;
1459 }
1460
1461 /*
1462 ** create our statistic list
1463 */
1464 static GtkWidget *create_list_budget(void)
1465 {
1466 GtkListStore *store;
1467 GtkWidget *view;
1468 GtkCellRenderer *renderer;
1469 GtkTreeViewColumn *column;
1470
1471 /* create list store */
1472 store = gtk_list_store_new(
1473 NUM_LST_BUDGET,
1474 G_TYPE_INT,
1475 G_TYPE_INT,
1476 G_TYPE_STRING,
1477 G_TYPE_DOUBLE,
1478 G_TYPE_DOUBLE,
1479 G_TYPE_DOUBLE
1480 );
1481
1482 //treeview
1483 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1484 g_object_unref(store);
1485
1486 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), PREFS->rules_hint);
1487
1488 /* column: Name */
1489 column = gtk_tree_view_column_new();
1490 gtk_tree_view_column_set_title(column, _("Category"));
1491 renderer = gtk_cell_renderer_text_new ();
1492 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1493 //gtk_tree_view_column_set_cell_data_func(column, renderer, ope_result_cell_data_function, NULL, NULL);
1494 gtk_tree_view_column_add_attribute(column, renderer, "text", LST_BUDGET_NAME);
1495 //gtk_tree_view_column_set_sort_column_id (column, LST_STAT_NAME);
1496 gtk_tree_view_column_set_resizable(column, TRUE);
1497 gtk_tree_view_column_set_alignment (column, 0.5);
1498 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1499
1500 /* column: Expense */
1501 column = amount_list_budget_column(_("Spent"), LST_BUDGET_SPENT);
1502 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1503
1504 /* column: Income */
1505 column = amount_list_budget_column(_("Budget"), LST_BUDGET_BUDGET);
1506 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1507
1508 /* column: Result */
1509 column = amount_list_budget_column(_("Result"), LST_BUDGET_RESULT);
1510 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1511
1512 /* column last: empty */
1513 column = gtk_tree_view_column_new();
1514 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1515
1516 /* sort */
1517 /*
1518 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_POS , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_POS), NULL);
1519 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_SPENT , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_SPENT), NULL);
1520 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_BUDGET, stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_BUDGET), NULL);
1521 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_RESULT , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_RESULT), NULL);
1522 */
1523
1524 return(view);
1525 }
1526
This page took 0.131169 seconds and 4 git commands to generate.