1 /* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2016 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
);
236 renderer
= gtk_cell_renderer_text_new ();
237 g_object_set(renderer
,
238 "ellipsize", PANGO_ELLIPSIZE_END
,
239 "ellipsize-set", TRUE
,
242 column
= gtk_tree_view_column_new();
243 gtk_tree_view_column_set_title(column
, _("Category"));
244 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
245 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_bud_listview_cell_data_function_text
, GINT_TO_POINTER(1), NULL
);
246 gtk_tree_view_column_set_alignment (column
, 0.5);
247 gtk_tree_view_column_set_min_width(column
, HB_MINWIDTH_LIST
);
248 //gtk_tree_view_column_set_sort_column_id (column, LST_DEFACC_NAME);
249 gtk_tree_view_column_set_resizable(column
, TRUE
);
250 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
253 column
= gtk_tree_view_column_new();
254 renderer
= gtk_cell_renderer_pixbuf_new ();
255 //gtk_cell_renderer_set_fixed_size(renderer, GLOBALS->lst_pixbuf_maxwidth, -1);
256 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
257 gtk_tree_view_column_set_cell_data_func(column
, renderer
, ui_bud_listview_icon_cell_data_function
, NULL
, NULL
);
258 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
261 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview
), ui_bud_listview_search_equal_func
, NULL
, NULL
);
264 //gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE);
265 //gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE);
273 ** index 0 is all month, then 1 -> 12 are months
275 static gchar
*ui_bud_manage_getcsvbudgetstr(Category
*item
)
277 gchar
*retval
= NULL
;
278 char buf
[G_ASCII_DTOSTR_BUF_SIZE
];
280 //DB( g_print(" get budgetstr for '%s'\n", item->name) );
282 if( !(item
->flags
& GF_CUSTOM
) )
284 if( item
->budget
[0] )
286 g_ascii_dtostr (buf
, sizeof (buf
), item
->budget
[0]);
287 retval
= g_strdup(buf
);
289 //DB( g_print(" => %d: %s\n", 0, retval) );
298 //if( item->budget[i] )
302 g_ascii_dtostr (buf
, sizeof (buf
), item
->budget
[i
]);
306 retval
= g_strconcat(retval
, ";", buf
, NULL
);
310 retval
= g_strdup(buf
);
312 //DB( g_print(" => %d: %s\n", i, retval) );
322 static gint
ui_bud_manage_category_exists (GtkTreeModel
*model
, gchar
*level
, gchar
*type
, gchar
*name
, GtkTreeIter
*return_iter
)
324 GtkTreeIter iter
, child
;
332 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
336 gtk_tree_model_get (model
, &iter
, LST_DEFCAT_DATAS
, &entry
, -1);
340 if(entry
->name
&& g_ascii_strcasecmp(name
, entry
->name
) == 0)
350 gint n_child
= gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model
), &iter
);
351 gtk_tree_model_iter_children (GTK_TREE_MODEL(model
), &child
, &iter
);
355 gtk_tree_model_get(GTK_TREE_MODEL(model
), &child
,
356 LST_DEFCAT_DATAS
, &entry
,
359 if(entry
->name
&& g_ascii_strcasecmp(name
, entry
->name
) == 0)
361 *return_iter
= child
;
366 gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &child
);
371 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
379 static void ui_bud_manage_load_csv( GtkWidget
*widget
, gpointer user_data
)
381 struct ui_bud_manage_data
*data
= user_data
;
382 gchar
*filename
= NULL
;
384 const gchar
*encoding
;
387 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data");
390 DB( g_print("(ui_bud_manage) load csv - data %p\n", data
) );
392 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_OPEN
, &filename
, NULL
) == TRUE
)
394 DB( g_print(" + filename is %s\n", filename
) );
396 encoding
= homebank_file_getencoding(filename
);
398 io
= g_io_channel_new_file(filename
, "r", NULL
);
403 gboolean error
= FALSE
;
407 DB( g_print(" -> encoding should be %s\n", encoding
) );
408 if( encoding
!= NULL
)
410 g_io_channel_set_encoding(io
, encoding
, NULL
);
413 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_cat
));
418 io_stat
= g_io_channel_read_line(io
, &tmpstr
, NULL
, NULL
, NULL
);
419 if( io_stat
== G_IO_STATUS_EOF
)
421 if( io_stat
== G_IO_STATUS_NORMAL
)
427 hb_string_strip_crlf(tmpstr
);
429 str_array
= g_strsplit (tmpstr
, ";", 15);
432 if( (g_strv_length (str_array
) < 4 || *str_array
[1] != '*') && (g_strv_length (str_array
) < 15))
438 DB( g_print(" csv read '%s : %s : %s ...'\n", str_array
[0], str_array
[1], str_array
[2]) );
440 gint pos
= ui_bud_manage_category_exists(model
, str_array
[0], str_array
[1], str_array
[2], &iter
);
442 DB( g_print(" pos=%d\n", pos
) );
450 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
,
451 LST_DEFCAT_DATAS
, &tmpitem
,
454 DB( g_print(" found cat, updating '%s'\n", tmpitem
->name
) );
458 tmpitem
->flags
&= ~(GF_CUSTOM
); //delete flag
459 if( *str_array
[1] == '*' )
461 tmpitem
->budget
[0] = g_ascii_strtod(str_array
[3], NULL
);
463 DB( g_print(" monthly '%.2f'\n", tmpitem
->budget
[0]) );
467 tmpitem
->flags
|= (GF_CUSTOM
);
471 tmpitem
->budget
[i
] = g_ascii_strtod(str_array
[2+i
], NULL
);
472 DB( g_print(" month %d '%.2f'\n", i
, tmpitem
->budget
[i
]) );
476 // if any value,set the flag to visual indicator
478 tmpitem
->flags
&= ~(GF_BUDGET
); //delete flag
481 if(tmpitem
->budget
[i
])
489 tmpitem
->flags
|= GF_BUDGET
;
492 g_strfreev (str_array
);
499 //update the treeview
500 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_cat
)));
503 g_io_channel_unref (io
);
507 ui_dialog_msg_infoerror(GTK_WINDOW(data
->window
), GTK_MESSAGE_ERROR
,
508 _("File format error"),
509 _("The CSV file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.")
521 static void ui_bud_manage_save_csv( GtkWidget
*widget
, gpointer user_data
)
523 struct ui_bud_manage_data
*data
= user_data
;
524 gchar
*filename
= NULL
;
526 GtkTreeIter iter
, child
;
530 DB( g_print("(ui_bud_manage) save csv\n") );
532 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
534 if( ui_file_chooser_csv(GTK_WINDOW(data
->window
), GTK_FILE_CHOOSER_ACTION_SAVE
, &filename
, NULL
) == TRUE
)
537 DB( g_print(" + filename is %s\n", filename
) );
539 io
= g_io_channel_new_file(filename
, "w", NULL
);
543 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(data
->LV_cat
));
545 valid
= gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
);
549 gchar
*outstr
, *outvalstr
;
553 gtk_tree_model_get (GTK_TREE_MODEL(model
), &iter
, LST_DEFCAT_DATAS
, &category
, -1);
555 if( category
->name
!= NULL
)
559 if( category
->flags
& GF_BUDGET
)
561 type
= (category
->flags
& GF_CUSTOM
) ? ' ' : '*';
563 outvalstr
= ui_bud_manage_getcsvbudgetstr(category
);
564 outstr
= g_strdup_printf("1;%c;%s;%s\n", type
, category
->name
, outvalstr
);
565 DB( g_print("%s", outstr
) );
566 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
572 //level 2: subcategory
573 gint n_child
= gtk_tree_model_iter_n_children (GTK_TREE_MODEL(model
), &iter
);
574 gtk_tree_model_iter_children (GTK_TREE_MODEL(model
), &child
, &iter
);
577 gtk_tree_model_get(GTK_TREE_MODEL(model
), &child
, LST_DEFCAT_DATAS
, &category
, -1);
579 type
= (category
->flags
& GF_CUSTOM
) ? ' ' : '*';
581 outvalstr
= ui_bud_manage_getcsvbudgetstr(category
);
584 outstr
= g_strdup_printf("2;%c;%s;%s\n", type
, category
->name
, outvalstr
);
585 DB( g_print("%s", outstr
) );
586 g_io_channel_write_chars(io
, outstr
, -1, NULL
, NULL
);
592 gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &child
);
596 valid
= gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
);
599 g_io_channel_unref (io
);
609 static void ui_bud_manage_expand_all(GtkWidget
*widget
, gpointer user_data
)
611 struct ui_bud_manage_data
*data
;
613 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
614 DB( g_print("\n(ui_bud_manage) expand all (data=%x)\n", (guint
)data
) );
616 gtk_tree_view_expand_all(GTK_TREE_VIEW(data
->LV_cat
));
621 static void ui_bud_manage_collapse_all(GtkWidget
*widget
, gpointer user_data
)
623 struct ui_bud_manage_data
*data
;
625 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget
, GTK_TYPE_WINDOW
)), "inst_data");
626 DB( g_print("\n(ui_bud_manage) collapse all (data=%x)\n", (guint
)data
) );
628 gtk_tree_view_collapse_all(GTK_TREE_VIEW(data
->LV_cat
));
632 static void ui_bud_manage_update(GtkWidget
*treeview
, gpointer user_data
)
634 struct ui_bud_manage_data
*data
;
635 gboolean name
, custom
, sensitive
;
638 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
640 DB( g_print("\n(ui_bud_manage) update %x\n", (gint
)data
) );
644 if(data
->cat
!= NULL
)
646 name
= data
->cat
->key
== 0 ? FALSE
: TRUE
;
651 gtk_widget_set_sensitive(data
->label_budget
, sensitive
);
652 gtk_widget_set_sensitive(data
->CM_type
[0], sensitive
);
653 gtk_widget_set_sensitive(data
->CM_type
[1], sensitive
);
655 gtk_widget_set_sensitive(data
->label_options
, sensitive
);
656 gtk_widget_set_sensitive(data
->CM_force
, sensitive
);
658 gtk_widget_set_sensitive(data
->BT_clear
, sensitive
);
661 gint toto
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0]));
662 DB( g_print(" monthly = %d\n", toto
) );
665 custom
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[1]));
666 DB( g_print(" custom = %d\n\n", custom
) );
668 sensitive
= name
== FALSE
? FALSE
: custom
== TRUE
? FALSE
: TRUE
;
669 gtk_widget_set_sensitive(data
->spinner
[0], sensitive
);
671 sensitive
= name
== FALSE
? FALSE
: custom
;
674 gtk_widget_set_sensitive(data
->label
[i
+1], sensitive
);
675 gtk_widget_set_sensitive(data
->spinner
[i
+1], sensitive
);
681 static void ui_bud_manage_clear(GtkWidget
*widget
, gpointer user_data
)
683 struct ui_bud_manage_data
*data
;
688 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget
), GTK_TYPE_WINDOW
)), "inst_data");
690 DB( g_print("(ui_bud_manage) clear\n") );
693 title
= _("Are you sure you want to clear input?");
695 secondtext
= _("If you proceed, every amount will be set to 0.");
697 result
= ui_dialog_msg_confirm_alert(
698 GTK_WINDOW(data
->window
),
704 if( result
== GTK_RESPONSE_OK
)
706 //g_signal_handler_block(data->CM_type[0], data->handler_id[HID_CUSTOM]);
707 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0]), TRUE
);
708 //g_signal_handler_unblock(data->CM_type[0], data->handler_id[HID_CUSTOM]);
712 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
714 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->spinner
[i
]), 0);
715 data
->cat
->budget
[i
] = 0;
717 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
720 data
->cat
->flags
&= ~(GF_BUDGET
); //delete flag
722 gtk_widget_queue_draw (data
->LV_cat
);
728 static void ui_bud_manage_set(GtkWidget
*widget
, gpointer user_data
)
730 struct ui_bud_manage_data
*data
;
734 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget
), GTK_TYPE_WINDOW
)), "inst_data");
736 DB( g_print("(ui_bud_manage) set\n") );
738 active
= data
->cat
->flags
& GF_CUSTOM
? 1 : 0;
739 //data->custom = active;
741 //DB( g_print(" set custom to %d\n", data->custom) );
743 g_signal_handler_block(data
->CM_type
[0], data
->handler_id
[HID_CUSTOM
]);
744 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_type
[active
]), TRUE
);
745 g_signal_handler_unblock(data
->CM_type
[0], data
->handler_id
[HID_CUSTOM
]);
749 //g_signal_handler_block(data->spinner[i], data->spinner_hid[i]);
751 gtk_spin_button_set_value(GTK_SPIN_BUTTON(data
->spinner
[i
]), data
->cat
->budget
[i
]);
752 //DB( g_print(" %.2f\n", data->cat->budget[i]) );
754 //g_signal_handler_unblock(data->spinner[i], data->spinner_hid[i]);
757 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data
->CM_force
), (data
->cat
->flags
& GF_FORCED
) ? 1 : 0);
761 static gboolean
ui_bud_manage_has_budget(GtkSpinButton
*spinbutton
, gpointer user_data
)
763 struct ui_bud_manage_data
*data
;
768 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(spinbutton
), GTK_TYPE_WINDOW
)), "inst_data");
770 DB( g_print("(ui_bud_manage) has budget\n") );
778 item
->flags
&= ~(GF_BUDGET
); //delete flag
781 gtk_spin_button_update(GTK_SPIN_BUTTON(data
->spinner
[i
]));
782 if( gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->spinner
[i
])) )
785 item
->flags
|= GF_BUDGET
;
795 static void ui_bud_manage_getlast(struct ui_bud_manage_data
*data
)
797 gboolean budget
, change
;
803 item
= data
->lastcatitem
;
805 DB( g_print("****\n(ui_bud_manage) getlast for '%s'\n", item
->name
) );
809 gushort old_flags
= item
->flags
;
811 item
->flags
&= ~(GF_CUSTOM
);
812 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[0])) == FALSE
)
813 item
->flags
|= GF_CUSTOM
;
815 DB( g_print(" custom flag=%d\n", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_type
[1]))) );
817 // if any value,set the flag to visual indicator
820 item
->flags
&= ~(GF_BUDGET
); //delete flag
823 gtk_spin_button_update(GTK_SPIN_BUTTON(data
->spinner
[i
]));
824 oldvalue
= item
->budget
[i
];
826 item
->budget
[i
] = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data
->spinner
[i
]));
828 if( oldvalue
!= item
->budget
[i
])
831 DB( g_print(" set value %d to %.2f\n", i
, item
->budget
[i
]) );
838 item
->flags
&= ~(GF_FORCED
); //delete flag
839 active
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data
->CM_force
));
841 item
->flags
|= GF_FORCED
;
843 if(budget
== TRUE
|| active
== 1)
844 item
->flags
|= GF_BUDGET
;
847 if( (old_flags
!= item
->flags
) || change
)
850 gtk_widget_queue_draw (data
->LV_cat
);
857 static void ui_bud_manage_selection_change(GtkWidget
*treeview
, gpointer user_data
)
859 struct ui_bud_manage_data
*data
;
863 data
= g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview
), GTK_TYPE_WINDOW
)), "inst_data");
865 DB( g_print("(ui_bud_manage) changed\n") );
869 if(gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data
->LV_cat
)), &model
, &iter
))
873 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
,
874 LST_DEFCAT_DATAS
, &item
,
877 DB( g_print(" selected %s\n", item
->name
) );
879 if(data
->lastcatitem
!= NULL
&& item
!= data
->lastcatitem
)
881 DB( g_print(" -> should do a get for last selected (%s)\n", data
->lastcatitem
->name
) );
882 ui_bud_manage_getlast(data
);
887 data
->lastcatitem
= item
;
889 ui_bud_manage_set(treeview
, NULL
);
893 data
->lastcatitem
= NULL
;
896 ui_bud_manage_update(treeview
, NULL
);
900 static void ui_bud_manage_toggle(GtkRadioButton
*radiobutton
, gpointer user_data
)
902 //struct ui_bud_manage_data *data;
904 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(radiobutton), GTK_TYPE_WINDOW)), "inst_data");
906 DB( g_print("(ui_bud_manage) toggle\n") );
908 //ui_bud_manage_get(GTK_WIDGET(radiobutton), GINT_TO_POINTER(FIELD_TYPE));
911 ui_bud_manage_update(GTK_WIDGET(radiobutton
), NULL
);
915 void ui_bud_manage_selection(GtkTreeSelection
*treeselection
, gpointer user_data
)
917 ui_bud_manage_selection_change(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection
)), NULL
);
921 static gboolean
ui_bud_manage_cleanup(struct ui_bud_manage_data
*data
, gint result
)
923 gboolean doupdate
= FALSE
;
925 DB( g_print("(ui_bud_manage) cleanup\n") );
927 if(data
->lastcatitem
!= NULL
)
929 DB( g_print(" -> should do a get for last selected (%s)\n", data
->lastcatitem
->name
) );
930 ui_bud_manage_getlast(data
);
933 //do_application_specific_something ();
934 DB( g_print(" accept\n") );
936 GLOBALS
->changes_count
+= data
->change
;
938 DB( g_print(" free tmp_list\n") );
943 static void ui_bud_manage_populate_listview(struct ui_bud_manage_data
*data
)
947 type
= radio_get_active(GTK_CONTAINER(data
->RA_type
)) == 1 ? CAT_TYPE_INCOME
: CAT_TYPE_EXPENSE
;
949 ui_cat_listview_populate(data
->LV_cat
, type
);
950 gtk_tree_view_expand_all (GTK_TREE_VIEW(data
->LV_cat
));
954 static void ui_bud_manage_setup(struct ui_bud_manage_data
*data
)
957 DB( g_print("(ui_bud_manage) setup\n") );
959 data
->tmp_list
= NULL
;
962 data
->lastcatitem
= NULL
;
964 ui_bud_manage_populate_listview(data
);
969 static void ui_bud_manage_type_changed_cb (GtkToggleButton
*button
, gpointer user_data
)
971 ui_bud_manage_populate_listview(user_data
);
972 //g_print(" toggle type=%d\n", gtk_toggle_button_get_active(button));
979 GtkWidget
*ui_bud_manage_dialog (void)
981 struct ui_bud_manage_data data
;
982 GtkWidget
*dialog
, *content_area
;
983 GtkWidget
*content_grid
, *group_grid
, *table
, *scrollwin
, *label
;
984 GtkWidget
*treeview
, *hpaned
, *bbox
, *vbox
, *hbox
;
985 GtkWidget
*menu
, *menuitem
, *widget
, *image
, *tbar
;
986 GtkToolItem
*toolitem
;
991 memset(&data
, 0, sizeof(struct ui_bud_manage_data
));
993 dialog
= gtk_dialog_new_with_buttons (_("Manage Budget"),
994 GTK_WINDOW(GLOBALS
->mainwindow
),
1000 data
.window
= dialog
;
1002 gtk_window_set_icon_name(GTK_WINDOW (dialog
), ICONNAME_HB_BUDGET
);
1004 //set a nice dialog size
1005 gtk_window_get_size(GTK_WINDOW(GLOBALS
->mainwindow
), &w
, &h
);
1006 gtk_window_set_default_size (GTK_WINDOW(dialog
), -1, h
/PHI
);
1009 //store our window private data
1010 g_object_set_data(G_OBJECT(dialog
), "inst_data", (gpointer
)&data
);
1011 DB( g_print("(ui_bud_manage) window=%p, inst_data=%p\n", dialog
, &data
) );
1014 content_area
= gtk_dialog_get_content_area(GTK_DIALOG (dialog
)); // return a vbox
1017 table
= gtk_grid_new ();
1018 gtk_grid_set_row_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1019 gtk_grid_set_column_spacing (GTK_GRID (table
), SPACING_MEDIUM
);
1020 g_object_set(table
, "margin", SPACING_MEDIUM
, NULL
);
1021 gtk_box_pack_start (GTK_BOX (content_area
), table
, TRUE
, TRUE
, 0);
1024 bbox
= make_radio(CYA_CAT_TYPE
, TRUE
, GTK_ORIENTATION_HORIZONTAL
);
1025 data
.RA_type
= bbox
;
1026 gtk_widget_set_halign (bbox
, GTK_ALIGN_CENTER
);
1027 gtk_grid_attach (GTK_GRID (table
), bbox
, 0, crow
, 1, 1);
1029 widget
= radio_get_nth_widget(GTK_CONTAINER(bbox
), 1);
1031 g_signal_connect (widget
, "toggled", G_CALLBACK (ui_bud_manage_type_changed_cb
), &data
);
1033 menu
= gtk_menu_new ();
1034 gtk_widget_set_halign (menu
, GTK_ALIGN_END
);
1036 menuitem
= gtk_menu_item_new_with_mnemonic (_("_Import CSV"));
1037 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1038 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (ui_bud_manage_load_csv
), &data
);
1040 menuitem
= gtk_menu_item_new_with_mnemonic (_("E_xport CSV"));
1041 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
1042 g_signal_connect (G_OBJECT (menuitem
), "activate", G_CALLBACK (ui_bud_manage_save_csv
), &data
);
1044 gtk_widget_show_all (menu
);
1046 widget
= gtk_menu_button_new();
1047 image
= gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_MENU
, GTK_ICON_SIZE_MENU
);
1050 //gtk_image_get_icon_name(image, &thename, NULL);
1051 //g_print("the name is %s\n", thename);
1053 g_object_set (widget
, "image", image
, "popup", GTK_MENU(menu
), NULL
);
1055 gtk_widget_set_hexpand (widget
, FALSE
);
1056 gtk_widget_set_halign (widget
, GTK_ALIGN_END
);
1057 gtk_grid_attach (GTK_GRID (table
), widget
, 0, crow
++, 1, 1);
1062 hpaned
= gtk_paned_new(GTK_ORIENTATION_HORIZONTAL
);
1063 //gtk_container_set_border_width (GTK_CONTAINER(hpaned), SPACING_MEDIUM);
1064 gtk_grid_attach (GTK_GRID (table
), hpaned
, 0, crow
++, 1, 1);
1068 vbox
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
1069 gtk_widget_set_margin_right(vbox
, SPACING_SMALL
);
1070 gtk_paned_pack1 (GTK_PANED(hpaned
), vbox
, TRUE
, FALSE
);
1072 scrollwin
= gtk_scrolled_window_new(NULL
,NULL
);
1073 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin
), GTK_SHADOW_ETCHED_IN
);
1074 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin
), GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1075 treeview
= (GtkWidget
*)ui_bud_listview_new();
1076 data
.LV_cat
= treeview
;
1077 gtk_widget_set_size_request(treeview
, HB_MINWIDTH_LIST
, -1);
1078 gtk_container_add(GTK_CONTAINER(scrollwin
), treeview
);
1079 gtk_box_pack_start (GTK_BOX(vbox
), scrollwin
, TRUE
, TRUE
, 0);
1082 tbar
= gtk_toolbar_new();
1083 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar
), GTK_ICON_SIZE_MENU
);
1084 gtk_toolbar_set_style(GTK_TOOLBAR(tbar
), GTK_TOOLBAR_ICONS
);
1085 gtk_box_pack_start (GTK_BOX (vbox
), tbar
, FALSE
, FALSE
, 0);
1087 gtk_style_context_add_class (gtk_widget_get_style_context (tbar
), GTK_STYLE_CLASS_INLINE_TOOLBAR
);
1089 toolitem
= gtk_separator_tool_item_new ();
1090 gtk_tool_item_set_expand (toolitem
, TRUE
);
1091 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem
), FALSE
);
1092 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
1094 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
1095 toolitem
= gtk_tool_item_new();
1096 gtk_container_add (GTK_CONTAINER(toolitem
), hbox
);
1097 gtk_toolbar_insert(GTK_TOOLBAR(tbar
), GTK_TOOL_ITEM(toolitem
), -1);
1099 widget
= make_image_button(ICONNAME_HB_BUTTON_EXPAND
, _("Expand all"));
1100 data
.BT_expand
= widget
;
1101 gtk_box_pack_start (GTK_BOX (hbox
), widget
, FALSE
, FALSE
, 0);
1103 widget
= make_image_button(ICONNAME_HB_BUTTON_COLLAPSE
, _("Collapse all"));
1104 data
.BT_collapse
= widget
;
1105 gtk_box_pack_start (GTK_BOX (hbox
), widget
, FALSE
, FALSE
, 0);
1109 content_grid
= gtk_grid_new();
1110 gtk_grid_set_row_spacing (GTK_GRID (content_grid
), SPACING_LARGE
);
1111 gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid
), GTK_ORIENTATION_VERTICAL
);
1112 //gtk_container_set_border_width (GTK_CONTAINER(content_grid), SPACING_MEDIUM);
1113 gtk_widget_set_margin_left(content_grid
, SPACING_SMALL
);
1114 gtk_paned_pack2 (GTK_PANED(hpaned
), content_grid
, FALSE
, FALSE
);
1120 group_grid
= gtk_grid_new ();
1121 gtk_grid_set_row_spacing (GTK_GRID (group_grid
), SPACING_SMALL
);
1122 gtk_grid_set_column_spacing (GTK_GRID (group_grid
), SPACING_MEDIUM
);
1123 gtk_grid_attach (GTK_GRID (content_grid
), group_grid
, 0, crow
++, 1, 1);
1125 label
= make_label_group(_("Budget for each month"));
1126 data
.label_budget
= label
;
1127 gtk_grid_attach (GTK_GRID (group_grid
), label
, 0, 0, 3, 1);
1130 widget
= gtk_radio_button_new_with_label (NULL
, _("is the same"));
1131 data
.CM_type
[0] = widget
;
1132 gtk_widget_set_hexpand (widget
, TRUE
);
1133 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1136 widget
= make_amount(label
);
1137 data
.spinner
[0] = widget
;
1138 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 2, row
, 1, 1);
1140 g_signal_connect (G_OBJECT (data
.spinner
[0]), "value-changed", G_CALLBACK (ui_bud_manage_has_budget
), NULL
);
1142 widget
= gtk_button_new_with_mnemonic (_("_Clear input"));
1143 data
.BT_clear
= widget
;
1144 gtk_widget_set_hexpand (widget
, TRUE
);
1145 gtk_widget_set_halign(widget
, GTK_ALIGN_START
);
1146 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 4, row
, 1, 1);
1151 button = gtk_button_new_with_label(_("Propagate"));
1152 gtk_grid_attach (GTK_GRID (group_grid), button, 1, 2, row, row+1);
1156 widget
= gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON (data
.CM_type
[0]), _("is different"));
1157 data
.CM_type
[1] = widget
;
1158 gtk_widget_set_hexpand (widget
, TRUE
);
1159 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1166 l
= ((i
<6) ? 1 : 3);
1167 t
= row
+ ((i
<6) ? i
: i
-6);
1169 label
= make_label_widget(months
[i
]);
1170 data
.label
[i
+1] = label
;
1171 gtk_grid_attach (GTK_GRID (group_grid
), label
, l
, t
, 1, 1);
1173 widget
= make_amount(label
);
1174 data
.spinner
[i
+1] = widget
;
1175 gtk_widget_set_hexpand (widget
, TRUE
);
1176 gtk_grid_attach (GTK_GRID (group_grid
), widget
, l
+1, t
, 1, 1);
1178 g_signal_connect (G_OBJECT (data
.spinner
[i
+1]), "value-changed", G_CALLBACK (ui_bud_manage_has_budget
), NULL
);
1180 //DB( g_print("(ui_bud_manage) %s, col=%d, row=%d", months[i], col, row) );
1184 group_grid
= gtk_grid_new ();
1185 gtk_grid_set_row_spacing (GTK_GRID (group_grid
), SPACING_SMALL
);
1186 gtk_grid_set_column_spacing (GTK_GRID (group_grid
), SPACING_MEDIUM
);
1187 gtk_grid_attach (GTK_GRID (content_grid
), group_grid
, 0, crow
++, 1, 1);
1189 label
= make_label_group(_("Options"));
1190 data
.label_options
= label
;
1191 gtk_grid_attach (GTK_GRID (group_grid
), label
, 0, 0, 3, 1);
1194 widget
= gtk_check_button_new_with_mnemonic (_("_Force monitoring this category"));
1195 data
.CM_force
= widget
;
1196 gtk_widget_set_hexpand (widget
, TRUE
);
1197 gtk_grid_attach (GTK_GRID (group_grid
), widget
, 1, row
, 4, 1);
1200 //connect all our signals
1201 g_signal_connect (dialog
, "destroy",
1202 G_CALLBACK (gtk_widget_destroyed
), &dialog
);
1205 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data
.LV_cat
)), "changed", G_CALLBACK (ui_bud_manage_selection
), NULL
);
1206 //g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_bud_manage_onRowActivated), NULL);
1208 g_signal_connect (G_OBJECT (data
.BT_expand
), "clicked", G_CALLBACK (ui_bud_manage_expand_all
), NULL
);
1209 g_signal_connect (G_OBJECT (data
.BT_collapse
), "clicked", G_CALLBACK (ui_bud_manage_collapse_all
), NULL
);
1211 data
.handler_id
[HID_CUSTOM
] = g_signal_connect (data
.CM_type
[0], "toggled", G_CALLBACK (ui_bud_manage_toggle
), NULL
);
1213 g_signal_connect (G_OBJECT (data
.BT_clear
), "clicked", G_CALLBACK (ui_bud_manage_clear
), NULL
);
1215 //data.custom = FALSE;
1216 //gtk_widget_set_sensitive(data.table, FALSE);
1218 //setup, init and show window
1219 ui_bud_manage_setup(&data
);
1220 ui_bud_manage_update(dialog
, NULL
);
1224 gtk_widget_show_all (dialog
);
1227 gint result
= gtk_dialog_run (GTK_DIALOG (dialog
));
1230 case GTK_RESPONSE_ACCEPT
:
1231 //do_application_specific_something ();
1234 //do_nothing_since_dialog_was_cancelled ();
1238 // cleanup and destroy
1239 ui_bud_manage_cleanup(&data
, result
);
1240 gtk_widget_destroy (dialog
);