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-balance.h"
25 #include "list-operation.h"
26 #include "gtk-chart.h"
27 #include "gtk-dateentry.h"
29 #include "ui-account.h"
30 #include "dsp-mainwindow.h"
31 #include "ui-transaction.h"
34 /****************************************************************************/
36 /****************************************************************************/
45 /* our global datas */
46 extern struct HomeBank
*GLOBALS
;
47 extern struct Preferences
*PREFS
;
51 static void repbalance_action_viewlist(GtkAction
*action
, gpointer user_data
);
52 static void repbalance_action_viewline(GtkAction
*action
, gpointer user_data
);
53 static void repbalance_action_detail(GtkAction
*action
, gpointer user_data
);
54 static void repbalance_action_refresh(GtkAction
*action
, gpointer user_data
);
55 static void repbalance_update_daterange(GtkWidget
*widget
, gpointer user_data
);
56 static void repbalance_update_detail(GtkWidget
*widget
, gpointer user_data
);
57 static void repbalance_toggle_detail(GtkWidget
*widget
, gpointer user_data
);
58 static void repbalance_detail(GtkWidget
*widget
, gpointer user_data
);
59 static void repbalance_sensitive(GtkWidget
*widget
, gpointer user_data
);
61 static void repbalance_date_change(GtkWidget
*widget
, gpointer user_data
);
62 static void repbalance_range_change(GtkWidget
*widget
, gpointer user_data
);
63 static void repbalance_update_info(GtkWidget
*widget
, gpointer user_data
);
64 static void repbalance_toggle_minor(GtkWidget
*widget
, gpointer user_data
);
65 static void repbalance_compute(GtkWidget
*widget
, gpointer user_data
);
66 static void repbalance_setup(struct repbalance_data
*data
, guint32 accnum
);
67 static gboolean
repbalance_window_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
);
68 static GtkWidget
*create_list_repbalance(void);
69 static void ui_repbalance_list_set_cur(GtkTreeView
*treeview
, guint32 kcur
);
75 static GtkRadioActionEntry radio_entries
[] = {
76 { "List" , ICONNAME_HB_VIEW_LIST
, N_("List") , NULL
, N_("View results as list") , 0 },
77 { "Line" , ICONNAME_HB_VIEW_LINE
, N_("Line") , NULL
, N_("View results as lines") , 1 },
78 // { "Column" , ICONNAME_HB_VIEW_COLUMN, N_("Column") , NULL, N_("View results as column"), 2 },
80 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 (repbalance_action_refresh
) },
86 static guint n_entries
= G_N_ELEMENTS (entries
);
88 static GtkToggleActionEntry toggle_entries
[] = {
89 { "Detail", ICONNAME_HB_OPE_SHOW
, /* name, icon-name */
90 N_("Detail"), NULL
, /* label, accelerator */
91 N_("Toggle detail"), /* tooltip */
92 G_CALLBACK (repbalance_action_detail
),
93 FALSE
}, /* is_active */
95 static guint n_toggle_entries
= G_N_ELEMENTS (toggle_entries
);
98 static const gchar
*ui_info
=
100 " <toolbar name='ToolBar'>"
101 " <toolitem action='List'/>"
102 " <toolitem action='Line'/>"
104 " <toolitem action='Detail'/>"
106 " <toolitem action='Refresh'/>"
111 //extern gchar *CYA_FLT_SELECT[];
114 /* action functions -------------------- */
115 static void repbalance_action_viewlist(GtkAction
*action
, gpointer user_data
)
117 struct repbalance_data
*data
= user_data
;
119 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 0);
120 repbalance_sensitive(data
->window
, NULL
);
123 static void repbalance_action_viewline(GtkAction
*action
, gpointer user_data
)
125 struct repbalance_data
*data
= user_data
;
127 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
128 repbalance_sensitive(data
->window
, NULL
);
132 static void ui_repbalance_action_mode (GtkRadioAction
*action
, GtkRadioAction
*current
, gpointer user_data
)
136 value
= gtk_radio_action_get_current_value(GTK_RADIO_ACTION(action
));
140 repbalance_action_viewlist(GTK_ACTION(action
), user_data
);
143 repbalance_action_viewline(GTK_ACTION(action
), user_data
);
148 static void repbalance_action_detail(GtkAction
*action
, gpointer user_data
)
150 struct repbalance_data
*data
= user_data
;
152 repbalance_toggle_detail(data
->window
, NULL
);
155 static void repbalance_action_refresh(GtkAction
*action
, gpointer user_data
)
157 struct repbalance_data
*data
= user_data
;
159 repbalance_compute(data
->window
, NULL
);
164 /* ======================== */
171 static void repbalance_date_change(GtkWidget
*widget
, gpointer user_data
)
173 struct repbalance_data
*data
;
175 DB( g_print(" \n[repbalance] date change\n") );
177 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
179 data
->filter
->mindate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_mindate
));
180 data
->filter
->maxdate
= gtk_date_entry_get_date(GTK_DATE_ENTRY(data
->PO_maxdate
));
182 // set min/max date for both widget
183 gtk_date_entry_set_maxdate(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->maxdate
);
184 gtk_date_entry_set_mindate(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->mindate
);
186 g_signal_handler_block(data
->CY_range
, data
->handler_id
[HID_REPBALANCE_RANGE
]);
187 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
), FLT_RANGE_OTHER
);
188 g_signal_handler_unblock(data
->CY_range
, data
->handler_id
[HID_REPBALANCE_RANGE
]);
191 repbalance_compute(widget
, NULL
);
192 repbalance_update_daterange(widget
, NULL
);
197 static void repbalance_update_quickdate(GtkWidget
*widget
, gpointer user_data
)
199 struct repbalance_data
*data
;
201 DB( g_print(" \n[repbalance] update quickdate\n") );
203 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
205 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_REPBALANCE_MINDATE
]);
206 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_REPBALANCE_MAXDATE
]);
208 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
209 gtk_date_entry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
211 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_REPBALANCE_MINDATE
]);
212 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_REPBALANCE_MAXDATE
]);
218 static void repbalance_range_change(GtkWidget
*widget
, gpointer user_data
)
220 struct repbalance_data
*data
;
223 DB( g_print(" \n[repbalance] range change\n") );
225 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
227 range
= hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
));
229 if(range
!= FLT_RANGE_OTHER
)
231 filter_preset_daterange_set(data
->filter
, range
, data
->accnum
);
233 repbalance_update_quickdate(widget
, NULL
);
235 repbalance_compute(widget
, NULL
);
236 repbalance_update_daterange(widget
, NULL
);
241 static void repbalance_update_daterange(GtkWidget
*widget
, gpointer user_data
)
243 struct repbalance_data
*data
;
246 DB( g_print(" \n[repbalance] update daterange\n") );
248 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
250 daterange
= filter_daterange_text_get(data
->filter
);
251 gtk_label_set_markup(GTK_LABEL(data
->TX_daterange
), daterange
);
256 static void repbalance_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
262 DB( g_print(" \n[repbalance] selection\n") );
264 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
266 gtk_tree_model_get(model
, &iter
, LST_OVER_DATE
, &key
, -1);
269 DB( g_print(" - active is %d\n", key
) );
271 repbalance_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
272 repbalance_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
277 ** update sensitivity
279 static void repbalance_sensitive(GtkWidget
*widget
, gpointer user_data
)
281 struct repbalance_data
*data
;
286 DB( g_print(" \n[repbalance] sensitive\n") );
288 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
290 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
292 action
= gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Detail");
293 visible
= page
== 0 ? TRUE
: FALSE
;
294 gtk_action_set_visible (action
, visible
);
295 //sensitive = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_report)), NULL, NULL);
296 //gtk_action_set_sensitive(action, sensitive);
298 visible
= page
== 0 ? FALSE
: TRUE
;
299 hb_widget_visible(data
->LB_zoomx
, visible
);
300 hb_widget_visible(data
->RG_zoomx
, visible
);
305 static void repbalance_update_info(GtkWidget
*widget
, gpointer user_data
)
307 struct repbalance_data
*data
;
312 DB( g_print(" \n[repbalance] update info\n") );
314 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
316 gboolean selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
318 guint32 acckey
= ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data
->PO_acc
));
320 DB( g_print(" acc key = %d\n", acckey
) );
322 acc
= da_acc_get(acckey
);
326 gboolean minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
328 hb_strfmon(buf
, 127, data
->minimum
, selectall
? GLOBALS
->kcur
: acc
->kcur
, minor
);
330 ////TRANSLATORS: count of transaction in balancedrawn / count of total transaction under abalancedrawn amount threshold
331 info
= g_strdup_printf(_("%d/%d under %s"), data
->nbbalance
, data
->nbope
, buf
);
332 gtk_label_set_text(GTK_LABEL(data
->TX_info
), info
);
339 static void repbalance_detail(GtkWidget
*widget
, gpointer user_data
)
341 struct repbalance_data
*data
;
342 guint active
= GPOINTER_TO_INT(user_data
);
348 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
350 DB( g_print(" \n[repbalance] detail\n") );
352 /* clear and detach our model */
353 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
));
354 gtk_list_store_clear (GTK_LIST_STORE(model
));
358 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
359 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), NULL
); /* Detach model from view */
362 gboolean selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
364 // get the account key
365 acckey
= ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data
->PO_acc
));
367 /* fill in the model */
368 list
= g_list_first(data
->ope_list
);
371 Transaction
*ope
= list
->data
;
373 //DB( g_print(" get %s\n", ope->ope_Word) );
376 if( ope
->date
== active
&& (ope
->kacc
== acckey
|| selectall
) )
378 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
379 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
380 LST_DSPOPE_DATAS
, ope
,
383 list
= g_list_next(list
);
386 /* Re-attach model to view */
387 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), model
);
388 g_object_unref(model
);
390 gtk_tree_view_columns_autosize( GTK_TREE_VIEW(data
->LV_detail
) );
396 static void repbalance_detail_onRowActivated (GtkTreeView
*treeview
,
398 GtkTreeViewColumn
*col
,
401 struct repbalance_data
*data
;
402 Transaction
*active_txn
;
405 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
407 DB( g_print ("\n[repbalance] A detail row has been double-clicked!\n") );
409 active_txn
= list_txn_get_active_transaction(GTK_TREE_VIEW(data
->LV_detail
));
412 Transaction
*old_txn
, *new_txn
;
414 old_txn
= da_transaction_clone (active_txn
);
415 new_txn
= active_txn
;
416 result
= deftransaction_external_edit(GTK_WINDOW(data
->window
), old_txn
, new_txn
);
418 if(result
== GTK_RESPONSE_ACCEPT
)
421 GLOBALS
->changes_count
++;
422 repbalance_compute (data
->window
, NULL
);
425 da_transaction_free (old_txn
);
431 static void repbalance_update_detail(GtkWidget
*widget
, gpointer user_data
)
433 struct repbalance_data
*data
;
435 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
439 GtkTreeSelection
*treeselection
;
444 treeselection
= gtk_tree_view_get_selection (GTK_TREE_VIEW(data
->LV_report
));
446 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
448 gtk_tree_model_get(model
, &iter
, LST_OVER_DATE
, &key
, -1);
450 DB( g_print(" - active is %d\n", key
) );
452 repbalance_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
457 gtk_widget_show(data
->GR_detail
);
460 gtk_widget_hide(data
->GR_detail
);
464 static void repbalance_toggle_detail(GtkWidget
*widget
, gpointer user_data
)
466 struct repbalance_data
*data
;
468 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
472 DB( g_print(" \n[repbalance] toggledetail to %d\n", (int)data
->detail
) );
474 repbalance_update_detail(widget
, user_data
);
479 static void repbalance_zoomx_callback(GtkWidget
*widget
, gpointer user_data
)
481 struct repbalance_data
*data
;
484 DB( g_print("(statistic) zoomx\n") );
486 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
488 value
= gtk_range_get_value(GTK_RANGE(data
->RG_zoomx
));
490 DB( g_print(" + scale is %f\n", value
) );
492 gtk_chart_set_barw(GTK_CHART(data
->RE_line
), value
);
497 static void repbalance_toggle_minor(GtkWidget
*widget
, gpointer user_data
)
499 struct repbalance_data
*data
;
501 DB( g_print(" \n[repbalance] toggle\n") );
503 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
505 GLOBALS
->minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
507 repbalance_update_info(widget
,NULL
);
509 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
511 gtk_chart_show_minor(GTK_CHART(data
->RE_line
), GLOBALS
->minor
);
515 static void repbalance_compute_full_datas(guint32 selkey
, gboolean selectall
, struct repbalance_data
*data
)
518 GList
*lst_acc
, *lnk_acc
;
520 DB( g_print(" \n[repbalance] compute_full\n") );
522 g_list_free(data
->ope_list
);
523 data
->ope_list
= hbfile_transaction_get_all();
525 if(g_list_length(data
->ope_list
) == 0) return;
527 Transaction
*omin
= g_list_first(data
->ope_list
)->data
;
528 Transaction
*omax
= g_list_last(data
->ope_list
)->data
;
530 // total days in the hbfile
531 data
->n_result
= omax
->date
- omin
->date
;
533 DB( g_print(" - %d days in slice\n", data
->n_result
) );
535 data
->tmp_income
= g_malloc0((data
->n_result
+2) * sizeof(gdouble
));
536 data
->tmp_expense
= g_malloc0((data
->n_result
+2) * sizeof(gdouble
));
538 // to store that initial balance was affected
539 gboolean
*accounts
= g_malloc0((da_acc_get_max_key()+2) * sizeof(gboolean
));
541 if(data
->tmp_income
&& data
->tmp_expense
)
545 /* account initial amount */
546 lst_acc
= g_hash_table_get_values(GLOBALS
->h_acc
);
547 lnk_acc
= g_list_first(lst_acc
);
548 while (lnk_acc
!= NULL
)
550 Account
*acc
= lnk_acc
->data
;
552 //#1674045 ony rely on nosummary
553 //if( (acc->flags & (AF_CLOSED|AF_NOREPORT)) )
554 if( (acc
->flags
& (AF_NOREPORT
)) )
559 trn_amount
= hb_amount_base(acc
->initial
, acc
->kcur
);
561 if( selkey
== acc
->key
)
562 trn_amount
= acc
->initial
;
565 data
->tmp_expense
[0] += trn_amount
;
567 data
->tmp_income
[0] += trn_amount
;
569 DB( g_print(" - stored initial %.2f for account %d:%s\n", trn_amount
, acc
->key
, acc
->name
) );
572 lnk_acc
= g_list_next(lnk_acc
);
574 g_list_free(lst_acc
);
576 /* compute the balance */
577 list
= g_list_first(data
->ope_list
);
581 Transaction
*ope
= list
->data
;
583 if(selkey
== ope
->kacc
|| selectall
== TRUE
)
585 Account
*acc
= da_acc_get(ope
->kacc
);
589 pos
= ope
->date
- omin
->date
;
591 // deal with account initial balance
592 /*if(accounts[ope->kacc] == 0)
595 trn_amount = hb_amount_base(acc->initial, acc->kcur);
597 trn_amount = acc->initial;
600 data->tmp_expense[pos] += trn_amount;
602 data->tmp_income[pos] += trn_amount;
604 DB( g_print(" - stored initial %.2f for account %d\n", trn_amount, ope->kacc) );
606 accounts[ope->kacc] = 1;
610 trn_amount
= hb_amount_base(ope
->amount
, acc
->kcur
);
612 trn_amount
= ope
->amount
;
614 //deal with transactions
616 data
->tmp_expense
[pos
] += trn_amount
;
618 data
->tmp_income
[pos
] += trn_amount
;
622 list
= g_list_next(list
);
632 static void repbalance_compute(GtkWidget
*widget
, gpointer user_data
)
634 struct repbalance_data
*data
;
638 gboolean range
, selectall
, eachday
;
641 DB( g_print(" \n[repbalance] compute\n") );
643 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
645 selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
646 eachday
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_eachday
));
647 range
= hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
));
649 // get the account key
650 acckey
= ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data
->PO_acc
));
652 DB( g_print(" acc key = %d\n", acckey
) );
659 // for a single account
662 acc
= da_acc_get(acckey
);
665 data
->minimum
= acc
->minimum
;
666 data
->accnum
= acc
->key
;
667 ui_repbalance_list_set_cur(GTK_TREE_VIEW(data
->LV_report
), acc
->kcur
);
668 gtk_chart_set_currency(GTK_CHART(data
->RE_line
), acc
->kcur
);
674 ui_repbalance_list_set_cur(GTK_TREE_VIEW(data
->LV_report
), GLOBALS
->kcur
);
675 gtk_chart_set_currency(GTK_CHART(data
->RE_line
), GLOBALS
->kcur
);
679 //#1715532 5.0.5: no... but only selectall
680 //#1756601 but only for FLT_RANGE_ALLDATE
681 if( (selectall
== TRUE
) && (range
== FLT_RANGE_ALLDATE
) )
683 filter_preset_daterange_set(data
->filter
, data
->filter
->range
, data
->accnum
);
684 repbalance_update_quickdate(widget
, NULL
);
687 repbalance_compute_full_datas(acckey
, selectall
, data
);
689 /* do nothing if no transaction */
690 if(g_list_length(data
->ope_list
) == 0) return;
693 /* clear and detach our model */
694 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
695 gtk_list_store_clear (GTK_LIST_STORE(model
));
696 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
697 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), NULL
); /* Detach model from view */
699 Transaction
*omin
= g_list_first(data
->ope_list
)->data
;
702 for(i
=0;i
<=data
->n_result
;i
++)
704 gboolean is_balance
= FALSE
;
709 posdate
= omin
->date
+ i
;
711 //DB( g_print("omin->date=%d posdate=%d\n", omin->date, posdate) );
714 balance
+= data
->tmp_expense
[i
];
715 balance
+= data
->tmp_income
[i
];
717 if(!eachday
&& data
->tmp_expense
[i
] == 0 && data
->tmp_income
[i
] == 0)
720 if( (posdate
>= data
->filter
->mindate
) && (posdate
<= data
->filter
->maxdate
) )
723 is_balance
= (balance
< data
->minimum
) ? TRUE
: FALSE
;
725 date
= g_date_new_julian (posdate
);
726 g_date_strftime (buf
, 256-1, PREFS
->date_format
, date
);
729 /* column 0: pos (gint) */
730 /* not used: column 1: key (gint) */
731 /* column 2: name (gchar) */
732 /* column x: values (double) */
734 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
735 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
736 LST_OVER_OVER
, is_balance
,
737 LST_OVER_DATE
, posdate
,
738 LST_OVER_DATESTR
, buf
,
739 LST_OVER_EXPENSE
, data
->tmp_expense
[i
],
740 LST_OVER_INCOME
, data
->tmp_income
[i
],
741 LST_OVER_BALANCE
, balance
,
743 if(is_balance
== TRUE
)
752 g_free(data
->tmp_expense
);
753 g_free(data
->tmp_income
);
755 repbalance_update_info(widget
, NULL
);
757 gtk_chart_show_legend(GTK_CHART(data
->RE_line
), FALSE
, FALSE
);
758 gtk_chart_show_xval(GTK_CHART(data
->RE_line
), TRUE
);
759 gtk_chart_set_overdrawn(GTK_CHART(data
->RE_line
), data
->minimum
);
760 gtk_chart_show_overdrawn(GTK_CHART(data
->RE_line
), !selectall
);
762 gboolean visible
= selectall
? FALSE
: TRUE
;
763 gtk_widget_set_visible (GTK_WIDGET(data
->TX_info
), visible
);
765 /* Re-attach model to view */
766 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), model
);
767 g_object_unref(model
);
769 /* update bar chart */
770 //DB( g_print(" set bar to %d\n\n", LST_STAT_EXPENSE+tmpkind) );
771 gtk_chart_set_datas(GTK_CHART(data
->RE_line
), model
, LST_OVER_BALANCE
, NULL
, NULL
);
772 //gtk_chart_set_line_datas(GTK_CHART(data->RE_line), model, LST_OVER_BALANCE, LST_OVER_DATE);
778 static void repbalance_toggle_selectall(GtkWidget
*widget
, gpointer user_data
)
780 struct repbalance_data
*data
;
783 DB( g_print(" \n[repbalance] toggle selectall\n") );
785 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
787 selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
789 gtk_widget_set_sensitive(GTK_WIDGET(data
->PO_acc
), selectall
^1);
791 repbalance_compute(widget
, data
);
796 static void repbalance_setup(struct repbalance_data
*data
, guint32 accnum
)
798 DB( g_print(" \n[repbalance] setup\n") );
800 data
->ope_list
= NULL
;
802 data
->filter
= da_flt_malloc();
803 filter_reset(data
->filter
);
805 data
->accnum
= accnum
;
806 filter_preset_daterange_set(data
->filter
, PREFS
->date_range_rep
, data
->accnum
);
807 repbalance_update_quickdate(data
->window
, NULL
);
809 ui_acc_comboboxentry_populate(GTK_COMBO_BOX(data
->PO_acc
), GLOBALS
->h_acc
, ACC_LST_INSERT_REPORT
);
811 ui_acc_comboboxentry_set_active(GTK_COMBO_BOX(data
->PO_acc
), accnum
);
813 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->PO_acc
), 0);
818 static gboolean
repbalance_window_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
820 struct repbalance_data
*data
= user_data
;
821 struct WinGeometry
*wg
;
823 DB( g_print(" \n[repbalance] dispose\n") );
825 g_list_free (data
->ope_list
);
827 da_flt_free(data
->filter
);
831 //store position and size
833 gtk_window_get_position(GTK_WINDOW(widget
), &wg
->l
, &wg
->t
);
834 gtk_window_get_size(GTK_WINDOW(widget
), &wg
->w
, &wg
->h
);
836 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg
->l
, wg
->t
, wg
->w
, wg
->h
) );
838 //enable define windows
839 GLOBALS
->define_off
--;
840 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
846 // the window creation
847 GtkWidget
*repbalance_window_new(gint accnum
)
849 struct repbalance_data
*data
;
850 struct WinGeometry
*wg
;
851 GtkWidget
*window
, *mainvbox
, *hbox
, *vbox
, *notebook
, *treeview
;
852 GtkWidget
*label
, *widget
, *table
;
855 GtkActionGroup
*actions
;
857 GError
*error
= NULL
;
859 data
= g_malloc0(sizeof(struct repbalance_data
));
860 if(!data
) return NULL
;
862 DB( g_print(" \n[repbalance] new\n") );
864 //disable define windows
865 GLOBALS
->define_off
++;
866 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
868 /* create window, etc */
869 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
870 data
->window
= window
;
872 //store our window private data
873 g_object_set_data(G_OBJECT(window
), "inst_data", (gpointer
)data
);
874 DB( g_print(" - new window=%p, inst_data=%p\n", window
, data
) );
876 gtk_window_set_title (GTK_WINDOW (window
), _("Balance report"));
878 //set the window icon
879 gtk_window_set_icon_name(GTK_WINDOW (window
), ICONNAME_HB_REP_BALANCE
);
882 mainvbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
883 gtk_container_add (GTK_CONTAINER (window
), mainvbox
);
885 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
886 gtk_box_pack_start (GTK_BOX (mainvbox
), hbox
, TRUE
, TRUE
, 0);
889 table
= gtk_grid_new ();
890 gtk_widget_set_hexpand (GTK_WIDGET(table
), FALSE
);
891 gtk_box_pack_start (GTK_BOX (hbox
), table
, FALSE
, FALSE
, 0);
893 gtk_container_set_border_width (GTK_CONTAINER (table
), SPACING_SMALL
);
894 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_SMALL
);
895 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
899 label
= make_label_group(_("Display"));
900 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
903 label
= make_label_widget(_("A_ccount:"));
904 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
905 widget
= ui_acc_comboboxentry_new(label
);
906 data
->PO_acc
= widget
;
907 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
910 widget
= gtk_check_button_new_with_mnemonic (_("Select _all"));
911 data
->CM_selectall
= widget
;
912 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
915 widget
= gtk_check_button_new_with_mnemonic (_("Each _day"));
916 //gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), TRUE);
917 data
->CM_eachday
= widget
;
918 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
921 widget
= gtk_check_button_new_with_mnemonic (_("Euro _minor"));
922 data
->CM_minor
= widget
;
923 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
926 label
= make_label_widget(_("_Zoom X:"));
927 data
->LB_zoomx
= label
;
928 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
929 widget
= make_scale(label
);
930 data
->RG_zoomx
= widget
;
931 gtk_grid_attach (GTK_GRID (table
), widget
, 2, row
, 1, 1);
934 widget
= gtk_separator_new(GTK_ORIENTATION_HORIZONTAL
);
935 gtk_grid_attach (GTK_GRID (table
), widget
, 0, row
, 3, 1);
938 label
= make_label_group(_("Date filter"));
939 gtk_grid_attach (GTK_GRID (table
), label
, 0, row
, 3, 1);
942 label
= make_label_widget(_("_Range:"));
943 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
944 data
->CY_range
= make_daterange(label
, DATE_RANGE_CUSTOM_DISABLE
);
945 gtk_grid_attach (GTK_GRID (table
), data
->CY_range
, 2, row
, 1, 1);
948 label
= make_label_widget(_("_From:"));
949 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
950 data
->PO_mindate
= gtk_date_entry_new();
951 gtk_grid_attach (GTK_GRID (table
), data
->PO_mindate
, 2, row
, 1, 1);
954 label
= make_label_widget(_("_To:"));
955 gtk_grid_attach (GTK_GRID (table
), label
, 1, row
, 1, 1);
956 data
->PO_maxdate
= gtk_date_entry_new();
957 gtk_grid_attach (GTK_GRID (table
), data
->PO_maxdate
, 2, row
, 1, 1);
960 //part: info + report
961 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
962 gtk_box_pack_start (GTK_BOX (hbox
), vbox
, TRUE
, TRUE
, 0);
965 actions
= gtk_action_group_new ("default");
968 gtk_action_group_set_translation_domain(actions
, GETTEXT_PACKAGE
);
970 // data to action callbacks is set here (data)
971 gtk_action_group_add_radio_actions (actions
, radio_entries
, n_radio_entries
, 0, G_CALLBACK(ui_repbalance_action_mode
), data
);
973 gtk_action_group_add_actions (actions
, entries
, n_entries
, data
);
975 gtk_action_group_add_toggle_actions (actions
,
976 toggle_entries
, n_toggle_entries
,
980 /* set which action should have priority in the toolbar */
981 //action = gtk_action_group_get_action(actions, "List");
982 //g_object_set(action, "is_important", TRUE, NULL);
984 //action = gtk_action_group_get_action(actions, "Line");
985 //g_object_set(action, "is_important", TRUE, NULL);
987 //action = gtk_action_group_get_action(actions, "Detail");
988 //g_object_set(action, "is_important", TRUE, NULL);
990 //action = gtk_action_group_get_action(actions, "Refresh");
991 //g_object_set(action, "is_important", TRUE, NULL);
995 ui
= gtk_ui_manager_new ();
996 gtk_ui_manager_insert_action_group (ui
, actions
, 0);
997 gtk_window_add_accel_group (GTK_WINDOW (window
), gtk_ui_manager_get_accel_group (ui
));
999 if (!gtk_ui_manager_add_ui_from_string (ui
, ui_info
, -1, &error
))
1001 g_message ("building UI failed: %s", error
->message
);
1002 g_error_free (error
);
1006 data
->actions
= actions
;
1009 data
->TB_bar
= gtk_ui_manager_get_widget (ui
, "/ToolBar");
1010 gtk_box_pack_start (GTK_BOX (vbox
), data
->TB_bar
, FALSE
, FALSE
, 0);
1013 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, SPACING_SMALL
);
1014 gtk_container_set_border_width (GTK_CONTAINER(hbox
), SPACING_SMALL
);
1015 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
1018 label
= gtk_label_new(NULL
);
1019 data
->TX_info
= label
;
1020 gtk_box_pack_start (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
1022 widget
= make_label(NULL
, 0.5, 0.5);
1023 gimp_label_set_attributes (GTK_LABEL (widget
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
1024 data
->TX_daterange
= widget
;
1025 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
1028 notebook
= gtk_notebook_new();
1029 data
->GR_result
= notebook
;
1030 gtk_widget_show(notebook
);
1031 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
1032 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
1034 gtk_box_pack_start (GTK_BOX (vbox
), notebook
, TRUE
, TRUE
, 0);
1037 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1038 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vbox
, NULL
);
1040 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1041 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1042 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1044 treeview
= create_list_repbalance();
1045 data
->LV_report
= treeview
;
1046 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1047 //gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL);
1048 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1051 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1052 data
->GR_detail
= widget
;
1053 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (widget), GTK_CORNER_TOP_RIGHT);
1054 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1055 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1056 treeview
= create_list_transaction(LIST_TXN_TYPE_DETAIL
, PREFS
->lst_ope_columns
);
1057 data
->LV_detail
= treeview
;
1058 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1060 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1064 widget
= gtk_chart_new(CHART_TYPE_LINE
);
1065 data
->RE_line
= widget
;
1066 //gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.suffix_symbol);
1067 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), widget
, NULL
);
1072 //todo:should move this
1073 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_minor
),GLOBALS
->minor
);
1077 /* attach our minor to treeview */
1078 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
))), "minor", (gpointer
)data
->CM_minor
);
1084 /* signal connect */
1085 g_signal_connect (window
, "delete-event", G_CALLBACK (repbalance_window_dispose
), (gpointer
)data
);
1087 g_signal_connect (data
->CM_minor
, "toggled", G_CALLBACK (repbalance_toggle_minor
), NULL
);
1090 data
->handler_id
[HID_REPBALANCE_MINDATE
] = g_signal_connect (data
->PO_mindate
, "changed", G_CALLBACK (repbalance_date_change
), (gpointer
)data
);
1091 data
->handler_id
[HID_REPBALANCE_MAXDATE
] = g_signal_connect (data
->PO_maxdate
, "changed", G_CALLBACK (repbalance_date_change
), (gpointer
)data
);
1093 data
->handler_id
[HID_REPBALANCE_RANGE
] = g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (repbalance_range_change
), NULL
);
1095 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), "changed", G_CALLBACK (repbalance_selection
), NULL
);
1097 //setup, init and show window
1098 repbalance_setup(data
, accnum
);
1100 g_signal_connect (data
->CM_selectall
, "toggled", G_CALLBACK (repbalance_toggle_selectall
), NULL
);
1101 g_signal_connect (data
->CM_eachday
, "toggled", G_CALLBACK (repbalance_compute
), NULL
);
1104 //let this here or the setup trigger a compute...
1105 g_signal_connect (data
->PO_acc
, "changed", G_CALLBACK (repbalance_compute
), NULL
);
1107 g_signal_connect (data
->RG_zoomx
, "value-changed", G_CALLBACK (repbalance_zoomx_callback
), NULL
);
1109 g_signal_connect (GTK_TREE_VIEW(data
->LV_detail
), "row-activated", G_CALLBACK (repbalance_detail_onRowActivated
), NULL
);
1113 if(PREFS
->toolbar_style
== 0)
1114 gtk_toolbar_unset_style(GTK_TOOLBAR(data
->TB_bar
));
1116 gtk_toolbar_set_style(GTK_TOOLBAR(data
->TB_bar
), PREFS
->toolbar_style
-1);
1119 //setup, init and show window
1120 wg
= &PREFS
->ove_wg
;
1121 gtk_window_move(GTK_WINDOW(window
), wg
->l
, wg
->t
);
1122 gtk_window_resize(GTK_WINDOW(window
), wg
->w
, wg
->h
);
1126 gtk_widget_show_all (window
);
1129 if( PREFS
->euro_active
)
1130 gtk_widget_show(data
->CM_minor
);
1132 gtk_widget_hide(data
->CM_minor
);
1134 repbalance_sensitive(window
, NULL
);
1135 repbalance_update_detail(window
, NULL
);
1137 hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data
->CY_range
), PREFS
->date_range_rep
);
1144 ** ============================================================================
1148 static void repbalance_date_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
1151 gboolean is_balance
;
1155 gtk_tree_model_get(model
, iter
,
1156 LST_OVER_DATESTR
, &datestr
,
1157 LST_OVER_OVER
, &is_balance
,
1161 weight
= PANGO_WEIGHT_NORMAL
;
1163 if(is_balance
==TRUE
)
1165 if(PREFS
->custom_colors
== TRUE
)
1166 color
= PREFS
->color_warn
;
1168 weight
= PANGO_WEIGHT_BOLD
;
1171 g_object_set(renderer
,
1173 "foreground", color
,
1182 static void repbalance_amount_cell_data_function (GtkTreeViewColumn
*col
,
1183 GtkCellRenderer
*renderer
,
1184 GtkTreeModel
*model
,
1189 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1190 gboolean is_balance
;
1193 guint32 kcur
= GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(gtk_tree_view_column_get_tree_view(col
)), "kcur_data"));
1197 gtk_tree_model_get(model
, iter
,
1198 LST_OVER_OVER
, &is_balance
,
1199 GPOINTER_TO_INT(user_data
), &value
,
1204 g_object_set(renderer
, "text", NULL
, NULL
);
1207 hb_strfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, kcur
, GLOBALS
->minor
);
1210 weight
= PANGO_WEIGHT_NORMAL
;
1213 if(value
!= 0.0 && PREFS
->custom_colors
== TRUE
)
1214 color
= (value
> 0.0) ? PREFS
->color_inc
: PREFS
->color_exp
;
1216 if(is_balance
==TRUE
)
1218 if(PREFS
->custom_colors
== TRUE
)
1219 color
= PREFS
->color_warn
;
1221 weight
= PANGO_WEIGHT_BOLD
;
1224 g_object_set(renderer
,
1226 "foreground", color
,
1233 static GtkTreeViewColumn
*amount_list_repbalance_column(gchar
*name
, gint id
)
1235 GtkTreeViewColumn
*column
;
1236 GtkCellRenderer
*renderer
;
1238 column
= gtk_tree_view_column_new();
1239 gtk_tree_view_column_set_title(column
, name
);
1240 renderer
= gtk_cell_renderer_text_new ();
1241 g_object_set(renderer
, "xalign", 1.0, NULL
);
1242 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1243 gtk_tree_view_column_set_cell_data_func(column
, renderer
, repbalance_amount_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1244 gtk_tree_view_column_set_alignment (column
, 0.5);
1245 //gtk_tree_view_column_set_sort_column_id (column, id);
1250 static void ui_repbalance_list_set_cur(GtkTreeView
*treeview
, guint32 kcur
)
1252 g_object_set_data(G_OBJECT(treeview
), "kcur_data", GUINT_TO_POINTER(kcur
));
1257 ** create our statistic list
1259 static GtkWidget
*create_list_repbalance(void)
1261 GtkListStore
*store
;
1263 GtkCellRenderer
*renderer
;
1264 GtkTreeViewColumn
*column
;
1266 /* create list store */
1267 store
= gtk_list_store_new(
1278 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1279 g_object_unref(store
);
1281 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view
), PREFS
->grid_lines
);
1283 /* column debug balance */
1285 column = gtk_tree_view_column_new();
1286 gtk_tree_view_column_set_title(column, "debug balance");
1287 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1288 renderer = gtk_cell_renderer_text_new();
1289 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1290 gtk_tree_view_column_add_attribute(column, renderer, "text", LST_OVER_OVER);
1294 column
= gtk_tree_view_column_new();
1295 gtk_tree_view_column_set_title(column
, _("Date"));
1296 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1297 renderer
= gtk_cell_renderer_text_new();
1298 g_object_set(renderer
, "xalign", 1.0, NULL
);
1299 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1300 //gtk_tree_view_column_add_attribute(column, renderer, "text", LST_OVER_DATE);
1301 gtk_tree_view_column_set_alignment (column
, 0.5);
1302 gtk_tree_view_column_set_cell_data_func(column
, renderer
, repbalance_date_cell_data_function
, NULL
, NULL
);
1305 /* column: Expense */
1306 column
= amount_list_repbalance_column(_("Expense"), LST_OVER_EXPENSE
);
1307 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1309 /* column: Income */
1310 column
= amount_list_repbalance_column(_("Income"), LST_OVER_INCOME
);
1311 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1313 /* column: Balance */
1314 column
= amount_list_repbalance_column(_("Balance"), LST_OVER_BALANCE
);
1315 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1317 /* column last: empty */
1318 column
= gtk_tree_view_column_new();
1319 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);