1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2018 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 "ui-category.h"
24 #include "ui-budget.h"
26 extern gchar
*CYA_CAT_TYPE
[];
28 /****************************************************************************/
30 /****************************************************************************/
39 /* our global datas */
40 extern struct HomeBank
*GLOBALS
;
41 extern struct Preferences
*PREFS
;
61 static gchar
*ui_bud_manage_getcsvbudgetstr(Category
*item
);
62 static void ui_bud_manage_update(GtkWidget
*treeview
, gpointer user_data
);
63 static void ui_bud_manage_set(GtkWidget
*widget
, gpointer user_data
);
64 static void ui_bud_manage_getlast(struct ui_bud_manage_data
*data
);
65 static void ui_bud_manage_selection_change(GtkWidget
*treeview
, gpointer user_data
);
66 static void ui_bud_manage_toggle(GtkRadioButton
*radiobutton
, gpointer user_data
);
67 static void ui_bud_manage_selection(GtkTreeSelection
*treeselection
, gpointer user_data
);
70 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
74 ** The function should return:
75 ** a negative integer if the first value comes before the second,
76 ** 0 if they are equal,
77 ** or a positive integer if the first value comes after the second.
79 static gint
ui_bud_listview_compare_funct (GtkTreeModel
*model
, GtkTreeIter
*a
, GtkTreeIter
*b
, gpointer userdata
)
82 Category
*entry1
, *entry2
;
84 gtk_tree_model_get(model
, a
, LST_DEFCAT_DATAS
, &entry1
, -1);
85 gtk_tree_model_get(model
, b
, LST_DEFCAT_DATAS
, &entry2
, -1);
87 retval
= (entry1
->flags
& GF_INCOME
) - (entry2
->flags
& GF_INCOME
);
90 retval
= hb_string_utf8_compare(entry1
->name
, entry2
->name
);
100 static void ui_bud_listview_icon_cell_data_function (GtkTreeViewColumn
*col
, GtkCellRenderer
*renderer
, GtkTreeModel
*model
, GtkTreeIter
*iter
, gpointer user_data
)
103 gchar
*iconname
= NULL
;
105 // get the transaction
106 gtk_tree_model_get(model
, iter
, LST_DEFCAT_DATAS
, &item
, -1);
108 iconname
= ( item
->flags
& GF_BUDGET
) ? ICONNAME_HB_OPE_BUDGET
: NULL
;
110 g_object_set(renderer
, "icon-name", iconname
, NULL
);
115 ** draw some text from the stored data structure
117 static void ui_bud_listview_cell_data_function_text (GtkTreeViewColumn
*col
,
118 GtkCellRenderer
*renderer
,
128 gtk_tree_model_get(model
, iter
, LST_DEFCAT_DATAS
, &entry
, -1);
131 name
= g_strdup(_("(no category)"));
135 type
= (entry
->flags
& GF_INCOME
) ? '+' : '-';
138 string
= g_markup_printf_escaped("%s ::(f=%d, %c)", name
, entry
->flags
, type
);
141 string
= g_strdup(name
);
144 if(entry
->flags
& GF_BUDGET
)
146 if( entry
->parent
== 0 )
147 string
= g_markup_printf_escaped("<b>%s</b> [%c]", name
, type
);
149 string
= g_markup_printf_escaped(" %c <b><i>%s</i></b>", type
, name
);
153 if( entry
->parent
== 0 )
154 string
= g_markup_printf_escaped("%s [%c]", name
, type
);
156 string
= g_markup_printf_escaped(" %c <i>%s</i>", type
, name
);
161 g_object_set(renderer
, "markup", string
, NULL
);
167 static gboolean
ui_bud_listview_search_equal_func (GtkTreeModel
*model
,
171 gpointer search_data
)
173 gboolean retval
= TRUE
;
174 gchar
*normalized_string
;
175 gchar
*normalized_key
;
176 gchar
*case_normalized_string
= NULL
;
177 gchar
*case_normalized_key
= NULL
;
180 //gtk_tree_model_get_value (model, iter, column, &value);
181 gtk_tree_model_get(model
, iter
, LST_DEFCAT_DATAS
, &item
, -1);
185 normalized_string
= g_utf8_normalize (item
->name
, -1, G_NORMALIZE_ALL
);
186 normalized_key
= g_utf8_normalize (key
, -1, G_NORMALIZE_ALL
);
188 if (normalized_string
&& normalized_key
)
190 case_normalized_string
= g_utf8_casefold (normalized_string
, -1);
191 case_normalized_key
= g_utf8_casefold (normalized_key
, -1);
193 if (strncmp (case_normalized_key
, case_normalized_string
, strlen (case_normalized_key
)) == 0)
197 g_free (normalized_key
);
198 g_free (normalized_string
);
199 g_free (case_normalized_key
);
200 g_free (case_normalized_string
);
210 static GtkWidget
*ui_bud_listview_new(void)
214 GtkCellRenderer
*renderer
;
215 GtkTreeViewColumn
*column
;
218 store
= gtk_tree_store_new (
227 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store
), LST_DEFCAT_DATAS
, ui_bud_listview_compare_funct
, NULL
, NULL
);
228 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store
), LST_DEFCAT_DATAS
, GTK_SORT_ASCENDING
);
232 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
233 g_object_unref(store
);
235 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview
), PREFS
->grid_lines
);
238 renderer
= gtk_cell_renderer_text_new ();
239 g_object_set(renderer
,
240 "ellipsize", PANGO_ELLIPSIZE_END
,
241 "ellipsize-set", TRUE
,
244 column
= gtk_tree_view_column_new();
245 gtk_tree_view_column_set_title(column
, _("Category"));
246 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
247 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_bud_listview_cell_data_function_text
, GINT_TO_POINTER(1), NULL
);
248 gtk_tree_view_column_set_alignment (column
, 0.5);
249 gtk_tree_view_column_set_min_width(column
, HB_MINWIDTH_LIST
);
250 //gtk_tree_view_column_set_sort_column_id (column, LST_DEFACC_NAME);
251 gtk_tree_view_column_set_resizable(column
, TRUE
);
252 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
255 column
= gtk_tree_view_column_new();
256 renderer
= gtk_cell_renderer_pixbuf_new ();
257 //gtk_cell_renderer_set_fixed_size(renderer, GLOBALS->lst_pixbuf_maxwidth, -1);
258 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
259 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_bud_listview_icon_cell_data_function
, NULL
, NULL
);
260 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
263 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview
), ui_bud_listview_search_equal_func
, NULL
, NULL
);
266 //gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE);
267 //gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE);
275 ** index 0 is all month, then 1 -> 12 are months
277 static gchar
*ui_bud_manage_getcsvbudgetstr(Category
*item
)
279 gchar
*retval
= NULL
;
280 char buf
[G_ASCII_DTOSTR_BUF_SIZE
];
282 //DB( g_print(" get budgetstr for '%s'\n", item->name) );
284 if( !(item
->flags
& GF_CUSTOM
) )
286 if( item
->budget
[0] )
288 g_ascii_dtostr (buf
, sizeof (buf
), item
->budget
[0]);
289 retval
= g_strdup(buf
);
291 //DB( g_print(" => %d: %s\n", 0, retval) );
300 //if( item->budget[i] )
304 g_ascii_dtostr (buf
, sizeof (buf
), item
->budget
[i
]);
308 retval
= g_strconcat(retval
, ";", buf
, NULL
);
312 retval
= g_strdup(buf
);
314 //DB( g_print(" => %d: %s\n", i, retval) );
324 static gint
ui_bud_manage_category_exists (GtkTreeModel
*model
, gchar
*level
, gchar
*type
, gchar
*name
, GtkTreeIter
*return_iter
)
326 GtkTreeIter iter
, child
;
334 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
338 gtk_tree_model_get (model
, &iter
, LST_DEFCAT_DATAS
, &entry
, -1);
342 if(entry
->name
&& g_ascii_strcasecmp(name
, entry
->name
) == 0)
352 gint n_child
= gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model
), &iter
);
353 gtk_tree_model_iter_children (GTK_TREE_MODEL(model
), &child
, &iter
);
357 gtk_tree_model_get(GTK_TREE_MODEL(model
), &child
,
358 LST_DEFCAT_DATAS
, &entry
,
361 if(entry
->name
&& g_ascii_strcasecmp(name
, entry
->name
) == 0)
363 *return_iter
= child
;
368 gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &child
);
373 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
381 static void ui_bud_manage_load_csv( GtkWidget
*widget
, gpointer user_data
)
383 struct ui_bud_manage_data
*data
= user_data
;
384 gchar
*filename
= NULL
;
386 const gchar
*encoding
;
389 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
392 DB( g_print("(ui_bud_manage) load csv - data %p\n", data
) );
394 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_OPEN
, &filename
, NULL
) == TRUE
)
396 DB( g_print(" + filename is %s\n", filename
) );
398 encoding
= homebank_file_getencoding(filename
);
400 io
= g_io_channel_new_file(filename
, "r", NULL
);
405 gboolean error
= FALSE
;
409 DB( g_print(" -> encoding should be %s\n", encoding
) );
410 if( encoding
!= NULL
)
412 g_io_channel_set_encoding(io
, encoding
, NULL
);
415 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_cat
));
420 io_stat
= g_io_channel_read_line(io
, &tmpstr
, NULL
, NULL
, NULL
);
421 if( io_stat
== G_IO_STATUS_EOF
)
423 if( io_stat
== G_IO_STATUS_NORMAL
)
429 hb_string_strip_crlf(tmpstr
);
431 str_array
= g_strsplit (tmpstr
, ";", 15);
434 if( (g_strv_length (str_array
) < 4 || *str_array
[1] != '*') && (g_strv_length (str_array
) < 15))
440 DB( g_print(" csv read '%s : %s : %s ...'\n", str_array
[0], str_array
[1], str_array
[2]) );
442 gint pos
= ui_bud_manage_category_exists(model
, str_array
[0], str_array
[1], str_array
[2], &iter
);
444 DB( g_print(" pos=%d\n", pos
) );
452 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
,
453 LST_DEFCAT_DATAS
, &tmpitem
,
456 DB( g_print(" found cat, updating '%s'\n", tmpitem
->name
) );
460 tmpitem
->flags
&= ~(GF_CUSTOM
); //delete flag
461 if( *str_array
[1] == '*' )
463 tmpitem
->budget
[0] = g_ascii_strtod(str_array
[3], NULL
);
465 DB( g_print(" monthly '%.2f'\n", tmpitem
->budget
[0]) );
469 tmpitem
->flags
|= (GF_CUSTOM
);
473 tmpitem
->budget
[i
] = g_ascii_strtod(str_array
[2+i
], NULL
);
474 DB( g_print(" month %d '%.2f'\n", i
, tmpitem
->budget
[i
]) );
478 // if any value,set the flag to visual indicator
480 tmpitem
->flags
&= ~(GF_BUDGET
); //delete flag
483 if(tmpitem
->budget
[i
])
491 tmpitem
->flags
|= GF_BUDGET
;
494 g_strfreev (str_array
);
501 //update the treeview
502 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_cat
)));
505 g_io_channel_unref (io
);
509 ui_dialog_msg_infoerror(GTK_WINDOW(data
->window
), GTK_MESSAGE_ERROR
,
510 _("File format error"),
511 _("The CSV file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.")
523 static void ui_bud_manage_save_csv( GtkWidget
*widget
, gpointer user_data
)
525 struct ui_bud_manage_data
*data
= user_data
;
526 gchar
*filename
= NULL
;
528 GtkTreeIter iter
, child
;
532 DB( g_print("(ui_bud_manage) save csv\n") );
534 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
536 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, NULL
) == TRUE
)
539 DB( g_print(" + filename is %s\n", filename
) );
541 io
= g_io_channel_new_file(filename
, "w", NULL
);
545 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_cat
));
547 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
551 gchar
*outstr
, *outvalstr
;
555 gtk_tree_model_get (GTK_TREE_MODEL(model
), &iter
, LST_DEFCAT_DATAS
, &category
, -1);
557 if( category
->name
!= NULL
)
561 if( category
->flags
& GF_BUDGET
)
563 type
= (category
->flags
& GF_CUSTOM
) ? ' ' : '*';
565 outvalstr
= ui_bud_manage_getcsvbudgetstr(category
);
566 outstr
= g_strdup_printf("1;%c;%s;%s\n", type
, category
->name
, outvalstr
);
567 DB( g_print("%s", outstr
) );
568 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
574 //level 2: subcategory
575 gint n_child
= gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model
), &iter
);
576 gtk_tree_model_iter_children (GTK_TREE_MODEL(model
), &child
, &iter
);
579 gtk_tree_model_get(GTK_TREE_MODEL(model
), &child
, LST_DEFCAT_DATAS
, &category
, -1);
581 type
= (category
->flags
& GF_CUSTOM
) ? ' ' : '*';
583 outvalstr
= ui_bud_manage_getcsvbudgetstr(category
);
586 outstr
= g_strdup_printf("2;%c;%s;%s\n", type
, category
->name
, outvalstr
);
587 DB( g_print("%s", outstr
) );
588 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
594 gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &child
);
598 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
601 g_io_channel_unref (io
);
611 static void ui_bud_manage_expand_all(GtkWidget
*widget
, gpointer user_data
)
613 struct ui_bud_manage_data
*data
;
615 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
616 DB( g_print("\n(ui_bud_manage) expand all (data=%x)\n", (guint
)data
) );
618 gtk_tree_view_expand_all(GTK_TREE_VIEW(data
->LV_cat
));
623 static void ui_bud_manage_collapse_all(GtkWidget
*widget
, gpointer user_data
)
625 struct ui_bud_manage_data
*data
;
627 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
628 DB( g_print("\n(ui_bud_manage) collapse all (data=%x)\n", (guint
)data
) );
630 gtk_tree_view_collapse_all(GTK_TREE_VIEW(data
->LV_cat
));
634 static void ui_bud_manage_update(GtkWidget
*treeview
, gpointer user_data
)
636 struct ui_bud_manage_data
*data
;
637 gboolean name
, custom
, sensitive
;
640 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
642 DB( g_print("\n(ui_bud_manage) update %x\n", (gint
)data
) );
646 if(data
->cat
!= NULL
)
648 name
= data
->cat
->key
== 0 ? FALSE
: TRUE
;
653 gtk_widget_set_sensitive(data
->label_budget
, sensitive
);
654 gtk_widget_set_sensitive(data
->CM_type
[0], sensitive
);
655 gtk_widget_set_sensitive(data
->CM_type
[1], sensitive
);
657 gtk_widget_set_sensitive(data
->label_options
, sensitive
);
658 gtk_widget_set_sensitive(data
->CM_force
, sensitive
);
660 gtk_widget_set_sensitive(data
->BT_clear
, sensitive
);
663 gint toto
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0]));
664 DB( g_print(" monthly = %d\n", toto
) );
667 custom
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[1]));
668 DB( g_print(" custom = %d\n\n", custom
) );
670 sensitive
= name
== FALSE
? FALSE
: custom
== TRUE
? FALSE
: TRUE
;
671 gtk_widget_set_sensitive(data
->spinner
[0], sensitive
);
673 sensitive
= name
== FALSE
? FALSE
: custom
;
676 gtk_widget_set_sensitive(data
->label
[i
+1], sensitive
);
677 gtk_widget_set_sensitive(data
->spinner
[i
+1], sensitive
);
683 static void ui_bud_manage_clear(GtkWidget
*widget
, gpointer user_data
)
685 struct ui_bud_manage_data
*data
;
690 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget
), GTK_TYPE_WINDOW
)), "inst_data");
692 DB( g_print("(ui_bud_manage) clear\n") );
695 title
= _("Are you sure you want to clear input?");
697 secondtext
= _("If you proceed, every amount will be set to 0.");
699 result
= ui_dialog_msg_confirm_alert(
700 GTK_WINDOW(data
->window
),
706 if( result
== GTK_RESPONSE_OK
)
708 //g_signal_handler_block(data->CM_type[0], data->handler_id[HID_CUSTOM]);
709 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0]), TRUE
);
710 //g_signal_handler_unblock(data->CM_type[0], data->handler_id[HID_CUSTOM]);
714 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
716 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->spinner
[i
]), 0);
717 data
->cat
->budget
[i
] = 0;
719 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
722 data
->cat
->flags
&= ~(GF_BUDGET
); //delete flag
724 gtk_widget_queue_draw (data
->LV_cat
);
730 static void ui_bud_manage_set(GtkWidget
*widget
, gpointer user_data
)
732 struct ui_bud_manage_data
*data
;
736 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget
), GTK_TYPE_WINDOW
)), "inst_data");
738 DB( g_print("(ui_bud_manage) set\n") );
740 active
= data
->cat
->flags
& GF_CUSTOM
? 1 : 0;
741 //data->custom = active;
743 //DB( g_print(" set custom to %d\n", data->custom) );
745 g_signal_handler_block(data
->CM_type
[0], data
->handler_id
[HID_CUSTOM
]);
746 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_type
[active
]), TRUE
);
747 g_signal_handler_unblock(data
->CM_type
[0], data
->handler_id
[HID_CUSTOM
]);
751 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
753 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->spinner
[i
]), data
->cat
->budget
[i
]);
754 //DB( g_print(" %.2f\n", data->cat->budget[i]) );
756 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
759 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_force
), (data
->cat
->flags
& GF_FORCED
) ? 1 : 0);
763 static gboolean
ui_bud_manage_has_budget(GtkSpinButton
*spinbutton
, gpointer user_data
)
765 struct ui_bud_manage_data
*data
;
770 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(spinbutton
), GTK_TYPE_WINDOW
)), "inst_data");
772 DB( g_print("(ui_bud_manage) has budget\n") );
780 item
->flags
&= ~(GF_BUDGET
); //delete flag
783 gtk_spin_button_update(GTK_SPIN_BUTTON(data
->spinner
[i
]));
784 if( gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->spinner
[i
])) )
787 item
->flags
|= GF_BUDGET
;
797 static void ui_bud_manage_getlast(struct ui_bud_manage_data
*data
)
799 gboolean budget
, change
;
805 item
= data
->lastcatitem
;
807 DB( g_print("****\n(ui_bud_manage) getlast for '%s'\n", item
->name
) );
811 gushort old_flags
= item
->flags
;
813 item
->flags
&= ~(GF_CUSTOM
);
814 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0])) == FALSE
)
815 item
->flags
|= GF_CUSTOM
;
817 DB( g_print(" custom flag=%d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[1]))) );
819 // if any value,set the flag to visual indicator
822 item
->flags
&= ~(GF_BUDGET
); //delete flag
825 gtk_spin_button_update(GTK_SPIN_BUTTON(data
->spinner
[i
]));
826 oldvalue
= item
->budget
[i
];
828 item
->budget
[i
] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->spinner
[i
]));
830 if( oldvalue
!= item
->budget
[i
])
833 DB( g_print(" set value %d to %.2f\n", i
, item
->budget
[i
]) );
840 item
->flags
&= ~(GF_FORCED
); //delete flag
841 active
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_force
));
843 item
->flags
|= GF_FORCED
;
845 if(budget
== TRUE
|| active
== 1)
846 item
->flags
|= GF_BUDGET
;
849 if( (old_flags
!= item
->flags
) || change
)
852 gtk_widget_queue_draw (data
->LV_cat
);
859 static void ui_bud_manage_selection_change(GtkWidget
*treeview
, gpointer user_data
)
861 struct ui_bud_manage_data
*data
;
865 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
867 DB( g_print("(ui_bud_manage) changed\n") );
871 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_cat
)), &model
, &iter
))
875 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
,
876 LST_DEFCAT_DATAS
, &item
,
879 DB( g_print(" selected %s\n", item
->name
) );
881 if(data
->lastcatitem
!= NULL
&& item
!= data
->lastcatitem
)
883 DB( g_print(" -> should do a get for last selected (%s)\n", data
->lastcatitem
->name
) );
884 ui_bud_manage_getlast(data
);
889 data
->lastcatitem
= item
;
891 ui_bud_manage_set(treeview
, NULL
);
895 data
->lastcatitem
= NULL
;
898 ui_bud_manage_update(treeview
, NULL
);
902 static void ui_bud_manage_toggle(GtkRadioButton
*radiobutton
, gpointer user_data
)
904 //struct ui_bud_manage_data *data;
906 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(radiobutton), GTK_TYPE_WINDOW)), "inst_data");
908 DB( g_print("(ui_bud_manage) toggle\n") );
910 //ui_bud_manage_get(GTK_WIDGET(radiobutton), GINT_TO_POINTER(FIELD_TYPE));
913 ui_bud_manage_update(GTK_WIDGET(radiobutton
), NULL
);
917 void ui_bud_manage_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
919 ui_bud_manage_selection_change(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
923 static gboolean
ui_bud_manage_cleanup(struct ui_bud_manage_data
*data
, gint result
)
925 gboolean doupdate
= FALSE
;
927 DB( g_print("(ui_bud_manage) cleanup\n") );
929 if(data
->lastcatitem
!= NULL
)
931 DB( g_print(" -> should do a get for last selected (%s)\n", data
->lastcatitem
->name
) );
932 ui_bud_manage_getlast(data
);
935 //do_application_specific_something ();
936 DB( g_print(" accept\n") );
938 GLOBALS
->changes_count
+= data
->change
;
940 DB( g_print(" free tmp_list\n") );
945 static void ui_bud_manage_populate_listview(struct ui_bud_manage_data
*data
)
949 type
= radio_get_active(GTK_CONTAINER(data
->RA_type
)) == 1 ? CAT_TYPE_INCOME
: CAT_TYPE_EXPENSE
;
951 ui_cat_listview_populate(data
->LV_cat
, type
);
952 gtk_tree_view_expand_all (GTK_TREE_VIEW(data
->LV_cat
));
956 static void ui_bud_manage_setup(struct ui_bud_manage_data
*data
)
959 DB( g_print("(ui_bud_manage) setup\n") );
961 data
->tmp_list
= NULL
;
964 data
->lastcatitem
= NULL
;
966 ui_bud_manage_populate_listview(data
);
971 static void ui_bud_manage_type_changed_cb (GtkToggleButton
*button
, gpointer user_data
)
973 ui_bud_manage_populate_listview(user_data
);
974 //g_print(" toggle type=%d\n", gtk_toggle_button_get_active(button));
981 GtkWidget
*ui_bud_manage_dialog (void)
983 struct ui_bud_manage_data data
;
984 GtkWidget
*dialog
, *content_area
;
985 GtkWidget
*content_grid
, *group_grid
, *table
, *scrollwin
, *label
;
986 GtkWidget
*treeview
, *hpaned
, *bbox
, *vbox
, *hbox
;
987 GtkWidget
*menu
, *menuitem
, *widget
, *image
, *tbar
;
988 GtkToolItem
*toolitem
;
994 memset(&data
, 0, sizeof(struct ui_bud_manage_data
));
996 dialog
= gtk_dialog_new_with_buttons (_("Manage Budget"),
997 GTK_WINDOW(GLOBALS
->mainwindow
),
1000 GTK_RESPONSE_ACCEPT
,
1003 data
.window
= dialog
;
1005 gtk_window_set_icon_name(GTK_WINDOW (dialog
), ICONNAME_HB_BUDGET
);
1007 //set a nice dialog size
1008 gtk_window_get_size(GTK_WINDOW(GLOBALS
->mainwindow
), &w
, &h
);
1009 gtk_window_set_default_size (GTK_WINDOW(dialog
), -1, h
/PHI
);
1012 //store our window private data
1013 g_object_set_data(G_OBJECT(dialog
), "inst_data", (gpointer
)&data
);
1014 DB( g_print("(ui_bud_manage) window=%p, inst_data=%p\n", dialog
, &data
) );
1017 content_area
= gtk_dialog_get_content_area(GTK_DIALOG (dialog
)); // return a vbox
1020 table
= gtk_grid_new ();
1021 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1022 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1023 g_object_set(table
, "margin", SPACING_MEDIUM
, NULL
);
1024 gtk_box_pack_start (GTK_BOX (content_area
), table
, TRUE
, TRUE
, 0);
1027 bbox
= make_radio(CYA_CAT_TYPE
, TRUE
, GTK_ORIENTATION_HORIZONTAL
);
1028 data
.RA_type
= bbox
;
1029 gtk_widget_set_halign (bbox
, GTK_ALIGN_CENTER
);
1030 gtk_grid_attach (GTK_GRID (table
), bbox
, 0, crow
, 1, 1);
1032 widget
= radio_get_nth_widget(GTK_CONTAINER(bbox
), 1);
1034 g_signal_connect (widget
, "toggled", G_CALLBACK (ui_bud_manage_type_changed_cb
), &data
);
1036 menu
= gtk_menu_new ();
1037 gtk_widget_set_halign (menu
, GTK_ALIGN_END
);
1039 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Import CSV"));
1040 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1041 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (ui_bud_manage_load_csv
), &data
);
1043 menuitem
= gtk_menu_item_new_with_mnemonic (_("E_xport CSV"));
1044 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1045 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (ui_bud_manage_save_csv
), &data
);
1047 gtk_widget_show_all (menu
);
1049 widget
= gtk_menu_button_new();
1050 image
= gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_MENU
, GTK_ICON_SIZE_MENU
);
1053 //gtk_image_get_icon_name(image, &thename, NULL);
1054 //g_print("the name is %s\n", thename);
1056 g_object_set (widget
, "image", image
, "popup", GTK_MENU(menu
), NULL
);
1058 gtk_widget_set_hexpand (widget
, FALSE
);
1059 gtk_widget_set_halign (widget
, GTK_ALIGN_END
);
1060 gtk_grid_attach (GTK_GRID (table
), widget
, 0, crow
++, 1, 1);
1065 hpaned
= gtk_paned_new(GTK_ORIENTATION_HORIZONTAL
);
1066 //gtk_container_set_border_width (GTK_CONTAINER(hpaned), SPACING_MEDIUM);
1067 gtk_grid_attach (GTK_GRID (table
), hpaned
, 0, crow
++, 1, 1);
1071 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1072 gtk_widget_set_margin_right(vbox
, SPACING_SMALL
);
1073 gtk_paned_pack1 (GTK_PANED(hpaned
), vbox
, FALSE
, FALSE
);
1075 scrollwin
= gtk_scrolled_window_new(NULL
,NULL
);
1076 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin
), GTK_SHADOW_ETCHED_IN
);
1077 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin
), GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1078 treeview
= (GtkWidget
*)ui_bud_listview_new();
1079 data
.LV_cat
= treeview
;
1080 gtk_widget_set_size_request(treeview
, HB_MINWIDTH_LIST
, -1);
1081 gtk_container_add(GTK_CONTAINER(scrollwin
), treeview
);
1082 gtk_widget_set_hexpand (scrollwin
, TRUE
);
1083 gtk_widget_set_vexpand (scrollwin
, TRUE
);
1084 gtk_box_pack_start (GTK_BOX(vbox
), scrollwin
, TRUE
, TRUE
, 0);
1087 tbar
= gtk_toolbar_new();
1088 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar
), GTK_ICON_SIZE_MENU
);
1089 gtk_toolbar_set_style(GTK_TOOLBAR(tbar
), GTK_TOOLBAR_ICONS
);
1090 gtk_box_pack_start (GTK_BOX (vbox
), tbar
, FALSE
, FALSE
, 0);
1092 gtk_style_context_add_class (gtk_widget_get_style_context (tbar
), GTK_STYLE_CLASS_INLINE_TOOLBAR
);
1094 toolitem
= gtk_separator_tool_item_new ();
1095 gtk_tool_item_set_expand (toolitem
, TRUE
);
1096 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem
), FALSE
);
1097 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
1099 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
1100 toolitem
= gtk_tool_item_new();
1101 gtk_container_add (GTK_CONTAINER(toolitem
), hbox
);
1102 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
1104 widget
= make_image_button(ICONNAME_HB_BUTTON_EXPAND
, _("Expand all"));
1105 data
.BT_expand
= widget
;
1106 gtk_box_pack_start (GTK_BOX (hbox
), widget
, FALSE
, FALSE
, 0);
1108 widget
= make_image_button(ICONNAME_HB_BUTTON_COLLAPSE
, _("Collapse all"));
1109 data
.BT_collapse
= widget
;
1110 gtk_box_pack_start (GTK_BOX (hbox
), widget
, FALSE
, FALSE
, 0);
1114 content_grid
= gtk_grid_new();
1115 gtk_grid_set_row_spacing (GTK_GRID (content_grid
), SPACING_LARGE
);
1116 gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid
), GTK_ORIENTATION_VERTICAL
);
1117 //gtk_container_set_border_width (GTK_CONTAINER(content_grid), SPACING_MEDIUM);
1118 gtk_widget_set_margin_left(content_grid
, SPACING_SMALL
);
1119 gtk_paned_pack2 (GTK_PANED(hpaned
), content_grid
, FALSE
, FALSE
);
1125 group_grid
= gtk_grid_new ();
1126 gtk_grid_set_row_spacing (GTK_GRID (group_grid
), SPACING_SMALL
);
1127 gtk_grid_set_column_spacing (GTK_GRID (group_grid
), SPACING_MEDIUM
);
1128 gtk_grid_attach (GTK_GRID (content_grid
), group_grid
, 0, crow
++, 1, 1);
1130 label
= make_label_group(_("Budget for each month"));
1131 data
.label_budget
= label
;
1132 gtk_grid_attach (GTK_GRID (group_grid
), label
, 0, 0, 3, 1);
1137 widget
= gtk_radio_button_new_with_label (NULL
, _("is the same"));
1138 data
.CM_type
[0] = widget
;
1139 gtk_widget_set_hexpand (widget
, TRUE
);
1140 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1141 fchain
= g_list_append(fchain
, widget
);
1144 widget
= make_amount(label
);
1145 data
.spinner
[0] = widget
;
1146 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 2, row
, 1, 1);
1147 fchain
= g_list_append(fchain
, widget
);
1149 g_signal_connect (G_OBJECT (data
.spinner
[0]), "value-changed", G_CALLBACK (ui_bud_manage_has_budget
), NULL
);
1151 widget
= gtk_button_new_with_mnemonic (_("_Clear input"));
1152 data
.BT_clear
= widget
;
1153 gtk_widget_set_hexpand (widget
, TRUE
);
1154 gtk_widget_set_halign(widget
, GTK_ALIGN_START
);
1155 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 4, row
, 1, 1);
1156 fchain
= g_list_append(fchain
, widget
);
1161 button = gtk_button_new_with_label(_("Propagate"));
1162 gtk_grid_attach (GTK_GRID (group_grid), button, 1, 2, row, row+1);
1166 widget
= gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (data
.CM_type
[0]), _("is different"));
1167 data
.CM_type
[1] = widget
;
1168 gtk_widget_set_hexpand (widget
, TRUE
);
1169 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1170 fchain
= g_list_append(fchain
, widget
);
1177 l
= ((i
<6) ? 1 : 3);
1178 t
= row
+ ((i
<6) ? i
: i
-6);
1180 label
= make_label_widget(months
[i
]);
1181 data
.label
[i
+1] = label
;
1182 gtk_grid_attach (GTK_GRID (group_grid
), label
, l
, t
, 1, 1);
1184 widget
= make_amount(label
);
1185 data
.spinner
[i
+1] = widget
;
1186 fchain
= g_list_append(fchain
, widget
);
1187 gtk_widget_set_hexpand (widget
, TRUE
);
1188 gtk_grid_attach (GTK_GRID (group_grid
), widget
, l
+1, t
, 1, 1);
1190 g_signal_connect (G_OBJECT (data
.spinner
[i
+1]), "value-changed", G_CALLBACK (ui_bud_manage_has_budget
), NULL
);
1192 //DB( g_print("(ui_bud_manage) %s, col=%d, row=%d", months[i], col, row) );
1195 gtk_container_set_focus_chain(GTK_CONTAINER(group_grid
), fchain
);
1196 g_list_free(fchain
);
1199 group_grid
= gtk_grid_new ();
1200 gtk_grid_set_row_spacing (GTK_GRID (group_grid
), SPACING_SMALL
);
1201 gtk_grid_set_column_spacing (GTK_GRID (group_grid
), SPACING_MEDIUM
);
1202 gtk_grid_attach (GTK_GRID (content_grid
), group_grid
, 0, crow
++, 1, 1);
1204 label
= make_label_group(_("Options"));
1205 data
.label_options
= label
;
1206 gtk_grid_attach (GTK_GRID (group_grid
), label
, 0, 0, 3, 1);
1209 widget
= gtk_check_button_new_with_mnemonic (_("_Force monitoring this category"));
1210 data
.CM_force
= widget
;
1211 gtk_widget_set_hexpand (widget
, TRUE
);
1212 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1215 //connect all our signals
1216 g_signal_connect (dialog
, "destroy",
1217 G_CALLBACK (gtk_widget_destroyed
), &dialog
);
1220 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
.LV_cat
)), "changed", G_CALLBACK (ui_bud_manage_selection
), NULL
);
1221 //g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_bud_manage_onRowActivated), NULL);
1223 g_signal_connect (G_OBJECT (data
.BT_expand
), "clicked", G_CALLBACK (ui_bud_manage_expand_all
), NULL
);
1224 g_signal_connect (G_OBJECT (data
.BT_collapse
), "clicked", G_CALLBACK (ui_bud_manage_collapse_all
), NULL
);
1226 data
.handler_id
[HID_CUSTOM
] = g_signal_connect (data
.CM_type
[0], "toggled", G_CALLBACK (ui_bud_manage_toggle
), NULL
);
1228 g_signal_connect (G_OBJECT (data
.BT_clear
), "clicked", G_CALLBACK (ui_bud_manage_clear
), NULL
);
1230 //data.custom = FALSE;
1231 //gtk_widget_set_sensitive(data.table, FALSE);
1233 //setup, init and show window
1234 ui_bud_manage_setup(&data
);
1235 ui_bud_manage_update(dialog
, NULL
);
1239 gtk_widget_show_all (dialog
);
1242 gint result
= gtk_dialog_run (GTK_DIALOG (dialog
));
1245 case GTK_RESPONSE_ACCEPT
:
1246 //do_application_specific_something ();
1249 //do_nothing_since_dialog_was_cancelled ();
1253 // cleanup and destroy
1254 ui_bud_manage_cleanup(&data
, result
);
1255 gtk_widget_destroy (dialog
);