/* HomeBank -- Free, easy, personal accounting for everyone. * Copyright (C) 1995-2019 Maxime DOYEN * * This file is part of HomeBank. * * HomeBank is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * HomeBank is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty ofdeftransaction_amountchanged * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "homebank.h" #include "ui-split.h" #include "ui-transaction.h" #include "ui-archive.h" #include "gtk-dateentry.h" #include "ui-payee.h" #include "ui-category.h" #include "ui-account.h" #include "hb-split.h" /****************************************************************************/ /* Debug macros */ /****************************************************************************/ #define MYDEBUG 0 #if MYDEBUG #define DB(x) (x); #else #define DB(x); #endif /* our global datas */ extern struct HomeBank *GLOBALS; extern struct Preferences *PREFS; #define GTK_RESPONSE_SPLIT_REM 10888 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ static void list_split_number_cell_data_function (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { GtkTreePath *path; gint *indices; gchar num[16]; path = gtk_tree_model_get_path(model, iter); indices = gtk_tree_path_get_indices(path); //num = gtk_tree_path_to_string(path); g_snprintf(num, 15, "%d", 1 + *indices); gtk_tree_path_free(path); g_object_set(renderer, "text", num, NULL); } static void list_split_amount_cell_data_function (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { Split *split; gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; gdouble amount; gchar *color; gtk_tree_model_get(model, iter, 0, &split, -1); //hb_strfmon(buf, G_ASCII_DTOSTR_BUF_SIZE-1, amount, ope->kcur, GLOBALS->minor); amount = split->amount; g_snprintf(buf, G_ASCII_DTOSTR_BUF_SIZE-1, "%.2f", amount); color = get_normal_color_amount(amount); g_object_set(renderer, "foreground", color, "text", buf, NULL); } static void list_split_memo_cell_data_function (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { Split *split; gtk_tree_model_get(model, iter, 0, &split, -1); g_object_set(renderer, "text", split->memo, NULL); } static void list_split_category_cell_data_function (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) { Split *split; Category *cat; gtk_tree_model_get(model, iter, 0, &split, -1); cat = da_cat_get(split->kcat); if( cat != NULL ) { g_object_set(renderer, "text", cat->fullname, NULL); } else g_object_set(renderer, "text", "", NULL); } static void list_split_populate(struct ui_split_dialog_data *data) { GtkTreeModel *model; GtkTreeIter iter; Split *split; gint count, i; DB( g_print("\n[list_split] populate\n") ); count = da_splits_length (data->tmp_splits); if( count <= 0 ) return; model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)); gtk_list_store_clear (GTK_LIST_STORE(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(data->LV_split), NULL); /* Detach model from view */ /* populate */ for(i=0 ; i < count ; i++) { split = da_splits_get(data->tmp_splits, i); DB( g_print("- set split %d : %d, %.2f, %s\n", i, split->kcat, split->amount, split->memo) ); gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, split, -1); } gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_split), model); /* Re-attach model to view */ g_object_unref(model); } static GtkWidget * list_split_new(void) { GtkListStore *store; GtkWidget *treeview; GtkCellRenderer *renderer; GtkTreeViewColumn *column; DB( g_print("\n[ui_split_listview] new\n") ); // create list store store = gtk_list_store_new(1, G_TYPE_POINTER ); // 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 0: line number renderer = gtk_cell_renderer_text_new (); g_object_set(renderer, "xalign", 1.0, NULL); column = gtk_tree_view_column_new_with_attributes("#", renderer, NULL); gtk_tree_view_column_set_alignment (column, 1.0); gtk_tree_view_column_set_cell_data_func(column, renderer, list_split_number_cell_data_function, NULL, NULL); gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); // column 1: category renderer = gtk_cell_renderer_text_new (); g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes(_("Category"), renderer, NULL); //gtk_tree_view_column_set_alignment (column, 0.5); gtk_tree_view_column_set_resizable(column, TRUE); //gtk_tree_view_column_set_sort_column_id (column, sortcolumnid); //gtk_tree_view_column_set_fixed_width( column, HB_MINWIDTH_LIST); gtk_tree_view_column_set_expand (column, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, list_split_category_cell_data_function, NULL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); // column 2: memo renderer = gtk_cell_renderer_text_new (); g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes(_("Memo"), renderer, NULL); //gtk_tree_view_column_set_alignment (column, 0.5); gtk_tree_view_column_set_resizable(column, TRUE); //gtk_tree_view_column_set_sort_column_id (column, sortcolumnid); //gtk_tree_view_column_set_fixed_width( column, HB_MINWIDTH_LIST); gtk_tree_view_column_set_expand (column, TRUE); gtk_tree_view_column_set_cell_data_func(column, renderer, list_split_memo_cell_data_function, NULL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); // column 3: amount renderer = gtk_cell_renderer_text_new (); g_object_set(renderer, "xalign", 1.0, NULL); column = gtk_tree_view_column_new_with_attributes(_("Amount"), renderer, NULL); gtk_tree_view_column_set_alignment (column, 1.0); gtk_tree_view_column_set_resizable(column, TRUE); //gtk_tree_view_column_set_sort_column_id (column, sortcolumnid); gtk_tree_view_column_set_fixed_width( column, HB_MINWIDTH_LIST); gtk_tree_view_column_set_cell_data_func(column, renderer, list_split_amount_cell_data_function, NULL, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); // column empty //column = gtk_tree_view_column_new(); //gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column); // treeviewattribute gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_reorderable (GTK_TREE_VIEW(treeview), TRUE); //gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(store), ui_acc_listview_compare_func, NULL, NULL); //gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); return treeview; } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ static void ui_split_dialog_filter_text_handler (GtkEntry *entry, const gchar *text, gint length, gint *position, gpointer data) { GtkEditable *editable = GTK_EDITABLE(entry); gint i, count=0; gchar *result = g_new0 (gchar, length+1); for (i=0; i < length; i++) { if (text[i]=='|') continue; result[count++] = text[i]; } if (count > 0) { g_signal_handlers_block_by_func (G_OBJECT (editable), G_CALLBACK (ui_split_dialog_filter_text_handler), data); gtk_editable_insert_text (editable, result, count, position); g_signal_handlers_unblock_by_func (G_OBJECT (editable), G_CALLBACK (ui_split_dialog_filter_text_handler), data); } g_signal_stop_emission_by_name (G_OBJECT (editable), "insert-text"); g_free (result); } static void ui_split_dialog_cb_eval_order(struct ui_split_dialog_data *data) { GtkTreeModel *model; GtkTreeIter iter; gboolean valid; guint i; DB( g_print("\n[ui_split_dialog] eval order\n") ); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)); i=1; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid) { Split *split; gtk_tree_model_get (model, &iter, 0, &split, -1); split->pos = i; DB( g_print("split pos: %d '%s' %.2f\n", i, split->memo, split->amount) ); i++; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } da_splits_sort(data->tmp_splits); } static void ui_split_dialog_cb_eval_split(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; gboolean tmpval = FALSE; gdouble amount; gint count; DB( g_print("\n[ui_split_dialog] eval split\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); amount= g_strtod(gtk_entry_get_text(GTK_ENTRY(data->ST_amount)), NULL); tmpval = hb_amount_round(amount, 2) != 0.0 ? TRUE : FALSE; gtk_widget_set_sensitive (data->BT_apply, tmpval); count = gtk_tree_model_iter_n_children(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)), NULL); if( count >= TXN_MAX_SPLIT ) tmpval = FALSE; gtk_widget_set_sensitive (data->BT_add, tmpval); DB( g_print(" - txt='%s' amt=%.2f, nbsplit=%d, valid=%d\n", gtk_entry_get_text(GTK_ENTRY(data->ST_amount)), amount, count, tmpval) ); } static void ui_split_dialog_update(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; gboolean tmpval; guint count; DB( g_print("\n[ui_split_dialog] update\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); count = da_splits_length (data->tmp_splits); //btn: edit/rem tmpval = gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_split)), NULL, NULL); gtk_widget_set_sensitive (data->BT_edit, (data->isedited) ? FALSE : tmpval); gtk_widget_set_sensitive (data->BT_rem, (data->isedited) ? FALSE : tmpval); //btn: remall tmpval = (count > 1) ? TRUE : FALSE; gtk_widget_set_sensitive (data->BT_remall, (data->isedited) ? FALSE : tmpval); ui_split_dialog_cb_eval_split(widget, NULL); //btn: add/apply /*amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount)); tmpval = hb_amount_round(amount, 2) != 0.0 ? TRUE : FALSE; gtk_widget_set_sensitive (data->BT_apply, tmpval); if( count >= TXN_MAX_SPLIT ) tmpval = FALSE; gtk_widget_set_sensitive (data->BT_add, tmpval); */ //btn: show/hide gtk_widget_set_sensitive (data->LV_split, !data->isedited); hb_widget_visible (data->BT_add, !data->isedited); hb_widget_visible (data->IM_edit, data->isedited); hb_widget_visible (data->BT_apply, data->isedited); hb_widget_visible (data->BT_cancel, data->isedited); } static void ui_split_dialog_edit_end(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; DB( g_print("\n[ui_split_dialog] edit_end\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); g_signal_handler_block(data->PO_cat, data->hid_cat); g_signal_handler_block(data->ST_amount, data->hid_amt); ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_cat), 0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), 0.0); gtk_entry_set_text(GTK_ENTRY(data->ST_memo), ""); g_signal_handler_unblock(data->ST_amount, data->hid_amt); g_signal_handler_unblock(data->PO_cat, data->hid_cat); data->isedited = FALSE; } static void ui_split_dialog_edit_start(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; DB( g_print("\n[ui_split_dialog] edit_start\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_split)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { Split *split; gchar *txt; gtk_tree_model_get(model, &iter, 0, &split, -1); ui_cat_comboboxentry_set_active(GTK_COMBO_BOX(data->PO_cat), split->kcat); gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_amount), split->amount); txt = (split->memo != NULL) ? split->memo : ""; gtk_entry_set_text(GTK_ENTRY(data->ST_memo), txt); data->isedited = TRUE; ui_split_dialog_update (data->dialog, user_data); } } static void ui_split_dialog_cancel_cb(GtkWidget *widget, gpointer user_data) { //struct ui_split_dialog_data *data; DB( g_print("\n[ui_split_dialog] cancel\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); ui_split_dialog_edit_end(widget, user_data); ui_split_dialog_update (widget, user_data); } static void ui_split_dialog_apply_cb(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; DB( g_print("\n[ui_split_dialog] apply\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_split)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { Split *split; gdouble amount; gtk_tree_model_get(model, &iter, 0, &split, -1); gtk_spin_button_update (GTK_SPIN_BUTTON(data->ST_amount)); amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount)); if(amount) { split->kcat = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(data->PO_cat)); g_free(split->memo); split->memo = g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_memo))); split->amount = amount; } } ui_split_dialog_edit_end(widget, user_data); ui_split_dialog_compute (widget, data); ui_split_dialog_update (widget, user_data); } static void ui_split_dialog_removeall_cb(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; DB( g_print("\n[ui_split_dialog] removeall_cb\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); gtk_list_store_clear (GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(data->LV_split)))); da_split_destroy(data->tmp_splits); data->tmp_splits = da_split_new (); ui_split_dialog_compute (widget, data); ui_split_dialog_update (widget, user_data); } static void ui_split_dialog_remove_cb(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; DB( g_print("\n[ui_split_dialog] remove_cb\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_split)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { Split *split; gtk_tree_model_get(model, &iter, 0, &split, -1); //todo: not implemented yet da_splits_remove(data->tmp_splits, split); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); } ui_split_dialog_compute (widget, data); ui_split_dialog_update (widget, user_data); } static void ui_split_dialog_add_cb(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; GtkTreeModel *model; GtkTreeIter iter; Split *split; guint count; gdouble amount; DB( g_print("\n[ui_split_dialog] add\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); count = da_splits_length (data->tmp_splits); if( count <= TXN_MAX_SPLIT ) { split = da_split_malloc (); gtk_spin_button_update (GTK_SPIN_BUTTON(data->ST_amount)); amount = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_amount)); if(amount) { split->amount = amount; split->kcat = ui_cat_comboboxentry_get_key_add_new(GTK_COMBO_BOX(data->PO_cat)); split->memo = g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_memo))); DB( g_print("- get split : %d, %.2f, %s\n", split->kcat, split->amount, split->memo) ); da_splits_append (data->tmp_splits, split); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)); gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, split, -1); ui_split_dialog_compute (widget, data); } else { //todo: msg max number reached da_split_free(split); } } ui_split_dialog_edit_end(widget, user_data); ui_split_dialog_update (widget, user_data); } static void ui_split_dialog_cb_activate_split(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; DB( g_print("\n[ui_split_dialog] cb activate split\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); if( data->isedited == TRUE ) ui_split_dialog_apply_cb(widget, NULL); else ui_split_dialog_add_cb(widget, NULL); } static void ui_split_rowactivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data) { DB( g_print("\n[ui_split_dialog] rowactivated\n") ); ui_split_dialog_edit_start(GTK_WIDGET(treeview), NULL); } static void ui_split_selection(GtkTreeSelection *treeselection, gpointer user_data) { DB( g_print("\n[ui_split_dialog] selection\n") ); ui_split_dialog_update (GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), user_data); } void ui_split_dialog_compute(GtkWidget *widget, gpointer user_data) { struct ui_split_dialog_data *data; gint i, count, nbvalid; gchar buf[48]; gboolean sensitive; GtkTreeModel *model; GtkTreeIter iter; gboolean valid; DB( g_print("\n[ui_split_dialog] compute\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(widget), GTK_TYPE_WINDOW)), "inst_data"); nbvalid = 0; data->sumsplit = 0.0; data->remsplit = 0.0; model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_split)); i=0; valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid) { Split *split; gtk_tree_model_get (model, &iter, 0, &split, -1); data->sumsplit += split->amount; if( hb_amount_round(split->amount, 2) != 0.0 ) nbvalid++; /* Make iter point to the next row in the list store */ i++; valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } count = i; DB( g_print("- count=%d, nbvalid=%d\n", count, nbvalid ) ); data->remsplit = data->amount - data->sumsplit; //validation: 2 split min sensitive = FALSE; if( (count == 0) || nbvalid >= 2 ) sensitive = TRUE; gtk_dialog_set_response_sensitive(GTK_DIALOG(data->dialog), GTK_RESPONSE_ACCEPT, sensitive); if( hb_amount_round(data->amount, 2) != 0.0 ) { if(!data->remsplit) g_sprintf(buf, "----"); else g_snprintf(buf, 48, "%.2f", data->remsplit); gtk_label_set_label(GTK_LABEL(data->LB_remain), buf); g_snprintf(buf, 48, "%.2f", data->amount); gtk_label_set_label(GTK_LABEL(data->LB_txnamount), buf); } g_snprintf(buf, 48, "%.2f", data->sumsplit); gtk_label_set_text(GTK_LABEL(data->LB_sumsplit), buf); } static void ui_split_dialog_setup(struct ui_split_dialog_data *data) { guint count; DB( g_print("\n[ui_split_dialog] set\n") ); count = da_splits_length(data->tmp_splits); data->nbsplit = count > 1 ? count-1 : 0; DB( g_print("- count = %d\n", count) ); list_split_populate (data); data->isedited = FALSE; ui_cat_comboboxentry_populate(GTK_COMBO_BOX(data->PO_cat), GLOBALS->h_cat); ui_split_dialog_compute(data->dialog, data); ui_split_dialog_update (data->dialog, data); } GtkWidget *ui_split_dialog (GtkWidget *parent, GPtrArray **src_splits, gdouble amount, void (update_callbackFunction(GtkWidget*, gdouble))) { struct ui_split_dialog_data *data; GtkWidget *dialog, *content, *table, *box, *scrollwin; GtkWidget *label, *widget; gint row; DB( g_print("\n[ui_split_dialog] new\n") ); data = g_malloc0(sizeof(struct ui_split_dialog_data)); dialog = gtk_dialog_new_with_buttons (_("Transaction splits"), GTK_WINDOW(parent), 0, _("_Cancel"), GTK_RESPONSE_CANCEL, NULL); //store our dialog private data g_object_set_data(G_OBJECT(dialog), "inst_data", (gpointer)data); DB( g_print(" - window=%p, inst_data=%p\n", dialog, data) ); g_signal_connect (dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), &dialog); data->dialog = dialog; //gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Remove"), GTK_RESPONSE_SPLIT_REM); gtk_dialog_add_button(GTK_DIALOG(dialog), _("_OK"), GTK_RESPONSE_ACCEPT); //todo: init should move //clone splits or create new data->src_splits = *src_splits; data->amount = amount; data->sumsplit = amount; if( *src_splits != NULL ) data->tmp_splits = da_splits_clone(*src_splits); else data->tmp_splits = da_split_new(); //dialog contents content = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); table = gtk_grid_new (); gtk_container_set_border_width (GTK_CONTAINER (table), SPACING_SMALL); gtk_grid_set_row_spacing (GTK_GRID (table), SPACING_TINY); gtk_grid_set_column_spacing (GTK_GRID (table), SPACING_TINY); gtk_box_pack_start (GTK_BOX (content), table, TRUE, TRUE, 0); row = 0; scrollwin = gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_ETCHED_IN); gtk_widget_set_size_request(scrollwin, HB_MINWIDTH_LIST, HB_MINHEIGHT_LIST); gtk_widget_set_hexpand (scrollwin, TRUE); gtk_widget_set_vexpand (scrollwin, TRUE); data->LV_split = list_split_new(); gtk_container_add(GTK_CONTAINER(scrollwin), data->LV_split); gtk_grid_attach (GTK_GRID (table), scrollwin, 0, row, 4, 1); box = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_TINY); gtk_widget_set_valign (box, GTK_ALIGN_CENTER); gtk_grid_attach (GTK_GRID (table), box, 4, row, 1, 1); widget = make_image_button(ICONNAME_LIST_REMOVE_ALL, _("Remove all")); data->BT_remall = widget; gtk_box_pack_end (GTK_BOX (box), widget, FALSE, FALSE, 0); widget = make_image_button(ICONNAME_LIST_REMOVE, _("Remove")); data->BT_rem = widget; gtk_box_pack_end (GTK_BOX(box), widget, FALSE, FALSE, 0); widget = make_image_button(ICONNAME_HB_OPE_EDIT, _("Edit")); data->BT_edit = widget; gtk_box_pack_end (GTK_BOX(box), widget, FALSE, FALSE, 0); row++; label = gtk_label_new(_("Category")); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_grid_attach (GTK_GRID (table), label, 0, row, 1, 1); label = gtk_label_new(_("Memo")); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); label = gtk_label_new(_("Amount")); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_grid_attach (GTK_GRID (table), label, 2, row, 1, 1); row++; widget = ui_cat_comboboxentry_new(NULL); data->PO_cat = widget; gtk_grid_attach (GTK_GRID (table), widget, 0, row, 1, 1); widget = make_string(NULL); data->ST_memo= widget; gtk_grid_attach (GTK_GRID (table), widget, 1, row, 1, 1); widget = make_amount(NULL); data->ST_amount = widget; gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1); box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_TINY); gtk_grid_attach (GTK_GRID (table), box, 3, row, 1, 1); widget = gtk_image_new_from_icon_name (ICONNAME_HB_OPE_EDIT, GTK_ICON_SIZE_BUTTON); data->IM_edit = widget; gtk_box_pack_start (GTK_BOX(box), widget, TRUE, TRUE, 0); widget = make_image_button(ICONNAME_LIST_ADD, _("Add")); data->BT_add = widget; gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0); widget = make_image_button(ICONNAME_EMBLEM_OK, _("Apply")); data->BT_apply = widget; gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0); widget = make_image_button(ICONNAME_WINDOW_CLOSE, _("Cancel")); data->BT_cancel = widget; gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0); if( hb_amount_round(data->amount, 2) != 0.0 ) { row++; label = gtk_label_new(_("Transaction amount:")); gtk_widget_set_halign (label, GTK_ALIGN_END); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); widget = gtk_label_new(NULL); gtk_widget_set_halign (widget, GTK_ALIGN_CENTER); data->LB_txnamount = widget; gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1); row++; label = gtk_label_new(_("Unassigned:")); gtk_widget_set_halign (label, GTK_ALIGN_END); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); widget = gtk_label_new(NULL); gtk_widget_set_halign (widget, GTK_ALIGN_CENTER); data->LB_remain = widget; gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1); row++; widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL); gtk_grid_attach (GTK_GRID (table), widget, 1, row, 2, 1); } row++; label = gtk_label_new(_("Sum of splits:")); gtk_widget_set_halign (label, GTK_ALIGN_END); gtk_grid_attach (GTK_GRID (table), label, 1, row, 1, 1); widget = gtk_label_new(NULL); gtk_widget_set_halign (widget, GTK_ALIGN_CENTER); data->LB_sumsplit = widget; gtk_grid_attach (GTK_GRID (table), widget, 2, row, 1, 1); //connect all our signals g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_split)), "changed", G_CALLBACK (ui_split_selection), data); g_signal_connect (GTK_TREE_VIEW(data->LV_split), "row-activated", G_CALLBACK (ui_split_rowactivated), data); g_signal_connect (data->ST_memo, "insert-text", G_CALLBACK(ui_split_dialog_filter_text_handler), data); data->hid_cat = g_signal_connect (data->PO_cat , "changed" , G_CALLBACK (ui_split_dialog_cb_eval_split), data); data->hid_amt = g_signal_connect (data->ST_amount, "changed", G_CALLBACK (ui_split_dialog_cb_eval_split), data); //data->hid_amt = g_signal_connect (data->ST_amount, "value-changed", G_CALLBACK (ui_split_dialog_cb_eval_split), data); //todo: add enter validate g_signal_connect (data->ST_amount, "activate", G_CALLBACK (ui_split_dialog_cb_activate_split), NULL); g_signal_connect (data->BT_edit , "clicked", G_CALLBACK (ui_split_dialog_edit_start), NULL); g_signal_connect (data->BT_rem , "clicked", G_CALLBACK (ui_split_dialog_remove_cb), NULL); g_signal_connect (data->BT_remall, "clicked", G_CALLBACK (ui_split_dialog_removeall_cb), NULL); g_signal_connect (data->BT_add , "clicked", G_CALLBACK (ui_split_dialog_add_cb), NULL); g_signal_connect (data->BT_apply , "clicked", G_CALLBACK (ui_split_dialog_apply_cb), NULL); g_signal_connect (data->BT_cancel, "clicked", G_CALLBACK (ui_split_dialog_cancel_cb), NULL); //gtk_window_set_default_size(GTK_WINDOW(dialog), 480, -1); gtk_widget_show_all (dialog); //setup, init and show dialog ui_split_dialog_setup(data); //wait for the user gint result = gtk_dialog_run (GTK_DIALOG (dialog)); switch (result) { // sum split and alter txn amount case GTK_RESPONSE_ACCEPT: if( da_splits_length(data->tmp_splits) ) { ui_split_dialog_cb_eval_order(data); // here we swap src_splits <> tmp_splits *src_splits = data->tmp_splits; data->tmp_splits = data->src_splits; update_callbackFunction(parent, data->sumsplit); } else { //remove split and revert back original amount da_split_destroy(*src_splits); *src_splits = NULL; update_callbackFunction(parent, data->amount); } break; /*case GTK_RESPONSE_SPLIT_REM: da_split_destroy(*src_splits); *src_splits = NULL; update_callbackFunction(parent, data->sumsplit); break; */ default: //do_nothing_since_dialog_was_cancelled (); break; } // debug /*#if MYDEBUG == 1 { guint i; for(i=0;iope_splits[i]; if(data->ope_splits[i] == NULL) break; g_print(" split %d : %d, %.2f, %s\n", i, split->kcat, split->amount, split->memo); } } #endif*/ // cleanup and destroy //GLOBALS->changes_count += data->change; gtk_widget_destroy (dialog); da_split_destroy (data->tmp_splits); g_free(data); return NULL; }