/* 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 of * 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 "dsp-account.h" #include "dsp-mainwindow.h" #include "list-operation.h" #include "hub-account.h" #include "ui-widgets.h" #include "ui-filter.h" #include "ui-transaction.h" #include "ui-txn-multi.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; //debug #define UI 1 extern gchar *CYA_FLT_TYPE[]; extern gchar *CYA_FLT_STATUS[]; static void register_panel_collect_filtered_txn(GtkWidget *view, gboolean emptysearch); static void register_panel_listview_populate(GtkWidget *view); static void register_panel_action(GtkWidget *widget, gpointer user_data); static void register_panel_update(GtkWidget *widget, gpointer user_data); static void register_panel_export_csv(GtkWidget *widget, gpointer user_data); static void register_panel_make_archive(GtkWidget *widget, gpointer user_data); static void status_selected_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata); static void register_panel_edit_multiple(GtkWidget *widget, Transaction *txn, gint column_id, gpointer user_data); static void register_panel_selection(GtkTreeSelection *treeselection, gpointer user_data); static void register_panel_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata); /* account action functions -------------------- */ static void register_panel_action_editfilter(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_FILTER)); } static void register_panel_action_add(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_ADD)); } static void register_panel_action_inherit(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_INHERIT)); } static void register_panel_action_edit(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_EDIT)); } static void register_panel_action_multiedit(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_edit_multiple(data->window, NULL, 0, user_data); } static void register_panel_action_reconcile(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_RECONCILE)); } static void register_panel_action_clear(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_CLEAR)); } static void register_panel_action_none(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_NONE)); } static void register_panel_action_remove(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_action(data->window, GINT_TO_POINTER(ACTION_ACCOUNT_DELETE)); } static void register_panel_action_createtemplate(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_make_archive(data->window, NULL); } static void register_panel_action_exportcsv(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_export_csv(data->window, NULL); } /* = = = = = = = = future version = = = = = = = = */ static void register_panel_action_exportpdf(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; gchar *name, *filepath; if(data->showall == FALSE) { name = g_strdup_printf("%s.pdf", data->acc->name); filepath = g_build_filename(PREFS->path_export, name, NULL); g_free(name); if( ui_dialog_export_pdf(GTK_WINDOW(data->window), &filepath) == GTK_RESPONSE_ACCEPT ) { DB( g_printf(" filename is'%s'\n", filepath) ); hb_export_pdf_listview(GTK_TREE_VIEW(data->LV_ope), filepath, data->acc->name); } g_free(filepath); } } static void register_panel_action_duplicate_mark(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; DB( g_print("check duplicate\n\n") ); // open dialog to select date tolerance in days // with info message // with check/fix button and progress bar // parse listview txn, clear/mark duplicate // apply filter if(data->showall == FALSE) { gint daygap; daygap = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_txn_daygap)); data->similar = transaction_similar_mark (data->acc, daygap); if( data->similar > 0 ) { gchar *text = g_strdup_printf(_("There is %d group of similar transactions"), data->similar); gtk_label_set_text(GTK_LABEL(data->LB_duplicate), text); g_free(text); } else gtk_label_set_text(GTK_LABEL(data->LB_duplicate), _("No similar transaction were found !")); gtk_widget_show(data->IB_duplicate); //#GTK+710888: hack waiting a fix gtk_widget_queue_resize (data->IB_duplicate); gtk_widget_queue_draw (data->LV_ope); } } static void register_panel_action_duplicate_unmark(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; DB( g_print("uncheck duplicate\n\n") ); if(data->showall == FALSE) { data->similar = 0; gtk_widget_hide(data->IB_duplicate); transaction_similar_unmark(data->acc); gtk_widget_queue_draw (data->LV_ope); } } static void register_panel_action_check_internal_xfer(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; GtkTreeModel *model; GtkTreeIter iter; GList *badxferlist; gboolean valid; gint count; DB( g_print("check intenal xfer\n\n") ); badxferlist = NULL; model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid) { Transaction *txn; gtk_tree_model_get (model, &iter, MODEL_TXN_POINTER, &txn, -1); if( txn->paymode == PAYMODE_INTXFER ) { if( transaction_xfer_child_strong_get(txn) == NULL ) { DB( g_print(" - invalid xfer: '%s'\n", txn->memo) ); //test unrecoverable (kxferacc = 0) if( txn->kxferacc <= 0 ) { DB( g_print(" - unrecoverable, revert to normal xfer\n") ); txn->flags |= OF_CHANGED; txn->paymode = PAYMODE_XFER; txn->kxfer = 0; txn->kxferacc = 0; } else { badxferlist = g_list_append(badxferlist, txn); } } } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } count = g_list_length (badxferlist); DB( g_print(" - found %d invalid int xfer\n", count) ); if(count <= 0) { ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_INFO, _("Check internal transfert result"), _("No inconsistency found !") ); } else { gboolean do_fix; do_fix = ui_dialog_msg_question( GTK_WINDOW(data->window), _("Check internal transfert result"), _("Inconsistency were found: %d\n" "do you want to review and fix ?"), count ); if(do_fix == GTK_RESPONSE_YES) { GList *tmplist = g_list_first(badxferlist); while (tmplist != NULL) { Transaction *stxn = tmplist->data; //future (open dialog to select date tolerance in days) transaction_xfer_search_or_add_child(GTK_WINDOW(data->window), stxn, 0); tmplist = g_list_next(tmplist); } } } g_list_free (badxferlist); } static void register_panel_action_exportqif(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; gchar *filename; // noaction if show all account if(data->showall) return; DB( g_print("(qif) test qif export\n\n") ); if( ui_file_chooser_qif(GTK_WINDOW(data->window), &filename) == TRUE ) { hb_export_qif_account_single(filename, data->acc); g_free( filename ); } } static void register_panel_action_converttoeuro(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; gchar *msg; gint result; // noaction if show all account if(data->showall) return; DB( g_print("action convert to euro\n") ); msg = g_strdup_printf(_("Every transaction amount will be divided by %.6f."), PREFS->euro_value); result = ui_dialog_msg_confirm_alert( GTK_WINDOW(data->window), _("Are you sure you want to convert this account\nto Euro as Major currency?"), msg, _("_Convert") ); g_free(msg); if(result == GTK_RESPONSE_OK) { account_convert_euro(data->acc); register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE)); } } static void register_panel_action_assign(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; gint count; gboolean usermode = TRUE; // noaction if show all account if(data->showall) return; DB( g_print("action assign\n") ); count = transaction_auto_assign(g_queue_peek_head_link(data->acc->txn_queue), data->acc->key); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_ope)); GLOBALS->changes_count += count; //inform the user if(usermode == TRUE) { gchar *txt; if(count == 0) txt = _("No transaction changed"); else txt = _("transaction changed: %d"); ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_INFO, _("Automatic assignment result"), txt, count); } //refresh main if( count > 0 ) ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void register_panel_action_close(GtkAction *action, gpointer user_data) { struct register_panel_data *data = user_data; DB( g_print("action close\n") ); DB( g_print("window %p\n", data->window) ); gtk_widget_destroy (GTK_WIDGET (data->window)); //g_signal_emit_by_name(data->window, "delete-event", NULL, &result); } /* these 5 functions are independant from account window */ /* account functions -------------------- */ static void register_panel_export_csv(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; gchar *filename = NULL; GString *node; GIOChannel *io; DB( g_print("\n[account] export csv\n") ); 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 ) { DB( g_print(" + filename is %s\n", filename) ); io = g_io_channel_new_file(filename, "w", NULL); if(io != NULL) { node = list_txn_to_string(GTK_TREE_VIEW(data->LV_ope), FALSE); g_io_channel_write_chars(io, node->str, -1, NULL, NULL); g_io_channel_unref (io); g_string_free(node, TRUE); } g_free( filename ); } } static void register_panel_edit_multiple(GtkWidget *widget, Transaction *txn, gint column_id, gpointer user_data) { struct register_panel_data *data; GtkWidget *dialog; DB( g_print("\n[account] edit multiple\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); DB( g_print(" - txn:%p, column: %d\n", txn, column_id) ); dialog = ui_multipleedit_dialog_new(GTK_WINDOW(data->window), GTK_TREE_VIEW(data->LV_ope)); if(txn != NULL && column_id != 0) { ui_multipleedit_dialog_prefill(dialog, txn, column_id); } //wait for the user gint result = gtk_dialog_run (GTK_DIALOG (dialog)); if( result == GTK_RESPONSE_ACCEPT ) { gboolean do_sort; gint changes; //#1792808: sort if date changed changes = ui_multipleedit_dialog_apply (dialog, &do_sort); data->do_sort = do_sort; if( changes > 0 ) { //#1782749 update account status if( data->acc != NULL ) data->acc->flags |= AF_CHANGED; ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } } gtk_widget_destroy (dialog); register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE)); } /* ** make an archive with the active transaction */ static void register_panel_make_archive(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; GtkTreeModel *model; GList *selection, *list; gint result, count; DB( g_print("\n[account] make archive\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); count = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope))); if( count > 0 ) { result = ui_dialog_msg_confirm_alert( GTK_WINDOW(data->window), NULL, _("Do you want to create a template with\neach of the selected transaction ?"), _("_Create") ); /* gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), _("%d archives will be created"), GLOBALS->changes_count ); */ if(result == GTK_RESPONSE_OK) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); selection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)), &model); list = g_list_first(selection); while(list != NULL) { Archive *item; Transaction *ope; GtkTreeIter iter; gtk_tree_model_get_iter(model, &iter, list->data); gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &ope, -1); DB( g_print(" create archive %s %.2f\n", ope->memo, ope->amount) ); item = da_archive_malloc(); da_archive_init_from_transaction(item, ope); //GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item); da_archive_append_new(item); GLOBALS->changes_count++; list = g_list_next(list); } g_list_foreach(selection, (GFunc)gtk_tree_path_free, NULL); g_list_free(selection); } } } static void register_panel_cb_bar_duplicate_response(GtkWidget *info_bar, gint response_id, gpointer user_data) { struct register_panel_data *data; DB( g_print("\n[account] bar_duplicate_response\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(info_bar, GTK_TYPE_WINDOW)), "inst_data"); switch( response_id ) { case HB_RESPONSE_REFRESH: register_panel_action_duplicate_mark(NULL, data); break; case GTK_RESPONSE_CLOSE: register_panel_action_duplicate_unmark(NULL, data); gtk_widget_hide (GTK_WIDGET (info_bar)); break; } } static void register_panel_cb_filter_daterange(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; gboolean future; gint range; DB( g_print("\n[account] filter_daterange\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); range = hbtk_combo_box_get_active_id(GTK_COMBO_BOX_TEXT(data->CY_range)); future = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_future)); data->filter->nbdaysfuture = 0; if(range != FLT_RANGE_OTHER) { filter_preset_daterange_set(data->filter, range, (data->showall == FALSE) ? data->acc->key : 0); // add eventual x days into future display if( future && (PREFS->date_future_nbdays > 0) ) filter_preset_daterange_add_futuregap(data->filter, PREFS->date_future_nbdays); register_panel_collect_filtered_txn(data->LV_ope, FALSE); register_panel_listview_populate(data->LV_ope); } else { if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, data->showall, TRUE) != GTK_RESPONSE_REJECT) { register_panel_collect_filtered_txn(data->LV_ope, FALSE); register_panel_listview_populate(data->LV_ope); register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE)); } } } static void register_panel_cb_filter_type(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; gint type; DB( g_print("\n[account] filter_type\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); type = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_type)); filter_preset_type_set(data->filter, type); register_panel_collect_filtered_txn(data->LV_ope, FALSE); register_panel_listview_populate(data->LV_ope); } static void register_panel_cb_filter_status(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; gint status; DB( g_print("\n[account] filter_status\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); status = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_status)); filter_preset_status_set(data->filter, status); register_panel_collect_filtered_txn(data->LV_ope, FALSE); register_panel_listview_populate(data->LV_ope); } static void register_panel_cb_filter_reset(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; DB( g_print("\n[account] filter_reset\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); filter_reset(data->filter); filter_preset_daterange_set (data->filter, PREFS->date_range_txn, (data->showall == FALSE) ? data->acc->key : 0); if(PREFS->hidereconciled) filter_preset_status_set (data->filter, FLT_STATUS_UNRECONCILED); // add eventual x days into future display if( PREFS->date_future_nbdays > 0 ) filter_preset_daterange_add_futuregap(data->filter, PREFS->date_future_nbdays); register_panel_collect_filtered_txn(data->LV_ope, TRUE); register_panel_listview_populate(data->LV_ope); g_signal_handler_block(data->CY_range, data->handler_id[HID_RANGE]); g_signal_handler_block(data->CY_type, data->handler_id[HID_TYPE]); g_signal_handler_block(data->CY_status, data->handler_id[HID_STATUS]); hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), data->filter->range); gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_type), data->filter->type); gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_status), data->filter->status); g_signal_handler_unblock(data->CY_status, data->handler_id[HID_STATUS]); g_signal_handler_unblock(data->CY_type, data->handler_id[HID_TYPE]); g_signal_handler_unblock(data->CY_range, data->handler_id[HID_RANGE]); } static void register_panel_balance_refresh(GtkWidget *view) { struct register_panel_data *data; GList *list; gdouble balance; GtkTreeModel *model; guint32 ldate = 0; gushort lpos = 1; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW)), "inst_data"); // noaction if show all account if(data->showall) return; DB( g_print("\n[account %d] balance refresh\n", data->acc != NULL ? (gint)data->acc->key : -1) ); balance = data->acc->initial; //#1270687: sort if date changed if(data->do_sort) { DB( g_print(" - complete txn sort\n") ); da_transaction_queue_sort(data->acc->txn_queue); data->do_sort = FALSE; } list = g_queue_peek_head_link(data->acc->txn_queue); while (list != NULL) { Transaction *ope = list->data; gdouble value; //#1267344 if(!(ope->status == TXN_STATUS_REMIND)) balance += ope->amount; ope->balance = balance; //#1661806 add show overdraft //#1672209 added round like for #400483 ope->overdraft = FALSE; value = hb_amount_round(balance, 2); if( value != 0.0 && value < data->acc->minimum ) ope->overdraft = TRUE; if(ope->date == ldate) { ope->pos = ++lpos; } else { ope->pos = lpos = 1; } ldate = ope->date; list = g_list_next(list); } model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); list_txn_sort_force(GTK_TREE_SORTABLE(model), NULL); } static void register_panel_collect_filtered_txn(GtkWidget *view, gboolean emptysearch) { struct register_panel_data *data; GList *lst_acc, *lnk_acc; GList *lnk_txn; DB( g_print("\n[register_panel] collect_filtered_txn\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(view, GTK_TYPE_WINDOW)), "inst_data"); if(data->gpatxn != NULL) g_ptr_array_free (data->gpatxn, TRUE); //todo: why this ? data->gpatxn = g_ptr_array_sized_new(64); lst_acc = g_hash_table_get_values(GLOBALS->h_acc); lnk_acc = g_list_first(lst_acc); while (lnk_acc != NULL) { Account *acc = lnk_acc->data; // skip closed in showall mode if( data->showall == TRUE && (acc->flags & AF_CLOSED) ) goto next_acc; // skip other than current in normal mode if( (data->showall == FALSE) && (data->acc != NULL) && (acc->key != data->acc->key) ) goto next_acc; lnk_txn = g_queue_peek_head_link(acc->txn_queue); while (lnk_txn != NULL) { Transaction *ope = lnk_txn->data; if(filter_txn_match(data->filter, ope) == 1) { //add to the list g_ptr_array_add(data->gpatxn, (gpointer)ope); } lnk_txn = g_list_next(lnk_txn); } next_acc: lnk_acc = g_list_next(lnk_acc); } g_list_free(lst_acc); //#1789698 not always empty if( emptysearch == TRUE ) { g_signal_handler_block(data->ST_search, data->handler_id[HID_SEARCH]); gtk_entry_set_text (GTK_ENTRY(data->ST_search), ""); g_signal_handler_unblock(data->ST_search, data->handler_id[HID_SEARCH]); } } static void register_panel_listview_populate(GtkWidget *widget) { struct register_panel_data *data; GtkTreeModel *model; GtkTreeIter iter; gboolean hastext; gchar *needle; gint sort_column_id; GtkSortType order; guint i, qs_flag; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); DB( g_print("\n[register_panel] listview_populate\n") ); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); // ref model to keep it //g_object_ref(model); //gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_ope), NULL); gtk_list_store_clear (GTK_LIST_STORE(model)); // perf: if you leave the sort, insert is damned slow gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), &sort_column_id, &order); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, PREFS->lst_ope_sort_order); hastext = gtk_entry_get_text_length (GTK_ENTRY(data->ST_search)) >= 2; needle = (gchar *)gtk_entry_get_text(GTK_ENTRY(data->ST_search)); //build the mask flag for quick search qs_flag = 0; if(hastext) { qs_flag = list_txn_get_quicksearch_column_mask(GTK_TREE_VIEW(data->LV_ope)); } data->total = 0; data->totalsum = 0.0; for(i=0;igpatxn->len;i++) { Transaction *txn = g_ptr_array_index(data->gpatxn, i); gboolean insert = TRUE; if(hastext) { insert = filter_txn_search_match(needle, txn, qs_flag); } if(insert) { //gtk_list_store_append (GTK_LIST_STORE(model), &iter); //gtk_list_store_set (GTK_LIST_STORE(model), &iter, gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter, -1, MODEL_TXN_POINTER, txn, -1); if( data->showall == FALSE ) data->totalsum += txn->amount; else data->totalsum += hb_amount_base (txn->amount, txn->kcur); data->total++; } } //gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_ope), model); /* Re-attach model to view */ //g_object_unref(model); // push back the sort id gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(GTK_LIST_STORE(model)), sort_column_id, order); /* update info range text */ { gchar *daterange; daterange = filter_daterange_text_get(data->filter); gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange); g_free(daterange); } register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE)); } static gint txn_list_get_count_reconciled(GtkTreeView *treeview) { GtkTreeModel *model; GList *lselection, *list; gint count = 0; model = gtk_tree_view_get_model(treeview); lselection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(treeview), &model); list = g_list_last(lselection); while(list != NULL) { GtkTreeIter iter; Transaction *txn; gtk_tree_model_get_iter(model, &iter, list->data); gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &txn, -1); if(txn->status == TXN_STATUS_RECONCILED) count++; list = g_list_previous(list); } g_list_foreach(lselection, (GFunc)gtk_tree_path_free, NULL); g_list_free(lselection); return count; } static void txn_list_add_by_value(GtkTreeView *treeview, Transaction *ope) { GtkTreeModel *model; GtkTreeIter iter; //GtkTreePath *path; //GtkTreeSelection *sel; DB( g_print("\n[transaction] add_treeview\n") ); model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, MODEL_TXN_POINTER, ope, -1); //activate that new line //path = gtk_tree_model_get_path(model, &iter); //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path); //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); //gtk_tree_selection_select_iter(sel, &iter); //gtk_tree_path_free(path); } /* used to remove a intxfer child from a treeview */ static void txn_list_remove_by_value(GtkTreeModel *model, Transaction *txn) { GtkTreeIter iter; gboolean valid; if( txn == NULL ) return; DB( g_print("remove by value %p\n\n", txn) ); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); while (valid) { Transaction *tmp; gtk_tree_model_get (model, &iter, MODEL_TXN_POINTER, &tmp, -1); if( txn == tmp ) { gtk_list_store_remove(GTK_LIST_STORE(model), &iter); break; } valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); } } static void status_selected_foreach_func (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer userdata) { gint targetstatus = GPOINTER_TO_INT(userdata); Transaction *txn; gtk_tree_model_get(model, iter, MODEL_TXN_POINTER, &txn, -1); account_balances_sub(txn); switch(targetstatus) { case TXN_STATUS_NONE: switch(txn->status) { case TXN_STATUS_CLEARED: case TXN_STATUS_RECONCILED: txn->status = TXN_STATUS_NONE; txn->flags |= OF_CHANGED; break; } break; case TXN_STATUS_CLEARED: switch(txn->status) { case TXN_STATUS_NONE: txn->status = TXN_STATUS_CLEARED; txn->flags |= OF_CHANGED; break; case TXN_STATUS_CLEARED: txn->status = TXN_STATUS_NONE; txn->flags |= OF_CHANGED; break; } break; case TXN_STATUS_RECONCILED: switch(txn->status) { case TXN_STATUS_NONE: case TXN_STATUS_CLEARED: txn->status = TXN_STATUS_RECONCILED; txn->flags |= OF_CHANGED; break; case TXN_STATUS_RECONCILED: txn->status = TXN_STATUS_CLEARED; txn->flags |= OF_CHANGED; break; } break; } transaction_changed(txn); account_balances_add(txn); /* #492755 let the child transfer unchanged */ } static void delete_active_transaction(GtkTreeView *treeview) { GtkTreeModel *model; GList *list; model = gtk_tree_view_get_model(treeview); list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(treeview), &model); if(list != NULL) { GtkTreeIter iter; gtk_tree_model_get_iter(model, &iter, list->data); gtk_list_store_remove(GTK_LIST_STORE(model), &iter); } g_list_foreach(list, (GFunc)gtk_tree_path_free, NULL); g_list_free(list); } static void register_panel_add_single_transaction(GtkWindow *window, Transaction *txn) { struct register_panel_data *data; DB( g_print("\n[account] add single txn\n") ); data = g_object_get_data(G_OBJECT(window), "inst_data"); txn_list_add_by_value(GTK_TREE_VIEW(data->LV_ope), txn); } static void register_panel_action(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; gint action = GPOINTER_TO_INT(user_data); guint changes = GLOBALS->changes_count; gboolean result; DB( g_print("\n[account] action\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //data = INST_DATA(widget); DB( g_print(" - action=%d\n", action) ); switch(action) { //add case ACTION_ACCOUNT_ADD: //inherit case ACTION_ACCOUNT_INHERIT: { GtkWidget *dialog; Transaction *src_txn; gint type = 0; homebank_app_date_get_julian(); if(action == ACTION_ACCOUNT_ADD) { DB( g_print("(transaction) add multiple\n") ); src_txn = da_transaction_malloc(); src_txn->date = GLOBALS->today; if( data->acc != NULL ) src_txn->kacc = data->acc->key; da_transaction_set_default_template(src_txn); type = TRANSACTION_EDIT_ADD; } else { DB( g_print("(transaction) inherit multiple\n") ); src_txn = da_transaction_clone(list_txn_get_active_transaction(GTK_TREE_VIEW(data->LV_ope))); //#1432204 src_txn->status = TXN_STATUS_NONE; type = TRANSACTION_EDIT_INHERIT; } dialog = create_deftransaction_window(GTK_WINDOW(data->window), type, FALSE, (data->acc != NULL) ? data->acc->key : 0 ); result = HB_RESPONSE_ADD; while(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP) { /* clone source transaction */ if( result == HB_RESPONSE_ADD ) { data->cur_ope = da_transaction_clone (src_txn); if( PREFS->heritdate == FALSE ) //fix: 318733 / 1335285 data->cur_ope->date = GLOBALS->today; } deftransaction_set_transaction(dialog, data->cur_ope); result = gtk_dialog_run (GTK_DIALOG (dialog)); if(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT) { Transaction *add_txn; deftransaction_get(dialog, NULL); add_txn = transaction_add(GTK_WINDOW(data->window), data->cur_ope); if((data->showall == TRUE) || ( (data->acc != NULL) && (data->cur_ope->kacc == data->acc->key) ) ) { txn_list_add_by_value(GTK_TREE_VIEW(data->LV_ope), add_txn); //#1716181 also add to the ptr_array (quickfilter) g_ptr_array_add(data->gpatxn, (gpointer)add_txn); } register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); //#1667201 already done into transaction_add //data->acc->flags |= AF_ADDED; GLOBALS->changes_count++; //store last date src_txn->date = data->cur_ope->date; } if( result == HB_RESPONSE_ADD ) { da_transaction_free (data->cur_ope); } } deftransaction_dispose(dialog, NULL); da_transaction_free (src_txn); gtk_widget_destroy (dialog); } break; case ACTION_ACCOUNT_EDIT: { Transaction *active_txn; DB( g_print(" - edit\n") ); active_txn = list_txn_get_active_transaction(GTK_TREE_VIEW(data->LV_ope)); if(active_txn) { Transaction *old_txn, *new_txn; old_txn = da_transaction_clone (active_txn); new_txn = active_txn; result = deftransaction_external_edit(GTK_WINDOW(data->window), old_txn, new_txn); if(result == GTK_RESPONSE_ACCEPT) { //manage current window display stuff //#1270687: sort if date changed if(old_txn->date != new_txn->date) data->do_sort = TRUE; // txn changed of account //TODO: maybe this should move to deftransaction_external_edit if( data->acc != NULL && (new_txn->kacc != data->acc->key) ) { Account *nacc; delete_active_transaction(GTK_TREE_VIEW(data->LV_ope)); //#1667501 update target account window is open nacc = da_acc_get(new_txn->kacc); if( nacc != NULL && nacc->window != NULL ) { DB( g_print("- account %d changed and window is open\n", nacc->key) ); if( GTK_IS_WINDOW(nacc->window) ) { register_panel_add_single_transaction(nacc->window, new_txn); register_panel_update(GTK_WIDGET(nacc->window), GINT_TO_POINTER(UF_BALANCE)); } } } //#1812470 txn is xfer update target account window is open if( (old_txn->paymode == PAYMODE_INTXFER) && (old_txn->amount != new_txn->amount) ) { Account *nacc = da_acc_get(new_txn->kxferacc); if( nacc != NULL && nacc->window != NULL ) { if( GTK_IS_WINDOW(nacc->window) ) { register_panel_update(GTK_WIDGET(nacc->window), GINT_TO_POINTER(UF_BALANCE)); } } } //da_transaction_copy(new_txn, old_txn); register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); transaction_changed(new_txn); GLOBALS->changes_count++; } da_transaction_free (old_txn); } } break; case ACTION_ACCOUNT_DELETE: { GtkTreeModel *model; GList *selection, *list; gint result; DB( g_print(" - delete\n") ); result = ui_dialog_msg_confirm_alert( GTK_WINDOW(data->window), NULL, _("Do you want to delete\neach of the selected transaction ?"), _("_Delete") ); if(result == GTK_RESPONSE_OK) { model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); selection = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)), &model); list = g_list_last(selection); while(list != NULL) { Transaction *entry; GtkTreeIter iter; gtk_tree_model_get_iter(model, &iter, list->data); gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &entry, -1); DB( g_print(" delete %s %.2f\n", entry->memo, entry->amount) ); //#1716181 also remove from the ptr_array (quickfilter) g_ptr_array_remove(data->gpatxn, (gpointer)entry); // 1) remove visible current and potential xfer gtk_list_store_remove(GTK_LIST_STORE(model), &iter); if(data->showall && entry->paymode == PAYMODE_INTXFER) { Transaction *child = transaction_xfer_child_strong_get(entry); if( child ) { txn_list_remove_by_value(model, child); //#1716181 also remove from the ptr_array (quickfilter) g_ptr_array_remove(data->gpatxn, (gpointer)child); } } // 2) remove datamodel transaction_remove(entry); GLOBALS->changes_count++; list = g_list_previous(list); } g_list_foreach(selection, (GFunc)gtk_tree_path_free, NULL); g_list_free(selection); register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); } } break; //none case ACTION_ACCOUNT_NONE: { GtkTreeSelection *selection; gint count, result; count = txn_list_get_count_reconciled(GTK_TREE_VIEW(data->LV_ope)); if(count > 0 ) { result = ui_dialog_msg_confirm_alert( GTK_WINDOW(data->window), _("Are you sure you want to change the status to None?"), _("Some transaction in your selection are already Reconciled."), _("_Change") ); } else result = GTK_RESPONSE_OK; if( result == GTK_RESPONSE_OK ) { selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)); gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func, GINT_TO_POINTER(TXN_STATUS_NONE)); DB( g_print(" - none\n") ); gtk_widget_queue_draw (data->LV_ope); //gtk_widget_queue_resize (data->LV_acc); register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); GLOBALS->changes_count++; } } break; //clear case ACTION_ACCOUNT_CLEAR: { GtkTreeSelection *selection; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)); gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func, GINT_TO_POINTER(TXN_STATUS_CLEARED)); DB( g_print(" - clear\n") ); gtk_widget_queue_draw (data->LV_ope); //gtk_widget_queue_resize (data->LV_acc); register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); GLOBALS->changes_count++; } break; //reconcile case ACTION_ACCOUNT_RECONCILE: { GtkTreeSelection *selection; gint count, result; count = txn_list_get_count_reconciled(GTK_TREE_VIEW(data->LV_ope)); if(count > 0 ) { result = ui_dialog_msg_confirm_alert( GTK_WINDOW(data->window), _("Are you sure you want to toggle the status Reconciled?"), _("Some transaction in your selection are already Reconciled."), _("_Toggle") ); } else result = GTK_RESPONSE_OK; if( result == GTK_RESPONSE_OK ) { selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)); gtk_tree_selection_selected_foreach(selection, (GtkTreeSelectionForeachFunc)status_selected_foreach_func, GINT_TO_POINTER(TXN_STATUS_RECONCILED)); DB( g_print(" - reconcile\n") ); gtk_widget_queue_draw (data->LV_ope); //gtk_widget_queue_resize (data->LV_acc); register_panel_update(widget, GINT_TO_POINTER(UF_BALANCE)); GLOBALS->changes_count++; } } break; case ACTION_ACCOUNT_FILTER: { if(ui_flt_manage_dialog_new(GTK_WINDOW(data->window), data->filter, data->showall, TRUE) != GTK_RESPONSE_REJECT) { register_panel_collect_filtered_txn(data->LV_ope, TRUE); register_panel_listview_populate(data->LV_ope); register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_SENSITIVE+UF_BALANCE)); g_signal_handler_block(data->CY_range, data->handler_id[HID_RANGE]); hbtk_combo_box_set_active_id(GTK_COMBO_BOX_TEXT(data->CY_range), FLT_RANGE_OTHER); g_signal_handler_unblock(data->CY_range, data->handler_id[HID_RANGE]); } } break; } //refresh main if( GLOBALS->changes_count > changes ) ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void register_panel_toggle_minor(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; DB( g_print("\n[account] toggle\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); register_panel_update(data->LV_ope, GINT_TO_POINTER(UF_BALANCE)); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_ope)); } static void register_panel_selection(GtkTreeSelection *treeselection, gpointer user_data) { DB( g_print("\n[account] selection changed cb\n") ); register_panel_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); } static void register_panel_update(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; GtkTreeSelection *selection; gint flags = GPOINTER_TO_INT(user_data); gint count = 0; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //data = INST_DATA(widget); DB( g_print("\n[account %d] update\n", data->acc != NULL ? (gint)data->acc->key : -1) ); GLOBALS->minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor)); /* set window title */ if(flags & UF_TITLE) { DB( g_print(" - UF_TITLE\n") ); } /* update disabled things */ if(flags & UF_SENSITIVE) { gboolean sensitive; DB( g_print(" - UF_SENSITIVE\n") ); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)); count = gtk_tree_selection_count_selected_rows(selection); DB( g_print(" - count = %d\n", count) ); //showall part sensitive = !data->showall; gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportPDF"), sensitive); gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportQIF"), sensitive); gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/AccountMenu/ExportCSV"), sensitive); gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/ChkIntXfer"), sensitive); gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/DuplicateMark"), sensitive); //gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/DuplicateClear"), sensitive); //5.3.1 if closed account : disable any change sensitive = TRUE; if( (data->showall == FALSE) && (data->acc->flags & AF_CLOSED) ) sensitive = FALSE; gtk_widget_set_sensitive (data->TB_bar, sensitive); //gtk_widget_set_sensitive (data->TB_tools, sensitive); gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/ToolBar/Assign"), data->showall ? FALSE : sensitive); gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/TxnMenu"), sensitive); gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/ToolsMenu"), sensitive); // multiple: disable inherit, edit sensitive = (count != 1 ) ? FALSE : TRUE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Inherit"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Edit"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Inherit"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Edit"), sensitive); // single: disable multiedit sensitive = (count <= 1 ) ? FALSE : TRUE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/MultiEdit"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/MultiEdit"), sensitive); // no selection: disable reconcile, delete sensitive = (count > 0 ) ? TRUE : FALSE; gtk_widget_set_sensitive(gtk_ui_manager_get_widget(data->ui, "/MenuBar/TxnMenu/TxnStatusMenu"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Delete"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/MenuBar/TxnMenu/Template"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Delete"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Cleared"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Reconciled"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->ui, "/TxnBar/Template"), sensitive); // euro convert sensitive = (data->showall == TRUE) ? FALSE : PREFS->euro_active; if( (data->acc != NULL) && currency_is_euro(data->acc->kcur) ) sensitive = FALSE; gtk_action_set_visible(gtk_ui_manager_get_action(data->ui, "/MenuBar/ToolsMenu/ConvToEuro"), sensitive); } /* update toolbar & list */ if(flags & UF_VISUAL) { DB( g_print(" - UF_VISUAL\n") ); if(PREFS->toolbar_style == 0) gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar)); else gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1); //minor ? if( PREFS->euro_active ) { gtk_widget_show(data->CM_minor); } else { gtk_widget_hide(data->CM_minor); } } /* update balances */ if(flags & UF_BALANCE) { DB( g_print(" - UF_BALANCE\n") ); if(data->showall == FALSE) { Account *acc = data->acc; register_panel_balance_refresh(widget); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[0]), acc->bal_bank, acc->kcur, GLOBALS->minor); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[1]), acc->bal_today, acc->kcur, GLOBALS->minor); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[2]), acc->bal_future, acc->kcur, GLOBALS->minor); } else { GList *lst_acc, *lnk_acc; gdouble bank, today, future; bank = today = future = 0.0; lst_acc = g_hash_table_get_values(GLOBALS->h_acc); lnk_acc = g_list_first(lst_acc); while (lnk_acc != NULL) { Account *acc = lnk_acc->data; bank += hb_amount_base(acc->bal_bank, acc->kcur); today += hb_amount_base(acc->bal_today, acc->kcur); future += hb_amount_base(acc->bal_future, acc->kcur); lnk_acc = g_list_next(lnk_acc); } g_list_free(lst_acc); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[0]), bank, GLOBALS->kcur, GLOBALS->minor); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[1]), today, GLOBALS->kcur, GLOBALS->minor); hb_label_set_colvalue(GTK_LABEL(data->TX_balance[2]), future, GLOBALS->kcur, GLOBALS->minor); } ui_hub_account_populate(GLOBALS->mainwindow, NULL); } /* update fltinfo */ DB( g_print(" - statusbar\n") ); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_ope)); count = gtk_tree_selection_count_selected_rows(selection); DB( g_print(" - nb selected = %d\n", count) ); /* if more than one ope selected, we make a sum to display to the user */ gdouble opeexp = 0.0; gdouble opeinc = 0.0; gchar buf1[64]; gchar buf2[64]; gchar buf3[64]; gchar fbufavg[64]; guint32 kcur; kcur = (data->showall == TRUE) ? GLOBALS->kcur : data->acc->kcur; if( count >= 1 ) { GList *list, *tmplist; GtkTreeModel *model; GtkTreeIter iter; model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope)); list = gtk_tree_selection_get_selected_rows(selection, &model); tmplist = g_list_first(list); while (tmplist != NULL) { Transaction *item; gtk_tree_model_get_iter(model, &iter, tmplist->data); gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &item, -1); if( data->showall == FALSE ) { if( item->flags & OF_INCOME ) opeinc += item->amount; else opeexp += item->amount; } else { if( item->flags & OF_INCOME ) opeinc += hb_amount_base(item->amount, item->kcur); else opeexp += hb_amount_base(item->amount, item->kcur); } DB( g_print(" - %s, %.2f\n", item->memo, item->amount ) ); tmplist = g_list_next(tmplist); } g_list_free(list); DB( g_print(" %f - %f = %f\n", opeinc, opeexp, opeinc + opeexp) ); hb_strfmon(buf1, 64-1, opeinc, kcur, GLOBALS->minor); hb_strfmon(buf2, 64-1, -opeexp, kcur, GLOBALS->minor); hb_strfmon(buf3, 64-1, opeinc + opeexp, kcur, GLOBALS->minor); hb_strfmon(fbufavg, 64-1, (opeinc + opeexp) / count, kcur, GLOBALS->minor); } gchar *msg; if( count <= 1 ) { msg = g_strdup_printf(_("%d transactions"), data->total); } else msg = g_strdup_printf(_("%d transactions, %d selected, avg: %s, sum: %s (%s - %s)"), data->total, count, fbufavg, buf3, buf1, buf2); gtk_label_set_markup(GTK_LABEL(data->TX_selection), msg); g_free (msg); } void register_panel_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { struct register_panel_data *data; GtkTreeModel *model; GtkTreeIter iter; gint col_id, count; Transaction *ope; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GTK_WIDGET(treeview), GTK_TYPE_WINDOW)), "inst_data"); //5.3.1 if closed account : disable any change if( (data->showall == FALSE) && (data->acc->flags & AF_CLOSED) ) return; col_id = gtk_tree_view_column_get_sort_column_id (col); count = gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(treeview)); model = gtk_tree_view_get_model(treeview); //get transaction double clicked to initiate the widget gtk_tree_model_get_iter(model, &iter, path); gtk_tree_model_get(model, &iter, MODEL_TXN_POINTER, &ope, -1); DB( g_print ("%d rows been double-clicked on column=%d! ope=%s\n", count, col_id, ope->memo) ); if( count == 1) { register_panel_action(GTK_WIDGET(treeview), GINT_TO_POINTER(ACTION_ACCOUNT_EDIT)); } else { if( data->showall == FALSE ) { if(col_id >= LST_DSPOPE_DATE && col_id != LST_DSPOPE_BALANCE) { register_panel_edit_multiple (data->window, ope, col_id, data); } } } } /* static gint listview_context_cb (GtkWidget *widget, GdkEventButton *event, GtkWidget *menu) { if (event->button == 3) { if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (treeview), (gint) event->x, (gint) event->y, &path, NULL, NULL, NULL)) { gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, NULL, FALSE); gtk_tree_path_free (path); } gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); // On indique à l'appelant que l'on a géré cet événement. return TRUE; } // On indique à l'appelant que l'on n'a pas géré cet événement. return FALSE; } */ /* ** populate the account window */ void register_panel_window_init(GtkWidget *widget, gpointer user_data) { struct register_panel_data *data; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); DB( g_print("\n[account] init window\n") ); if( data->showall == TRUE ) { gtk_label_set_text (GTK_LABEL(data->LB_name), _("All transactions")); hb_widget_visible (data->IM_closed, FALSE); } else { gtk_label_set_text (GTK_LABEL(data->LB_name), data->acc->name); hb_widget_visible (data->IM_closed, (data->acc->flags & AF_CLOSED) ? TRUE : FALSE); DB( g_print(" - sort transactions\n") ); da_transaction_queue_sort(data->acc->txn_queue); } list_txn_set_column_acc_visible(GTK_TREE_VIEW(data->LV_ope), data->showall); //DB( g_print(" mindate=%d, maxdate=%d %x\n", data->filter->mindate,data->filter->maxdate) ); DB( g_print(" - call update visual\n") ); register_panel_update(widget, GINT_TO_POINTER(UF_VISUAL|UF_SENSITIVE)); DB( g_print(" - set range or populate+update sensitive+balance\n") ); register_panel_cb_filter_reset(widget, user_data); } /* ** */ static gboolean register_panel_getgeometry(GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { //struct register_panel_data *data = user_data; struct WinGeometry *wg; DB( g_print("\n[account] get geometry\n") ); //store position and size wg = &PREFS->acc_wg; gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t); gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h); GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget)); GdkWindowState state = gdk_window_get_state(gdk_window); wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0; DB( g_print(" window: l=%d, t=%d, w=%d, h=%d s=%d, state=%d\n", wg->l, wg->t, wg->w, wg->h, wg->s, state & GDK_WINDOW_STATE_MAXIMIZED) ); return FALSE; } /* ** */ static gboolean register_panel_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data) { struct register_panel_data *data = user_data; data = g_object_get_data(G_OBJECT(widget), "inst_data"); DB( g_print("\n[account] delete-event\n") ); register_panel_getgeometry(data->window, NULL, data); return FALSE; } /* Another callback */ static gboolean register_panel_destroy( GtkWidget *widget, gpointer user_data ) { struct register_panel_data *data; data = g_object_get_data(G_OBJECT(widget), "inst_data"); DB( g_print ("\n[account] destroy event occurred\n") ); //enable define windows GLOBALS->define_off--; /* unset transaction edit mutex */ if(data->showall == FALSE) data->acc->window = NULL; else GLOBALS->alltxnwindow = NULL; /* free title and filter */ DB( g_print(" user_data=%p to be free\n", user_data) ); g_free(data->wintitle); if(data->gpatxn != NULL) g_ptr_array_free (data->gpatxn, TRUE); da_flt_free(data->filter); g_free(data); //our global list has changed, so update the treeview ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL)); return FALSE; } static void quick_search_text_changed_cb (GtkWidget *widget, gpointer user_data) { struct register_panel_data *data = user_data; register_panel_listview_populate (data->window); } static GtkActionEntry entries[] = { /* name, icon-name, label */ { "AccountMenu" , NULL, N_("A_ccount"), NULL, NULL, NULL }, { "TxnMenu" , NULL, N_("Transacti_on"), NULL, NULL, NULL }, { "TxnStatusMenu", NULL, N_("_Status"), NULL, NULL, NULL }, { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL }, /* name, icon-name, label, accelerator, tooltip */ { "ExportPDF" , NULL , N_("Export as PDF..."), NULL, N_("Export to a PDF file"), G_CALLBACK (register_panel_action_exportpdf) }, { "ExportQIF" , NULL , N_("Export QIF..."), NULL, N_("Export as QIF"), G_CALLBACK (register_panel_action_exportqif) }, { "ExportCSV" , NULL , N_("Export CSV..."), NULL, N_("Export as CSV"), G_CALLBACK (register_panel_action_exportcsv) }, { "Close" , ICONNAME_CLOSE , N_("_Close") , "W", N_("Close the current account"), G_CALLBACK (register_panel_action_close) }, { "Add" , ICONNAME_HB_OPE_ADD , N_("_Add..."), NULL, N_("Add a new transaction"), G_CALLBACK (register_panel_action_add) }, { "Inherit" , ICONNAME_HB_OPE_HERIT , N_("_Inherit..."), NULL, N_("Inherit from the active transaction"), G_CALLBACK (register_panel_action_inherit) }, { "Edit" , ICONNAME_HB_OPE_EDIT , N_("_Edit..."), NULL, N_("Edit the active transaction"), G_CALLBACK (register_panel_action_edit) }, { "None" , NULL , N_("_None"), "N", N_("Toggle none for selected transaction(s)"), G_CALLBACK (register_panel_action_none) }, { "Cleared" , ICONNAME_HB_OPE_CLEARED , N_("_Cleared"), "C", N_("Toggle cleared for selected transaction(s)"), G_CALLBACK (register_panel_action_clear) }, { "Reconciled" , ICONNAME_HB_OPE_RECONCILED, N_("_Reconciled"), "R", N_("Toggle reconciled for selected transaction(s)"), G_CALLBACK (register_panel_action_reconcile) }, { "MultiEdit" , ICONNAME_HB_OPE_MULTIEDIT , N_("_Multiple Edit..."), NULL, N_("Edit multiple transaction"), G_CALLBACK (register_panel_action_multiedit) }, { "Template" , ICONNAME_CONVERT , N_("Create template..."), NULL, N_("Create template"), G_CALLBACK (register_panel_action_createtemplate) }, { "Delete" , ICONNAME_HB_OPE_DELETE , N_("_Delete..."), NULL, N_("Delete selected transaction(s)"), G_CALLBACK (register_panel_action_remove) }, { "DuplicateMark", NULL , N_("Mark duplicate..."), NULL, NULL, G_CALLBACK (register_panel_action_duplicate_mark) }, // { "DuplicateClear", NULL , N_("Unmark duplicate"), NULL, NULL, G_CALLBACK (register_panel_action_duplicate_unmark) }, { "ChkIntXfer" , NULL , N_("Check internal xfer"), NULL, NULL, G_CALLBACK (register_panel_action_check_internal_xfer) }, { "Assign" , ICONNAME_HB_ASSIGN_RUN , N_("Auto. assignments"), NULL, N_("Run automatic assignments"), G_CALLBACK (register_panel_action_assign) }, { "Filter" , ICONNAME_HB_FILTER , N_("_Filter..."), NULL, N_("Open the list filter"), G_CALLBACK (register_panel_action_editfilter) }, { "ConvToEuro" , NULL , N_("Convert to Euro..."), NULL, N_("Convert this account to Euro currency"), G_CALLBACK (register_panel_action_converttoeuro) }, }; static guint n_entries = G_N_ELEMENTS (entries); static const gchar *ui_info = "" "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " //" " " " " " " " " " " " " " " " " " "" "" " " " " " " " " " " " " " " " " " " " " "" "" " " " " "" ""; /* * if accnum = 0 or acc is null : show all account */ GtkWidget *register_panel_window_new(Account *acc) { struct register_panel_data *data; struct WinGeometry *wg; GtkWidget *window, *mainbox, *table, *sw, *bar; GtkWidget *treeview, *label, *widget, *image; //GtkWidget *menu, *menu_items; GtkUIManager *ui; GtkActionGroup *actions; GtkAction *action; GError *error = NULL; DB( g_print("\n[account] create_register_panel_window\n") ); data = g_malloc0(sizeof(struct register_panel_data)); if(!data) return NULL; //disable define windows GLOBALS->define_off++; ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE)); /* create window, etc */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); data->window = window; //store our window private data g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data); DB( g_print(" - new window=%p, inst_data=%p\n", window, data) ); data->acc = acc; data->showall = (acc != NULL) ? FALSE : TRUE; if(data->showall == FALSE) { data->acc->window = GTK_WINDOW(window); if( data->acc->flags & AF_CLOSED ) data->wintitle = g_strdup_printf("%s %s - HomeBank", data->acc->name, _("(closed)")); else data->wintitle = g_strdup_printf("%s - HomeBank", data->acc->name); } else { GLOBALS->alltxnwindow = window; data->wintitle = g_strdup_printf(_("%s - HomeBank"), _("All transactions")); } gtk_window_set_title (GTK_WINDOW (window), data->wintitle); gtk_window_set_icon_name(GTK_WINDOW (window), ICONNAME_HB_OPE_SHOW ); // connect our dispose function g_signal_connect (window, "delete-event", G_CALLBACK (register_panel_dispose), (gpointer)data); // connect our dispose function g_signal_connect (window, "destroy", G_CALLBACK (register_panel_destroy), (gpointer)data); // connect our dispose function //g_signal_connect (window, "configure-event", // G_CALLBACK (register_panel_getgeometry), (gpointer)data); #if UI == 1 //start test uimanager actions = gtk_action_group_new ("Account"); //as we use gettext gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE); DB( g_print(" - add actions: %p user_data: %p\n", actions, data) ); gtk_action_group_add_actions (actions, entries, n_entries, data); /* set which action should have priority in the toolbar */ action = gtk_action_group_get_action(actions, "Add"); g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL); action = gtk_action_group_get_action(actions, "Inherit"); g_object_set(action, "is_important", TRUE, "short_label", _("Inherit"), NULL); action = gtk_action_group_get_action(actions, "Edit"); g_object_set(action, "is_important", TRUE, "short_label", _("Edit"), NULL); action = gtk_action_group_get_action(actions, "Filter"); g_object_set(action, "is_important", TRUE, "short_label", _("Filter"), NULL); //action = gtk_action_group_get_action(actions, "Reconciled"); //g_object_set(action, "is_important", TRUE, "short_label", _("Reconciled"), NULL); ui = gtk_ui_manager_new (); DB( g_print(" - insert action group:\n") ); gtk_ui_manager_insert_action_group (ui, actions, 0); GtkAccelGroup *ag = gtk_ui_manager_get_accel_group (ui); DB( g_print(" - add_accel_group actions=%p, ui=%p, ag=%p\n", actions, ui, ag) ); gtk_window_add_accel_group (GTK_WINDOW (window), ag); DB( g_print(" - add ui from string:\n") ); if (!gtk_ui_manager_add_ui_from_string (ui, ui_info, -1, &error)) { g_message ("building menus failed: %s", error->message); g_error_free (error); } data->ui = ui; data->actions = actions; #endif mainbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); //gtk_container_set_border_width(GTK_CONTAINER(mainbox), SPACING_SMALL); gtk_container_add (GTK_CONTAINER (window), mainbox); widget = gtk_ui_manager_get_widget (ui, "/MenuBar"); //data->menu = widget; gtk_box_pack_start (GTK_BOX (mainbox), widget, FALSE, FALSE, 0); // info bar for duplicate bar = gtk_info_bar_new_with_buttons (_("_Refresh"), HB_RESPONSE_REFRESH, NULL); data->IB_duplicate = bar; gtk_box_pack_start (GTK_BOX (mainbox), bar, FALSE, FALSE, 0); gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING); gtk_info_bar_set_show_close_button (GTK_INFO_BAR (bar), TRUE); label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_WARNING"); data->LB_duplicate = label; gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); gtk_label_set_xalign (GTK_LABEL (label), 0); gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0); widget = make_numeric(NULL, 0, HB_DATE_MAX_GAP); data->NB_txn_daygap = widget; gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), widget, FALSE, FALSE, 0); 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_container_set_border_width (GTK_CONTAINER(table), SPACING_SMALL); gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0); // account name (+ balance) widget = gtk_image_new_from_icon_name (ICONNAME_CHANGES_PREVENT, GTK_ICON_SIZE_BUTTON); data->IM_closed = widget; gtk_grid_attach (GTK_GRID(table), widget, 0, 0, 1, 1); label = gtk_label_new(NULL); data->LB_name = label; gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_LARGE, -1); gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_hexpand (label, TRUE); gtk_grid_attach (GTK_GRID(table), label, 1, 0, 1, 1); /* balances area */ label = gtk_label_new(_("Bank:")); gtk_grid_attach (GTK_GRID(table), label, 3, 0, 1, 1); widget = gtk_label_new(NULL); data->TX_balance[0] = widget; gtk_grid_attach (GTK_GRID(table), widget, 4, 0, 1, 1); label = gtk_label_new(_("Today:")); gtk_grid_attach (GTK_GRID(table), label, 5, 0, 1, 1); widget = gtk_label_new(NULL); data->TX_balance[1] = widget; gtk_grid_attach (GTK_GRID(table), widget, 6, 0, 1, 1); label = gtk_label_new(_("Future:")); gtk_grid_attach (GTK_GRID(table), label, 7, 0, 1, 1); widget = gtk_label_new(NULL); data->TX_balance[2] = widget; gtk_grid_attach (GTK_GRID(table), widget, 8, 0, 1, 1); //quick search widget = make_search (); data->ST_search = widget; gtk_widget_set_size_request(widget, HB_MINWIDTH_SEARCH, -1); gtk_grid_attach (GTK_GRID(table), widget, 9, 0, 1, 1); data->handler_id[HID_SEARCH] = g_signal_connect (data->ST_search, "search-changed", G_CALLBACK (quick_search_text_changed_cb), data); // windows interior 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_container_set_border_width (GTK_CONTAINER(table), SPACING_SMALL); gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0); label = make_label_widget(_("_Range:")); gtk_grid_attach (GTK_GRID(table), label, 0, 0, 1, 1); data->CY_range = make_daterange(label, DATE_RANGE_CUSTOM_SHOW); gtk_grid_attach (GTK_GRID(table), data->CY_range, 1, 0, 1, 1); widget = gtk_toggle_button_new(); image = gtk_image_new_from_icon_name (ICONNAME_HB_OPE_FUTURE, GTK_ICON_SIZE_MENU); g_object_set (widget, "image", image, NULL); gtk_widget_set_tooltip_text (widget, _("Toggle show future transaction")); data->CM_future = widget; gtk_grid_attach (GTK_GRID(table), widget, 2, 0, 1, 1); label = make_label_widget(_("_Type:")); gtk_grid_attach (GTK_GRID(table), label, 3, 0, 1, 1); data->CY_type = make_cycle(label, CYA_FLT_TYPE); gtk_grid_attach (GTK_GRID(table), data->CY_type, 4, 0, 1, 1); label = make_label_widget(_("_Status:")); gtk_grid_attach (GTK_GRID(table), label, 5, 0, 1, 1); data->CY_status = make_cycle(label, CYA_FLT_STATUS); gtk_grid_attach (GTK_GRID(table), data->CY_status, 6, 0, 1, 1); //widget = gtk_button_new_with_mnemonic (_("Reset _filters")); widget = gtk_button_new_with_mnemonic (_("_Reset")); data->BT_reset = widget; gtk_grid_attach (GTK_GRID(table), widget, 7, 0, 1, 1); //TRANSLATORS: this is for Euro specific users, a toggle to display in 'Minor' currency widget = gtk_check_button_new_with_mnemonic (_("Euro _minor")); data->CM_minor = widget; gtk_grid_attach (GTK_GRID(table), widget, 8, 0, 1, 1); label = make_label(NULL, 0.0, 0.5); data->TX_selection = label; gtk_widget_set_halign (label, GTK_ALIGN_END); gtk_widget_set_hexpand (label, TRUE); gtk_grid_attach (GTK_GRID(table), label, 10, 0, 1, 1); /* label = make_label_widget(_("_Month:")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); data->CY_month = make_cycle(label, CYA_SELECT); gtk_box_pack_start (GTK_BOX (hbox), data->CY_month, FALSE, FALSE, 0); label = make_label_widget(_("_Year:"),); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); data->NB_year = make_year(label); gtk_box_pack_start (GTK_BOX (hbox), data->NB_year, FALSE, FALSE, 0); */ //list sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); treeview = (GtkWidget *)create_list_transaction(LIST_TXN_TYPE_BOOK, PREFS->lst_ope_columns); data->LV_ope = treeview; gtk_container_add (GTK_CONTAINER (sw), treeview); gtk_box_pack_start (GTK_BOX (mainbox), sw, TRUE, TRUE, 0); list_txn_set_save_column_width(GTK_TREE_VIEW(treeview), TRUE); /* toolbars */ table = gtk_grid_new(); gtk_box_pack_start (GTK_BOX (mainbox), table, FALSE, FALSE, 0); widget = gtk_ui_manager_get_widget (ui, "/TxnBar"); data->TB_bar = widget; //gtk_widget_set_halign (widget, GTK_ALIGN_START); //gtk_style_context_add_class (gtk_widget_get_style_context (widget), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_widget_set_hexpand (widget, TRUE); gtk_grid_attach (GTK_GRID(table), widget, 0, 0, 1, 1); widget = gtk_ui_manager_get_widget (ui, "/ToolBar"); data->TB_tools = widget; //gtk_widget_set_halign (widget, GTK_ALIGN_END); //gtk_style_context_add_class (gtk_widget_get_style_context (widget), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_widget_set_hexpand (widget, TRUE); gtk_grid_attach (GTK_GRID(table), widget, 2, 0, 1, 1); #ifdef G_OS_WIN32 if(PREFS->toolbar_style == 0) { gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_bar)); gtk_toolbar_unset_style(GTK_TOOLBAR(data->TB_tools)); } else { gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_bar), PREFS->toolbar_style-1); gtk_toolbar_set_style(GTK_TOOLBAR(data->TB_tools), PREFS->toolbar_style-1); } #endif //todo: should move this //setup g_object_set_data(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_ope))), "minor", data->CM_minor); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_future), (PREFS->date_future_nbdays > 0) ? TRUE : FALSE ); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_minor), GLOBALS->minor); gtk_widget_grab_focus(GTK_WIDGET(data->LV_ope)); // connect signals g_signal_connect (data->IB_duplicate , "response", G_CALLBACK (register_panel_cb_bar_duplicate_response), NULL); data->handler_id[HID_RANGE] = g_signal_connect (data->CY_range , "changed", G_CALLBACK (register_panel_cb_filter_daterange), NULL); data->handler_id[HID_TYPE] = g_signal_connect (data->CY_type , "changed", G_CALLBACK (register_panel_cb_filter_type), NULL); data->handler_id[HID_STATUS] = g_signal_connect (data->CY_status, "changed", G_CALLBACK (register_panel_cb_filter_status), NULL); g_signal_connect (data->CM_future, "toggled", G_CALLBACK (register_panel_cb_filter_daterange), NULL); g_signal_connect (data->BT_reset , "clicked", G_CALLBACK (register_panel_cb_filter_reset), NULL); g_signal_connect (data->CM_minor , "toggled", G_CALLBACK (register_panel_toggle_minor), NULL); //g_signal_connect (GTK_TREE_VIEW(treeview), "cursor-changed", G_CALLBACK (register_panel_update), (gpointer)2); g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)), "changed", G_CALLBACK (register_panel_selection), NULL); g_signal_connect (GTK_TREE_VIEW(treeview), "row-activated", G_CALLBACK (register_panel_onRowActivated), GINT_TO_POINTER(2)); //todo: test context menu /* menu = gtk_menu_new(); menu_items = gtk_ui_manager_get_widget (ui, "/MenuBar/TxnMenu/Add"); menu_items = gtk_menu_item_new_with_label ("test"); gtk_widget_show(menu_items); gtk_menu_shell_append (GTK_MENU (menu), menu_items); //todo: debug test g_signal_connect (treeview, "button-press-event", G_CALLBACK (listview_context_cb), // todo: here is not a GtkMenu but GtkImageMenuItem... menu //gtk_ui_manager_get_widget (ui, "/MenuBar") ); */ //setup, init and show window wg = &PREFS->acc_wg; if(wg->s == 0) { gtk_window_move(GTK_WINDOW(window), wg->l, wg->t); gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h); } else gtk_window_maximize(GTK_WINDOW(window)); gtk_widget_show_all (window); gtk_widget_hide(data->IB_duplicate); /* hide showfuture */ hb_widget_visible (data->CM_future, PREFS->date_future_nbdays > 0 ? TRUE : FALSE); /* make sure splash is up */ while (gtk_events_pending ()) gtk_main_iteration (); /* setup to moove later */ data->filter = da_flt_malloc(); DB( g_print(" - filter ok %p\n", data->filter) ); return window; }