X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=blobdiff_plain;f=src%2Fui-category.c;h=6f88fb47e2f51451adb0899150e4eadf32ae16cc;hp=56002f25785f62a565e28db5f40870d38d44aaba;hb=996fa4ab9f6b836001f8ad0eecbfd3821687fea7;hpb=27f6e3b112df235c8e9afc9911b1f6bce208a001 diff --git a/src/ui-category.c b/src/ui-category.c index 56002f2..6f88fb4 100644 --- a/src/ui-category.c +++ b/src/ui-category.c @@ -1,5 +1,5 @@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2014 Maxime DOYEN + * Copyright (C) 1995-2016 Maxime DOYEN * * This file is part of HomeBank. * @@ -17,6 +17,7 @@ * along with this program. If not, see . */ + #include "homebank.h" #include "ui-category.h" @@ -31,6 +32,16 @@ /* our global datas */ extern struct HomeBank *GLOBALS; +extern struct Preferences *PREFS; + + +gchar *CYA_CAT_TYPE[] = { + N_("Expense"), + N_("Income"), + NULL +}; + +static void ui_cat_manage_populate_listview(struct ui_cat_manage_dialog_data *data); /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ @@ -123,6 +134,25 @@ gchar *name; return -1; } + +Category +*ui_cat_comboboxentry_get(GtkComboBox *entry_box) +{ +Category *item = NULL; +gchar *name; + + DB( g_print ("ui_cat_comboboxentry_get_key()\n") ); + + name = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box)))); + if(name == NULL) + return NULL; + + item = da_cat_get_by_fullname(name); + + return item; +} + + gboolean ui_cat_comboboxentry_set_active(GtkComboBox *entry_box, guint32 key) { @@ -186,8 +216,11 @@ gchar *fullname, *name; gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, - 0, fullname, - 1, name, + LST_CMBCAT_DATAS, item, + LST_CMBCAT_FULLNAME, fullname, + LST_CMBCAT_SORTNAME, NULL, + LST_CMBCAT_NAME, name, + LST_CMBCAT_SUBCAT, item->parent == 0 ? 1 : 0, -1); g_free(fullname); @@ -202,34 +235,58 @@ ui_cat_comboboxentry_populate_ghfunc(gpointer key, gpointer value, struct catPop { GtkTreeIter iter; Category *item = value; -gchar *fullname, *name; +Category *pitem = NULL; +gchar *fullname, *name, *sortname; gchar type; if( ( item->key != ctx->except_key ) ) { - type = (item->flags & GF_INCOME) ? '+' : '-'; + pitem = da_cat_get(item->parent); + type = (item->flags & GF_INCOME) ? '+' : '-'; fullname = da_cat_get_fullname(item); - + sortname = NULL; + name = NULL; + //DB( g_print ("cat combo populate [%d:%d] %s\n", item->parent, item->key, fullname) ); if(item->key == 0) + { name = g_strdup(item->name); + sortname = g_strdup(item->name); + } else { if( item->parent == 0 ) + { name = g_strdup_printf("%s [%c]", item->name, type); + sortname = g_strdup_printf("%s", item->name); + } else - name = g_strdup_printf(" %c %s", type, item->name); + { + if(pitem) + { + name = g_strdup_printf(" %c %s", type, item->name); + sortname = g_strdup_printf("%s_%s", pitem->name, item->name); + } + } } - gtk_list_store_append (GTK_LIST_STORE(ctx->model), &iter); - gtk_list_store_set (GTK_LIST_STORE(ctx->model), &iter, - 0, fullname, - 1, name, - 2, item->parent == 0 ? 1 : 0, + hb_string_replace_char(' ', sortname); + + //gtk_list_store_append (GTK_LIST_STORE(ctx->model), &iter); + //gtk_list_store_set (GTK_LIST_STORE(ctx->model), &iter, + gtk_list_store_insert_with_values(GTK_LIST_STORE(ctx->model), &iter, -1, + LST_CMBCAT_DATAS, item, + LST_CMBCAT_FULLNAME, fullname, + LST_CMBCAT_SORTNAME, sortname, + LST_CMBCAT_NAME, name, + LST_CMBCAT_SUBCAT, item->parent == 0 ? 1 : 0, -1); + DB( g_print(" - add [%2d:%2d] '%-12s' '%-12s' '%s' '%s' %d\n", item->parent, item->key, pitem->name, name, fullname, sortname, item->parent == 0 ? 1 : 0) ); + + g_free(sortname); g_free(fullname); g_free(name); } @@ -254,30 +311,33 @@ void ui_cat_comboboxentry_populate_except(GtkComboBox *entry_box, GHashTable *hash, guint except_key) { GtkTreeModel *model; -GtkEntryCompletion *completion; +//GtkEntryCompletion *completion; struct catPopContext ctx; DB( g_print ("ui_cat_comboboxentry_populate()\n") ); model = gtk_combo_box_get_model(GTK_COMBO_BOX(entry_box)); - completion = gtk_entry_get_completion(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box)))); + //completion = gtk_entry_get_completion(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (entry_box)))); /* keep our model alive and detach from comboboxentry and completion */ - g_object_ref(model); - gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), NULL); - gtk_entry_completion_set_model (completion, NULL); + //g_object_ref(model); + //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), NULL); + //gtk_entry_completion_set_model (completion, NULL); /* clear and populate */ + ctx.model = model; ctx.except_key = except_key; - gtk_list_store_clear (GTK_LIST_STORE(model)); + + //gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING); + g_hash_table_foreach(hash, (GHFunc)ui_cat_comboboxentry_populate_ghfunc, &ctx); /* reatach our model */ - gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), model); - gtk_entry_completion_set_model (completion, model); - g_object_unref(model); + //gtk_combo_box_set_model(GTK_COMBO_BOX(entry_box), model); + //gtk_entry_completion_set_model (completion, model); + //g_object_unref(model); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); @@ -291,23 +351,22 @@ ui_cat_comboboxentry_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTree gint retval = 0; gchar *name1, *name2; - gtk_tree_model_get(model, a, 0, &name1, -1); - gtk_tree_model_get(model, b, 0, &name2, -1); + gtk_tree_model_get(model, a, + LST_CMBCAT_SORTNAME, &name1, + -1); + gtk_tree_model_get(model, b, + LST_CMBCAT_SORTNAME, &name2, + -1); + + //DB( g_print(" compare '%s' '%s'\n", name1, name2) ); retval = hb_string_utf8_compare(name1, name2); -/* - retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME); - if(!retval) - { - retval = hb_string_utf8_compare(entry1->name, entry2->name); - } -*/ + g_free(name2); g_free(name1); return retval; - } - +} static void @@ -324,8 +383,8 @@ gint style; //PANGO_STYLE_ITALIC gtk_tree_model_get(tree_model, iter, - 1, &name, - 2, &subcat, + LST_CMBCAT_NAME, &name, + LST_CMBCAT_SUBCAT, &subcat, -1); style = subcat == 0 ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL; @@ -358,7 +417,7 @@ ui_cat_comboboxentry_completion_func (GtkEntryCompletion *completion, model = gtk_entry_completion_get_model (completion); gtk_tree_model_get (model, iter, - 0, &item, + LST_CMBCAT_FULLNAME, &item, -1); if (item != NULL) @@ -406,9 +465,10 @@ GtkCellRenderer *renderer; DB( g_print ("ui_cat_comboboxentry_new()\n") ); - - store = gtk_list_store_new (3, + store = gtk_list_store_new (NUM_LST_CMBCAT, + G_TYPE_POINTER, G_TYPE_STRING, //fullname Car:Fuel + G_TYPE_STRING, //parent name Car G_TYPE_STRING, //name Car or Fuel G_TYPE_BOOLEAN //subcat = 1 ); @@ -416,38 +476,38 @@ GtkCellRenderer *renderer; completion = gtk_entry_completion_new (); gtk_entry_completion_set_model (completion, GTK_TREE_MODEL(store)); - g_object_set(completion, "text-column", 0, NULL); + //g_object_set(completion, "text-column", LST_CMBCAT_FULLNAME, NULL); gtk_entry_completion_set_match_func(completion, ui_cat_comboboxentry_completion_func, NULL, NULL); - gtk_entry_completion_set_minimum_key_length(completion, 2); + //gtk_entry_completion_set_minimum_key_length(completion, 2); - renderer = gtk_cell_renderer_text_new (); + gtk_entry_completion_set_text_column(completion, 1); + + /*renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, "text", 0, NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), renderer, "text", LST_CMBCAT_FULLNAME, NULL); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (completion), renderer, ui_cat_comboboxentry_test, NULL, NULL); + */ // dothe same for combobox comboboxentry = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(store)); - gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(comboboxentry), 0); - + gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(comboboxentry), LST_CMBCAT_FULLNAME); gtk_cell_layout_clear(GTK_CELL_LAYOUT (comboboxentry)); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comboboxentry), renderer, TRUE); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comboboxentry), renderer, "text", 0, NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (comboboxentry), renderer, "text", LST_CMBCAT_FULLNAME, NULL); gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (comboboxentry), renderer, ui_cat_comboboxentry_test, NULL, NULL); - - gtk_entry_set_completion (GTK_ENTRY (gtk_bin_get_child(GTK_BIN (comboboxentry))), completion); g_object_unref(store); @@ -455,7 +515,7 @@ GtkCellRenderer *renderer; if(label) gtk_label_set_mnemonic_widget (GTK_LABEL(label), comboboxentry); - gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_COMBO, -1); + gtk_widget_set_size_request(comboboxentry, HB_MINWIDTH_LIST, -1); return comboboxentry; } @@ -486,26 +546,30 @@ ui_cat_listview_fixed_toggled (GtkCellRendererToggle *cell, gtk_tree_path_free (path); } -/* -** -** The function should return: -** a negative integer if the first value comes before the second, -** 0 if they are equal, -** or a positive integer if the first value comes after the second. -*/ static gint ui_cat_listview_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata) { -gint retval = 0; +gint sortcol = GPOINTER_TO_INT(userdata); Category *entry1, *entry2; - +gint retval = 0; + gtk_tree_model_get(model, a, LST_DEFCAT_DATAS, &entry1, -1); gtk_tree_model_get(model, b, LST_DEFCAT_DATAS, &entry2, -1); - retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME); - if(!retval) - { - retval = hb_string_utf8_compare(entry1->name, entry2->name); + switch (sortcol) + { + case LST_DEFCAT_SORT_NAME: + retval = (entry1->flags & GF_INCOME) - (entry2->flags & GF_INCOME); + if(!retval) + { + retval = hb_string_utf8_compare(entry1->name, entry2->name); + } + break; + case LST_DEFCAT_SORT_USED: + retval = entry1->usage_count - entry2->usage_count; + break; + default: + g_return_val_if_reached(0); } return retval; } @@ -556,6 +620,28 @@ gchar *string; } +static void +ui_cat_listview_count_cell_data_function (GtkTreeViewColumn *col, + GtkCellRenderer *renderer, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ +Category *entry; +gchar buffer[256]; + + gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &entry, -1); + if(entry->usage_count > 0) + { + g_snprintf(buffer, 256-1, "%d", entry->usage_count); + g_object_set(renderer, "text", buffer, NULL); + } + else + g_object_set(renderer, "text", "", NULL); +} + + +/* = = = = = = = = = = = = = = = = */ void @@ -759,46 +845,56 @@ Category *item; } -static void ui_cat_listview_populate_cat_ghfunc(gpointer key, gpointer value, GtkTreeModel *model) +static void ui_cat_listview_populate_cat_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx) { GtkTreeIter toplevel; Category *item = value; +gint item_type; - //DB( g_print("cat listview populate: %d %s\n", (guint32 *)key, item->name) ); + item_type = (item->flags & GF_INCOME) ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE; - if( item->parent == 0 ) + //DB( g_print("cat listview populate: %d %s\n", (guint32 *)key, item->name) ); + if( (ctx->type == CAT_TYPE_ALL) || ctx->type == item_type || item->key == 0 ) { - gtk_tree_store_append (GTK_TREE_STORE(model), &toplevel, NULL); + if( item->parent == 0 ) + { + gtk_tree_store_append (GTK_TREE_STORE(ctx->model), &toplevel, NULL); - gtk_tree_store_set (GTK_TREE_STORE(model), &toplevel, - LST_DEFCAT_TOGGLE , FALSE, - LST_DEFCAT_DATAS, item, - LST_DEFCAT_NAME, item->name, - -1); + gtk_tree_store_set (GTK_TREE_STORE(ctx->model), &toplevel, + LST_DEFCAT_TOGGLE , FALSE, + LST_DEFCAT_DATAS, item, + LST_DEFCAT_NAME, item->name, + -1); + } } + } -static void ui_cat_listview_populate_subcat_ghfunc(gpointer key, gpointer value, GtkTreeModel *model) +static void ui_cat_listview_populate_subcat_ghfunc(gpointer key, gpointer value, struct catPopContext *ctx) { GtkTreeIter toplevel, child; Category *item = value; gboolean ret; +gint item_type; + item_type = (item->flags & GF_INCOME) ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE; - if( item->parent != 0 ) + if( (ctx->type == CAT_TYPE_ALL) || ctx->type == item_type) { - ret = ui_cat_listview_get_top_level(model, item->parent, &toplevel); - if( ret == TRUE ) + if( item->parent != 0 ) { - gtk_tree_store_append (GTK_TREE_STORE(model), &child, &toplevel); - - gtk_tree_store_set (GTK_TREE_STORE(model), &child, - LST_DEFCAT_TOGGLE , FALSE, - LST_DEFCAT_DATAS, item, - LST_DEFCAT_NAME, item->name, - -1); + ret = ui_cat_listview_get_top_level(ctx->model, item->parent, &toplevel); + if( ret == TRUE ) + { + gtk_tree_store_append (GTK_TREE_STORE(ctx->model), &child, &toplevel); + gtk_tree_store_set (GTK_TREE_STORE(ctx->model), &child, + LST_DEFCAT_TOGGLE , FALSE, + LST_DEFCAT_DATAS, item, + LST_DEFCAT_NAME, item->name, + -1); + } } } @@ -820,11 +916,10 @@ GtkSortType order; } - - -void ui_cat_listview_populate(GtkWidget *view) +void ui_cat_listview_populate(GtkWidget *view, gint type) { GtkTreeModel *model; +struct catPopContext ctx = { 0 }; DB( g_print("ui_cat_listview_populate() \n") ); @@ -836,10 +931,14 @@ GtkTreeModel *model; g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */ gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL); /* Detach model from view */ + /* clear and populate */ + ctx.model = model; + ctx.type = type; + /* we have to do this in 2 times to ensure toplevel (cat) will be added before childs */ /* populate cat 1st */ - g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_cat_ghfunc, model); - g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_subcat_ghfunc, model); + g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_cat_ghfunc, &ctx); + g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)ui_cat_listview_populate_subcat_ghfunc, &ctx); gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); /* Re-attach model to view */ @@ -850,8 +949,47 @@ GtkTreeModel *model; } +static gboolean ui_cat_listview_search_equal_func (GtkTreeModel *model, + gint column, + const gchar *key, + GtkTreeIter *iter, + gpointer search_data) +{ + gboolean retval = TRUE; + gchar *normalized_string; + gchar *normalized_key; + gchar *case_normalized_string = NULL; + gchar *case_normalized_key = NULL; + Category *item; + + //gtk_tree_model_get_value (model, iter, column, &value); + gtk_tree_model_get(model, iter, LST_DEFCAT_DATAS, &item, -1); + + if(item != NULL) + { + normalized_string = g_utf8_normalize (item->name, -1, G_NORMALIZE_ALL); + normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL); + + if (normalized_string && normalized_key) + { + case_normalized_string = g_utf8_casefold (normalized_string, -1); + case_normalized_key = g_utf8_casefold (normalized_key, -1); + + if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0) + retval = FALSE; + } + + g_free (normalized_key); + g_free (normalized_string); + g_free (case_normalized_key); + g_free (case_normalized_string); + } + return retval; +} + + GtkWidget * -ui_cat_listview_new(gboolean withtoggle) +ui_cat_listview_new(gboolean withtoggle, gboolean withcount) { GtkTreeStore *store; GtkWidget *treeview; @@ -860,7 +998,6 @@ GtkTreeViewColumn *column; DB( g_print("ui_cat_listview_new() \n") ); - /* create tree store */ store = gtk_tree_store_new( NUM_LST_DEFCAT, G_TYPE_BOOLEAN, @@ -868,16 +1005,18 @@ GtkTreeViewColumn *column; G_TYPE_STRING ); - //treeview treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); g_object_unref(store); + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (treeview), PREFS->grid_lines); + // column 1: toggle if( withtoggle == TRUE ) { renderer = gtk_cell_renderer_toggle_new (); - column = gtk_tree_view_column_new_with_attributes ("Show", renderer, "active", LST_DEFCAT_TOGGLE, NULL); + column = gtk_tree_view_column_new_with_attributes (_("Visible"), + renderer, "active", LST_DEFCAT_TOGGLE, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); g_signal_connect (G_OBJECT(renderer), "toggled", @@ -885,35 +1024,52 @@ GtkTreeViewColumn *column; } - // column 1 - column = gtk_tree_view_column_new(); + // column 2: name renderer = gtk_cell_renderer_text_new (); + g_object_set(renderer, + "ellipsize", PANGO_ELLIPSIZE_END, + "ellipsize-set", TRUE, + NULL); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Name")); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, ui_cat_listview_text_cell_data_function, GINT_TO_POINTER(LST_DEFCAT_NAME), NULL); - //gtk_tree_view_column_set_sort_column_id (column, LST_DEFACC_NAME); + gtk_tree_view_column_set_alignment (column, 0.5); + gtk_tree_view_column_set_min_width(column, HB_MINWIDTH_LIST); + gtk_tree_view_column_set_sort_column_id (column, LST_DEFCAT_SORT_NAME); + gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); + if( withcount == TRUE ) + { + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Usage")); + renderer = gtk_cell_renderer_text_new (); + g_object_set(renderer, "xalign", 0.5, NULL); + gtk_tree_view_column_pack_start(column, renderer, TRUE); + gtk_tree_view_column_set_cell_data_func(column, renderer, ui_cat_listview_count_cell_data_function, GINT_TO_POINTER(LST_DEFCAT_DATAS), NULL); + gtk_tree_view_column_set_alignment (column, 0.5); + gtk_tree_view_column_set_sort_column_id (column, LST_DEFCAT_SORT_USED); + gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); + } - // parameters - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), FALSE); + + gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), ui_cat_listview_search_equal_func, NULL, NULL); - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, ui_cat_listview_compare_func, NULL, NULL); - gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFCAT_DATAS, GTK_SORT_ASCENDING); + // treeview attribute + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), withcount); - //gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE); - //gtk_tree_view_set_expander_column(GTK_TREE_VIEW(treeview), column); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_NAME, ui_cat_listview_compare_func, GINT_TO_POINTER(LST_DEFCAT_SORT_NAME), NULL); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_USED, ui_cat_listview_compare_func, GINT_TO_POINTER(LST_DEFCAT_SORT_USED), NULL); + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), LST_DEFCAT_SORT_NAME, GTK_SORT_ASCENDING); return treeview; } -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -//todo amiga/linux -//add exist function + check before add -//save -//load - +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /** * ui_cat_manage_filter_text_handler @@ -928,7 +1084,7 @@ static void ui_cat_manage_filter_text_handler (GtkEntry *entry, gpointer data) { GtkEditable *editable = GTK_EDITABLE(entry); -gint i, count=0, pos; +gint i, count=0; gchar *result = g_new0 (gchar, length+1); for (i=0; i < length; i++) @@ -943,7 +1099,7 @@ gchar *result = g_new0 (gchar, length+1); g_signal_handlers_block_by_func (G_OBJECT (editable), G_CALLBACK (ui_cat_manage_filter_text_handler), data); - gtk_editable_insert_text (editable, result, count, &pos); + gtk_editable_insert_text (editable, result, count, position); g_signal_handlers_unblock_by_func (G_OBJECT (editable), G_CALLBACK (ui_cat_manage_filter_text_handler), data); @@ -954,6 +1110,36 @@ gchar *result = g_new0 (gchar, length+1); } +static void +ui_cat_manage_dialog_delete_unused( GtkWidget *widget, gpointer user_data) +{ +struct ui_cat_manage_dialog_data *data = user_data; +gboolean result; + + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); + + DB( g_print("(ui_cat_manage_dialog) delete unused - data %p\n", data) ); + + result = ui_dialog_msg_confirm_alert( + GTK_WINDOW(data->window), + _("Delete unused categories"), + _("Are you sure you want to permanently\ndelete unused categories?"), + _("_Delete") + ); + + if( result == GTK_RESPONSE_OK ) + { + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat)); + gtk_tree_store_clear (GTK_TREE_STORE(model)); + + category_delete_unused(); + + ui_cat_manage_populate_listview (data); + } +} + /** @@ -963,11 +1149,11 @@ gchar *result = g_new0 (gchar, length+1); static void ui_cat_manage_dialog_load_csv( GtkWidget *widget, gpointer user_data) { -struct ui_cat_manage_dialog_data *data; +struct ui_cat_manage_dialog_data *data = user_data; gchar *filename = NULL; gchar *error; - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); DB( g_print("(ui_cat_manage_dialog) load csv - data %p\n", data) ); @@ -979,12 +1165,12 @@ gchar *error; { ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, _("File format error"), - _("The csv file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.") + _("The CSV file must contains the exact numbers of column,\nseparated by a semi-colon, please see the help for more details.") ); } g_free( filename ); - ui_cat_listview_populate(data->LV_cat); + ui_cat_manage_populate_listview(data); } } @@ -996,13 +1182,13 @@ gchar *error; static void ui_cat_manage_dialog_save_csv( GtkWidget *widget, gpointer user_data) { -struct ui_cat_manage_dialog_data *data; +struct ui_cat_manage_dialog_data *data = user_data; gchar *filename = NULL; gchar *error; DB( g_print("(defcategory) save csv\n") ); - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); if( ui_file_chooser_csv(GTK_WINDOW(data->window), GTK_FILE_CHOOSER_ACTION_SAVE, &filename, NULL) == TRUE ) { @@ -1029,7 +1215,7 @@ const gchar *name; GtkTreeIter parent_iter; GtkWidget *tmpwidget; Category *item, *paritem; -gboolean type; +gint type; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); DB( g_print("\n(defcategory) add (data=%p) is subcat=%d\n", data, subcat) ); @@ -1051,8 +1237,8 @@ gboolean type; /* if cat use new id */ if(subcat == FALSE) { - type = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_type)); - if(type == TRUE) + type = radio_get_active(GTK_CONTAINER(data->RA_type)); + if(type == 1) item->flags |= GF_INCOME; if( da_cat_append(item) ) @@ -1086,7 +1272,7 @@ gboolean type; } -static void ui_cat_manage_dialog_modify_entry_cb(GtkEditable *editable, gpointer user_data) +static void ui_cat_manage_dialog_edit_entry_cb(GtkEditable *editable, gpointer user_data) { GtkDialog *window = user_data; const gchar *buffer; @@ -1096,20 +1282,16 @@ const gchar *buffer; } -/* -** -*/ -static void -ui_cat_manage_dialog_modify(GtkWidget *widget, gpointer user_data) +static void ui_cat_manage_dialog_edit(GtkWidget *widget, gpointer user_data) { struct ui_cat_manage_dialog_data *data; -GtkWidget *window, *content, *mainvbox, *w_name, *w_type = NULL; +GtkWidget *dialog, *content, *mainvbox, *w_name, *w_type = NULL; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - DB( g_print("\n(defcategory) modify\n") ); + DB( g_print("\n(defcategory) edit\n") ); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)); //if true there is a selected node @@ -1119,19 +1301,19 @@ GtkTreeIter iter; gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1); - window = gtk_dialog_new_with_buttons (_("Modify..."), + dialog = gtk_dialog_new_with_buttons (_("Edit..."), GTK_WINDOW (data->window), 0, - GTK_STOCK_CANCEL, + _("_Cancel"), GTK_RESPONSE_REJECT, - GTK_STOCK_OK, + _("_OK"), GTK_RESPONSE_ACCEPT, NULL); - content = gtk_dialog_get_content_area(GTK_DIALOG (window)); - mainvbox = gtk_vbox_new (FALSE, 0); + content = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (mainvbox), HB_MAINBOX_SPACING); + gtk_container_set_border_width (GTK_CONTAINER (mainvbox), SPACING_MEDIUM); w_name = gtk_entry_new(); gtk_box_pack_start (GTK_BOX (mainvbox), w_name, TRUE, TRUE, 0); @@ -1148,14 +1330,15 @@ GtkTreeIter iter; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_type), item->flags & GF_INCOME ? TRUE : FALSE); } + g_signal_connect (G_OBJECT (w_name), "changed", G_CALLBACK (ui_cat_manage_dialog_edit_entry_cb), dialog); + + gtk_widget_show_all(mainvbox); - g_signal_connect (G_OBJECT (w_name), "changed", G_CALLBACK (ui_cat_manage_dialog_modify_entry_cb), window); - - gtk_dialog_set_default_response(GTK_DIALOG( window ), GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response(GTK_DIALOG( dialog ), GTK_RESPONSE_ACCEPT); //wait for the user - gint result = gtk_dialog_run (GTK_DIALOG (window)); + gint result = gtk_dialog_run (GTK_DIALOG (dialog)); if(result == GTK_RESPONSE_ACCEPT) { @@ -1168,6 +1351,8 @@ GtkTreeIter iter; { if( category_rename(item, name) ) { + //to redraw the active entry + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_cat)); data->change++; } else @@ -1189,7 +1374,7 @@ GtkTreeIter iter; } - ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR, + ui_dialog_msg_infoerror(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR, _("Error"), _("Cannot rename this Category,\n" "from '%s' to '%s',\n" @@ -1217,182 +1402,219 @@ GtkTreeIter iter; } // cleanup and destroy - gtk_widget_destroy (window); + gtk_widget_destroy (dialog); } } -static void ui_cat_manage_dialog_move_entry_cb(GtkComboBox *widget, gpointer user_data) +static void ui_cat_manage_dialog_merge_entry_cb(GtkComboBox *widget, gpointer user_data) { GtkDialog *window = user_data; gchar *buffer; buffer = (gchar *)gtk_entry_get_text(GTK_ENTRY (gtk_bin_get_child(GTK_BIN (widget)))); - gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, strlen(buffer) > 0 ? TRUE : FALSE); + gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_OK, strlen(buffer) > 0 ? TRUE : FALSE); } -/* -** -*/ -static void ui_cat_manage_dialog_move(GtkWidget *widget, gpointer user_data) +static void ui_cat_manage_dialog_merge(GtkWidget *widget, gpointer user_data) { struct ui_cat_manage_dialog_data *data; -GtkWidget *window, *content, *mainvbox, *getwidget; +GtkWidget *dialog, *content, *mainvbox; +GtkWidget *getwidget, *togglebutton; GtkTreeSelection *selection; -GtkTreeModel *model; -GtkTreeIter iter; +GtkTreeModel *model; +GtkTreeIter iter; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - DB( g_print("(defcategory) move\n") ); + DB( g_print("(defcategory) merge\n") ); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_cat)); //if true there is a selected node if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - Category *item; + Category *srccat; + gchar *title; + gchar *secondtext; - gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &item, -1); + gtk_tree_model_get(model, &iter, LST_DEFCAT_DATAS, &srccat, -1); - window = gtk_dialog_new_with_buttons (_("Move to..."), - GTK_WINDOW (data->window), - 0, - GTK_STOCK_CANCEL, - GTK_RESPONSE_REJECT, - GTK_STOCK_OK, - GTK_RESPONSE_ACCEPT, - NULL); + title = g_strdup_printf ( + _("Merge category '%s'"), srccat->name); + + dialog = gtk_message_dialog_new (GTK_WINDOW (data->window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + title, + NULL + ); + + gtk_dialog_add_buttons (GTK_DIALOG(dialog), + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("Merge"), GTK_RESPONSE_OK, + NULL); + + gtk_dialog_set_default_response(GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL); - content = gtk_dialog_get_content_area(GTK_DIALOG (window)); - mainvbox = gtk_vbox_new (FALSE, 0); + content = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG (dialog)); + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL); gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER (mainvbox), HB_BOX_SPACING); + + secondtext = _("Transactions assigned to this category,\n" + "will be moved to the category selected below."); + + g_object_set(GTK_MESSAGE_DIALOG (dialog), "secondary-text", secondtext, NULL); + g_free(title); getwidget = ui_cat_comboboxentry_new(NULL); - gtk_box_pack_start (GTK_BOX (mainvbox), getwidget, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (mainvbox), getwidget, FALSE, FALSE, 0); - gtk_dialog_set_response_sensitive(GTK_DIALOG(window), GTK_RESPONSE_ACCEPT, FALSE); - - gtk_widget_show_all(mainvbox); + secondtext = g_strdup_printf ( + _("_Delete the category '%s'"), srccat->name); + togglebutton = gtk_check_button_new_with_mnemonic(secondtext); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), TRUE); + g_free(secondtext); + gtk_box_pack_start (GTK_BOX (mainvbox), togglebutton, FALSE, FALSE, 0); - g_signal_connect (G_OBJECT (getwidget), "changed", G_CALLBACK (ui_cat_manage_dialog_move_entry_cb), window); - - ui_cat_comboboxentry_populate_except(GTK_COMBO_BOX(getwidget), GLOBALS->h_cat, item->key); + //setup + //gtk_combo_box_set_active(GTK_COMBO_BOX(getwidget), oldpos); + g_signal_connect (G_OBJECT (getwidget), "changed", G_CALLBACK (ui_cat_manage_dialog_merge_entry_cb), dialog); + gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE); + + ui_cat_comboboxentry_populate_except(GTK_COMBO_BOX(getwidget), GLOBALS->h_cat, srccat->key); gtk_widget_grab_focus (getwidget); + gtk_widget_show_all(mainvbox); + //wait for the user - gint result = gtk_dialog_run (GTK_DIALOG (window)); + gint result = gtk_dialog_run (GTK_DIALOG (dialog)); - if(result == GTK_RESPONSE_ACCEPT) + if(result == GTK_RESPONSE_OK) { - gboolean result; - gchar *npn; - - npn = ui_cat_comboboxentry_get_name(GTK_COMBO_BOX(getwidget)), - - result = ui_dialog_msg_question( - GTK_WINDOW(window), - _("Move this category to another one ?"), - _("This will replace '%s' by '%s',\n" - "and then remove '%s'"), - item->name, - npn, - item->name, - NULL - ); - - if( result == GTK_RESPONSE_YES ) - { - Category *newcat, *parent; - guint dstkey; + GtkTreeModel *model; + Category *newcat, *parent; + guint dstcatkey; - dstkey = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(getwidget)); - newcat = da_cat_get (dstkey); - DB( g_print(" moving to %d\n", dstkey) ); + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat)); + gtk_tree_store_clear (GTK_TREE_STORE(model)); - category_move(item->key, dstkey); + dstcatkey = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(getwidget)); - //keep the income with us - parent = da_cat_get(item->parent); - if(parent != NULL && (parent->flags & GF_INCOME)) - newcat->flags |= GF_INCOME; + DB( g_print(" -> move cat to %d\n", dstcatkey) ); - // remove the old category - da_cat_remove(item->key); - ui_cat_listview_remove_selected(GTK_TREE_VIEW(data->LV_cat)); + category_move(srccat->key, dstcatkey); + + newcat = da_cat_get (dstcatkey); + + //keep the income type with us + parent = da_cat_get(srccat->parent); + if(parent != NULL && (parent->flags & GF_INCOME)) + newcat->flags |= GF_INCOME; - //add the new category into listview - if(newcat) - ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), newcat, NULL); + //add the new category into listview + if(newcat) + ui_cat_listview_add(GTK_TREE_VIEW(data->LV_cat), newcat, NULL); - data->change++; + // delete the old category + if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)) ) + { + DB( g_print(" -> delete %d '%s'\n", srccat->key, srccat->name ) ); + + da_cat_remove(srccat->key); + ui_cat_listview_remove_selected(GTK_TREE_VIEW(data->LV_cat)); } - } + + + data->change++; + + ui_cat_manage_populate_listview(data); + + } // cleanup and destroy - gtk_widget_destroy (window); + gtk_widget_destroy (dialog); } } /* -** remove the selected payee to our treeview and temp GList +** delete the selected payee to our treeview and temp GList */ -static void ui_cat_manage_dialog_remove(GtkWidget *widget, gpointer user_data) +static void ui_cat_manage_dialog_delete(GtkWidget *widget, gpointer user_data) { struct ui_cat_manage_dialog_data *data; Category *item; gint result; -gboolean do_remove; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - DB( g_print("\n(defcategory) remove (data=%x)\n", (guint)data) ); + DB( g_print("\n(defcategory) delete (data=%x)\n", (guint)data) ); - do_remove = TRUE; item = ui_cat_listview_get_selected(GTK_TREE_VIEW(data->LV_cat)); if( item != NULL ) { - if( category_is_used(item->key) == TRUE ) + gchar *title = NULL; + gchar *secondtext = NULL; + + title = g_strdup_printf ( + _("Are you sure you want to permanently delete '%s'?"), item->name); + + if( item->usage_count > 0 ) { - result = ui_dialog_msg_question( - GTK_WINDOW(data->window), - _("Remove a category ?"), - _("If you remove '%s', archive and transaction referencing this category\n" - "will set place to 'no category'"), - item->name, - NULL - ); - - if( result == GTK_RESPONSE_YES ) - { - category_move(item->key, 0); - } - else if( result == GTK_RESPONSE_NO ) - { - do_remove = FALSE; - } + secondtext = _("This category is used.\n" + "Any transaction using that category will be set to (no category)"); } - if( do_remove ) + result = ui_dialog_msg_confirm_alert( + GTK_WINDOW(data->window), + title, + secondtext, + _("_Delete") + ); + + g_free(title); + + if( result == GTK_RESPONSE_OK ) { + category_move(item->key, 0); ui_cat_listview_remove(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_cat)), item->key); da_cat_remove(item->key); data->change++; } + } +} + + + +static void ui_cat_manage_dialog_expand_all(GtkWidget *widget, gpointer user_data) +{ +struct ui_cat_manage_dialog_data *data; + + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + DB( g_print("\n(defcategory) expand all (data=%x)\n", (guint)data) ); + + gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_cat)); } -/** - * ui_cat_manage_dialog_update: - * - */ -static void -ui_cat_manage_dialog_update(GtkWidget *treeview, gpointer user_data) +static void ui_cat_manage_dialog_collapse_all(GtkWidget *widget, gpointer user_data) +{ +struct ui_cat_manage_dialog_data *data; + + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + DB( g_print("\n(defcategory) collapse all (data=%x)\n", (guint)data) ); + + gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_cat)); + +} + + +static void ui_cat_manage_dialog_update(GtkWidget *treeview, gpointer user_data) { struct ui_cat_manage_dialog_data *data; //gint count; @@ -1469,8 +1691,8 @@ gboolean haschild = FALSE; LST_DEFCAT_DATAS, &tmpitem, -1); - category = tmpitem->name; - + if(tmpitem->key > 0) + category = tmpitem->name; DB( g_print(" => parent is %s\n", category) ); @@ -1484,14 +1706,13 @@ gboolean haschild = FALSE; sensitive = (selected == TRUE) ? TRUE : FALSE; gtk_widget_set_sensitive(data->ST_name2, sensitive); - gtk_widget_set_sensitive(data->BT_add2, sensitive); - gtk_widget_set_sensitive(data->BT_mov, sensitive); - gtk_widget_set_sensitive(data->BT_mod, sensitive); + gtk_widget_set_sensitive(data->BT_edit, sensitive); + gtk_widget_set_sensitive(data->BT_merge, sensitive); //avoid removing top categories sensitive = (haschild == TRUE) ? FALSE : sensitive; - gtk_widget_set_sensitive(data->BT_rem, sensitive); + gtk_widget_set_sensitive(data->BT_delete, sensitive); } @@ -1518,16 +1739,11 @@ GtkTreeIter iter; gtk_tree_model_get_iter_first(model, &iter); if(gtk_tree_selection_iter_is_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), &iter) == FALSE) { - ui_cat_manage_dialog_modify(GTK_WIDGET(treeview), NULL); + ui_cat_manage_dialog_edit(GTK_WIDGET(treeview), NULL); } } - - -/* -** -*/ static gboolean ui_cat_manage_dialog_cleanup(struct ui_cat_manage_dialog_data *data, gint result) { gboolean doupdate = FALSE; @@ -1551,11 +1767,23 @@ gboolean doupdate = FALSE; return doupdate; } + +static void ui_cat_manage_populate_listview(struct ui_cat_manage_dialog_data *data) +{ +gint type; + + type = radio_get_active(GTK_CONTAINER(data->RA_type)) == 1 ? CAT_TYPE_INCOME : CAT_TYPE_EXPENSE; + ui_cat_listview_populate(data->LV_cat, type); + gtk_tree_view_expand_all (GTK_TREE_VIEW(data->LV_cat)); +} + + /* ** */ static void ui_cat_manage_dialog_setup(struct ui_cat_manage_dialog_data *data) { + DB( g_print("(defcategory) setup\n") ); //init GList @@ -1565,32 +1793,43 @@ static void ui_cat_manage_dialog_setup(struct ui_cat_manage_dialog_data *data) //debug //da_cat_debug_list(); + ui_cat_manage_populate_listview(data); + +} - ui_cat_listview_populate(data->LV_cat); - gtk_tree_view_expand_all (GTK_TREE_VIEW(data->LV_cat)); +static void ui_cat_manage_type_changed_cb (GtkToggleButton *button, gpointer user_data) +{ + ui_cat_manage_populate_listview(user_data); + //g_print(" toggle type=%d\n", gtk_toggle_button_get_active(button)); } -// the window creation + GtkWidget *ui_cat_manage_dialog (void) { struct ui_cat_manage_dialog_data data; -GtkWidget *window, *content, *mainvbox, *table, *hbox, *label, *scrollwin, *vbox, *separator, *treeview; -gint row; +GtkWidget *window, *content, *mainvbox, *bbox, *table, *hbox, *vbox, *label, *scrollwin, *treeview; +GtkWidget *menu, *menuitem, *widget, *image, *tbar; +GtkToolItem *toolitem; +gint w, h, row; window = gtk_dialog_new_with_buttons (_("Manage Categories"), GTK_WINDOW(GLOBALS->mainwindow), 0, - GTK_STOCK_CLOSE, + _("_Close"), GTK_RESPONSE_ACCEPT, NULL); data.window = window; + data.change = 0; + + gtk_window_set_icon_name(GTK_WINDOW (window), ICONNAME_HB_CATEGORY); - //set the window icon - //homebank_window_set_icon_from_file(GTK_WINDOW (window), "category.svg"); - gtk_window_set_icon_name(GTK_WINDOW (window), HB_STOCK_CATEGORY); + //set a nice dialog size + gtk_window_get_size(GTK_WINDOW(GLOBALS->mainwindow), &w, &h); + gtk_window_set_default_size (GTK_WINDOW(window), -1, h/PHI); + //store our window private data g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data); DB( g_print("(defcategory) window=%x, inst_data=%x\n", (guint)window, (guint)&data) ); @@ -1600,115 +1839,191 @@ gint row; //window contents content = gtk_dialog_get_content_area(GTK_DIALOG (window)); - mainvbox = gtk_vbox_new (FALSE, 0); + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL); gtk_box_pack_start (GTK_BOX (content), mainvbox, TRUE, TRUE, 0); - gtk_container_set_border_width (GTK_CONTAINER(mainvbox), HB_MAINBOX_SPACING); + gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); //our table - table = gtk_table_new (3, 2, FALSE); - gtk_table_set_row_spacings (GTK_TABLE (table), HB_TABROW_SPACING); - gtk_table_set_col_spacings (GTK_TABLE (table), HB_TABCOL_SPACING); + table = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_SMALL); + gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_MEDIUM); gtk_box_pack_start (GTK_BOX (mainvbox), table, TRUE, TRUE, 0); - // category item + add button row = 0; - hbox = gtk_hbox_new (FALSE, HB_BOX_SPACING); - gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (0), 0, 0); - data.ST_name1 = gtk_entry_new (); - gtk_box_pack_start (GTK_BOX (hbox), data.ST_name1, TRUE, TRUE, 0); - data.CM_type = gtk_check_button_new_with_mnemonic(_("I_ncome")); - gtk_box_pack_start (GTK_BOX (hbox), data.CM_type, FALSE, FALSE, 0); + bbox = make_radio(CYA_CAT_TYPE, TRUE, GTK_ORIENTATION_HORIZONTAL); + data.RA_type = bbox; + gtk_widget_set_halign (bbox, GTK_ALIGN_CENTER); + gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1); + + widget = radio_get_nth_widget(GTK_CONTAINER(bbox), 1); + if(widget) + g_signal_connect (widget, "toggled", G_CALLBACK (ui_cat_manage_type_changed_cb), &data); + + menu = gtk_menu_new (); + gtk_widget_set_halign (menu, GTK_ALIGN_END); + + menuitem = gtk_menu_item_new_with_mnemonic (_("_Import CSV")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_load_csv), &data); + + menuitem = gtk_menu_item_new_with_mnemonic (_("E_xport CSV")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_save_csv), &data); + + menuitem = gtk_separator_menu_item_new(); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + + menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete unused")); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); + g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (ui_cat_manage_dialog_delete_unused), &data); - data.BT_add1 = gtk_button_new_from_stock(GTK_STOCK_ADD); - gtk_table_attach (GTK_TABLE (table), data.BT_add1, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); + gtk_widget_show_all (menu); + + widget = gtk_menu_button_new(); + image = gtk_image_new_from_icon_name (ICONNAME_HB_BUTTON_MENU, GTK_ICON_SIZE_MENU); + + //gchar *thename; + //gtk_image_get_icon_name(image, &thename, NULL); + //g_print("the name is %s\n", thename); + + g_object_set (widget, "image", image, "popup", GTK_MENU(menu), NULL); + gtk_widget_set_halign (widget, GTK_ALIGN_END); + gtk_grid_attach (GTK_GRID (table), widget, 1, row, 1, 1); + + row++; + widget = gtk_entry_new (); + data.ST_name1 = widget; + gtk_entry_set_placeholder_text(GTK_ENTRY(data.ST_name1), _("new category") ); + gtk_widget_set_hexpand (widget, TRUE); + gtk_grid_attach (GTK_GRID (table), widget, 0, row, 2, 1); // subcategory + add button row++; - hbox = gtk_hbox_new (FALSE, HB_BOX_SPACING); - gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (0), 0, 0); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL); + gtk_grid_attach (GTK_GRID (table), hbox, 0, row, 2, 1); data.LA_category = gtk_label_new(NULL); gtk_box_pack_start (GTK_BOX (hbox), data.LA_category, FALSE, FALSE, 0); label = gtk_label_new(":"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); data.ST_name2 = gtk_entry_new (); + gtk_entry_set_placeholder_text(GTK_ENTRY(data.ST_name2), _("new subcategory") ); gtk_box_pack_start (GTK_BOX (hbox), data.ST_name2, TRUE, TRUE, 0); - data.BT_add2 = gtk_button_new_from_stock(GTK_STOCK_ADD); - gtk_table_attach (GTK_TABLE (table), data.BT_add2, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - - - //list row++; + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_grid_attach (GTK_GRID (table), vbox, 0, row, 2, 1); + scrollwin = gtk_scrolled_window_new(NULL,NULL); - gtk_table_attach (GTK_TABLE (table), scrollwin, 0, 1, row, row+1, (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN); - //gtk_container_set_border_width (GTK_CONTAINER(scrollwin), 5); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - treeview = (GtkWidget *)ui_cat_listview_new(FALSE); - gtk_widget_set_size_request(treeview, HB_MINWIDTH_LIST, -1); - data.LV_cat = treeview; + gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrollwin), HB_MINHEIGHT_LIST); + treeview = ui_cat_listview_new(FALSE, TRUE); + data.LV_cat = treeview; gtk_container_add(GTK_CONTAINER(scrollwin), treeview); - - vbox = gtk_vbox_new (FALSE, HB_BOX_SPACING); - gtk_table_attach (GTK_TABLE (table), vbox, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); - + gtk_widget_set_hexpand (scrollwin, TRUE); + gtk_widget_set_vexpand (scrollwin, TRUE); + gtk_box_pack_start (GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0); + + //list toolbar + tbar = gtk_toolbar_new(); + gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); + gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); + gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0); + + /*widget = gtk_tool_item_new (); + label = gtk_label_new("test"); + gtk_container_add(GTK_CONTAINER(widget), label); + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(widget), -1);*/ + + //hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); /* - widget = gtk_check_button_new_with_mnemonic("Income type"); - data.CM_type = widget; - gtk_box_pack_start (GTK_BOX (vbox), data.CM_type, FALSE, FALSE, 0); + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + toolitem = gtk_tool_item_new(); + gtk_container_add (GTK_CONTAINER(toolitem), hbox); + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); + + //widget = make_image_button("text-editor-symbolic", _("Edit")); + widget = gtk_button_new_with_mnemonic(_("_Edit")); + data.BT_edit = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + + //widget = make_image_button("merge-symbolic", _("Merge")); + widget = gtk_button_new_with_mnemonic(_("_Merge")); + data.BT_merge = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + + //widget = make_image_button(ICONNAME_SYM_EDIT_DELETE, _("Delete")); + widget = gtk_button_new_with_mnemonic(_("_Delete")); + data.BT_delete = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); */ + + toolitem = gtk_separator_tool_item_new (); + gtk_tool_item_set_expand (toolitem, TRUE); + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + toolitem = gtk_tool_item_new(); + gtk_container_add (GTK_CONTAINER(toolitem), hbox); + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); + + widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all")); + data.BT_expand = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); - data.BT_rem = gtk_button_new_from_stock(GTK_STOCK_REMOVE); - gtk_box_pack_start (GTK_BOX (vbox), data.BT_rem, FALSE, FALSE, 0); + widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all")); + data.BT_collapse = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); - data.BT_mod = gtk_button_new_from_stock(GTK_STOCK_EDIT); - //data.BT_mod = gtk_button_new_with_mnemonic(_("_Modify")); - gtk_box_pack_start (GTK_BOX (vbox), data.BT_mod, FALSE, FALSE, 0); - data.BT_mov = gtk_button_new_with_mnemonic(_("_Move")); - gtk_box_pack_start (GTK_BOX (vbox), data.BT_mov, FALSE, FALSE, 0); + row++; + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START); + gtk_box_set_spacing (GTK_BOX (bbox), SPACING_SMALL); + gtk_grid_attach (GTK_GRID (table), bbox, 0, row, 2, 1); + + data.BT_edit = gtk_button_new_with_mnemonic(_("_Edit")); + gtk_container_add (GTK_CONTAINER (bbox), data.BT_edit); - separator = gtk_hseparator_new(); - gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, HB_BOX_SPACING); + data.BT_merge = gtk_button_new_with_mnemonic(_("_Merge")); + gtk_container_add (GTK_CONTAINER (bbox), data.BT_merge); + data.BT_delete = gtk_button_new_with_mnemonic(_("_Delete")); + gtk_container_add (GTK_CONTAINER (bbox), data.BT_delete); - data.BT_import = gtk_button_new_with_mnemonic(_("_Import")); - //data.BT_import = gtk_button_new_from_stock(GTK_STOCK_OPEN); - gtk_box_pack_start (GTK_BOX (vbox), data.BT_import, FALSE, FALSE, 0); - data.BT_export = gtk_button_new_with_mnemonic(_("E_xport")); - //data.BT_export = gtk_button_new_from_stock(GTK_STOCK_SAVE); - gtk_box_pack_start (GTK_BOX (vbox), data.BT_export, FALSE, FALSE, 0); + /*row++; + widget = gtk_check_button_new_with_mnemonic(_("I_ncome")); + data.CM_type = widget; + gtk_grid_attach (GTK_GRID (table), widget, 0, row, 3, 1);*/ + //connect all our signals g_signal_connect (G_OBJECT (data.ST_name1), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(FALSE)); g_signal_connect (G_OBJECT (data.ST_name2), "activate", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(TRUE)); - g_signal_connect(G_OBJECT(data.ST_name1), "insert_text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL); - g_signal_connect(G_OBJECT(data.ST_name2), "insert_text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL); + g_signal_connect(G_OBJECT(data.ST_name1), "insert-text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL); + g_signal_connect(G_OBJECT(data.ST_name2), "insert-text", G_CALLBACK(ui_cat_manage_filter_text_handler), NULL); g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_cat)), "changed", G_CALLBACK (ui_cat_manage_dialog_selection), NULL); g_signal_connect (GTK_TREE_VIEW(data.LV_cat), "row-activated", G_CALLBACK (ui_cat_manage_dialog_onRowActivated), NULL); - g_signal_connect (G_OBJECT (data.BT_add1), "clicked", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(FALSE)); - g_signal_connect (G_OBJECT (data.BT_add2), "clicked", G_CALLBACK (ui_cat_manage_dialog_add), GINT_TO_POINTER(TRUE)); - g_signal_connect (G_OBJECT (data.BT_mod), "clicked", G_CALLBACK (ui_cat_manage_dialog_modify), NULL); - g_signal_connect (G_OBJECT (data.BT_mov), "clicked", G_CALLBACK (ui_cat_manage_dialog_move), NULL); - g_signal_connect (G_OBJECT (data.BT_rem), "clicked", G_CALLBACK (ui_cat_manage_dialog_remove), NULL); + g_signal_connect (G_OBJECT (data.BT_edit), "clicked", G_CALLBACK (ui_cat_manage_dialog_edit), NULL); + g_signal_connect (G_OBJECT (data.BT_merge), "clicked", G_CALLBACK (ui_cat_manage_dialog_merge), NULL); + g_signal_connect (G_OBJECT (data.BT_delete), "clicked", G_CALLBACK (ui_cat_manage_dialog_delete), NULL); - g_signal_connect (G_OBJECT (data.BT_import), "clicked", G_CALLBACK (ui_cat_manage_dialog_load_csv), NULL); - g_signal_connect (G_OBJECT (data.BT_export), "clicked", G_CALLBACK (ui_cat_manage_dialog_save_csv), NULL); + g_signal_connect (G_OBJECT (data.BT_expand), "clicked", G_CALLBACK (ui_cat_manage_dialog_expand_all), NULL); + g_signal_connect (G_OBJECT (data.BT_collapse), "clicked", G_CALLBACK (ui_cat_manage_dialog_collapse_all), NULL); //setup, init and show window + category_fill_usage(); ui_cat_manage_dialog_setup(&data); ui_cat_manage_dialog_update(data.LV_cat, NULL); - gtk_window_resize(GTK_WINDOW(window), 200, 320); - - gtk_widget_show_all (window); //wait for the user @@ -1728,7 +2043,9 @@ gint row; ui_cat_manage_dialog_cleanup(&data, result); gtk_widget_destroy (window); - return NULL; + GLOBALS->changes_count += data.change; + + return NULL; }