1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2019 Maxime DOYEN
4 * This file is part of HomeBank.
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "rep-budget.h"
25 #include "list-operation.h"
26 #include "gtk-chart-progress.h"
27 #include "gtk-dateentry.h"
29 #include "dsp-mainwindow.h"
30 #include "ui-transaction.h"
33 /****************************************************************************/
35 /****************************************************************************/
46 /* our global datas */
47 extern struct HomeBank
*GLOBALS
;
48 extern struct Preferences
*PREFS
;
51 static void repbudget_action_viewlist(GtkAction
*action
, gpointer user_data
);
52 static void repbudget_action_viewstack(GtkAction
*action
, gpointer user_data
);
53 static void repbudget_action_detail(GtkAction
*action
, gpointer user_data
);
54 static void repbudget_action_refresh(GtkAction
*action
, gpointer user_data
);
56 static void repbudget_date_change(GtkWidget
*widget
, gpointer user_data
);
57 static void repbudget_range_change(GtkWidget
*widget
, gpointer user_data
);
58 static void repbudget_toggle_detail(GtkWidget
*widget
, gpointer user_data
);
59 static void repbudget_detail(GtkWidget
*widget
, gpointer user_data
);
60 static void repbudget_compute(GtkWidget
*widget
, gpointer user_data
);
61 static void repbudget_update_total(GtkWidget
*widget
, gpointer user_data
);
62 static void repbudget_sensitive(GtkWidget
*widget
, gpointer user_data
);
63 static void repbudget_toggle(GtkWidget
*widget
, gpointer user_data
);
64 static GtkWidget
*create_list_budget(void);
65 static void repbudget_update_detail(GtkWidget
*widget
, gpointer user_data
);
66 static void repbudget_update_daterange(GtkWidget
*widget
, gpointer user_data
);
68 static GString
*ui_list_repbudget_to_string(GtkTreeView
*treeview
, gboolean clipboard
);
71 extern gchar
*CYA_CATSUBCAT
[];
72 extern gchar
*CYA_KIND
[];
75 static GtkRadioActionEntry radio_entries
[] = {
76 { "List" , ICONNAME_HB_VIEW_LIST
, N_("List") , NULL
, N_("View results as list") , 0 },
77 { "Stack" , ICONNAME_HB_VIEW_STACK
, N_("Stack") , NULL
, N_("View results as stack bars"), 1 },
79 static guint n_radio_entries
= G_N_ELEMENTS (radio_entries
);
82 static GtkActionEntry entries
[] = {
83 { "Refresh" , ICONNAME_HB_REFRESH
, N_("Refresh"), NULL
, N_("Refresh results"), G_CALLBACK (repbudget_action_refresh
) },
85 // { "Export" , ICONNAME_HB_FILE_EXPORT , N_("Export") , NULL, N_("Export as CSV"), G_CALLBACK (repbudget_action_export) },
87 static guint n_entries
= G_N_ELEMENTS (entries
);
90 static GtkToggleActionEntry toggle_entries
[] = {
91 { "Detail", ICONNAME_HB_OPE_SHOW
, /* name, icon-name */
92 N_("Detail"), NULL
, /* label, accelerator */
93 N_("Toggle detail"), /* tooltip */
94 G_CALLBACK (repbudget_action_detail
),
95 FALSE
}, /* is_active */
98 static guint n_toggle_entries
= G_N_ELEMENTS (toggle_entries
);
101 static const gchar
*ui_info
=
103 " <toolbar name='ToolBar'>"
104 " <toolitem action='List'/>"
105 " <toolitem action='Stack'/>"
107 " <toolitem action='Detail'/>"
109 " <toolitem action='Refresh'/>"
111 //" <toolitem action='Export'/>"
112 // replaced by a menubutton
118 /* action functions -------------------- */
119 static void repbudget_action_viewlist(GtkAction
*action
, gpointer user_data
)
121 struct repbudget_data
*data
= user_data
;
123 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 0);
124 repbudget_sensitive(data
->window
, NULL
);
127 static void repbudget_action_viewstack(GtkAction
*action
, gpointer user_data
)
129 struct repbudget_data
*data
= user_data
;
131 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
132 repbudget_sensitive(data
->window
, NULL
);
136 static void repbudget_action_mode (GtkRadioAction
*action
, GtkRadioAction
*current
, gpointer user_data
)
140 value
= gtk_radio_action_get_current_value(GTK_RADIO_ACTION(action
));
144 repbudget_action_viewlist(GTK_ACTION(action
), user_data
);
147 repbudget_action_viewstack(GTK_ACTION(action
), user_data
);
153 static void repbudget_action_detail(GtkAction
*action
, gpointer user_data
)
155 struct repbudget_data
*data
= user_data
;
157 repbudget_toggle_detail(data
->window
, NULL
);
161 static void repbudget_action_refresh(GtkAction
*action
, gpointer user_data
)
163 struct repbudget_data
*data
= user_data
;
165 repbudget_compute(data
->window
, NULL
);
168 /*static void repbudget_action_export(GtkAction *action, gpointer user_data)
170 struct repbudget_data *data = user_data;
172 repbudget_export_csv(data->window, NULL);
175 /* ======================== */
178 static gint
getmonth(guint date
)
183 date1
= g_date_new_julian(date
);
184 month
= g_date_get_month(date1
);
187 g_print("\n[repbudget] getmonth\n");
189 g_date_strftime (buffer1, 128-1, "%x", date1);
190 g_print(" date is '%s', month=%d\n", buffer1, month);
198 static gint
countmonth(guint32 mindate
, guint32 maxdate
)
200 GDate
*date1
, *date2
;
203 date1
= g_date_new_julian(mindate
);
204 date2
= g_date_new_julian(maxdate
);
207 while(g_date_compare(date1
, date2
) < 0)
210 g_date_add_months(date1
, 1);
219 static gdouble
budget_compute_result(gdouble budget
, gdouble spent
)
224 //result = ABS(budget) - ABS(spent);
226 retval
= spent
- budget
;
235 static void repbudget_date_change(GtkWidget
*widget
, gpointer user_data
)
237 struct repbudget_data
*data
;
239 DB( g_print("\n[repbudget] date change\n") );
241 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
243 data
->filter
->mindate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_mindate
));
244 data
->filter
->maxdate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_maxdate
));
246 // set min/max date for both widget
247 gtk_date_entry_set_maxdate(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->maxdate
);
248 gtk_date_entry_set_mindate(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->mindate
);
250 g_signal_handler_block(data
->CY_range
, data
->handler_id
[HID_REPBUDGET_RANGE
]);
251 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
), FLT_RANGE_OTHER
);
252 g_signal_handler_unblock(data
->CY_range
, data
->handler_id
[HID_REPBUDGET_RANGE
]);
255 repbudget_compute(widget
, NULL
);
256 repbudget_update_daterange(widget
, NULL
);
261 static void repbudget_range_change(GtkWidget
*widget
, gpointer user_data
)
263 struct repbudget_data
*data
;
266 DB( g_print("\n[repbudget] range change\n") );
268 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
270 range
= hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
));
273 if(range
!= FLT_RANGE_OTHER
)
275 filter_preset_daterange_set(data
->filter
, range
, 0);
277 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPBUDGET_MINDATE
]);
278 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPBUDGET_MAXDATE
]);
280 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
281 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
283 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPBUDGET_MINDATE
]);
284 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPBUDGET_MAXDATE
]);
286 repbudget_compute(widget
, NULL
);
287 repbudget_update_daterange(widget
, NULL
);
292 static void repbudget_update_daterange(GtkWidget
*widget
, gpointer user_data
)
294 struct repbudget_data
*data
;
297 DB( g_print("\n[repbudget] update daterange\n") );
299 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
301 daterange
= filter_daterange_text_get(data
->filter
);
302 gtk_label_set_markup(GTK_LABEL(data
->TX_daterange
), daterange
);
307 static void repbudget_toggle_detail(GtkWidget
*widget
, gpointer user_data
)
309 struct repbudget_data
*data
;
311 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
313 DB( g_print("\n[repbudget] toggle detail\n") );
317 repbudget_update_detail(widget
, user_data
);
322 static void repbudget_detail_onRowActivated (GtkTreeView
*treeview
,
324 GtkTreeViewColumn
*col
,
327 struct repbudget_data
*data
;
328 Transaction
*active_txn
;
331 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
333 DB( g_print ("\n[repbudget] A detail row has been double-clicked!\n") );
335 active_txn
= list_txn_get_active_transaction(GTK_TREE_VIEW(data
->LV_detail
));
338 Transaction
*old_txn
, *new_txn
;
340 old_txn
= da_transaction_clone (active_txn
);
341 new_txn
= active_txn
;
342 result
= deftransaction_external_edit(GTK_WINDOW(data
->window
), old_txn
, new_txn
);
344 if(result
== GTK_RESPONSE_ACCEPT
)
347 GLOBALS
->changes_count
++;
348 repbudget_compute(data
->window
, NULL
);
351 da_transaction_free (old_txn
);
356 static void repbudget_update_detail(GtkWidget
*widget
, gpointer user_data
)
358 struct repbudget_data
*data
;
360 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
362 DB( g_print("\n[repbudget] update detail\n") );
364 if(GTK_IS_TREE_VIEW(data
->LV_report
))
368 GtkTreeSelection
*treeselection
;
373 treeselection
= gtk_tree_view_get_selection (GTK_TREE_VIEW(data
->LV_report
));
375 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
377 gtk_tree_model_get(model
, &iter
, LST_BUDGET_KEY
, &key
, -1);
379 //DB( g_print(" - active is %d\n", pos) );
381 repbudget_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
385 gtk_widget_show(data
->GR_detail
);
388 gtk_widget_hide(data
->GR_detail
);
395 static void repbudget_export_result_clipboard(GtkWidget
*widget
, gpointer user_data
)
397 struct repbudget_data
*data
;
398 GtkClipboard
*clipboard
;
401 DB( g_print("\n[repbudget] export result clipboard\n") );
404 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
406 node
= ui_list_repbudget_to_string(GTK_TREE_VIEW(data
->LV_report
), TRUE
);
408 clipboard
= gtk_clipboard_get_default(gdk_display_get_default());
409 gtk_clipboard_set_text(clipboard
, node
->str
, node
->len
);
411 g_string_free(node
, TRUE
);
415 static void repbudget_export_result_csv(GtkWidget
*widget
, gpointer user_data
)
417 struct repbudget_data
*data
;
418 gchar
*filename
= NULL
;
424 DB( g_print("\n[repbudget] export result csv\n") );
427 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
429 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_for
));
430 name
= g_strdup_printf("hb-repbudget_%s.csv", CYA_CATSUBCAT
[tmpfor
]);
432 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, name
) == TRUE
)
434 DB( g_print(" + filename is %s\n", filename
) );
435 io
= g_io_channel_new_file(filename
, "w", NULL
);
438 node
= ui_list_repbudget_to_string(GTK_TREE_VIEW(data
->LV_report
), FALSE
);
439 g_io_channel_write_chars(io
, node
->str
, -1, NULL
, NULL
);
440 g_io_channel_unref (io
);
441 g_string_free(node
, TRUE
);
449 static void repbudget_export_detail_clipboard(GtkWidget
*widget
, gpointer user_data
)
451 struct repbudget_data
*data
;
452 GtkClipboard
*clipboard
;
455 DB( g_print("\n[repbudget] export detail clipboard\n") );
458 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
460 node
= list_txn_to_string(GTK_TREE_VIEW(data
->LV_detail
), TRUE
);
462 clipboard
= gtk_clipboard_get_default(gdk_display_get_default());
463 gtk_clipboard_set_text(clipboard
, node
->str
, node
->len
);
465 g_string_free(node
, TRUE
);
469 static void repbudget_export_detail_csv(GtkWidget
*widget
, gpointer user_data
)
471 struct repbudget_data
*data
;
472 gchar
*filename
= NULL
;
478 DB( g_print("\n[repbudget] export detail csv\n") );
481 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
483 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_for
));
484 name
= g_strdup_printf("hb-repstat-detail_%s.csv", CYA_CATSUBCAT
[tmpfor
]);
486 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, name
) == TRUE
)
488 DB( g_print(" + filename is %s\n", filename
) );
490 io
= g_io_channel_new_file(filename
, "w", NULL
);
493 node
= list_txn_to_string(GTK_TREE_VIEW(data
->LV_detail
), FALSE
);
494 g_io_channel_write_chars(io
, node
->str
, -1, NULL
, NULL
);
496 g_io_channel_unref (io
);
497 g_string_free(node
, TRUE
);
509 static void repbudget_detail(GtkWidget
*widget
, gpointer user_data
)
511 struct repbudget_data
*data
;
512 guint active
= GPOINTER_TO_INT(user_data
);
518 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
520 DB( g_print("\n[repbudget] detail\n") );
524 /* clear and detach our model */
525 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
));
526 gtk_list_store_clear (GTK_LIST_STORE(model
));
527 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
528 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), NULL
); /* Detach model from view */
530 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_for
));
532 /* fill in the model */
533 list
= g_queue_peek_head_link(data
->txn_queue
);
537 Transaction
*ope
= list
->data
;
538 gdouble dtlamt
= ope
->amount
;
540 gboolean insert
= FALSE
;
542 //DB( g_print(" get %s\n", ope->ope_Word) );
544 acc
= da_acc_get(ope
->kacc
);
547 if((acc
->flags
& AF_NOBUDGET
)) goto next1
;
551 if( ope
->flags
& OF_SPLIT
)
553 guint nbsplit
= da_splits_length(ope
->splits
);
558 for(i
=0;i
<nbsplit
;i
++)
560 split
= da_splits_get(ope
->splits
, i
);
565 Category
*catentry
= da_cat_get(split
->kcat
);
567 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
570 case BUDG_SUBCATEGORY
:
578 dtlamt
+= split
->amount
;
579 // no more break here as we need to compute split 4 cat
590 Category
*catentry
= da_cat_get(ope
->kcat
);
592 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
595 case BUDG_SUBCATEGORY
:
608 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
609 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
610 MODEL_TXN_POINTER
, ope
,
611 MODEL_TXN_SPLITAMT
, dtlamt
,
617 list
= g_list_next(list
);
620 /* Re-attach model to view */
621 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), model
);
622 g_object_unref(model
);
624 gtk_tree_view_columns_autosize( GTK_TREE_VIEW(data
->LV_detail
) );
631 static void repbudget_compute_cat_spent(guint32 key
, gdouble amount
, gdouble
*tmp_spent
, gdouble
*tmp_budget
)
635 cat
= da_cat_get(key
);
638 DB( g_print(" cat %02d:%02d (sub=%d), bud=%.2f\n", cat
->parent
, cat
->key
, (cat
->flags
& GF_SUB
), tmp_budget
[cat
->key
]) );
640 if( (cat
->flags
& GF_FORCED
) || (cat
->flags
& GF_BUDGET
) )
642 DB( g_print(" + spend %.2f to cat %d\n", amount
, cat
->key
) );
643 tmp_spent
[cat
->key
] += amount
;
646 //#1825653 subcat without budget must be computed
647 if( (cat
->flags
& GF_SUB
) )
649 Category
*pcat
= da_cat_get(cat
->parent
);
653 if( (cat
->flags
& GF_FORCED
) || (cat
->flags
& GF_BUDGET
) || (pcat
->flags
& GF_FORCED
) || (pcat
->flags
& GF_BUDGET
) )
655 DB( g_print(" + spend %.2f to parent %d\n", amount
, cat
->parent
) );
656 tmp_spent
[pcat
->key
] += amount
;
665 static void repbudget_compute(GtkWidget
*widget
, gpointer user_data
)
667 struct repbudget_data
*data
;
669 gint tmpfor
, tmpkind
, tmponlyout
;
670 guint32 mindate
, maxdate
;
676 gdouble
*tmp_spent
, *tmp_budget
;
677 gboolean
*tmp_hassub
;
681 DB( g_print("\n[repbudget] compute\n") );
683 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
685 tmpfor
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_for
));
686 tmpkind
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_kind
));
687 tmponlyout
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_onlyout
));
689 mindate
= data
->filter
->mindate
;
690 maxdate
= data
->filter
->maxdate
;
691 if(maxdate
< mindate
) return;
693 g_queue_free (data
->txn_queue
);
694 data
->txn_queue
= hbfile_transaction_get_partial_budget(data
->filter
->mindate
, data
->filter
->maxdate
);
696 DB( g_print(" for=%d, kind=%d\n", tmpfor
, tmpkind
) );
698 nbmonth
= countmonth(mindate
, maxdate
);
699 DB( g_print(" date: min=%d max=%d nbmonth=%d\n", mindate
, maxdate
, nbmonth
) );
701 n_result
= da_cat_get_max_key();
702 DB( g_print(" nbcat=%d\n", n_result
) );
704 /* allocate some memory */
705 tmp_spent
= g_malloc0((n_result
+1) * sizeof(gdouble
));
706 tmp_budget
= g_malloc0((n_result
+1) * sizeof(gdouble
));
707 tmp_hassub
= g_malloc0((n_result
+1) * sizeof(gboolean
));
709 if(tmp_spent
&& tmp_budget
&& tmp_hassub
)
712 /* compute the results */
713 data
->total_spent
= 0.0;
714 data
->total_budget
= 0.0;
716 /* compute budget for each category */
717 DB( g_print("\n+ compute budget\n") );
719 //fixed #328034: here <=n_result
720 for(i
=1; i
<=n_result
; i
++)
724 entry
= da_cat_get(i
);
728 DB( g_print(" %d:'%s' issub=%d hasbudget=%d custom=%d\n",
729 entry
->key
, entry
->name
, (entry
->flags
& GF_SUB
), (entry
->flags
& GF_BUDGET
), (entry
->flags
& GF_CUSTOM
)) );
734 g_print(" budget vector: ");
736 g_print( " %d:[%.2f]", k, entry->budget[k]);
740 // same value each month ?
741 if(!(entry
->flags
& GF_CUSTOM
))
743 DB( g_print(" - monthly %.2f\n", entry
->budget
[0]) );
744 tmp_budget
[entry
->key
] += entry
->budget
[0]*nbmonth
;
745 if( entry
->flags
& GF_SUB
)
747 tmp_budget
[entry
->parent
] += entry
->budget
[0]*nbmonth
;
748 tmp_hassub
[entry
->parent
] = TRUE
;
751 //otherwise sum each month from mindate month
754 gint month
= getmonth(mindate
);
757 DB( g_print(" - custom each month for %d months\n", nbmonth
) );
758 for(j
=0;j
<nbmonth
;j
++) {
759 DB( g_print(" j=%d month=%d budg=%.2f\n", j
, month
, entry
->budget
[month
]) );
760 tmp_budget
[entry
->key
] += entry
->budget
[month
];
761 if( entry
->flags
& GF_SUB
)
763 tmp_budget
[entry
->parent
] += entry
->budget
[month
];
764 tmp_hassub
[entry
->parent
] = TRUE
;
767 if(month
> 12) { month
= 1; }
773 // compute spent for each transaction */
774 DB( g_print("\n+ compute spent from transactions\n") );
776 list
= g_queue_peek_head_link(data
->txn_queue
);
779 Transaction
*ope
= list
->data
;
781 DB( g_print("ope: %s :: acc=%d, cat=%d, mnt=%.2f\n", ope
->memo
, ope
->kacc
, ope
->kcat
, ope
->amount
) );
783 if( ope
->flags
& OF_SPLIT
)
785 guint nbsplit
= da_splits_length(ope
->splits
);
788 for(i
=0;i
<nbsplit
;i
++)
790 split
= da_splits_get(ope
->splits
, i
);
791 repbudget_compute_cat_spent(split
->kcat
, hb_amount_base(split
->amount
, ope
->kcur
), tmp_spent
, tmp_budget
);
796 repbudget_compute_cat_spent(ope
->kcat
, hb_amount_base(ope
->amount
, ope
->kcur
), tmp_spent
, tmp_budget
);
799 list
= g_list_next(list
);
803 DB( g_print("\nclear and detach model\n") );
805 /* clear and detach our model */
806 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
807 gtk_list_store_clear (GTK_LIST_STORE(model
));
808 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
809 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), NULL
); /* Detach model from view */
811 for(i
=1, id
=0; i
<=n_result
; i
++)
814 gboolean outofbudget
;
817 entry
= da_cat_get(i
);
821 name
= entry
->key
== 0 ? "(None)" : entry
->fullname
;
824 //if( (tmpfor == BUDG_CATEGORY && !(entry->flags & GF_SUB)) || (tmpfor == BUDG_SUBCATEGORY) )
825 if( (tmpfor
== BUDG_CATEGORY
&& !(entry
->flags
& GF_SUB
)) ||
826 (tmpfor
== BUDG_SUBCATEGORY
&& ((entry
->flags
& GF_SUB
) || !tmp_hassub
[i
]) ) )
835 Category
*catentry
= da_cat_get(i
);
837 pos
= (catentry
->flags
& GF_SUB
) ? catentry
->parent
: catentry
->key
;
840 case BUDG_SUBCATEGORY
:
845 // display expense or income (filter on amount and not category hypothetical flag
846 if( tmpkind
== 1 && tmp_budget
[pos
] > 0)
849 if( tmpkind
== 2 && tmp_budget
[pos
] < 0)
852 //DB( g_print(" eval %d '%s' : spen=%.2f bud=%.2f \n", i, name, tmp_spent[pos], tmp_budget[pos] ) );
854 if((entry
->flags
& (GF_BUDGET
|GF_FORCED
)) || tmp_budget
[pos
] /*|| tmp_spent[pos]*/)
856 gdouble result
, rawrate
;
859 result
= budget_compute_result(tmp_budget
[pos
], tmp_spent
[pos
]);
861 if(ABS(tmp_budget
[pos
]) > 0)
863 rawrate
= tmp_spent
[pos
] / tmp_budget
[pos
];
865 else if(tmp_budget
[pos
] == 0.0)
866 rawrate
= ABS(tmp_spent
[pos
]);
879 if(tmp_budget
[pos
] < 0.0)
881 else if(tmp_budget
[pos
] > 0.0)
883 status
= _(" under");
889 if(tmponlyout
== TRUE
&& outofbudget
== FALSE
)
892 DB( g_print(" => insert '%s' s:%.2f b:%.2f r:%.2f (%%%.2f) '%s' '%d'\n\n", name
, tmp_spent
[pos
], tmp_budget
[pos
], result
, rawrate
, status
, outofbudget
) );
894 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
895 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
896 LST_BUDGET_POS
, id
++,
898 LST_BUDGET_NAME
, name
,
899 LST_BUDGET_SPENT
, tmp_spent
[pos
],
900 LST_BUDGET_BUDGET
, tmp_budget
[pos
],
901 LST_BUDGET_RESULT
, result
,
902 LST_BUDGET_STATUS
, status
,
906 data
->total_spent
+= tmp_spent
[pos
];
907 data
->total_budget
+= tmp_budget
[pos
];
912 /* update column 0 title */
913 GtkTreeViewColumn
*column
= gtk_tree_view_get_column( GTK_TREE_VIEW(data
->LV_report
), 0);
914 gtk_tree_view_column_set_title(column
, _(CYA_CATSUBCAT
[tmpfor
]));
916 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
918 /* Re-attach model to view */
919 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), model
);
920 g_object_unref(model
);
923 repbudget_update_total(widget
, NULL
);
925 /* update stack chart */
926 title
= g_strdup_printf(_("Budget for %s"), _(CYA_CATSUBCAT
[tmpfor
]) );
928 ui_chart_progress_set_currency(GTK_CHARTPROGRESS(data
->RE_stack
), GLOBALS
->kcur
);
930 /* set chart color scheme */
931 ui_chart_progress_set_color_scheme(GTK_CHARTPROGRESS(data
->RE_stack
), PREFS
->report_color_scheme
);
932 ui_chart_progress_set_dualdatas(GTK_CHARTPROGRESS(data
->RE_stack
), model
, _("Budget"), _("Result"), title
, NULL
);
937 //DB( g_print(" inserting %i, %f %f\n", i, total_expense, total_income) );
939 /* free our memory */
947 static void repbudget_update_total(GtkWidget
*widget
, gpointer user_data
)
949 struct repbudget_data
*data
;
951 DB( g_print("\n[repbudget] update total\n") );
953 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
955 GLOBALS
->minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
957 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[0]), data
->total_spent
, GLOBALS
->kcur
, GLOBALS
->minor
);
958 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[1]), data
->total_budget
, GLOBALS
->kcur
, GLOBALS
->minor
);
959 hb_label_set_colvalue(GTK_LABEL(data
->TX_total
[2]), budget_compute_result(data
->total_budget
, data
->total_spent
), GLOBALS
->kcur
, GLOBALS
->minor
);
966 ** update sensitivity
968 static void repbudget_sensitive(GtkWidget
*widget
, gpointer user_data
)
970 struct repbudget_data
*data
;
972 gboolean visible
, sensitive
;
975 DB( g_print("\n[repbudget] sensitive\n") );
977 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
979 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
981 visible
= page
== 0 ? TRUE
: FALSE
;
982 action
= gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Detail");
983 gtk_action_set_visible (action
, visible
);
984 //sensitive = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), NULL, NULL);
985 //gtk_action_set_sensitive(action, sensitive);
986 //action = gtk_ui_manager_get_action(data->ui, "/ToolBar/Export");
987 //gtk_action_set_visible (action, visible);
988 hb_widget_visible (data
->BT_export
, visible
);
990 sensitive
= gtk_tree_model_iter_n_children(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
)), NULL
) > 0 ? TRUE
: FALSE
;
991 gtk_widget_set_sensitive(data
->MI_detailtoclip
, sensitive
);
992 gtk_widget_set_sensitive(data
->MI_detailtocsv
, sensitive
);
997 static void repbudget_toggle(GtkWidget
*widget
, gpointer user_data
)
999 struct repbudget_data
*data
;
1002 DB( g_print("\n[repbudget] toggle\n") );
1004 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
1006 repbudget_update_total(widget
, NULL
);
1008 //hbfile_update(data->LV_acc, (gpointer)4);
1009 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
1011 minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
1012 ui_chart_progress_show_minor(GTK_CHARTPROGRESS(data
->RE_stack
), minor
);
1016 static void repbudget_setup(struct repbudget_data
*data
)
1018 DB( g_print("\n[repbudget] setup\n") );
1020 data
->txn_queue
= g_queue_new ();
1022 data
->filter
= da_flt_malloc();
1023 filter_reset(data
->filter
);
1025 data
->detail
= PREFS
->budg_showdetail
;
1028 /* 3.4 : make int transfer out of stats */
1029 data
->filter
->option
[FILTER_PAYMODE
] = 1;
1030 data
->filter
->paymode
[PAYMODE_INTXFER
] = FALSE
;
1032 filter_preset_daterange_set(data
->filter
, PREFS
->date_range_rep
, 0);
1034 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPBUDGET_MINDATE
]);
1035 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPBUDGET_MAXDATE
]);
1037 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
1038 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
1040 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPBUDGET_MINDATE
]);
1041 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPBUDGET_MAXDATE
]);
1046 static void repbudget_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
1048 GtkTreeModel
*model
;
1052 DB( g_print("\n[repbudget] selection\n") );
1054 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
1056 gtk_tree_model_get(model
, &iter
, LST_BUDGET_KEY
, &key
, -1);
1059 DB( g_print(" - active is %d\n", key
) );
1061 repbudget_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
1062 repbudget_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
1069 static gboolean
repbudget_window_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
1071 struct repbudget_data
*data
= user_data
;
1072 struct WinGeometry
*wg
;
1074 DB( g_print("\n[repbudget] start dispose\n") );
1076 g_queue_free (data
->txn_queue
);
1078 da_flt_free(data
->filter
);
1082 //store position and size
1083 wg
= &PREFS
->bud_wg
;
1084 gtk_window_get_position(GTK_WINDOW(widget
), &wg
->l
, &wg
->t
);
1085 gtk_window_get_size(GTK_WINDOW(widget
), &wg
->w
, &wg
->h
);
1087 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg
->l
, wg
->t
, wg
->w
, wg
->h
) );
1089 //enable define windows
1090 GLOBALS
->define_off
--;
1091 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
1093 DB( g_print("\n[repbudget] end dispose\n") );
1099 // the window creation
1100 GtkWidget
*repbudget_window_new(void)
1102 struct repbudget_data
*data
;
1103 struct WinGeometry
*wg
;
1104 GtkWidget
*window
, *mainvbox
, *hbox
, *vbox
, *notebook
, *treeview
;
1105 GtkWidget
*label
, *widget
, *table
, *entry
;
1108 GtkActionGroup
*actions
;
1110 GError
*error
= NULL
;
1112 data
= g_malloc0(sizeof(struct repbudget_data
));
1113 if(!data
) return NULL
;
1115 DB( g_print("\n[repbudget] new\n") );
1117 //disable define windows
1118 GLOBALS
->define_off
++;
1119 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
1121 /* create window, etc */
1122 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1123 data
->window
= window
;
1125 //store our window private data
1126 g_object_set_data(G_OBJECT(window
), "inst_data", (gpointer
)data
);
1127 DB( g_print(" - new window=%p, inst_data=%p\n", window
, data
) );
1129 gtk_window_set_title (GTK_WINDOW (window
), _("Budget report"));
1131 //set the window icon
1132 gtk_window_set_icon_name(GTK_WINDOW (window
), ICONNAME_HB_REP_BUDGET
);
1136 mainvbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1137 gtk_container_add (GTK_CONTAINER (window
), mainvbox
);
1139 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
1140 gtk_box_pack_start (GTK_BOX (mainvbox
), hbox
, TRUE
, TRUE
, 0);
1143 table
= gtk_grid_new ();
1144 // gtk_alignment_new(xalign, yalign, xscale, yscale)
1145 //alignment = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
1146 //gtk_container_add(GTK_CONTAINER(alignment), table);
1147 gtk_box_pack_start (GTK_BOX (hbox
), table
, FALSE
, FALSE
, 0);
1149 gtk_container_set_border_width (GTK_CONTAINER (table
), SPACING_SMALL
);
1150 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_SMALL
);
1151 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1154 label
= make_label_group(_("Display"));
1155 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
1158 label
= make_label_widget(_("_View by:"));
1159 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1160 widget
= make_cycle(label
, CYA_CATSUBCAT
);
1161 data
->CY_for
= widget
;
1162 gtk_grid_attach (GTK_GRID (table
), data
->CY_for
, 2, row
, 1, 1);
1166 label
= make_label_widget(_("_Type:"));
1167 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1168 widget
= make_cycle(label
, CYA_KIND
);
1169 data
->CY_kind
= widget
;
1170 gtk_grid_attach (GTK_GRID (table
), data
->CY_kind
, 2, row
, 1, 1);
1173 widget
= gtk_check_button_new_with_mnemonic (_("Only out of budget"));
1174 data
->CM_onlyout
= widget
;
1175 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1178 widget
= gtk_check_button_new_with_mnemonic (_("Euro _minor"));
1179 data
->CM_minor
= widget
;
1180 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
1183 widget
= gtk_separator_new(GTK_ORIENTATION_HORIZONTAL
);
1184 gtk_grid_attach (GTK_GRID (table
), widget
, 0, row
, 3, 1);
1187 label
= make_label_group(_("Date filter"));
1188 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
1191 label
= make_label_widget(_("_Range:"));
1192 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1193 data
->CY_range
= make_daterange(label
, DATE_RANGE_CUSTOM_DISABLE
);
1194 gtk_grid_attach (GTK_GRID (table
), data
->CY_range
, 2, row
, 1, 1);
1197 label
= make_label_widget(_("_From:"));
1198 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1199 data
->PO_mindate
= gtk_date_entry_new();
1200 gtk_grid_attach (GTK_GRID (table
), data
->PO_mindate
, 2, row
, 1, 1);
1203 label
= make_label_widget(_("_To:"));
1204 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
1205 data
->PO_maxdate
= gtk_date_entry_new();
1206 gtk_grid_attach (GTK_GRID (table
), data
->PO_maxdate
, 2, row
, 1, 1);
1209 //part: info + report
1210 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1211 gtk_box_pack_start (GTK_BOX (hbox
), vbox
, TRUE
, TRUE
, 0);
1214 actions
= gtk_action_group_new ("default");
1217 gtk_action_group_set_translation_domain(actions
, GETTEXT_PACKAGE
);
1219 // data to action callbacks is set here (data)
1220 gtk_action_group_add_radio_actions (actions
, radio_entries
, n_radio_entries
, 0, G_CALLBACK(repbudget_action_mode
), data
);
1222 gtk_action_group_add_actions (actions
, entries
, n_entries
, data
);
1224 gtk_action_group_add_toggle_actions (actions
,
1225 toggle_entries
, n_toggle_entries
,
1229 /* set which action should have priority in the toolbar */
1230 //action = gtk_action_group_get_action(actions, "List");
1231 //g_object_set(action, "is_important", TRUE, NULL);
1233 //action = gtk_action_group_get_action(actions, "Stack");
1234 //g_object_set(action, "is_important", TRUE, NULL);
1236 action
= gtk_action_group_get_action(actions
, "Detail");
1237 //g_object_set(action, "is_important", TRUE, NULL);
1238 g_object_set(action
, "active", PREFS
->budg_showdetail
, NULL
);
1240 //action = gtk_action_group_get_action(actions, "Refresh");
1241 //g_object_set(action, "is_important", TRUE, NULL);
1244 ui
= gtk_ui_manager_new ();
1245 gtk_ui_manager_insert_action_group (ui
, actions
, 0);
1246 gtk_window_add_accel_group (GTK_WINDOW (window
), gtk_ui_manager_get_accel_group (ui
));
1248 if (!gtk_ui_manager_add_ui_from_string (ui
, ui_info
, -1, &error
))
1250 g_message ("building UI failed: %s", error
->message
);
1251 g_error_free (error
);
1257 data
->TB_bar
= gtk_ui_manager_get_widget (ui
, "/ToolBar");
1258 gtk_box_pack_start (GTK_BOX (vbox
), data
->TB_bar
, FALSE
, FALSE
, 0);
1260 //add export menu button
1261 GtkToolItem
*toolitem
;
1262 GtkWidget
*menu
, *menuitem
, *image
;
1264 menu
= gtk_menu_new ();
1265 //gtk_widget_set_halign (menu, GTK_ALIGN_END);
1267 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Result to clipboard"));
1268 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1269 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (repbudget_export_result_clipboard
), data
);
1271 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Result to CSV"));
1272 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1273 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (repbudget_export_result_csv
), data
);
1275 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Detail to clipboard"));
1276 data
->MI_detailtoclip
= menuitem
;
1277 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1278 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (repbudget_export_detail_clipboard
), data
);
1280 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Detail to CSV"));
1281 data
->MI_detailtocsv
= menuitem
;
1282 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1283 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (repbudget_export_detail_csv
), data
);
1285 gtk_widget_show_all (menu
);
1287 widget
= gtk_menu_button_new();
1288 data
->BT_export
= widget
;
1289 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget
)), GTK_STYLE_CLASS_FLAT
);
1291 //gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_DOWN);
1292 //gtk_widget_set_halign (widget, GTK_ALIGN_END);
1293 image
= gtk_image_new_from_icon_name (ICONNAME_HB_FILE_EXPORT
, GTK_ICON_SIZE_LARGE_TOOLBAR
);
1294 g_object_set (widget
, "image", image
, "popup", GTK_MENU(menu
), NULL
);
1296 toolitem
= gtk_tool_item_new();
1297 gtk_container_add (GTK_CONTAINER(toolitem
), widget
);
1298 gtk_toolbar_insert(GTK_TOOLBAR(data
->TB_bar
), GTK_TOOL_ITEM(toolitem
), -1);
1301 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, SPACING_SMALL
);
1302 gtk_container_set_border_width (GTK_CONTAINER(hbox
), SPACING_SMALL
);
1303 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1305 widget
= make_label(NULL
, 0.5, 0.5);
1306 gimp_label_set_attributes (GTK_LABEL (widget
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
1307 data
->TX_daterange
= widget
;
1308 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1311 entry
= gtk_label_new(NULL
);
1312 data
->TX_total
[2] = entry
;
1313 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1314 label
= gtk_label_new(_("Result:"));
1315 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1317 entry
= gtk_label_new(NULL
);
1318 data
->TX_total
[1] = entry
;
1319 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1320 label
= gtk_label_new(_("Budget:"));
1321 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1323 entry
= gtk_label_new(NULL
);
1324 data
->TX_total
[0] = entry
;
1325 gtk_box_pack_end (GTK_BOX (hbox
), entry
, FALSE
, FALSE
, 0);
1326 label
= gtk_label_new(_("Spent:"));
1327 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1330 notebook
= gtk_notebook_new();
1331 data
->GR_result
= notebook
;
1332 gtk_widget_show(notebook
);
1333 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
1334 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
1336 gtk_box_pack_start (GTK_BOX (vbox
), notebook
, TRUE
, TRUE
, 0);
1340 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1341 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vbox
, NULL
);
1343 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1344 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1345 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1346 treeview
= create_list_budget();
1347 data
->LV_report
= treeview
;
1348 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1349 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1352 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1353 data
->GR_detail
= widget
;
1354 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1355 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1356 treeview
= create_list_transaction(LIST_TXN_TYPE_DETAIL
, PREFS
->lst_ope_columns
);
1357 data
->LV_detail
= treeview
;
1358 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1360 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1363 //widget = gtk_chart_new(CHART_TYPE_COL);
1364 widget
= ui_chart_progress_new();
1365 data
->RE_stack
= widget
;
1366 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), widget
, NULL
);
1368 //todo:should move this
1369 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_minor
),GLOBALS
->minor
);
1372 /* attach our minor to treeview */
1373 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
))), "minor", (gpointer
)data
->CM_minor
);
1374 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
))), "minor", (gpointer
)data
->CM_minor
);
1376 /* signal connect */
1377 g_signal_connect (window
, "delete-event", G_CALLBACK (repbudget_window_dispose
), (gpointer
)data
);
1379 g_signal_connect (data
->CM_onlyout
, "toggled", G_CALLBACK (repbudget_compute
), NULL
);
1380 g_signal_connect (data
->CM_minor
, "toggled", G_CALLBACK (repbudget_toggle
), NULL
);
1383 data
->handler_id
[HID_REPBUDGET_RANGE
] = g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (repbudget_range_change
), NULL
);
1385 g_signal_connect (data
->CY_for
, "changed", G_CALLBACK (repbudget_compute
), (gpointer
)data
);
1386 g_signal_connect (data
->CY_kind
, "changed", G_CALLBACK (repbudget_compute
), (gpointer
)data
);
1388 data
->handler_id
[HID_REPBUDGET_MINDATE
] = g_signal_connect (data
->PO_mindate
, "changed", G_CALLBACK (repbudget_date_change
), (gpointer
)data
);
1389 data
->handler_id
[HID_REPBUDGET_MAXDATE
] = g_signal_connect (data
->PO_maxdate
, "changed", G_CALLBACK (repbudget_date_change
), (gpointer
)data
);
1391 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), "changed", G_CALLBACK (repbudget_selection
), NULL
);
1393 g_signal_connect (GTK_TREE_VIEW(data
->LV_detail
), "row-activated", G_CALLBACK (repbudget_detail_onRowActivated
), NULL
);
1396 //setup, init and show window
1397 repbudget_setup(data
);
1401 if(PREFS
->toolbar_style
== 0)
1402 gtk_toolbar_unset_style(GTK_TOOLBAR(data
->TB_bar
));
1404 gtk_toolbar_set_style(GTK_TOOLBAR(data
->TB_bar
), PREFS
->toolbar_style
-1);
1407 //setup, init and show window
1408 wg
= &PREFS
->bud_wg
;
1409 gtk_window_move(GTK_WINDOW(window
), wg
->l
, wg
->t
);
1410 gtk_window_resize(GTK_WINDOW(window
), wg
->w
, wg
->h
);
1414 gtk_widget_show_all (window
);
1418 if( PREFS
->euro_active
)
1419 gtk_widget_show(data
->CM_minor
);
1421 gtk_widget_hide(data
->CM_minor
);
1423 //check for any account included into the budget or warn
1428 lacc
= list
= g_hash_table_get_values(GLOBALS
->h_acc
);
1430 while (list
!= NULL
)
1434 //#1674045 ony rely on nosummary
1435 //if((acc->flags & (AF_CLOSED|AF_NOREPORT))) goto next1;
1436 if((acc
->flags
& (AF_NOREPORT
))) goto next1
;
1437 if(!(acc
->flags
& AF_NOBUDGET
))
1440 list
= g_list_next(list
);
1446 ui_dialog_msg_infoerror(GTK_WINDOW(data
->window
), GTK_MESSAGE_WARNING
,
1447 _("No account is defined to be part of the budget."),
1448 _("You should include some accounts from the account dialog.")
1458 //gtk_widget_hide(data->GR_detail);
1460 repbudget_sensitive(window
, NULL
);
1461 repbudget_update_detail(window
, NULL
);
1463 if( PREFS
->date_range_rep
!= 0)
1464 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
), PREFS
->date_range_rep
);
1466 repbudget_compute(window
, NULL
);
1472 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1474 static GString
*ui_list_repbudget_to_string(GtkTreeView
*treeview
, gboolean clipboard
)
1477 GtkTreeModel
*model
;
1480 const gchar
*format
;
1482 node
= g_string_new(NULL
);
1485 format
= (clipboard
== TRUE
) ? "%s\t%s\t%s\t%s\t\n" : "%s;%s;%s;%s;\n";
1486 g_string_append_printf(node
, format
, _("Category"), _("Spent"), _("Budget"), _("Result"));
1488 model
= gtk_tree_view_get_model(treeview
);
1489 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
1492 gchar
*name
, *status
;
1493 gdouble spent
, budget
, result
;
1495 gtk_tree_model_get (model
, &iter
,
1496 //LST_REPDIST_KEY, i,
1497 LST_BUDGET_NAME
, &name
,
1498 LST_BUDGET_SPENT
, &spent
,
1499 LST_BUDGET_BUDGET
, &budget
,
1500 LST_BUDGET_RESULT
, &result
,
1501 LST_BUDGET_STATUS
, &status
,
1504 format
= (clipboard
== TRUE
) ? "%s\t%.2f\t%.2f\t%.2f\t%s\n" : "%s;%.2f;%.2f;%.2f;%s\n";
1505 g_string_append_printf(node
, format
, name
, spent
, budget
, result
, status
);
1511 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
1514 //DB( g_print("text is:\n%s", node->str) );
1524 ** The function should return:
1525 ** a negative integer if the first value comes before the second,
1526 ** 0 if they are equal,
1527 ** or a positive integer if the first value comes after the second.
1529 static gint
budget_listview_compare_funct (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
)
1532 //Category *entry1, *entry2;
1533 gchar
*entry1
, *entry2
;
1535 gtk_tree_model_get(model
, a
, LST_BUDGET_NAME
, &entry1
, -1);
1536 gtk_tree_model_get(model
, b
, LST_BUDGET_NAME
, &entry2
, -1);
1538 retval
= hb_string_utf8_compare(entry1
, entry2
);
1548 static void budget_amount_cell_data_function (GtkTreeViewColumn
*col
,
1549 GtkCellRenderer
*renderer
,
1550 GtkTreeModel
*model
,
1556 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1557 gint column_id
= GPOINTER_TO_INT(user_data
);
1559 gtk_tree_model_get(model
, iter
, column_id
, &value
, -1);
1563 hb_strfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, GLOBALS
->kcur
, GLOBALS
->minor
);
1565 if( column_id
== LST_BUDGET_RESULT
)
1566 color
= get_minimum_color_amount (value
, 0.0);
1568 color
= get_normal_color_amount(value
);
1570 g_object_set(renderer
,
1571 "foreground", color
,
1577 g_object_set(renderer
, "text", "", NULL
);
1583 static void budget_result_cell_data_function (GtkTreeViewColumn
*col
,
1584 GtkCellRenderer
*renderer
,
1585 GtkTreeModel
*model
,
1592 gint column_id
= GPOINTER_TO_INT(user_data
);
1594 gtk_tree_model_get(model
, iter
,
1596 LST_BUDGET_STATUS
, &status
,
1601 color
= get_minimum_color_amount (value
, 0.0);
1602 g_object_set(renderer
,
1603 "foreground", color
,
1609 g_object_set(renderer
, "text", "", NULL
);
1618 static GtkTreeViewColumn
*amount_list_budget_column(gchar
*name
, gint id
)
1620 GtkTreeViewColumn
*column
;
1621 GtkCellRenderer
*renderer
;
1623 column
= gtk_tree_view_column_new();
1624 gtk_tree_view_column_set_title(column
, name
);
1625 renderer
= gtk_cell_renderer_text_new ();
1626 g_object_set(renderer
, "xalign", 1.0, NULL
);
1627 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1628 gtk_tree_view_column_set_cell_data_func(column
, renderer
, budget_amount_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1629 gtk_tree_view_column_set_alignment (column
, 0.5);
1630 //gtk_tree_view_column_set_sort_column_id (column, id);
1635 ** create our statistic list
1637 static GtkWidget
*create_list_budget(void)
1639 GtkListStore
*store
;
1641 GtkCellRenderer
*renderer
;
1642 GtkTreeViewColumn
*column
;
1644 DB( g_print("\n[repbudget] create list\n") );
1647 /* create list store */
1648 store
= gtk_list_store_new(
1653 G_TYPE_DOUBLE
, //spent
1654 G_TYPE_DOUBLE
, //budget
1655 G_TYPE_DOUBLE
, //result
1656 G_TYPE_STRING
//status
1660 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1661 g_object_unref(store
);
1663 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view
), PREFS
->grid_lines
);
1666 column
= gtk_tree_view_column_new();
1667 gtk_tree_view_column_set_title(column
, _("Category"));
1668 renderer
= gtk_cell_renderer_text_new ();
1669 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1670 //gtk_tree_view_column_set_cell_data_func(column, renderer, ope_result_cell_data_function, NULL, NULL);
1671 gtk_tree_view_column_add_attribute(column
, renderer
, "text", LST_BUDGET_NAME
);
1672 //gtk_tree_view_column_set_sort_column_id (column, LST_STAT_NAME);
1673 gtk_tree_view_column_set_resizable(column
, TRUE
);
1674 gtk_tree_view_column_set_alignment (column
, 0.5);
1675 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1677 /* column: Expense */
1678 column
= amount_list_budget_column(_("Spent"), LST_BUDGET_SPENT
);
1679 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1681 /* column: Income */
1682 column
= amount_list_budget_column(_("Budget"), LST_BUDGET_BUDGET
);
1683 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1685 /* column: Result */
1686 column
= amount_list_budget_column(_("Result"), LST_BUDGET_RESULT
);
1687 renderer
= gtk_cell_renderer_text_new ();
1688 //g_object_set(renderer, "xalign", 0.0, NULL);
1689 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1690 gtk_tree_view_column_set_cell_data_func(column
, renderer
, budget_result_cell_data_function
, GINT_TO_POINTER(LST_BUDGET_RESULT
), NULL
);
1691 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1693 /* column last: empty */
1694 column
= gtk_tree_view_column_new();
1695 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1698 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store
), budget_listview_compare_funct
, NULL
, NULL
);
1699 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
, GTK_SORT_ASCENDING
);
1702 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_POS , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_POS), NULL);
1703 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_SPENT , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_SPENT), NULL);
1704 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_BUDGET, stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_BUDGET), NULL);
1705 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_BUDGET_RESULT , stat_list_compare_func, GINT_TO_POINTER(LST_BUDGET_RESULT), NULL);