1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2014 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"
33 /****************************************************************************/
35 /****************************************************************************/
44 /* our global datas */
45 extern struct HomeBank
*GLOBALS
;
46 extern struct Preferences
*PREFS
;
57 struct repbalance_data
64 GtkActionGroup
*actions
;
69 GtkWidget
*TX_daterange
;
73 GtkWidget
*CM_selectall
;
74 GtkWidget
*CM_eachday
;
77 GtkWidget
*PO_mindate
, *PO_maxdate
;
96 guint nbbalance
, nbope
;
98 gulong handler_id
[MAX_HID
];
106 static void repbalance_action_viewlist(GtkAction
*action
, gpointer user_data
);
107 static void repbalance_action_viewline(GtkAction
*action
, gpointer user_data
);
108 static void repbalance_action_detail(GtkAction
*action
, gpointer user_data
);
109 static void repbalance_action_refresh(GtkAction
*action
, gpointer user_data
);
110 static void repbalance_update_daterange(GtkWidget
*widget
, gpointer user_data
);
111 static void repbalance_update_detail(GtkWidget
*widget
, gpointer user_data
);
112 static void repbalance_toggle_detail(GtkWidget
*widget
, gpointer user_data
);
113 static void repbalance_detail(GtkWidget
*widget
, gpointer user_data
);
114 static void repbalance_sensitive(GtkWidget
*widget
, gpointer user_data
);
120 static GtkActionEntry entries
[] = {
121 { "List" , "hb-view-list" , N_("List") , NULL
, N_("View results as list"), G_CALLBACK (repbalance_action_viewlist
) },
122 { "Line" , "hb-view-line" , N_("Line") , NULL
, N_("View results as lines"), G_CALLBACK (repbalance_action_viewline
) },
123 { "Refresh" , GTK_STOCK_REFRESH
, N_("Refresh"), NULL
, N_("Refresh results"), G_CALLBACK (repbalance_action_refresh
) },
126 static guint n_entries
= G_N_ELEMENTS (entries
);
128 static GtkToggleActionEntry toggle_entries
[] = {
129 { "Detail", "hb-ope-show", /* name, stock id */
130 N_("Detail"), NULL
, /* label, accelerator */
131 N_("Toggle detail"), /* tooltip */
132 G_CALLBACK (repbalance_action_detail
),
133 FALSE
}, /* is_active */
135 static guint n_toggle_entries
= G_N_ELEMENTS (toggle_entries
);
138 static const gchar
*ui_info
=
140 " <toolbar name='ToolBar'>"
141 " <toolitem action='List'/>"
142 " <toolitem action='Line'/>"
144 " <toolitem action='Detail'/>"
146 " <toolitem action='Refresh'/>"
162 //extern gchar *CYA_FLT_SELECT[];
165 static void repbalance_date_change(GtkWidget
*widget
, gpointer user_data
);
166 static void repbalance_range_change(GtkWidget
*widget
, gpointer user_data
);
167 static void repbalance_update_info(GtkWidget
*widget
, gpointer user_data
);
168 static void repbalance_toggle_minor(GtkWidget
*widget
, gpointer user_data
);
169 static void repbalance_compute(GtkWidget
*widget
, gpointer user_data
);
170 static void repbalance_setup(struct repbalance_data
*data
, guint32 accnum
);
171 static gboolean
repbalance_window_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
);
172 static GtkWidget
*create_list_repbalance(void);
176 /* action functions -------------------- */
177 static void repbalance_action_viewlist(GtkAction
*action
, gpointer user_data
)
179 struct repbalance_data
*data
= user_data
;
181 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 0);
182 //repbalance_sensitive(data->window, NULL);
185 static void repbalance_action_viewline(GtkAction
*action
, gpointer user_data
)
187 struct repbalance_data
*data
= user_data
;
189 gtk_notebook_set_current_page(GTK_NOTEBOOK(data
->GR_result
), 1);
190 //repbalance_sensitive(data->window, NULL);
193 static void repbalance_action_detail(GtkAction
*action
, gpointer user_data
)
195 struct repbalance_data
*data
= user_data
;
197 repbalance_toggle_detail(data
->window
, NULL
);
200 static void repbalance_action_refresh(GtkAction
*action
, gpointer user_data
)
202 struct repbalance_data
*data
= user_data
;
204 repbalance_compute(data
->window
, NULL
);
209 /* ======================== */
216 static void repbalance_date_change(GtkWidget
*widget
, gpointer user_data
)
218 struct repbalance_data
*data
;
220 DB( g_print("(repbalance) date change\n") );
222 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
224 data
->filter
->mindate
= gtk_dateentry_get_date(GTK_DATE_ENTRY(data
->PO_mindate
));
225 data
->filter
->maxdate
= gtk_dateentry_get_date(GTK_DATE_ENTRY(data
->PO_maxdate
));
227 // set min/max date for both widget
228 gtk_dateentry_set_maxdate(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->maxdate
);
229 gtk_dateentry_set_mindate(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->mindate
);
231 g_signal_handler_block(data
->CY_range
, data
->handler_id
[HID_RANGE
]);
232 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), FLT_RANGE_OTHER
);
233 g_signal_handler_unblock(data
->CY_range
, data
->handler_id
[HID_RANGE
]);
236 repbalance_compute(widget
, NULL
);
237 repbalance_update_daterange(widget
, NULL
);
242 static void repbalance_range_change(GtkWidget
*widget
, gpointer user_data
)
244 struct repbalance_data
*data
;
247 DB( g_print("(repbalance) range change\n") );
249 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
251 range
= gtk_combo_box_get_active(GTK_COMBO_BOX(data
->CY_range
));
253 if(range
!= FLT_RANGE_OTHER
)
255 filter_preset_daterange_set(data
->filter
, range
);
257 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_MINDATE
]);
258 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_MAXDATE
]);
260 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
261 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
263 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_MINDATE
]);
264 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_MAXDATE
]);
266 repbalance_compute(widget
, NULL
);
267 repbalance_update_daterange(widget
, NULL
);
272 static void repbalance_update_daterange(GtkWidget
*widget
, gpointer user_data
)
274 struct repbalance_data
*data
;
277 DB( g_print("(repbalance) update daterange\n") );
279 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
281 daterange
= filter_daterange_text_get(data
->filter
);
282 gtk_label_set_markup(GTK_LABEL(data
->TX_daterange
), daterange
);
287 static void repbalance_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
293 DB( g_print("(repbalance) selection\n") );
295 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
297 gtk_tree_model_get(model
, &iter
, LST_OVER_DATE
, &key
, -1);
299 DB( g_print(" - active is %d\n", key
) );
301 repbalance_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
304 repbalance_sensitive(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
309 ** update sensitivity
311 static void repbalance_sensitive(GtkWidget
*widget
, gpointer user_data
)
313 struct repbalance_data
*data
;
318 DB( g_print("(repbalance) sensitive\n") );
320 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
322 active
= gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), NULL
, NULL
);
324 page
= gtk_notebook_get_current_page(GTK_NOTEBOOK(data
->GR_result
));
326 sensitive
= page
== 0 ? active
: FALSE
;
327 // gtk_widget_set_sensitive(data->TB_buttons[ACTION_REPBUDGET_DETAIL], sensitive);
328 gtk_action_set_sensitive(gtk_ui_manager_get_action(data
->ui
, "/ToolBar/Detail"), sensitive
);
336 static void repbalance_update_info(GtkWidget
*widget
, gpointer user_data
)
338 struct repbalance_data
*data
;
343 DB( g_print("(repbalance) update info\n") );
345 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
347 //gboolean selectall = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_selectall));
349 //guint32 acckey = ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data->PO_acc));
351 mystrfmon(buf
, 127, data
->minimum
, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
)) );
352 //DB( g_print(" acc key = %d\n", acckey) );
353 //acc = da_acc_get(acckey);
354 //hb_strfmon(buf, 127, data->minimum, selectall ? GLOBALS->kcur : acc->kcur);
356 ////TRANSLATORS: count of transaction in balancedrawn / count of total transaction under abalancedrawn amount threshold
357 info
= g_strdup_printf(_("%d/%d under %s"), data
->nbbalance
, data
->nbope
, buf
);
358 gtk_label_set_text(GTK_LABEL(data
->TX_info
), info
);
362 static void repbalance_detail(GtkWidget
*widget
, gpointer user_data
)
364 struct repbalance_data
*data
;
365 guint active
= GPOINTER_TO_INT(user_data
);
371 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
373 DB( g_print("(repbalance) detail\n") );
375 /* clear and detach our model */
376 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_detail
));
377 gtk_list_store_clear (GTK_LIST_STORE(model
));
381 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
382 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), NULL
); /* Detach model from view */
385 gboolean selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
387 // get the account key
388 acckey
= ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data
->PO_acc
));
390 /* fill in the model */
391 list
= g_list_first(GLOBALS
->ope_list
);
394 Transaction
*ope
= list
->data
;
396 //DB( g_print(" get %s\n", ope->ope_Word) );
399 if( !(ope
->flags
& OF_REMIND
) )
401 if( ope
->date
== active
&& (ope
->kacc
== acckey
|| selectall
) )
403 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
404 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
405 LST_DSPOPE_DATAS
, ope
,
409 list
= g_list_next(list
);
412 /* Re-attach model to view */
413 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_detail
), model
);
414 g_object_unref(model
);
420 static void repbalance_update_detail(GtkWidget
*widget
, gpointer user_data
)
422 struct repbalance_data
*data
;
424 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
428 GtkTreeSelection
*treeselection
;
433 treeselection
= gtk_tree_view_get_selection (GTK_TREE_VIEW(data
->LV_report
));
435 if (gtk_tree_selection_get_selected(treeselection
, &model
, &iter
))
437 gtk_tree_model_get(model
, &iter
, LST_OVER_DATE
, &key
, -1);
439 DB( g_print(" - active is %d\n", key
) );
441 repbalance_detail(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), GINT_TO_POINTER(key
));
446 gtk_widget_show(data
->GR_detail
);
449 gtk_widget_hide(data
->GR_detail
);
452 static void repbalance_toggle_detail(GtkWidget
*widget
, gpointer user_data
)
454 struct repbalance_data
*data
;
456 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
460 DB( printf("(repbalance) toggledetail to %d\n", (int)data
->detail
) );
462 repbalance_update_detail(widget
, user_data
);
466 static void repbalance_zoomx_callback(GtkWidget
*widget
, gpointer user_data
)
468 struct repbalance_data
*data
;
471 DB( g_print("(statistic) zoomx\n") );
473 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
475 value
= gtk_range_get_value(GTK_RANGE(data
->RG_zoomx
));
477 DB( g_print(" + scale is %f\n", value
) );
479 gtk_chart_set_barw(GTK_CHART(data
->RE_line
), value
);
484 static void repbalance_toggle_minor(GtkWidget
*widget
, gpointer user_data
)
486 struct repbalance_data
*data
;
488 DB( g_print("(repbalance) toggle\n") );
490 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
492 GLOBALS
->minor
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_minor
));
494 repbalance_update_info(widget
,NULL
);
496 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data
->LV_report
));
498 gtk_chart_show_minor(GTK_CHART(data
->RE_line
), GLOBALS
->minor
);
502 static void repbalance_compute_full_datas(guint32 selkey
, gboolean selectall
, struct repbalance_data
*data
)
506 if(g_list_length(GLOBALS
->ope_list
) == 0) return;
508 DB( g_print("(repbalance) compute_full\n") );
511 Transaction
*omin
= g_list_first(GLOBALS
->ope_list
)->data
;
512 Transaction
*omax
= g_list_last(GLOBALS
->ope_list
)->data
;
514 // total days in the hbfile
515 data
->n_result
= omax
->date
- omin
->date
;
517 DB( g_print(" - %d days in hbfile\n", data
->n_result
) );
519 data
->tmp_income
= g_malloc0((data
->n_result
+2) * sizeof(gdouble
));
520 data
->tmp_expense
= g_malloc0((data
->n_result
+2) * sizeof(gdouble
));
522 // to store that initial balance was affected
523 gboolean
*accounts
= g_malloc0((da_acc_get_max_key()+2) * sizeof(gboolean
));
525 if(data
->tmp_income
&& data
->tmp_expense
)
528 /* compute the balance */
529 list
= g_list_first(GLOBALS
->ope_list
);
534 Transaction
*ope
= list
->data
;
537 if(ope
->flags
& OF_REMIND
) goto next1
;
539 acc
= da_acc_get(ope
->kacc
);
541 if(acc
== NULL
) goto next1
;
542 if((acc
->flags
& (AF_CLOSED
|AF_NOREPORT
))) goto next1
;
544 if(selkey
== ope
->kacc
|| selectall
== TRUE
)
546 pos
= ope
->date
- omin
->date
;
548 // deal with account initial balance
549 if(accounts
[ope
->kacc
] == 0)
552 // trn_amount = to_base_amount(acc->initial, selacc->kcur);
554 trn_amount
= acc
->initial
;
557 data
->tmp_expense
[pos
] += trn_amount
;
559 data
->tmp_income
[pos
] += trn_amount
;
561 DB( g_print(" - stored initial %.2f for account %d\n", trn_amount
, ope
->kacc
) );
563 accounts
[ope
->kacc
] = 1;
567 // trn_amount = to_base_amount(ope->amount, selacc->kcur);
569 trn_amount
= ope
->amount
;
571 //deal with transactions
573 data
->tmp_expense
[pos
] += trn_amount
;
575 data
->tmp_income
[pos
] += trn_amount
;
579 list
= g_list_next(list
);
589 static void repbalance_compute(GtkWidget
*widget
, gpointer user_data
)
591 struct repbalance_data
*data
;
595 gboolean selectall
, eachday
;
598 DB( g_print("(repbalance) compute\n") );
600 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
602 /* do nothing if no transaction */
603 if(g_list_length(GLOBALS
->ope_list
) == 0) return;
605 selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
606 eachday
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_eachday
));
608 // get the account key
609 acckey
= ui_acc_comboboxentry_get_key(GTK_COMBO_BOX(data
->PO_acc
));
611 DB( g_print(" acc key = %d\n", acckey
) );
617 // for a single account
620 acc
= da_acc_get(acckey
);
623 data
->minimum
= acc
->minimum
;
624 //ui_repbalance_list_set_cur(GTK_TREE_VIEW(data->LV_report), acc->kcur);
625 //gtk_chart_set_currency(GTK_CHART(data->RE_line), acc->kcur);
630 //ui_repbalance_list_set_cur(GTK_TREE_VIEW(data->LV_report), GLOBALS->kcur);
631 //gtk_chart_set_currency(GTK_CHART(data->RE_line), GLOBALS->kcur);
634 repbalance_compute_full_datas(acckey
, selectall
, data
);
636 /* clear and detach our model */
637 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
));
638 gtk_list_store_clear (GTK_LIST_STORE(model
));
639 g_object_ref(model
); /* Make sure the model stays with us after the tree view unrefs it */
640 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), NULL
); /* Detach model from view */
642 Transaction
*omin
= g_list_first(GLOBALS
->ope_list
)->data
;
645 for(i
=0;i
<=data
->n_result
;i
++)
647 gboolean is_balance
= FALSE
;
652 posdate
= omin
->date
+ i
;
654 balance
+= data
->tmp_expense
[i
];
655 balance
+= data
->tmp_income
[i
];
657 if(!eachday
&& data
->tmp_expense
[i
] == 0 && data
->tmp_income
[i
] == 0)
660 if( (posdate
>= data
->filter
->mindate
) && (posdate
<= data
->filter
->maxdate
) )
663 is_balance
= balance
< data
->minimum
? TRUE
: FALSE
;
665 date
= g_date_new_julian (posdate
);
666 g_date_strftime (buf
, 256-1, PREFS
->date_format
, date
);
669 /* column 0: pos (gint) */
670 /* not used: column 1: key (gint) */
671 /* column 2: name (gchar) */
672 /* column x: values (double) */
674 gtk_list_store_append (GTK_LIST_STORE(model
), &iter
);
675 gtk_list_store_set (GTK_LIST_STORE(model
), &iter
,
676 LST_OVER_OVER
, is_balance
,
677 LST_OVER_DATE
, posdate
,
678 LST_OVER_DATESTR
, buf
,
679 LST_OVER_EXPENSE
, data
->tmp_expense
[i
],
680 LST_OVER_INCOME
, data
->tmp_income
[i
],
681 LST_OVER_BALANCE
, balance
,
683 if(is_balance
== TRUE
)
692 g_free(data
->tmp_expense
);
693 g_free(data
->tmp_income
);
695 repbalance_update_info(widget
, NULL
);
697 gtk_chart_show_legend(GTK_CHART(data
->RE_line
), FALSE
, FALSE
);
698 gtk_chart_show_xval(GTK_CHART(data
->RE_line
), TRUE
);
699 gtk_chart_set_overdrawn(GTK_CHART(data
->RE_line
), data
->minimum
);
700 gtk_chart_show_overdrawn(GTK_CHART(data
->RE_line
), !selectall
);
702 gboolean visible
= selectall
? FALSE
: TRUE
;
703 gtk_widget_set_visible (GTK_WIDGET(data
->TX_info
), visible
);
705 /* Re-attach model to view */
706 gtk_tree_view_set_model(GTK_TREE_VIEW(data
->LV_report
), model
);
707 g_object_unref(model
);
709 /* update bar chart */
710 //DB( g_print(" set bar to %d\n\n", LST_STAT_EXPENSE+tmpkind) );
711 gtk_chart_set_datas(GTK_CHART(data
->RE_line
), model
, LST_OVER_BALANCE
, NULL
);
712 //gtk_chart_set_line_datas(GTK_CHART(data->RE_line), model, LST_OVER_BALANCE, LST_OVER_DATE);
718 static void repbalance_toggle_selectall(GtkWidget
*widget
, gpointer user_data
)
720 struct repbalance_data
*data
;
723 DB( g_print("(repbalance) toggle selectall\n") );
725 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
727 selectall
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_selectall
));
729 gtk_widget_set_sensitive(GTK_WIDGET(data
->PO_acc
), selectall
^1);
731 repbalance_compute(widget
, data
);
741 static void repbalance_setup(struct repbalance_data
*data
, guint32 accnum
)
743 DB( g_print("(repbalance) setup\n") );
745 data
->filter
= da_filter_malloc();
746 filter_default_all_set(data
->filter
);
748 filter_preset_daterange_set(data
->filter
, PREFS
->date_range_rep
);
750 g_signal_handler_block(data
->PO_mindate
, data
->handler_id
[HID_MINDATE
]);
751 g_signal_handler_block(data
->PO_maxdate
, data
->handler_id
[HID_MAXDATE
]);
753 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_mindate
), data
->filter
->mindate
);
754 gtk_dateentry_set_date(GTK_DATE_ENTRY(data
->PO_maxdate
), data
->filter
->maxdate
);
756 g_signal_handler_unblock(data
->PO_mindate
, data
->handler_id
[HID_MINDATE
]);
757 g_signal_handler_unblock(data
->PO_maxdate
, data
->handler_id
[HID_MAXDATE
]);
759 ui_acc_comboboxentry_populate(GTK_COMBO_BOX(data
->PO_acc
), GLOBALS
->h_acc
, ACC_LST_INSERT_REPORT
);
760 ui_acc_comboboxentry_set_active(GTK_COMBO_BOX(data
->PO_acc
), accnum
);
770 static gboolean
repbalance_window_dispose(GtkWidget
*widget
, GdkEvent
*event
, gpointer user_data
)
772 struct repbalance_data
*data
= user_data
;
773 struct WinGeometry
*wg
;
775 DB( g_print("(repbalance) dispose\n") );
777 da_filter_free(data
->filter
);
781 //store position and size
783 gtk_window_get_position(GTK_WINDOW(widget
), &wg
->l
, &wg
->t
);
784 gtk_window_get_size(GTK_WINDOW(widget
), &wg
->w
, &wg
->h
);
786 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d\n", wg
->l
, wg
->t
, wg
->w
, wg
->h
) );
788 //enable define windows
789 GLOBALS
->define_off
--;
790 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(UF_SENSITIVE
));
796 // the window creation
797 GtkWidget
*repbalance_window_new(gint accnum
)
799 struct repbalance_data
*data
;
800 struct WinGeometry
*wg
;
801 GtkWidget
*window
, *mainvbox
, *hbox
, *vbox
, *notebook
, *treeview
;
802 GtkWidget
*label
, *widget
, *table
, *alignment
;
805 GtkActionGroup
*actions
;
807 GError
*error
= NULL
;
809 data
= g_malloc0(sizeof(struct repbalance_data
));
810 if(!data
) return NULL
;
812 DB( g_print("(repbalance) new\n") );
814 //disable define windows
815 GLOBALS
->define_off
++;
816 ui_mainwindow_update(GLOBALS
->mainwindow
, GINT_TO_POINTER(2));
818 /* create window, etc */
819 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
820 data
->window
= window
;
822 //store our window private data
823 g_object_set_data(G_OBJECT(window
), "inst_data", (gpointer
)data
);
825 gtk_window_set_title (GTK_WINDOW (window
), _("Balance report"));
827 //set the window icon
828 //homebank_window_set_icon_from_file(GTK_WINDOW (window), "report_balancedrawn.svg");
829 gtk_window_set_icon_name(GTK_WINDOW (window
), HB_STOCK_REP_BALANCE
);
832 mainvbox
= gtk_vbox_new (FALSE
, 0);
833 gtk_container_add (GTK_CONTAINER (window
), mainvbox
);
835 hbox
= gtk_hbox_new(FALSE
, 0);
836 gtk_box_pack_start (GTK_BOX (mainvbox
), hbox
, TRUE
, TRUE
, 0);
839 table
= gtk_table_new (6, 3, FALSE
);
840 // gtk_alignment_new(xalign, yalign, xscale, yscale)
841 alignment
= gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
842 gtk_container_add(GTK_CONTAINER(alignment
), table
);
843 gtk_box_pack_start (GTK_BOX (hbox
), alignment
, FALSE
, FALSE
, 0);
845 gtk_container_set_border_width (GTK_CONTAINER (table
), HB_BOX_SPACING
);
846 gtk_table_set_row_spacings (GTK_TABLE (table
), HB_TABROW_SPACING
);
847 gtk_table_set_col_spacings (GTK_TABLE (table
), HB_TABCOL_SPACING
);
851 label
= make_label(_("Display"), 0.0, 0.5);
852 gimp_label_set_attributes(GTK_LABEL(label
), PANGO_ATTR_WEIGHT
, PANGO_WEIGHT_BOLD
, -1);
853 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 3, row
, row
+1);
856 label
= make_label(_("A_ccount:"), 0, 0.5);
857 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
858 widget
= ui_acc_comboboxentry_new(label
);
859 data
->PO_acc
= widget
;
860 gtk_widget_set_size_request (widget
, 10, -1);
861 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 2, 3, row
, row
+1);
864 widget
= gtk_check_button_new_with_mnemonic (_("Select _all"));
865 data
->CM_selectall
= widget
;
866 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 1, 3, row
, row
+1);
869 widget
= gtk_check_button_new_with_mnemonic (_("Each _day"));
870 //gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), TRUE);
871 data
->CM_eachday
= widget
;
872 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 1, 3, row
, row
+1);
875 widget
= gtk_check_button_new_with_mnemonic (_("_Minor currency"));
876 data
->CM_minor
= widget
;
877 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 1, 3, row
, row
+1);
880 label
= make_label(_("_Zoom X:"), 0, 0.5);
881 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
882 widget
= make_scale(label
);
883 data
->RG_zoomx
= widget
;
884 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 2, 3, row
, row
+1);
887 widget
= gtk_hseparator_new();
888 gtk_table_attach_defaults (GTK_TABLE (table
), widget
, 0, 3, row
, row
+1);
891 label
= make_label(_("Date filter"), 0.0, 0.5);
892 gimp_label_set_attributes(GTK_LABEL(label
), PANGO_ATTR_WEIGHT
, PANGO_WEIGHT_BOLD
, -1);
893 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 3, row
, row
+1);
896 label
= make_label(_("_Range:"), 0, 0.5);
897 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
898 data
->CY_range
= make_daterange(label
, FALSE
);
899 gtk_table_attach_defaults (GTK_TABLE (table
), data
->CY_range
, 2, 3, row
, row
+1);
902 label
= make_label(_("_From:"), 0, 0.5);
903 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
904 data
->PO_mindate
= gtk_dateentry_new();
905 gtk_table_attach_defaults (GTK_TABLE (table
), data
->PO_mindate
, 2, 3, row
, row
+1);
908 label
= make_label(_("_To:"), 0, 0.5);
909 gtk_table_attach (GTK_TABLE (table
), label
, 1, 2, row
, row
+1, (GtkAttachOptions
) (GTK_FILL
), (GtkAttachOptions
) (0), 0, 0);
910 data
->PO_maxdate
= gtk_dateentry_new();
911 gtk_table_attach_defaults (GTK_TABLE (table
), data
->PO_maxdate
, 2, 3, row
, row
+1);
914 //part: info + report
915 vbox
= gtk_vbox_new (FALSE
, 0);
916 gtk_box_pack_start (GTK_BOX (hbox
), vbox
, TRUE
, TRUE
, 0);
919 actions
= gtk_action_group_new ("Account");
922 gtk_action_group_set_translation_domain(actions
, GETTEXT_PACKAGE
);
924 // data to action callbacks is set here (data)
925 gtk_action_group_add_actions (actions
, entries
, n_entries
, data
);
927 gtk_action_group_add_toggle_actions (actions
,
928 toggle_entries
, n_toggle_entries
,
932 /* set which action should have priority in the toolbar */
933 action
= gtk_action_group_get_action(actions
, "List");
934 g_object_set(action
, "is_important", TRUE
, NULL
);
936 action
= gtk_action_group_get_action(actions
, "Line");
937 g_object_set(action
, "is_important", TRUE
, NULL
);
939 action
= gtk_action_group_get_action(actions
, "Detail");
940 g_object_set(action
, "is_important", TRUE
, NULL
);
942 action
= gtk_action_group_get_action(actions
, "Refresh");
943 g_object_set(action
, "is_important", TRUE
, NULL
);
947 ui
= gtk_ui_manager_new ();
948 gtk_ui_manager_insert_action_group (ui
, actions
, 0);
949 gtk_window_add_accel_group (GTK_WINDOW (window
), gtk_ui_manager_get_accel_group (ui
));
951 if (!gtk_ui_manager_add_ui_from_string (ui
, ui_info
, -1, &error
))
953 g_message ("building UI failed: %s", error
->message
);
954 g_error_free (error
);
958 data
->actions
= actions
;
961 data
->TB_bar
= gtk_ui_manager_get_widget (ui
, "/ToolBar");
962 gtk_box_pack_start (GTK_BOX (vbox
), data
->TB_bar
, FALSE
, FALSE
, 0);
965 hbox
= gtk_hbox_new (FALSE
, HB_BOX_SPACING
);
966 gtk_container_set_border_width (GTK_CONTAINER(hbox
), HB_BOX_SPACING
);
967 gtk_box_pack_start (GTK_BOX (vbox
), hbox
, FALSE
, FALSE
, 0);
970 widget
= make_label(NULL
, 0.5, 0.5);
971 gimp_label_set_attributes (GTK_LABEL (widget
), PANGO_ATTR_SCALE
, PANGO_SCALE_SMALL
, -1);
972 data
->TX_daterange
= widget
;
973 gtk_box_pack_start (GTK_BOX (hbox
), widget
, TRUE
, TRUE
, 0);
976 label
= gtk_label_new(NULL
);
977 data
->TX_info
= label
;
978 gtk_box_pack_end (GTK_BOX (hbox
), label
, FALSE
, FALSE
, 0);
980 notebook
= gtk_notebook_new();
981 data
->GR_result
= notebook
;
982 gtk_widget_show(notebook
);
983 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
984 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
986 gtk_box_pack_start (GTK_BOX (vbox
), notebook
, TRUE
, TRUE
, 0);
989 vbox
= gtk_vbox_new (FALSE
, 0);
990 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), vbox
, NULL
);
992 widget
= gtk_scrolled_window_new (NULL
, NULL
);
993 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
994 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
996 treeview
= create_list_repbalance();
997 data
->LV_report
= treeview
;
998 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
999 //gtk_notebook_append_page(GTK_NOTEBOOK(notebook), widget, NULL);
1000 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1003 widget
= gtk_scrolled_window_new (NULL
, NULL
);
1004 data
->GR_detail
= widget
;
1005 //gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW (widget), GTK_CORNER_TOP_RIGHT);
1006 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget
), GTK_SHADOW_ETCHED_IN
);
1007 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
1008 treeview
= create_list_transaction(TRN_LIST_TYPE_DETAIL
, PREFS
->lst_ope_columns
);
1009 data
->LV_detail
= treeview
;
1010 gtk_container_add (GTK_CONTAINER(widget
), treeview
);
1012 gtk_box_pack_start (GTK_BOX (vbox
), widget
, TRUE
, TRUE
, 0);
1016 widget
= gtk_chart_new(CHART_TYPE_LINE
);
1017 data
->RE_line
= widget
;
1018 //gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.suffix_symbol);
1019 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), widget
, NULL
);
1024 //todo:should move this
1025 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_minor
),GLOBALS
->minor
);
1029 /* attach our minor to treeview */
1030 g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_report
))), "minor", (gpointer
)data
->CM_minor
);
1036 /* signal connect */
1037 g_signal_connect (window
, "delete-event", G_CALLBACK (repbalance_window_dispose
), (gpointer
)data
);
1039 g_signal_connect (data
->CM_minor
, "toggled", G_CALLBACK (repbalance_toggle_minor
), NULL
);
1042 data
->handler_id
[HID_MINDATE
] = g_signal_connect (data
->PO_mindate
, "changed", G_CALLBACK (repbalance_date_change
), (gpointer
)data
);
1043 data
->handler_id
[HID_MAXDATE
] = g_signal_connect (data
->PO_maxdate
, "changed", G_CALLBACK (repbalance_date_change
), (gpointer
)data
);
1045 data
->handler_id
[HID_RANGE
] = g_signal_connect (data
->CY_range
, "changed", G_CALLBACK (repbalance_range_change
), NULL
);
1047 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_report
)), "changed", G_CALLBACK (repbalance_selection
), NULL
);
1049 //setup, init and show window
1050 repbalance_setup(data
, accnum
);
1052 g_signal_connect (data
->CM_selectall
, "toggled", G_CALLBACK (repbalance_toggle_selectall
), NULL
);
1053 g_signal_connect (data
->CM_eachday
, "toggled", G_CALLBACK (repbalance_compute
), NULL
);
1056 //let this here or the setup trigger a compute...
1057 g_signal_connect (data
->PO_acc
, "changed", G_CALLBACK (repbalance_compute
), NULL
);
1059 g_signal_connect (data
->RG_zoomx
, "value-changed", G_CALLBACK (repbalance_zoomx_callback
), NULL
);
1063 if(PREFS
->toolbar_style
== 0)
1064 gtk_toolbar_unset_style(GTK_TOOLBAR(data
->TB_bar
));
1066 gtk_toolbar_set_style(GTK_TOOLBAR(data
->TB_bar
), PREFS
->toolbar_style
-1);
1069 //setup, init and show window
1070 wg
= &PREFS
->ove_wg
;
1071 gtk_window_move(GTK_WINDOW(window
), wg
->l
, wg
->t
);
1072 gtk_window_resize(GTK_WINDOW(window
), wg
->w
, wg
->h
);
1076 gtk_widget_show_all (window
);
1079 if( PREFS
->euro_active
)
1080 gtk_widget_show(data
->CM_minor
);
1082 gtk_widget_hide(data
->CM_minor
);
1084 repbalance_sensitive(window
, NULL
);
1085 repbalance_update_detail(window
, NULL
);
1087 gtk_combo_box_set_active(GTK_COMBO_BOX(data
->CY_range
), PREFS
->date_range_rep
);
1094 ** ============================================================================
1098 static void repbalance_date_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
1101 gboolean is_balance
;
1105 gtk_tree_model_get(model
, iter
,
1106 LST_OVER_DATESTR
, &datestr
,
1107 LST_OVER_OVER
, &is_balance
,
1111 weight
= PANGO_WEIGHT_NORMAL
;
1113 if(is_balance
==TRUE
)
1115 if(PREFS
->custom_colors
== TRUE
)
1116 color
= PREFS
->color_warn
;
1118 weight
= PANGO_WEIGHT_BOLD
;
1121 g_object_set(renderer
,
1123 "foreground", color
,
1129 static void repbalance_amount_cell_data_function (GtkTreeViewColumn
*col
,
1130 GtkCellRenderer
*renderer
,
1131 GtkTreeModel
*model
,
1136 gchar buf
[G_ASCII_DTOSTR_BUF_SIZE
];
1137 gboolean is_balance
;
1140 //guint32 kcur = (guint32)g_object_get_data(G_OBJECT(gtk_tree_view_column_get_tree_view(col)), "kcur_data");
1144 gtk_tree_model_get(model
, iter
,
1145 LST_OVER_OVER
, &is_balance
,
1146 GPOINTER_TO_INT(user_data
), &value
,
1150 //value = arrondi(value, PREFS->base_cur.frac_digits);
1153 g_object_set(renderer
, "text", NULL
, NULL
);
1157 mystrfmon(buf
, G_ASCII_DTOSTR_BUF_SIZE
-1, value
, GLOBALS
->minor
);
1158 //hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, value, kcur);
1161 weight
= PANGO_WEIGHT_NORMAL
;
1164 if(value
!= 0.0 && PREFS
->custom_colors
== TRUE
)
1165 color
= (value
> 0.0) ? PREFS
->color_inc
: PREFS
->color_exp
;
1167 if(is_balance
==TRUE
)
1169 if(PREFS
->custom_colors
== TRUE
)
1170 color
= PREFS
->color_warn
;
1172 weight
= PANGO_WEIGHT_BOLD
;
1175 g_object_set(renderer
,
1177 "foreground", color
,
1184 static GtkTreeViewColumn
*amount_list_repbalance_column(gchar
*name
, gint id
)
1186 GtkTreeViewColumn
*column
;
1187 GtkCellRenderer
*renderer
;
1189 column
= gtk_tree_view_column_new();
1190 gtk_tree_view_column_set_title(column
, name
);
1191 renderer
= gtk_cell_renderer_text_new ();
1192 g_object_set(renderer
, "xalign", 1.0, NULL
);
1193 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1194 gtk_tree_view_column_set_cell_data_func(column
, renderer
, repbalance_amount_cell_data_function
, GINT_TO_POINTER(id
), NULL
);
1195 gtk_tree_view_column_set_alignment (column
, 0.5);
1196 //gtk_tree_view_column_set_sort_column_id (column, id);
1201 static void ui_repbalance_list_set_cur(GtkTreeView *treeview, guint32 kcur)
1203 g_object_set_data(G_OBJECT(treeview), "kcur_data", (guint32)kcur);
1208 ** create our statistic list
1210 static GtkWidget
*create_list_repbalance(void)
1212 GtkListStore
*store
;
1214 GtkCellRenderer
*renderer
;
1215 GtkTreeViewColumn
*column
;
1217 /* create list store */
1218 store
= gtk_list_store_new(
1229 view
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1230 g_object_unref(store
);
1232 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view
), PREFS
->rules_hint
);
1234 /* column debug balance */
1236 column = gtk_tree_view_column_new();
1237 gtk_tree_view_column_set_title(column, "debug balance");
1238 gtk_tree_view_append_column (GTK_TREE_VIEW(view), column);
1239 renderer = gtk_cell_renderer_text_new();
1240 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1241 gtk_tree_view_column_add_attribute(column, renderer, "text", LST_OVER_OVER);
1245 column
= gtk_tree_view_column_new();
1246 gtk_tree_view_column_set_title(column
, _("Date"));
1247 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1248 renderer
= gtk_cell_renderer_text_new();
1249 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1250 //gtk_tree_view_column_add_attribute(column, renderer, "text", LST_OVER_DATE);
1251 gtk_tree_view_column_set_alignment (column
, 0.5);
1252 gtk_tree_view_column_set_cell_data_func(column
, renderer
, repbalance_date_cell_data_function
, NULL
, NULL
);
1255 /* column: Expense */
1256 column
= amount_list_repbalance_column(_("Expense"), LST_OVER_EXPENSE
);
1257 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1259 /* column: Income */
1260 column
= amount_list_repbalance_column(_("Income"), LST_OVER_INCOME
);
1261 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1263 /* column: Balance */
1264 column
= amount_list_repbalance_column(_("Balance"), LST_OVER_BALANCE
);
1265 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);
1267 /* column last: empty */
1268 column
= gtk_tree_view_column_new();
1269 gtk_tree_view_append_column (GTK_TREE_VIEW(view
), column
);