From: Charles McGarvey Date: Thu, 25 Apr 2019 05:07:35 +0000 (-0600) Subject: Merge branch 'master' into ext-perl X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=0e1e5f856e9ab5faa63fd822354781baccccbcd9;p=chaz%2Fhomebank Merge branch 'master' into ext-perl --- 0e1e5f856e9ab5faa63fd822354781baccccbcd9 diff --cc src/Makefile.am index 20da8f1,9e4fd20..7acfc87 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -121,21 -128,13 +129,23 @@@ homebank_SOURCES = ui-transaction.h \ ui-txn-multi.c \ ui-txn-multi.h \ + ui-widgets-data.c \ ui-widgets.c \ - ui-widgets.h + ui-widgets.h \ + refcount.h \ + ext.c \ + ext.h \ + ext-value.c \ + ext-value.h \ + ext-native.c \ + ext-perl.xs + +EXTRA_homebank_DEPENDENCIES = $(PERL_OBJS) + homebank_LDADD = $(DEPS_LIBS) \ - $(LIBSOUP_LIBS) + $(LIBSOUP_LIBS) \ + $(PERL_OBJS) AM_CPPFLAGS = \ $(DEPS_CFLAGS) \ diff --cc src/dsp-mainwindow.c index c733f4c,1f53410..0b21f9d --- a/src/dsp-mainwindow.c +++ b/src/dsp-mainwindow.c @@@ -20,15 -20,16 +20,18 @@@ #include "homebank.h" - #include "dsp_mainwindow.h" + #include "dsp-mainwindow.h" +#include "ext.h" + - #include "list_account.h" - #include "list_upcoming.h" - #include "list_topspending.h" + #include "list-account.h" - #include "dsp_account.h" + #include "hub-account.h" + #include "hub-scheduled.h" + #include "hub-spending.h" + #include "hub-transaction.h" + + #include "dsp-account.h" #include "ui-assist-import.h" #include "ui-assist-start.h" #include "ui-account.h" @@@ -149,26 -149,9 +153,10 @@@ void ui_mainwindow_update(GtkWidget *wi void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data); void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); - static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data); - - static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data); - void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data); - void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); +static void ui_mainwindow_showprefs(gint page); - static void ui_panel_accounts_setup(struct hbfile_data *data); - - extern gchar *CYA_ACC_TYPE[]; - - gchar *CYA_CATSUBCAT[] = { - N_("Category"), - N_("Subcategory"), - NULL - }; - - static GtkActionEntry entries[] = { /* name, icon-name, label */ @@@ -200,11 -185,12 +191,12 @@@ { "Quit" , ICONNAME_QUIT , N_("_Quit") , "Q", N_("Quit HomeBank"), G_CALLBACK (ui_mainwindow_action_quit) }, /* Exchange */ - { "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, - { "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, - { "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, - - { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export QIF file...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) }, + { "Import" , ICONNAME_HB_FILE_IMPORT , N_("Import...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, + //{ "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, + //{ "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, + //{ "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, - ++ + { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export as QIF...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) }, /* EditMenu */ { "Preferences", ICONNAME_PREFERENCES , N_("Preferences..."), NULL, N_("Configure HomeBank"), G_CALLBACK (ui_mainwindow_action_preferences) }, @@@ -235,10 -223,7 +229,10 @@@ { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) }, { "FileStats" , NULL , N_("File statistics...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_file_statistics) }, { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) }, -- ++ + /* Plugins */ + { "PluginPreferences", "prf-plugins", N_("_Plugins..."), "U", N_("Configure plugin preferences"), G_CALLBACK(ui_mainwindow_action_pluginprefs) }, + /* HelpMenu */ { "Contents" , ICONNAME_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) }, { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) }, @@@ -399,7 -383,7 +398,7 @@@ gint result title = g_strdup_printf ( _("Revert unsaved changes to file '%s'?"), basename); -- secondtext = ++ secondtext = _("- Changes made to the file will be permanently lost\n" "- File will be reloaded from the last save (.xhb~)"); @@@ -416,7 -400,7 +415,7 @@@ if( result == GTK_RESPONSE_OK ) { DB( g_print(" - should revert\n") ); -- ++ hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~")); ui_mainwindow_open_internal(widget, NULL); hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); @@@ -431,7 -415,7 +430,7 @@@ activate_url (GtkAboutDialog *about gpointer data) { DB( g_print("activate url %s\n", link) ); -- ++ homebank_util_url_show (link); } @@@ -471,18 -454,18 +470,18 @@@ gchar *version gtk_get_major_version (), gtk_get_minor_version (), gtk_get_micro_version ()); -- ++ dialog = gtk_about_dialog_new(); gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(GLOBALS->mainwindow)); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); -- ++ gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), g_get_application_name ()); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Free, easy, personal accounting for everyone")); gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0); -- ++ //gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(dialog), ); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://homebank.free.fr"); gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Visit the HomeBank website"); @@@ -498,7 -481,7 +497,7 @@@ gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf); g_object_unref (pixbuf); } -- ++ gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors); gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artists); //gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(dialog), ); @@@ -511,7 -494,7 +510,7 @@@ gtk_widget_destroy (dialog); g_free(version); -- ++ } @@@ -602,7 -584,7 +606,7 @@@ gchar *secondtext title = _("Are you sure you want to anonymize the file?"); -- secondtext = ++ secondtext = _("Proceeding will anonymize any text, \n" "like 'account x', 'payee y', 'memo z', ..."); @@@ -615,7 -597,7 +619,7 @@@ //#1707201 //if( result == GTK_RESPONSE_CANCEL ) -- // return; ++ // return; if( result == GTK_RESPONSE_OK ) { hbfile_anonymize(); @@@ -699,12 -682,16 +704,21 @@@ static void ui_mainwindow_action_defass } + static void ui_mainwindow_action_deftag(void) + { + + ui_tag_manage_dialog(); + + //ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); + } + + static void ui_mainwindow_action_preferences(void) +{ + ui_mainwindow_showprefs(PREF_GENERAL); +} + +static void ui_mainwindow_showprefs(gint page) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); @@@ -756,8 -743,8 +770,8 @@@ struct hbfile_data *data = g_object_get // top spending gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor); -- - ui_panel_topspending_update(data->window, data); ++ + ui_hub_spending_update(data->window, data); } @@@ -802,7 -807,7 +834,7 @@@ static void ui_mainwindow_action_statis static void ui_mainwindow_action_trendtime(void) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); -- ++ ui_reptime_window_new(data->acc != NULL ? data->acc->key : 0); } @@@ -930,7 -935,7 +962,7 @@@ GtkWidget *mainvbox, *widget, *label NULL); content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); -- ++ mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (content_area), mainvbox, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); @@@ -956,11 -961,11 +988,11 @@@ widget = gtk_button_new_with_mnemonic(_("Read HomeBank _Manual")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome1), dialog); -- ++ widget = gtk_button_new_with_mnemonic(_("Configure _preferences")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome2), dialog); -- ++ widget = gtk_button_new_with_mnemonic(_("Create a _new file")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome3), dialog); @@@ -1095,10 -1100,10 +1127,10 @@@ gboolean file_clear = GPOINTER_TO_INT(u gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)))); gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)))); gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)))); -- ++ data->showall = FALSE; - ui_panel_accounts_setup(data); - + ui_hub_account_setup(data); - ++ hbfile_cleanup(file_clear); hbfile_setup(file_clear); @@@ -1143,6 -1148,8 +1175,8 @@@ gint account, count if( PREFS->heritdate == FALSE ) //fix: 318733 ope->date = GLOBALS->today; - ++ + da_transaction_set_default_template(ope); } // normally we can't be in addkeep without initialized ope with add @@@ -1160,8 -1167,8 +1194,8 @@@ DB( g_print(" - added 1 transaction to %d\n", ope->kacc) ); - ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); - + ui_hub_account_populate(GLOBALS->mainwindow, NULL); - ++ count++; //todo: still usefull ? store last date date = ope->date; @@@ -1187,47 -1194,31 +1221,31 @@@ } } - struct tmptop - { - guint32 key; - gdouble value; - }; - - - #define MAX_TOPSPENDING 10 - - - static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2) - { - return tt1->value > tt2->value ? 1 : -1; - } - - static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data) + gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath) { - struct hbfile_data *data; - GtkTreeModel *model; - gchar *title; - gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE]; - - DB( g_print("\n[ui-mainwindow] topspending_update\n") ); + gboolean retval = FALSE; + gchar *basename, *secondtext; + gboolean result; - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + basename = g_path_get_basename(filepath); + secondtext = g_strdup_printf ( - _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename); ++ _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename); - hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, data->toptotal, GLOBALS->kcur, GLOBALS->minor); - //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor); - title = g_strdup_printf("%s %s", _("Top spending"), strbuffer); + result = ui_dialog_msg_confirm_alert( + GTK_WINDOW(GLOBALS->mainwindow), + _("Open the backup file ?"), + secondtext, + _("_Open backup") - ); ++ ); - model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); - - gtk_chart_set_color_scheme(GTK_CHART(data->RE_pie), PREFS->report_color_scheme); - gtk_chart_set_currency(GTK_CHART(data->RE_pie), GLOBALS->kcur); - gtk_chart_set_datas(GTK_CHART(data->RE_pie), model, LST_TOPSPEND_AMOUNT, title, NULL); + g_free(secondtext); + g_free(basename); - g_free(title); + if( result == GTK_RESPONSE_OK ) + retval = TRUE; - + - //future usage - gchar *fu = _("Top %d spending"); title = fu; + return retval; } @@@ -1331,906 -1253,179 +1280,179 @@@ gchar *filename = NULL } else { - struct tmptop *item; - - pos = category_report_id(ope->kcat, type); - - //#1297054 if( trn_amount < 0 ) { - item = &g_array_index (garray, struct tmptop, pos); - item->key = pos; - item->value += trn_amount; - //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) ); - //} + g_free(filename); + return; } - - - } - - list = g_list_next(list); - } - - g_queue_free (txn_queue); - - // we need to sort this and limit before - g_array_sort(garray, (GCompareFunc)tmptop_compare_func); - - n_items = MIN(garray->len,MAX_TOPSPENDING); - other = 0; - for(i=0 ; ilen ; i++) - { - struct tmptop *item; - - item = &g_array_index (garray, struct tmptop, i); - if(item->value < 0) - { - total += item->value; - - if(i >= n_items) - other += item->value; - - DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i, item->key, item->value, total) ); - - } + } - } - model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); - 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_top), NULL); /* Detach model from view */ - - /* insert into the treeview */ - for(i=0 ; ilen,MAX_TOPSPENDING) ; i++) - { - gchar *name; - Category *entry; - struct tmptop *item; - gdouble value; - - item = &g_array_index (garray, struct tmptop, i); - - if(!item->value) continue; - - value = hb_amount_round(item->value, 2); - entry = da_cat_get(item->key); - if(entry == NULL) continue; - - name = entry->key == 0 ? _("(no category)") : da_cat_get_fullname(entry); - - // append test - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_TOPSPEND_ID, i, - LST_TOPSPEND_KEY, 0, - LST_TOPSPEND_NAME, name, - LST_TOPSPEND_AMOUNT, value, - //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5), - -1); - - } - - // append test - if(ABS(other) > 0) - { - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_TOPSPEND_ID, n_items, - LST_TOPSPEND_KEY, 0, - LST_TOPSPEND_NAME, _("Other"), - LST_TOPSPEND_AMOUNT, other, - //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5), - -1); - } - - /* Re-attach model to view */ - gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model); - g_object_unref(model); - - - // update chart and widgets - { - gchar *daterange; - - data->toptotal = total; - ui_panel_topspending_update(widget, data); - - daterange = filter_daterange_text_get(data->filter); - gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange); - g_free(daterange); + hbfile_change_filepath(filename); + ui_mainwindow_open_internal(widget, NULL); } } - - /* free our memory */ - g_array_free (garray, TRUE); - } - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - /* scheduled */ - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - static Archive * - ui_mainwindow_scheduled_get_selected_item(GtkTreeView *treeview) + /* + * open the file stored in GLOBALS->xhb_filepath + */ + void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data) { - GtkTreeSelection *treeselection; - GtkTreeModel *model; - GtkTreeIter iter; - - treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if( gtk_tree_selection_get_selected(treeselection, &model, &iter) ) - { - Archive *arc; + struct hbfile_data *data; + gint r; - gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1); - return arc; - } + DB( g_print("\n[ui-mainwindow] open internal\n") ); - return NULL; - } + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); + if( GLOBALS->xhb_filepath != NULL ) + { + DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) ); - static void ui_mainwindow_scheduled_onRowActivated (GtkTreeView *treeview, - GtkTreePath *path, - GtkTreeViewColumn *col, - gpointer userdata) - { - //struct hbfile_data *data; - Archive *arc; + ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); + GLOBALS->hbfile_is_new = FALSE; - DB( g_print ("\n[ui-mainwindow] A scheduled row has been double-clicked!\n") ); + r = homebank_load_xml(GLOBALS->xhb_filepath); + if( r == XML_OK ) + { + DB( g_print(" - file loaded ok : rcode=%d\n", r) ); - //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data"); + GLOBALS->xhb_timemodified = hbfile_file_get_time_modified(GLOBALS->xhb_filepath); + hbfile_file_hasrevert(GLOBALS->xhb_filepath); - + - arc = ui_mainwindow_scheduled_get_selected_item(treeview); - ui_mainwindow_defarchive(arc); - } + if(PREFS->appendscheduled) + scheduled_post_all_pending(); + if(PREFS->do_update_currency) + ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow)); - static void ui_mainwindow_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data) - { - struct hbfile_data *data = user_data; - GtkWidget *window; - gint result; - Transaction *txn; + homebank_lastopenedfiles_save(); - window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE); + //todo: delete this after computing done at xml read + account_compute_balances(); - /* fill in the transaction */ - txn = da_transaction_malloc(); - da_transaction_init_from_template(txn, arc); - txn->date = scheduled_get_postdate(arc, arc->nextdate); + ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath); + } + else + { + gchar *msg = _("Unknown error"); - deftransaction_set_transaction(window, txn); + switch(r) + { + case XML_IO_ERROR: + msg = _("I/O error for file '%s'."); + break; + case XML_FILE_ERROR: + msg = _("The file '%s' is not a valid HomeBank file."); + break; - case XML_VERSION_ERROR: ++ case XML_VERSION_ERROR: + msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version."); + break; + } - result = gtk_dialog_run (GTK_DIALOG (window)); + ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, + _("File error"), + msg, + GLOBALS->xhb_filepath + ); - DB( g_print(" - dialog result is %d\n", result) ); + ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); - if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT) - { - deftransaction_get(window, NULL); - transaction_add(txn); - GLOBALS->changes_count++; + } - scheduled_date_advance(arc); + ui_hub_account_populate(GLOBALS->mainwindow, NULL); + ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL); + ui_hub_spending_populate(GLOBALS->mainwindow, NULL); + ui_hub_transaction_populate(data); - + - DB( g_print(" - added 1 transaction to %d\n", txn->kacc) ); + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); } - da_transaction_free(txn); - - deftransaction_dispose(window, NULL); - gtk_widget_destroy (window); } - static void ui_mainwindow_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data) + /* + ** + */ + void ui_mainwindow_save(GtkWidget *widget, gpointer user_data) { - struct hbfile_data *data = user_data; - - Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); - - if( (arc != NULL) ) - { - ui_mainwindow_scheduled_do_post(arc, TRUE, data); - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); - } - } + struct hbfile_data *data; + gboolean saveas = GPOINTER_TO_INT(user_data); + gchar *filename = NULL; + gint r = XML_UNSET; + DB( g_print("\n[ui-mainwindow] save\n") ); - static void ui_mainwindow_scheduled_post_cb(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data = user_data; + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - DB( g_print("\n[ui-mainwindow] scheduled post\n") ); + if( GLOBALS->hbfile_is_new == TRUE ) + saveas = 1; - Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); + //#1710955 test for backup open + if( GLOBALS->hbfile_is_bak == TRUE ) + { + //todo: later for backup, should also remove datetime and .bak + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); + saveas = 1; + } - if( (arc != NULL) ) + if(saveas == 1) { - if( scheduled_is_postable(arc) ) + if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename, FALSE) == TRUE) { - Transaction *txn = da_transaction_malloc (); - - da_transaction_init_from_template(txn, arc); - txn->date = scheduled_get_postdate(arc, arc->nextdate); - transaction_add(txn); - - GLOBALS->changes_count++; - scheduled_date_advance(arc); - - da_transaction_free (txn); + DB( g_print(" + should save as '%s'\n", filename) ); + homebank_file_ensure_xhb(filename); + homebank_backup_current_file(); + r = homebank_save_xml(GLOBALS->xhb_filepath); + GLOBALS->hbfile_is_new = FALSE; + GLOBALS->hbfile_is_bak = FALSE; } else - { - ui_mainwindow_scheduled_do_post(arc, FALSE, data); - } - - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); + return; } - } + else + { + guint64 time_modified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath); + gint result = GTK_RESPONSE_OK; + DB( g_print(" + should quick save '%s'\n + time: open=%lu :: now=%lu\n", GLOBALS->xhb_filepath, GLOBALS->xhb_timemodified, time_modified) ); - static void ui_mainwindow_scheduled_skip_cb(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data = user_data; - - Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); - if( (arc != NULL) && (arc->flags & OF_AUTO) ) - { - GLOBALS->changes_count++; - scheduled_date_advance(arc); - - ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE)); - } - } - - - - static void ui_mainwindow_scheduled_update(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - //gint filter; - - DB( g_print("\n[ui-mainwindow] scheduled update\n") ); - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter)); - - Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); - - if(arc) - { - DB( g_print("archive is %s\n", arc->memo) ); - - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE); - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE); - } - else - { - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE); - gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE); - } - - } - - - - static void ui_mainwindow_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data) - { - - - ui_mainwindow_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); - } - - - - /* - ** called after load, importamiga, on demand - */ - void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data) - { - //struct hbfile_data *data; - gint count; - gint usermode = GPOINTER_TO_INT(user_data); - - DB( g_print("\n[ui-mainwindow] check scheduled\n") ); - - //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - count = scheduled_post_all_pending(); - - //inform the user - if(usermode == TRUE) - { - gchar *txt; - - //#125534 - if( count > 0 ) - { - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL)); - } - - if(count == 0) - txt = _("No transaction to add"); - else - txt = _("transaction added: %d"); - - ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO, - _("Check scheduled transactions result"), - txt, - count); - } - - } - - - static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - GtkTreeModel *model; - GtkTreeIter iter; - GList *list; - gdouble totexp = 0; - gdouble totinc = 0; - gint count = 0; - gchar buffer[256]; - guint32 maxpostdate; - GDate *date; - //Account *acc; - - DB( g_print("\n[ui-mainwindow] scheduled populate list\n") ); - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); - gtk_list_store_clear (GTK_LIST_STORE(model)); - - homebank_app_date_get_julian(); - - maxpostdate = scheduled_date_get_post_max(); - - date = g_date_new_julian (maxpostdate); - g_date_strftime (buffer, 256-1, PREFS->date_format, date); - g_date_free(date); - - gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer); - - - list = g_list_first(GLOBALS->arc_list); - while (list != NULL) - { - Archive *arc = list->data; - Account *acc; - gdouble inc, exp; - guint nbdays, nblate; - - if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0) - { - count++; - nbdays = arc->nextdate - maxpostdate; - nblate = scheduled_get_latepost_count(arc, GLOBALS->today); - - DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) ); - - if(arc->flags & OF_INCOME) - { - inc = arc->amount; - exp = 0.0; - } - else - { - exp = arc->amount; - inc = 0.0; - } - - /* insert normal txn */ - acc = da_acc_get(arc->kacc); - if( acc) - { - totinc += hb_amount_base(inc, acc->kcur); - totexp += hb_amount_base(exp, acc->kcur); - } - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_DSPUPC_DATAS, arc, - LST_DSPUPC_ACCOUNT, acc, - LST_DSPUPC_MEMO, arc->memo, - LST_DSPUPC_EXPENSE, exp, - LST_DSPUPC_INCOME, inc, - LST_DSPUPC_REMAINING, nbdays, - LST_DSPUPC_NB_LATE, nblate, - -1); - - /* insert internal xfer txn : 1378836 */ - if(arc->paymode == PAYMODE_INTXFER) - { - acc = da_acc_get(arc->kxferacc); - if( acc) - { - totinc += hb_amount_base(-inc, acc->kcur); - totexp += hb_amount_base(-exp, acc->kcur); - } - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_DSPUPC_DATAS, arc, - LST_DSPUPC_ACCOUNT, acc, - LST_DSPUPC_MEMO, arc->memo, - LST_DSPUPC_EXPENSE, -inc, - LST_DSPUPC_INCOME, -exp, - LST_DSPUPC_REMAINING, nbdays, - LST_DSPUPC_NB_LATE, nblate, - -1); - } - - } - list = g_list_next(list); - } - - // insert total - if(count > 0 ) - { - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_DSPUPC_DATAS, NULL, - LST_DSPUPC_ACCOUNT, NULL, - LST_DSPUPC_MEMO, _("Total"), - LST_DSPUPC_EXPENSE, totexp, - LST_DSPUPC_INCOME, totinc, - -1); - } - - ui_mainwindow_scheduled_update(widget, NULL); - - } - - - gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath) - { - gboolean retval = FALSE; - gchar *basename, *secondtext; - gboolean result; - - basename = g_path_get_basename(filepath); - secondtext = g_strdup_printf ( - _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename); - - result = ui_dialog_msg_confirm_alert( - GTK_WINDOW(GLOBALS->mainwindow), - _("Open a backup file ?"), - secondtext, - _("_Open backup") - ); - - g_free(secondtext); - g_free(basename); - - if( result == GTK_RESPONSE_OK ) - retval = TRUE; - - return retval; - } - - - /* - ** - */ - void ui_mainwindow_open(GtkWidget *widget, gpointer user_data) - { - //struct hbfile_data *data; - gchar *filename = NULL; - - DB( g_print("\n[ui-mainwindow] open\n") ); - - //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) - { - if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename) == TRUE ) - { - //#1710955 test for backup open - if( hbfile_file_isbackup(filename) ) - { - if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE ) - { - GLOBALS->hbfile_is_bak = TRUE; - } - else - { - g_free(filename); - return; - } - } - - hbfile_change_filepath(filename); - ui_mainwindow_open_internal(widget, NULL); - } - } - } - - - /* - * open the file stored in GLOBALS->xhb_filepath - */ - void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - gint r; - - DB( g_print("\n[ui-mainwindow] open internal\n") ); - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - if( GLOBALS->xhb_filepath != NULL ) - { - DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) ); - - ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); - GLOBALS->hbfile_is_new = FALSE; - - r = homebank_load_xml(GLOBALS->xhb_filepath); - if( r == XML_OK ) - { - DB( g_print(" - file loaded ok : rcode=%d\n", r) ); - - hbfile_file_hasbackup(GLOBALS->xhb_filepath); - - if(PREFS->appendscheduled) - scheduled_post_all_pending(); - - if(PREFS->do_update_currency) - ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow)); - - homebank_lastopenedfiles_save(); - - //todo: delete this after computing done at xml read - account_compute_balances(); - - ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath); - } - else - { - gchar *msg = _("Unknow error"); - - switch(r) - { - case XML_IO_ERROR: - msg = _("I/O error for file '%s'."); - break; - case XML_FILE_ERROR: - msg = _("The file '%s' is not a valid HomeBank file."); - break; - case XML_VERSION_ERROR: - msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version."); - break; - } - - ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, - _("File error"), - msg, - GLOBALS->xhb_filepath - ); - - ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); - - } - - ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); - ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); - ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); - } - - - } - - - /* - ** - */ - void ui_mainwindow_save(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - gboolean saveas = GPOINTER_TO_INT(user_data); - gchar *filename = NULL; - gint r = XML_UNSET; - - DB( g_print("\n[ui-mainwindow] save\n") ); - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - if( GLOBALS->hbfile_is_new == TRUE ) - saveas = 1; - - //#1710955 test for backup open - if( GLOBALS->hbfile_is_bak == TRUE ) - { - //todo: later for backup, should also remove datetime and .bak - hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); - saveas = 1; - } - - if(saveas == 1) - { - if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename) == TRUE) - { - DB( g_print(" + should save as '%s'\n", filename) ); - homebank_file_ensure_xhb(filename); - homebank_backup_current_file(); - r = homebank_save_xml(GLOBALS->xhb_filepath); - GLOBALS->hbfile_is_new = FALSE; - GLOBALS->hbfile_is_bak = FALSE; - } - else - return; - } - else - { - DB( g_print(" + should quick save %s\n", GLOBALS->xhb_filepath) ); - homebank_file_ensure_xhb(NULL); - homebank_backup_current_file(); - r = homebank_save_xml(GLOBALS->xhb_filepath); - } - - - if(r == XML_OK) - { - GLOBALS->changes_count = 0; - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); - } - else - { - gchar *msg = _("I/O error for file '%s'."); - - ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, - _("File error"), - msg, - GLOBALS->xhb_filepath - ); - - } - - - } - - - static void ui_panel_accounts_expand_all(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); - } - - - static void ui_panel_accounts_collapse_all(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_acc)); - } - - - - static GHashTable *ui_panel_accounts_groups_get(GList *lacc, gint groupby, gboolean showall) - { - GHashTable *hash; - GList *elt; - gchar *groupname; - gint nballoc; - - DB( g_print("\n[ui-mainwindow] accounts_groups_get\n") ); - - nballoc = da_acc_length (); - - DB( g_print(" %d accounts\n", nballoc) ); - - hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); - elt = g_list_first(lacc); - while (elt != NULL) - { - Account *acc = elt->data; - GPtrArray *group; - - //#1674045 ony rely on nosummary - //if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) ) - if( showall || !(acc->flags & AF_NOSUMMARY) ) - { - if( groupby == DSPACC_GROUP_BY_BANK ) - { - groupname = _("(no institution)"); - if( (acc->bankname != NULL) && strlen(acc->bankname) > 0 ) - groupname = acc->bankname; - } - else - { - //pre 5.1.3 historical by type display - groupname = _(CYA_ACC_TYPE[acc->type]); - } - - if( g_hash_table_contains(hash, groupname) == FALSE ) - { - g_hash_table_insert(hash, g_strdup(groupname), g_ptr_array_sized_new(nballoc) ); - //DB( g_print(" - type hash insert '%s' = %d\n", groupname, inserted) ); - } - - group = g_hash_table_lookup(hash, groupname); - if( group != NULL ) - { - g_ptr_array_add(group, (gpointer)acc); - DB( g_print(" -- add '%s' to group '%s'\n", acc->name, groupname) ); - } - } - elt = g_list_next(elt); - } - - return hash; - } - - - - - - - void ui_mainwindow_populate_accounts(GtkWidget *widget, gpointer user_data) - { - struct hbfile_data *data; - GtkTreeModel *model; - GtkTreeIter iter1, child_iter; - GList *lacc, *elt; - Account *acc; - guint j, nbtype; - gdouble gtbank, gttoday, gtfuture; - - GHashTable *h_group; - GHashTableIter grp_iter; - gpointer key, value; - - DB( g_print("\n[ui-mainwindow] populate accounts\n") ); - - data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - - /* here we create a count and a list of every account pointer by type */ - lacc = elt = g_hash_table_get_values(GLOBALS->h_acc); - - h_group = ui_panel_accounts_groups_get(lacc, PREFS->pnl_acc_show_by, data->showall); - g_list_free(lacc); - - - gtbank = gttoday = gtfuture = 0; - - DB( g_print(" - populate listview, %d group(s)\n", g_hash_table_size(h_group)) ); - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)); - gtk_tree_store_clear (GTK_TREE_STORE(model)); - - nbtype = 0; - g_hash_table_iter_init (&grp_iter, h_group); - while (g_hash_table_iter_next (&grp_iter, &key, &value)) - { - GPtrArray *gpa = value; - gdouble tbank, ttoday, tfuture; - gint position; - - if(gpa != NULL) + if( GLOBALS->xhb_timemodified != time_modified ) { - nbtype++; - //1: Header: Bank, Cash, ... - DB( g_print(" - add group '%s'\n", (gchar *)key) ); - - //#1663399 keep type position like in dropdown - position = 0; - if( PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE ) - { - gint t = 0; - - while(CYA_ACC_TYPE[t] != NULL && t < 15) - { - if( !strcmp(CYA_ACC_TYPE[t], key) ) - break; - t++; - } - - position = t; - } - - gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); - gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, - LST_DSPACC_POS, position, - LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER, - LST_DSPACC_NAME, key, - -1); - - tbank = ttoday = tfuture = 0; - - //2: Accounts for real - for(j=0;jlen;j++) - { - acc = g_ptr_array_index(gpa, j); - - //tbank += acc->bal_bank; - //ttoday += acc->bal_today; - //tfuture += acc->bal_future; - tbank += hb_amount_base(acc->bal_bank, acc->kcur); - ttoday += hb_amount_base(acc->bal_today, acc->kcur); - tfuture += hb_amount_base(acc->bal_future, acc->kcur); - - DB( g_print(" - add account '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) ); - - gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); - gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, - LST_DSPACC_DATAS, acc, - LST_DSPACC_DATATYPE, DSPACC_TYPE_NORMAL, - LST_DSPACC_BANK, acc->bal_bank, - LST_DSPACC_TODAY, acc->bal_today, - LST_DSPACC_FUTURE, acc->bal_future, - -1); - } - - if(gpa->len > 1) - { - DB( g_print(" - group total :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); - - // insert the total line - gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); - gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, - LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, - LST_DSPACC_NAME, _("Total"), - LST_DSPACC_BANK, tbank, - LST_DSPACC_TODAY, ttoday, - LST_DSPACC_FUTURE, tfuture, - -1); - } - - /* set balance to header to display when collasped */ - DB( g_print(" - enrich group total header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); - gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, - LST_DSPACC_BANK, tbank, - LST_DSPACC_TODAY, ttoday, - LST_DSPACC_FUTURE, tfuture, - -1); - - /* add to grand total */ - gtbank += tbank; - gttoday += ttoday; - gtfuture += tfuture; + result = ui_dialog_msg_confirm_alert( + GTK_WINDOW(GLOBALS->mainwindow), + _("The file has been modified since reading it."), + _("If you save it, all the external changes could be lost. Save it anyway?"), + _("S_ave Anyway") + ); - + + if( result != GTK_RESPONSE_OK ) + return; } + DB( g_print(" + saving...\n") ); + homebank_file_ensure_xhb(NULL); + homebank_backup_current_file(); + r = homebank_save_xml(GLOBALS->xhb_filepath); } - DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) ); - - // Grand total - if( nbtype > 1 ) + if(r == XML_OK) { - gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); - gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, - LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, - LST_DSPACC_NAME, _("Grand total"), - LST_DSPACC_BANK, gtbank, - LST_DSPACC_TODAY, gttoday, - LST_DSPACC_FUTURE, gtfuture, - -1); + DB( g_print(" + OK...\n") ); + GLOBALS->changes_count = 0; + GLOBALS->xhb_timemodified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath); + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); } - - - gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); - - DB( g_print(" - free ressources\n") ); - - g_hash_table_iter_init (&grp_iter, h_group); - while (g_hash_table_iter_next (&grp_iter, &key, &value)) + else { - g_ptr_array_free (value, TRUE); - } - g_hash_table_destroy (h_group); + gchar *msg = _("I/O error for file '%s'."); + ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, + _("File error"), + msg, + GLOBALS->xhb_filepath + ); + } } @@@ -2262,8 -1457,12 +1484,12 @@@ gint flags changed = (GLOBALS->changes_count > 0) ? "*" : ""; + #if MYDEBUG == 1 + data->wintitle = g_strdup_printf("%s%s (%d)- %s - " PROGNAME, changed, basename, GLOBALS->changes_count, GLOBALS->owner); + #else data->wintitle = g_strdup_printf("%s%s - %s - " PROGNAME, changed, basename, GLOBALS->owner); + #endif - + gtk_window_set_title (GTK_WINDOW (gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), data->wintitle); g_free(basename); @@@ -2395,7 -1586,7 +1613,7 @@@ gtk_widget_hide(GTK_WIDGET(data->GR_top)); -- ++ DB( g_print(" - show upcoming=%d\n", PREFS->wal_upcoming) ); if(PREFS->wal_upcoming) gtk_widget_show(GTK_WIDGET(data->GR_upc)); @@@ -2502,9 -1690,12 +1720,12 @@@ gboolean retval = FALSE PREFS->wal_vpaned = gtk_paned_get_position(GTK_PANED(data->vpaned)); PREFS->wal_hpaned = gtk_paned_get_position(GTK_PANED(data->hpaned)); - DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); + if(PREFS->pnl_list_tab) + g_free(PREFS->pnl_list_tab); + PREFS->pnl_list_tab = g_strdup(gtk_stack_get_visible_child_name(GTK_STACK(data->stack))); - ++ //todo if(ui_dialog_msg_savechanges(widget, NULL) == FALSE) { @@@ -2517,9 -1708,9 +1738,9 @@@ gtk_widget_destroy(data->LV_top); g_free(data->wintitle); - da_filter_free(data->filter); + da_flt_free(data->filter); g_free(user_data); -- ++ gtk_main_quit(); } @@@ -2656,8 -1822,9 +1852,9 @@@ static void ui_mainwindow_drag_data_rec { gchar **uris, **str; gchar *newseldata; - gint filetype, slen; + gint n_uris, filetype, slen; + GError *error = NULL; - + if (info != TARGET_URI_LIST) return; @@@ -2668,57 -1835,77 +1865,77 @@@ newseldata = g_new (gchar, slen + 1); memcpy (newseldata, gtk_selection_data_get_data(selection_data), slen); newseldata[slen] = 0; + //DB( g_print(" - seldata ='%s'\n", gtk_selection_data_get_data(selection_data) ) ); + //DB( g_print(" - newseldata ='%s'\n", newseldata ) ); - + uris = g_uri_list_extract_uris (newseldata); + n_uris = g_strv_length(uris); + DB( g_print(" - dragged %d files (len=%d)\n", n_uris, slen ) ); - DB( g_print(" - dragged %d %d files\n", slen, g_strv_length(uris) ) ); + g_free(newseldata); - str = uris; - //for (str = uris; *str; str++) - if( *str ) + //single file: check for xhb + if(n_uris == 1) - { + { - GError *error = NULL; - gchar *path = g_filename_from_uri (*str, NULL, &error); + filetype = hb_filename_type_get_by_extension(*uris); - if (path) - { - filetype = homebank_alienfile_recognize(path); + DB( g_print(" - filetype is homebank (%d)\n", filetype) ); - DB( g_print(" - dragged %s, type is %d\n", path, filetype ) ); + if( filetype == FILETYPE_HOMEBANK ) + { + gchar *path = g_filename_from_uri (*uris, NULL, &error); - if( filetype == FILETYPE_HOMEBANK) + if( path != NULL ) { + DB( g_print(" - path is '%s'\n", path) ); hbfile_change_filepath(g_strdup(path)); ui_mainwindow_open_internal(GTK_WIDGET(window), NULL); + goto end_drop; } else { - //todo: future here to implement import for other filetype - // ui_import_assistant_new(); - // + write a method into assistant to catch other filename - - - ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR, + g_warning ("Could not convert uri to local path: %s", error->message); + g_error_free (error); + } + g_free (path); + } + /* we no more manage error here + ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR, _("File error"), _("The file %s is not a valid HomeBank file."), - path - ); - + path); + */ + } - } + //collect known filetype to import + DB( g_print(" - collect %d files\n", n_uris) ); - + - } - else + gchar **paths = g_new (gchar *, n_uris + 1); + slen = 0; + for (str = uris; *str; str++) + { + filetype = hb_filename_type_get_by_extension(*str); + if( filetype != FILETYPE_HOMEBANK && filetype != FILETYPE_UNKNOWN ) { - g_warning ("Could not convert uri to local path: %s", error->message); + gchar *path = g_filename_from_uri (*str, NULL, NULL); - g_error_free (error); + if( path != NULL ) + { + DB( g_print(" - append %d '%s'\n", slen, path ) ); + paths[slen++] = path; + } - } + } - g_free (path); } + paths[slen] = NULL; + + if( slen > 0 ) + { + ui_import_assistant_new( paths ); + } - - ++ ++ + end_drop: g_strfreev (uris); - - g_free(newseldata); } @@@ -3246,7 -2105,7 +2135,7 @@@ GtkWidget *bar, *label gtk_label_set_markup (GTK_LABEL(label), "Unstable Development Version"); gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0); #endif -- ++ /* Add the main area */ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); //gtk_container_set_border_width (GTK_CONTAINER(vbox), SPACING_MEDIUM); @@@ -3271,6 -2127,29 +2157,29 @@@ //gtk_widget_set_size_request (widget, -1, 100); gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + data->GR_upc = box; + gtk_paned_pack2 (GTK_PANED(vpaned), box, TRUE, FALSE); + + sidebar = gtk_stack_sidebar_new (); + gtk_box_pack_start (GTK_BOX (box), sidebar, FALSE, FALSE, 0); + + stack = gtk_stack_new (); + //gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN); + gtk_stack_sidebar_set_stack (GTK_STACK_SIDEBAR (sidebar), GTK_STACK (stack)); + data->stack = stack; + gtk_box_pack_start (GTK_BOX (box), stack, TRUE, TRUE, 0); - ++ + page = ui_hub_scheduled_create(data); + gtk_stack_add_titled (GTK_STACK (stack), page, "sched", _("Scheduled")); + //gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE); + + page = ui_hub_transaction_create(data, HUB_TXN_TYPE_FUTURE); + gtk_stack_add_titled (GTK_STACK (stack), page, "futur", _("Future")); + + page = ui_hub_transaction_create(data, HUB_TXN_TYPE_REMIND); + gtk_stack_add_titled (GTK_STACK (stack), page, "remin", _("Remind")); - ++ //setup, init and show window wg = &PREFS->wal_wg; @@@ -3292,6 -2171,10 +2201,10 @@@ if(PREFS->wal_vpaned > 0) gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned); + if( PREFS->pnl_list_tab != NULL ) + gtk_stack_set_visible_child_name (GTK_STACK(data->stack), PREFS->pnl_list_tab); + - ++ //todo: move this elsewhere DB( g_print(" - setup stuff\n") ); diff --cc src/ext-perl.xs index 4890db8,0000000..c8e1f25 mode 100644,000000..100644 --- a/src/ext-perl.xs +++ b/src/ext-perl.xs @@@ -1,1043 -1,0 +1,1043 @@@ + +#include +#include +#include + +#include + +#undef _ +#include "homebank.h" +#include "ext.h" +#include "refcount.h" + +extern struct HomeBank *GLOBALS; - #include "dsp_mainwindow.h" - #include "dsp_account.h" ++#include "dsp-mainwindow.h" ++#include "dsp-account.h" +#include "ui-transaction.h" + + +static gint ext_perl_init(int* argc, char** argv[], char** env[]); +static void ext_perl_term(void); +static gboolean ext_perl_check_file(const gchar* plugin_filepath); +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath); +static gint ext_perl_load_plugin(const gchar* plugin_filepath); +static void ext_perl_unload_plugin(const gchar* plugin_filepath); +static void ext_perl_execute_action(const gchar* plugin_filepath); +static void ext_perl_call_hook(const gchar* hook_id, GList* args); + +static SV* val_to_sv(GValue* val); +static GValue* sv_to_val(SV* sv); + +static gboolean gperl_value_from_sv(GValue* value, SV* sv); +static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed); + + +static inline GValue* EXT_SV(GValue* v, SV* sv, GType type) +{ + g_value_init(v, type); + gperl_value_from_sv(v, sv); + return v; +} + + +#define EXT_P2C_OBJECT(PKG, ARG, VAR, TYP) \ +if (sv_derived_from(ARG, PKG)) { \ + IV iv = SvIV((SV*)SvRV(ARG)); \ + VAR = INT2PTR(TYP, iv); \ +} else { \ + croak(#VAR" is not of type "PKG); \ +} + +#define EXT_C2P_OBJECT(PKG, ARG, VAR) \ +sv_setref_pv(ARG, PKG, (void*)VAR) + + +static inline GPtrArray* SvGptrarray(const SV* sv) +{ + if (SvROK(sv)) { + sv = MUTABLE_SV(SvRV(sv)); + } + if (SvTYPE(sv) == SVt_PVAV) { + AV* av = (AV*)sv; + int i; + int top = av_len(av); + GPtrArray* array = g_ptr_array_new(); + for (i = 0; i <= top; ++i) { + SV** item = av_fetch(av, i, 0); + if (!item) continue; + g_ptr_array_add(array, sv_to_val(*item)); + } + return array; + // TODO- leaking + } else { + croak("var is not an array"); + } +} + +static inline SV* newSVgptrarray(const GPtrArray* a) +{ + if (a) { + AV* av = newAV(); + int i; + for (i = 0; i < a->len; ++i) { + GValue* item = g_ptr_array_index(a, i); + av_push(av, val_to_sv(item)); + } + return newRV((SV*)av); + } + return &PL_sv_undef; +} + + +static inline GHashTable* SvGhashtable(const SV* sv) +{ + if (SvROK(sv)) { + sv = MUTABLE_SV(SvRV(sv)); + } + if (SvTYPE(sv) == SVt_PVHV) { + HV* hv = (HV*)sv; + hv_iterinit(hv); + gchar* key; + I32 len; + SV* item; + GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal); + while ((item = hv_iternextsv(hv, &key, &len))) { + g_hash_table_insert(hash, key, sv_to_val(item)); + } + return hash; + // TODO- leaking + } else { + croak("var is not a hash"); + } +} + +static inline SV* newSVghashtable(GHashTable* h) +{ + if (h) { + HV* hv = newHV(); + GHashTableIter it; + g_hash_table_iter_init(&it, h); + gchar* key = NULL; + GValue* item = NULL; + while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) { + hv_store(hv, key, -g_utf8_strlen(key, -1), val_to_sv(item), 0); + } + return newRV((SV*)hv); + } + return &PL_sv_undef; +} + + +static inline gboolean SvGboolean(SV* sv) +{ + if (!sv) { + return FALSE; + } + if (SvROK(sv)) { + return !!SvIV(SvRV(sv)); + } else { + return SvTRUE(sv); + } +} + +static inline SV* newSVgboolean(gboolean b) +{ + return sv_setref_iv(newSV(0), "HomeBank::Boolean", !!b); +} + + +static inline gchar* SvGchar_ptr(SV* sv) +{ + return SvPVutf8_nolen(sv); +} + +static inline SV* newSVgchar_ptr(const gchar* str) +{ + if (!str) return &PL_sv_undef; + + SV* sv = newSVpv(str, 0); + SvUTF8_on(sv); + return sv; +} + + +static inline GObject* SvGobject(const SV* sv) +{ + GObject* (*func)(const SV*) = ext_symbol_lookup("gperl_get_object"); + if (func) { + return func(sv); + } + return NULL; +} + +static inline SV* newSVgobject(const GObject* o) +{ + SV* (*func)(const GObject*, gboolean) = ext_symbol_lookup("gperl_new_object"); + if (func) { + return func(o, FALSE); + } + return &PL_sv_undef; +} + + +static PerlInterpreter* context = NULL; + + +static gint ext_perl_init(int* argc, char** argv[], char** env[]) +{ + int ret = 0; + + PERL_SYS_INIT3(argc, argv, env); + context = perl_alloc(); + perl_construct(context); + + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + PL_origalen = 1; + PL_perl_destruct_level = 1; + + gchar* bootstrap = g_strdup_printf("-e" + "use lib '%s';" + "use HomeBank;" + "HomeBank->bootstrap;", + homebank_app_get_pkglib_dir()); + char *args[] = { "", bootstrap }; + + EXTERN_C void xs_init(pTHX); + if (perl_parse(context, xs_init, 2, args, NULL) || perl_run(context)) { + ext_perl_term(); + ret = -1; + } + + g_free(bootstrap); + return ret; +} + +static void ext_perl_term(void) +{ + if (context) { + perl_destruct(context); + perl_free(context); + context = NULL; + } + PERL_SYS_TERM(); +} + +static gboolean ext_perl_check_file(const gchar* plugin_filepath) +{ + if (g_str_has_suffix(plugin_filepath, ".pl")) { + return TRUE; + } + return FALSE; +} + +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath) +{ + GHashTable* table = NULL; + + if (!context) return NULL; + PERL_SET_CONTEXT(context); + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + mXPUSHs(newSVgchar_ptr(plugin_filepath)); + PUTBACK; + + int ret = call_pv("HomeBank::read_metadata", G_SCALAR | G_EVAL); + + SPAGAIN; + + if (ret == 1) { + table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + SV* sv = POPs; + if (SvROK(sv)) { + sv = MUTABLE_SV(SvRV(sv)); + } + if (SvTYPE(sv) == SVt_PVHV) { + HV* hv = (HV*)sv; + hv_iterinit(hv); + gchar* key; + I32 len; + SV* item; + while ((item = hv_iternextsv(hv, &key, &len))) { + if (SvPOK(item)) { + gchar* val = SvPVutf8_nolen(item); + g_hash_table_insert(table, g_strdup(key), g_strdup(val)); + } + } + } + } + + PUTBACK; + FREETMPS; + LEAVE; + + return table; +} + +static gint ext_perl_load_plugin(const gchar* plugin_filepath) +{ + if (!context) return -1; + PERL_SET_CONTEXT(context); + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + mXPUSHs(newSVgchar_ptr(plugin_filepath)); + PUTBACK; + call_pv("HomeBank::load_plugin", G_DISCARD | G_EVAL); + SPAGAIN; + + gint ret = 0; + if (SvTRUE(ERRSV)) { + g_printerr("%s", SvPV_nolen(ERRSV)); + ret = -1; + } + + PUTBACK; + FREETMPS; + LEAVE; + + return ret; +} + +static void ext_perl_unload_plugin(const gchar* plugin_filepath) +{ + if (!context) return; + PERL_SET_CONTEXT(context); + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + mXPUSHs(newSVgchar_ptr(plugin_filepath)); + PUTBACK; + call_pv("HomeBank::unload_plugin", G_DISCARD | G_EVAL); + SPAGAIN; + + if (SvTRUE(ERRSV)) { + g_printerr("%s", SvPV_nolen(ERRSV)); + } + + PUTBACK; + FREETMPS; + LEAVE; +} + +static void ext_perl_execute_action(const gchar* plugin_filepath) +{ + if (!context) return; + PERL_SET_CONTEXT(context); + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + mXPUSHs(newSVgchar_ptr(plugin_filepath)); + PUTBACK; + call_pv("HomeBank::execute_action", G_DISCARD | G_EVAL); + SPAGAIN; + + if (SvTRUE(ERRSV)) { + g_printerr("%s", SvPV_nolen(ERRSV)); + } + + PUTBACK; + FREETMPS; + LEAVE; +} + +static void ext_perl_call_hook(const gchar* hook_id, GList* args) +{ + if (!context) return; + PERL_SET_CONTEXT(context); + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + mXPUSHs(newSVgchar_ptr(hook_id)); + + GList *list = g_list_first(args); + while (list) { + GValue* val = list->data; + XPUSHs(sv_2mortal(val_to_sv(val))); + list = g_list_next(list); + } + + PUTBACK; + call_pv("HomeBank::call_hook", G_ARRAY); + SPAGAIN; + POPi; + PUTBACK; + FREETMPS; + LEAVE; +} + + +static SV* val_to_sv(GValue* val) +{ + if (!val || !G_IS_VALUE(val) || G_VALUE_TYPE(val) == G_TYPE_NONE) { + return &PL_sv_undef; + } + if (G_VALUE_TYPE(val) == G_TYPE_BOOLEAN) { + return newSVgboolean(g_value_get_boolean(val)); + } + if (G_VALUE_TYPE(val) == G_TYPE_PTR_ARRAY) { + return newSVgptrarray((GPtrArray*)g_value_get_boxed(val)); + } + if (G_VALUE_TYPE(val) == G_TYPE_HASH_TABLE) { + return newSVghashtable((GHashTable*)g_value_get_boxed(val)); + } +#define obj(CTYPE, _2, PART, GTYPE, _5) \ + if (G_VALUE_TYPE(val) == GTYPE) { \ + SV* sv = newSV(0); \ + CTYPE* ptr = (CTYPE*)g_value_get_##PART(val); \ + EXT_C2P_OBJECT("HomeBank::"#CTYPE, sv, rc_ref(ptr)); \ + return sv; \ + } +#include "ext-value.h" +#undef obj + return gperl_sv_from_value(val, FALSE); +} + +static GValue* sv_to_val(SV* sv) +{ + GValue* val = g_new0(GValue, 1); + + if (SvUOK(sv)) return EXT_SV(val, sv, G_TYPE_UINT); + if (SvIOK(sv)) return EXT_SV(val, sv, G_TYPE_INT); + if (SvNOK(sv)) return EXT_SV(val, sv, G_TYPE_DOUBLE); + if (SvPOK(sv)) return EXT_SV(val, sv, G_TYPE_STRING); + if (sv_isobject(sv)) { + if (sv_derived_from(sv, "HomeBank::Boolean")) { + return EXT_BOOLEAN(val, SvGboolean(sv)); + } +#define obj(CTYPE, NAME, _3, _4, _5) \ + if (sv_derived_from(sv, "HomeBank::"#CTYPE)) { \ + CTYPE* ptr; \ + EXT_P2C_OBJECT("HomeBank::"#CTYPE, sv, ptr, CTYPE*); \ + return EXT_##NAME(val, ptr); \ + } +#include "ext-value.h" +#undef obj + return EXT_SV(val, sv, G_TYPE_OBJECT); + } + if (SvROK(sv)) { + sv = SvRV(sv); + switch (SvTYPE(sv)) { + case SVt_IV: + return EXT_BOOLEAN(val, SvGboolean(sv)); + case SVt_PVAV: + return EXT_ARRAY(val, SvGptrarray(sv)); + case SVt_PVHV: + return EXT_HASH_TABLE(val, SvGhashtable(sv)); + default: + break; + } + } + switch (SvTYPE(sv)) { + case SVt_PVAV: + return EXT_ARRAY(val, SvGptrarray(sv)); + case SVt_PVHV: + return EXT_HASH_TABLE(val, SvGhashtable(sv)); + default: + break; + } + + g_free(val); + return NULL; +} + + +static gboolean gperl_value_from_sv(GValue* value, SV* sv) +{ + gboolean (*func)(GValue*, SV*) = ext_symbol_lookup("gperl_value_from_sv"); + if (func) return func(value, sv); + + GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value)); + if (!SvOK(sv)) return TRUE; + switch (type) { + case G_TYPE_CHAR: + { + gchar *tmp = SvGchar_ptr(sv); + g_value_set_schar(value, (gint8)(tmp ? tmp[0] : 0)); + break; + } + case G_TYPE_UCHAR: + { + char *tmp = SvPV_nolen(sv); + g_value_set_uchar(value, (guchar)(tmp ? tmp[0] : 0)); + break; + } + case G_TYPE_BOOLEAN: + g_value_set_boolean(value, SvTRUE(sv)); + break; + case G_TYPE_INT: + g_value_set_int(value, SvIV(sv)); + break; + case G_TYPE_UINT: + g_value_set_uint(value, SvIV(sv)); + break; + case G_TYPE_LONG: + g_value_set_long(value, SvIV(sv)); + break; + case G_TYPE_ULONG: + g_value_set_ulong(value, SvIV(sv)); + break; + case G_TYPE_FLOAT: + g_value_set_float(value, (gfloat)SvNV(sv)); + break; + case G_TYPE_DOUBLE: + g_value_set_double(value, SvNV(sv)); + break; + case G_TYPE_STRING: + g_value_set_string(value, SvGchar_ptr(sv)); + break; + } + return TRUE; +} + +static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed) +{ + SV* (*func)(const GValue*, gboolean) = ext_symbol_lookup("gperl_sv_from_value"); + if (func) return func(value, copy_boxed); + + GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value)); + switch (type) { + case G_TYPE_CHAR: + return newSViv(g_value_get_schar(value)); + case G_TYPE_UCHAR: + return newSVuv(g_value_get_uchar(value)); + case G_TYPE_BOOLEAN: + return newSViv(g_value_get_boolean(value)); + case G_TYPE_INT: + return newSViv(g_value_get_int(value)); + case G_TYPE_UINT: + return newSVuv(g_value_get_uint(value)); + case G_TYPE_LONG: + return newSViv(g_value_get_long(value)); + case G_TYPE_ULONG: + return newSVuv(g_value_get_ulong(value)); + case G_TYPE_FLOAT: + return newSVnv(g_value_get_float(value)); + case G_TYPE_DOUBLE: + return newSVnv(g_value_get_double(value)); + case G_TYPE_STRING: + return newSVgchar_ptr(g_value_get_string(value)); + } + return &PL_sv_undef; +} + + +static void _register(void) __attribute__((constructor)); +static void _register() +{ + ext_register("perl", + ext_perl_init, + ext_perl_term, + ext_perl_check_file, + ext_perl_read_plugin_metadata, + ext_perl_load_plugin, + ext_perl_unload_plugin, + ext_perl_execute_action, + ext_perl_call_hook); +} + + +MODULE = HomeBank PACKAGE = HomeBank + +PROTOTYPES: ENABLE + +const gchar* +version(void) + CODE: + RETVAL = VERSION; + OUTPUT: + RETVAL + +const gchar* +config_dir(void) + CODE: + RETVAL = homebank_app_get_config_dir(); + OUTPUT: + RETVAL + +gboolean +has(const gchar* CLASS, ...) + PREINIT: + int i; + CODE: + PERL_UNUSED_ARG(CLASS); + RETVAL = TRUE; + for (i = 1; i < items; ++i) { + gchar* feature = SvGchar_ptr(ST(i)); + if (!feature || !ext_has(feature)) { + RETVAL = FALSE; + break; + } + } + OUTPUT: + RETVAL + +GObject* +main_window(void) + CODE: + RETVAL = G_OBJECT(GLOBALS->mainwindow); + OUTPUT: + RETVAL + +GObject* +main_ui_manager(void) + PREINIT: + struct hbfile_data *data; + CODE: + RETVAL = NULL; + if (GLOBALS->mainwindow) { + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GLOBALS->mainwindow, GTK_TYPE_WINDOW)), "inst_data"); + if (data) { + RETVAL = G_OBJECT(data->manager); + } + } + OUTPUT: + RETVAL + +void +info(const gchar* CLASS, const gchar* title, const gchar* text) + CODE: + PERL_UNUSED_ARG(CLASS); + ext_run_modal(title, text, "info"); + +void +warn(const gchar* CLASS, const gchar* title, const gchar* text) + CODE: + PERL_UNUSED_ARG(CLASS); + ext_run_modal(title, text, "warn"); + +void +error(const gchar* CLASS, const gchar* title, const gchar* text) + CODE: + PERL_UNUSED_ARG(CLASS); + ext_run_modal(title, text, "error"); + +void +hook(const gchar* CLASS, const gchar* hook_name, ...) + PREINIT: + int i; + GList* list = NULL; + CODE: + PERL_UNUSED_ARG(CLASS); + for (i = 2; i < items; ++i) { + SV* sv = ST(i); + GValue *val = sv_to_val(sv); + list = g_list_append(list, val); + } + CLEANUP: + ext_vhook(hook_name, list); + g_list_free(list); + // TODO free all the things + +GObject* +open_prefs(const gchar* CLASS) + CODE: + PERL_UNUSED_ARG(CLASS); + RETVAL = G_OBJECT(defpref_dialog_new(PREF_GENERAL)); + OUTPUT: + RETVAL + + +MODULE = HomeBank PACKAGE = HomeBank::File + +const gchar* +owner(const gchar* CLASS, ...) + CODE: + PERL_UNUSED_ARG(CLASS); + if (1 < items) { + hbfile_change_owner(g_strdup(SvGchar_ptr(ST(1)))); + } + RETVAL = GLOBALS->owner; + OUTPUT: + RETVAL + +void +transactions(const gchar* CLASS) + PPCODE: + PERL_UNUSED_ARG(CLASS); + + GList* acc_list = g_hash_table_get_values(GLOBALS->h_acc); + GList* acc_link = g_list_first(acc_list); + for (; acc_link; acc_link = g_list_next(acc_link)) { + Account *acc = acc_link->data; + + GList* txn_link = g_queue_peek_head_link(acc->txn_queue); + for (; txn_link; txn_link = g_list_next(txn_link)) { + Transaction* txn = txn_link->data; + + GValue val = G_VALUE_INIT; + SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn)); + mXPUSHs(sv); + } + } + + g_list_free(acc_list); + +void +anonymize(void) + CODE: + hbfile_anonymize(); + +void +baz(const gchar* CLASS, Account* account) + CODE: + PERL_UNUSED_ARG(CLASS); + g_print("hello: %s\n", account->name); + +GPtrArray* +meh(const gchar* CLASS, GPtrArray* asdf) + CODE: + PERL_UNUSED_ARG(CLASS); + g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n"); + if (asdf) { + ; + } else { + g_print("the array is nil\n"); + } + RETVAL = asdf; + OUTPUT: + RETVAL + CLEANUP: + g_ptr_array_unref(asdf); + +GHashTable* +foo(const gchar* CLASS, GHashTable* asdf) + CODE: + PERL_UNUSED_ARG(CLASS); + g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n"); + if (asdf) { + GHashTableIter it; + g_hash_table_iter_init(&it, asdf); + gchar* key = NULL; + GValue* item = NULL; + while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) { + g_print("hash with key: %s\n", key); + } + } else { + g_print("the hash is nil\n"); + } + RETVAL = asdf; + OUTPUT: + RETVAL + CLEANUP: + g_hash_table_unref(asdf); + + +MODULE = HomeBank PACKAGE = HomeBank::Account + +void +compute_balances(const gchar* CLASS) + CODE: + PERL_UNUSED_ARG(CLASS); + account_compute_balances(); + +Account* +new(void) + CODE: + RETVAL = da_acc_malloc(); + OUTPUT: + RETVAL + +void +DESTROY(Account* SELF) + CODE: + da_acc_free(SELF); + +Account* +get(const gchar* CLASS, guint key) + CODE: + PERL_UNUSED_ARG(CLASS); + RETVAL = rc_ref(da_acc_get(key)); + OUTPUT: + RETVAL + +Account* +get_by_name(const gchar* CLASS, const gchar* name) + CODE: + PERL_UNUSED_ARG(CLASS); + RETVAL = rc_ref(da_acc_get_by_name((gchar*)name)); + OUTPUT: + RETVAL + +const gchar* +name(Account* SELF, ...) + CODE: + if (1 < items) { + account_rename(SELF, SvGchar_ptr(ST(1))); + } + RETVAL = SELF->name; + OUTPUT: + RETVAL + +const gchar* +number(Account* SELF, ...) + CODE: + if (1 < items) { + g_free(SELF->number); + SELF->number = g_strdup(SvGchar_ptr(ST(1))); + } + RETVAL = SELF->number; + OUTPUT: + RETVAL + +const gchar* +bankname(Account* SELF, ...) + CODE: + if (1 < items) { + g_free(SELF->bankname); + SELF->bankname = g_strdup(SvGchar_ptr(ST(1))); + } + RETVAL = SELF->bankname; + OUTPUT: + RETVAL + +gdouble +initial(Account* SELF, ...) + CODE: + if (1 < items) { + SELF->initial = SvNV(ST(1)); + } + RETVAL = SELF->initial; + OUTPUT: + RETVAL + +gdouble +minimum(Account* SELF, ...) + CODE: + if (1 < items) { + SELF->minimum = SvNV(ST(1)); + } + RETVAL = SELF->minimum; + OUTPUT: + RETVAL + +guint +cheque1(Account* SELF, ...) + ALIAS: + check1 = 1 + CODE: + PERL_UNUSED_VAR(ix); + if (1 < items) { + SELF->cheque1 = SvUV(ST(1)); + } + RETVAL = SELF->cheque1; + OUTPUT: + RETVAL + +guint +cheque2(Account* SELF, ...) + ALIAS: + check2 = 1 + CODE: + PERL_UNUSED_VAR(ix); + if (1 < items) { + SELF->cheque2 = SvUV(ST(1)); + } + RETVAL = SELF->cheque2; + OUTPUT: + RETVAL + +gdouble +balance(Account* SELF) + ALIAS: + bank_balance = 1 + future_balance = 2 + CODE: + switch (ix) { + case 1: + RETVAL = SELF->bal_bank; + break; + case 2: + RETVAL = SELF->bal_future; + break; + default: + RETVAL = SELF->bal_today; + break; + } + OUTPUT: + RETVAL + +gboolean +is_inserted(Account* SELF) + CODE: + RETVAL = da_acc_get(SELF->key) == SELF; + OUTPUT: + RETVAL + +gboolean +is_used(Account* SELF) + CODE: + RETVAL = account_is_used(SELF->key); + OUTPUT: + RETVAL + +gboolean +insert(Account* SELF) + CODE: + if (SELF->key == 0 || account_is_used(SELF->key)) + RETVAL = da_acc_append(rc_ref(SELF)); + else + RETVAL = da_acc_insert(rc_ref(SELF)); + OUTPUT: + RETVAL + +void +remove(Account* SELF) + CODE: + da_acc_remove(SELF->key); + +void +transactions(Account* SELF) + PPCODE: + GList* list = g_queue_peek_head_link(SELF->txn_queue); + for (; list; list = g_list_next(list)) { + Transaction* txn = list->data; + GValue val = G_VALUE_INIT; + SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn)); + mXPUSHs(sv); + } + +GObject* +open(Account* SELF) + CODE: - RETVAL = G_OBJECT(register_panel_window_new(SELF->key, SELF)); ++ RETVAL = G_OBJECT(register_panel_window_new(SELF)); + OUTPUT: + RETVAL + + +MODULE = HomeBank PACKAGE = HomeBank::Transaction + +Transaction* +new(void) + CODE: + RETVAL = da_transaction_malloc(); + OUTPUT: + RETVAL + +void +DESTROY(Transaction* SELF) + CODE: + da_transaction_free(SELF); + +gdouble +amount(Transaction* SELF, ...) + CODE: + if (1 < items) { + SELF->amount = SvNV(ST(1)); + } + RETVAL = SELF->amount; + OUTPUT: + RETVAL + +guint +account_num(Transaction* SELF, ...) + CODE: + if (1 < items) { + SELF->kacc = SvIV(ST(1)); + } + RETVAL = SELF->kacc; + OUTPUT: + RETVAL + +guint +paired_account_num(Transaction* SELF, ...) + CODE: + if (1 < items) { + SELF->kxferacc = SvIV(ST(1)); + } + RETVAL = SELF->kxferacc; + OUTPUT: + RETVAL + +void +date(Transaction* SELF, ...) + PPCODE: + if (1 < items) { + SELF->date = SvIV(ST(1)); + } + if (GIMME_V == G_ARRAY) { + GDate* d = g_date_new_julian(SELF->date); + mXPUSHp("day", 3); + mXPUSHi(g_date_get_day(d)); + mXPUSHp("month", 5); + mXPUSHi(g_date_get_month(d)); + mXPUSHp("year", 4); + mXPUSHi(g_date_get_year(d)); + g_date_free(d); + XSRETURN(6); + } else { + XSRETURN_IV(SELF->date); + } + +const gchar* +memo(Transaction* SELF, ...) + CODE: + if (1 < items) { + if (SELF->memo) g_free(SELF->memo); + SELF->memo = g_strdup(SvGchar_ptr(ST(1))); + } + RETVAL = SELF->memo ? SELF->memo : ""; + OUTPUT: + RETVAL + +const gchar* +info(Transaction* SELF, ...) + CODE: + if (1 < items) { + if (SELF->info) g_free(SELF->info); + SELF->info = g_strdup(SvGchar_ptr(ST(1))); + } + RETVAL = SELF->info ? SELF->info : ""; + OUTPUT: + RETVAL + +GObject* +open(Transaction* SELF) + CODE: - RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE)); ++ RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE, 0)); + deftransaction_set_transaction(GTK_WIDGET(RETVAL), SELF); + OUTPUT: + RETVAL + +Transaction* +pair_with(Transaction* SELF, Transaction* other, ...) + PREINIT: + int i; + GList* list = NULL; + CODE: + if (2 < items) { + list = g_list_append(list, other); + for (i = 2; i < items; ++i) { + Transaction* ptr = NULL; + SV* sv = ST(i); + EXT_P2C_OBJECT("HomeBank::Transaction", sv, ptr, Transaction*); + list = g_list_append(list, ptr); + } - other = ui_dialog_transaction_xfer_select_child(SELF, list); ++ ui_dialog_transaction_xfer_select_child(NULL, SELF, list, &other); + } + if (other) { + transaction_xfer_change_to_child(SELF, other); + SELF->paymode = PAYMODE_INTXFER; + } + RETVAL = other; + OUTPUT: + RETVAL + CLEANUP: + g_list_free(list); + +void +dump(Transaction* SELF) + CODE: + g_print("txn: %p (%s) at %u (%d/%d) flags:%d, paymode:%d, kpay:%d, kcat:%d", SELF, + SELF->memo, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat); + diff --cc src/hb-account.c index ee5055f,b6888c9..2ecbb6f --- a/src/hb-account.c +++ b/src/hb-account.c @@@ -51,10 -47,10 +50,10 @@@ da_acc_free(Account *item g_free(item->number); g_free(item->bankname); g_free(item->notes); -- ++ g_queue_free (item->txn_queue); -- - g_free(item); ++ + rc_free(item); } } @@@ -65,7 -61,8 +64,8 @@@ da_acc_malloc(void Account *item; DB( g_print("da_acc_malloc\n") ); - item = g_malloc0(sizeof(Account)); + item = rc_alloc(sizeof(Account)); + item->kcur = GLOBALS->kcur; item->txn_queue = g_queue_new (); return item; } @@@ -182,28 -177,13 +183,17 @@@ Account *existitem DB( g_print("da_acc_append\n") ); - /* ensure no duplicate */ - g_strstrip(item->name); - if(item->name != NULL) + existitem = da_acc_get_by_name( item->name ); + if( existitem == NULL ) { - existitem = da_acc_get_by_name( item->name ); - if( existitem == NULL ) - { - new_key = g_new0(guint32, 1); - *new_key = da_acc_get_max_key() + 1; - item->key = *new_key; - item->pos = da_acc_length() + 1; + item->key = da_acc_get_max_key() + 1; + item->pos = da_acc_length() + 1; + da_acc_insert(item); + - DB( g_print(" -> insert id: %d\n", *new_key) ); ++ GValue item_val = G_VALUE_INIT; ++ ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL); + - g_hash_table_insert(GLOBALS->h_acc, new_key, item); - - GValue item_val = G_VALUE_INIT; - ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL); - - return TRUE; - } + return TRUE; } DB( g_print(" -> %s already exist: %d\n", item->name, item->key) ); @@@ -240,19 -211,24 +221,24 @@@ static gboolean da_acc_name_grfunc(gpoi * */ Account * - da_acc_get_by_name(gchar *name) + da_acc_get_by_name(gchar *rawname) { + Account *retval = NULL; + gchar *stripname; + DB( g_print("da_acc_get_by_name\n") ); - return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_name_grfunc, name); - } + if( rawname ) + { + stripname = g_strdup(rawname); + g_strstrip(stripname); + if( strlen(stripname) > 0 ) + retval = g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_name_grfunc, stripname); - Account * - da_acc_get_by_imp_name(gchar *name) - { - DB( g_print("da_acc_get_by_imp_name\n") ); + g_free(stripname); + } - return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_imp_name_grfunc, name); - return retval; ++ return retval; } @@@ -369,14 -345,14 +355,14 @@@ gboolean retval while (lnk_acc != NULL) { Account *acc = lnk_acc->data; -- ++ if(acc->key != key) { lnk_txn = g_queue_peek_head_link(acc->txn_queue); while (lnk_txn != NULL) { Transaction *entry = lnk_txn->data; -- ++ if( key == entry->kxferacc) { retval = TRUE; @@@ -439,21 -415,24 +425,24 @@@ account_rename(Account *item, gchar *ne Account *existitem; gchar *stripname = account_get_stripname(newname); - existitem = da_acc_get_by_name(stripname); - if( existitem == NULL ) + if( strlen(stripname) > 0 ) { - g_free(item->name); - item->name = g_strdup(stripname); - return TRUE; - } + existitem = da_acc_get_by_name(stripname); + if( existitem == NULL ) + { + g_free(item->name); + item->name = g_strdup(stripname); + return TRUE; + } - g_free(stripname); + g_free(stripname); + } - + return FALSE; } --/* ++/* * change the account currency * change every txn to currency * ensure dst xfer transaction account will be set to same currency @@@ -494,7 -473,7 +483,7 @@@ guint32 maxkey, i acc->kcur = kcur; DB( g_print(" - '%s'\n", acc->name) ); -- ++ for(i=1;idata; -- ++ /* set initial amount */ acc->bal_bank = acc->initial; acc->bal_today = acc->initial; acc->bal_future = acc->initial; -- ++ /* add every txn */ lnk_txn = g_queue_peek_head_link(acc->txn_queue); while (lnk_txn != NULL) { Transaction *txn = lnk_txn->data; -- ++ if(!(txn->status == TXN_STATUS_REMIND)) { account_balances_add_internal(acc, txn); } lnk_txn = g_list_next(lnk_txn); } -- ++ lnk_acc = g_list_next(lnk_acc); } g_list_free(lst_acc); diff --cc src/hb-archive.c index 628e978,890cd7f..db3b101 --- a/src/hb-archive.c +++ b/src/hb-archive.c @@@ -41,7 -38,11 +41,11 @@@ extern struct HomeBank *GLOBALS Archive *da_archive_malloc(void) { - return rc_alloc(sizeof(Archive)); + Archive *item; + - item = g_malloc0(sizeof(Archive)); ++ item = rc_alloc(sizeof(Archive)); + item->key = 1; + return item; } @@@ -67,11 -75,9 +78,9 @@@ void da_archive_free(Archive *item { if(item->memo != NULL) g_free(item->memo); - - da_splits_free(item->splits); - //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared - + if(item->splits != NULL) + da_split_destroy(item->splits); - g_free(item); + rc_free(item); } } @@@ -111,6 -117,64 +120,64 @@@ guint da_archive_length(void } + /* append a fav with an existing key (from xml file only) */ + gboolean + da_archive_append(Archive *item) + { + GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item); + return TRUE; + } + + + gboolean + da_archive_append_new(Archive *item) + { + item->key = da_archive_get_max_key() + 1; + GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item); + return TRUE; + } + + + guint32 + da_archive_get_max_key(void) + { + GList *tmplist = g_list_first(GLOBALS->arc_list); + guint32 max_key = 0; + + while (tmplist != NULL) + { + Archive *item = tmplist->data; + - max_key = MAX(item->key, max_key); ++ max_key = MAX(item->key, max_key); + tmplist = g_list_next(tmplist); + } - ++ + return max_key; + } + + + Archive * + da_archive_get(guint32 key) + { + GList *tmplist; + Archive *retval = NULL; + + tmplist = g_list_first(GLOBALS->arc_list); + while (tmplist != NULL) + { + Archive *item = tmplist->data; + + if(item->key == key) + { + retval = item; + break; + } + tmplist = g_list_next(tmplist); + } + return retval; + } + + void da_archive_consistency(Archive *item) { Account *acc; @@@ -125,9 -190,20 +193,20 @@@ guint nbsplit item->kcat = 0; GLOBALS->changes_count++; } - - split_cat_consistency(item->splits); - + - //#1340142 check split category ++ //#1340142 check split category + if( item->splits != NULL ) + { + nbsplit = da_splits_consistency(item->splits); + //# 1416624 empty category when split + if(nbsplit > 0 && item->kcat > 0) + { + g_warning("txn consistency: fixed invalid cat on split txn"); + item->kcat = 0; + GLOBALS->changes_count++; + } + } - ++ // check payee exists pay = da_pay_get(item->kpay); if(pay == NULL) @@@ -169,13 -245,15 +248,15 @@@ Archive *da_archive_init_from_transacti arc->kpay = txn->kpay; arc->kcat = txn->kcat; if(txn->memo != NULL) - arc->memo = g_strdup(txn->memo); + arc->memo = g_strdup(txn->memo); else - arc->memo = g_strdup(_("(new archive)")); + arc->memo = g_strdup(_("(new archive)")); - if( da_splits_clone(txn->splits, arc->splits) > 0) + arc->tags = tags_clone(txn->tags); + arc->splits = da_splits_clone(txn->splits); + if( da_splits_length (arc->splits) > 0 ) arc->flags |= OF_SPLIT; //Flag that Splits are active -- ++ return arc; } @@@ -211,7 -289,7 +292,7 @@@ guint32 nextpostdate = nextdate /* get the final post date and free */ nextpostdate = g_date_get_julian(tmpdate); -- ++ return nextpostdate; } @@@ -239,7 -317,7 +320,7 @@@ gint shift finalpostdate = postdate; -- ++ tmpdate = g_date_new_julian(finalpostdate); /* manage weekend exception */ if( arc->weekend > 0 ) @@@ -266,11 -344,11 +347,11 @@@ } } } -- ++ /* get the final post date and free */ finalpostdate = g_date_get_julian(tmpdate); g_date_free(tmpdate); -- ++ return finalpostdate; } @@@ -314,10 -392,10 +395,10 @@@ guint32 nblate = 0 if(arc->flags & OF_LIMIT) nblate = MIN(nblate, arc->limit); -- ++ nblate = MIN(nblate, 11); */ -- ++ // pre 5.1 way post_date = g_date_new(); @@@ -373,7 -451,7 +454,7 @@@ gushort lastday } arc->daygap = CLAMP(lastday - g_date_get_day(post_date), 0, 3); -- ++ DB( g_print(" daygap is %d\n", arc->daygap) ); } else @@@ -410,10 -488,10 +491,10 @@@ GDate *today, *maxdate DB( g_print("\n[scheduled] date_get_post_max\n") ); //add until xx of the next month (excluded) -- if(GLOBALS->auto_smode == 0) ++ if(GLOBALS->auto_smode == 0) { DB( g_print(" - max is %d of next month\n", GLOBALS->auto_weekday) ); -- ++ today = g_date_new_julian(GLOBALS->today); //we compute user xx weekday of next month @@@ -421,9 -499,9 +502,9 @@@ g_date_set_day(maxdate, GLOBALS->auto_weekday); if(g_date_get_day (today) >= GLOBALS->auto_weekday) g_date_add_months(maxdate, 1); -- ++ nbdays = g_date_days_between(today, maxdate); -- ++ g_date_free(maxdate); g_date_free(today); } @@@ -454,7 -532,7 +535,7 @@@ Transaction *txn maxpostdate = scheduled_date_get_post_max(); txn = da_transaction_malloc(); -- ++ list = g_list_first(GLOBALS->arc_list); while (list != NULL) { @@@ -474,7 -552,7 +555,7 @@@ while(mydate < maxpostdate) { DB( hb_print_date(mydate, arc->memo) ); -- ++ da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, mydate); /* todo: ? fill in cheque number */ @@@ -500,7 -578,7 +581,7 @@@ nextarchive } da_transaction_free (txn); -- ++ return count; } diff --cc src/hb-category.c index 9487886,3dc34e4..e26b2b8 --- a/src/hb-category.c +++ b/src/hb-category.c @@@ -64,7 -62,8 +65,8 @@@ da_cat_free(Category *item DB( g_print(" => %d, %s\n", item->key, item->name) ); g_free(item->name); + g_free(item->fullname); - g_free(item); + rc_free(item); } } @@@ -149,6 -165,57 +168,57 @@@ da_cat_remove(guint32 key return g_hash_table_foreach_remove(GLOBALS->h_cat, (GHRFunc)da_cat_remove_grfunc, &key); } + + static void + da_cat_build_fullname(Category *item) + { + Category *parent; + + g_free(item->fullname); + if( item->parent == 0 ) + item->fullname = g_strdup(item->name); + else + { + parent = da_cat_get(item->parent); + if( parent != NULL ) + item->fullname = g_strconcat(parent->name, ":", item->name, NULL); + } - ++ + DB( g_print("- updated %d:'%s' fullname='%s'\n", item->key, item->name, item->fullname) ); + + } + + + static void + da_cat_rename(Category *item, gchar *newname) + { + + DB( g_print("- renaming %s' => '%s'\n", item->name, newname) ); - ++ + g_free(item->name); + item->name = g_strdup(newname); + da_cat_build_fullname(item); - ++ + if( item->parent == 0 ) + { + GHashTableIter iter; + gpointer value; + + DB( g_print("- updating subcat fullname\n") ); - ++ + g_hash_table_iter_init (&iter, GLOBALS->h_cat); + while (g_hash_table_iter_next (&iter, NULL, &value)) + { + Category *subcat = value; - ++ + if( subcat->parent == item->key ) + da_cat_build_fullname(subcat); + } + + } + } + + /** * da_cat_insert: * @@@ -162,12 -229,16 +232,16 @@@ da_cat_insert(Category *item { guint32 *new_key; - DB( g_print("da_cat_insert\n") ); + DB( g_print("\nda_cat_insert\n") ); + + DB( g_print("- '%s'\n", item->name) ); - + new_key = g_new0(guint32, 1); *new_key = item->key; g_hash_table_insert(GLOBALS->h_cat, new_key, item); + da_cat_build_fullname(item); - ++ return TRUE; } @@@ -184,30 -256,18 +259,18 @@@ gboolea da_cat_append(Category *cat) { Category *existitem; - guint32 *new_key; - gchar *fullname; - - DB( g_print("da_cat_append\n") ); - - if( cat->name != NULL) - { - - fullname = da_cat_get_fullname(cat); - existitem = da_cat_get_by_fullname( fullname ); - g_free(fullname); - if( existitem == NULL ) - { - new_key = g_new0(guint32, 1); - *new_key = da_cat_get_max_key() + 1; - cat->key = *new_key; - - DB( g_print(" -> insert id: %d\n", *new_key) ); + DB( g_print("\nda_cat_append\n") ); - g_hash_table_insert(GLOBALS->h_cat, new_key, cat); - return TRUE; - } + if( !cat->fullname ) + da_cat_build_fullname(cat); - + + existitem = da_cat_get_by_fullname( cat->fullname ); + if( existitem == NULL ) + { + cat->key = da_cat_get_max_key() + 1; + da_cat_insert(cat); + return TRUE; } DB( g_print(" -> %s already exist\n", cat->name) ); @@@ -334,69 -311,71 +314,71 @@@ struct fullcatcontext ctx } - /* fullname i.e. car:refuel */ - struct fullcatcontext + static gchar **da_cat_get_by_fullname_split_clean(gchar *rawfullname, guint *outlen) { - guint parent; - gchar *name; - }; + gchar **partstr = g_strsplit(rawfullname, ":", 2); + guint len = g_strv_length(partstr); + gboolean valid = TRUE; + DB( g_print("- spliclean '%s' - %d parts\n", rawfullname, g_strv_length(partstr)) ); - static gboolean - da_cat_fullname_grfunc(gpointer key, Category *item, struct fullcatcontext *ctx) - { + if( outlen != NULL ) + *outlen = len; - + - //DB( g_print("'%s' == '%s'\n", ctx->name, item->name) ); - if( item->parent == ctx->parent ) + if(len >= 1) { - if(!strcasecmp(ctx->name, item->name)) - return TRUE; + g_strstrip(partstr[0]); + if( strlen(partstr[0]) == 0 ) + valid = FALSE; + + if(len == 2) + { + g_strstrip(partstr[1]); + if( strlen(partstr[1]) == 0 ) + valid = FALSE; + } } - return FALSE; + + if(valid == TRUE) + return partstr; + + DB( g_print("- is invalid\n") ); + + g_strfreev(partstr); + return NULL; } + Category * - da_cat_get_by_fullname(gchar *fullname) + da_cat_get_by_fullname(gchar *rawfullname) { - struct fullcatcontext ctx; - gchar **typestr; - Category *item = NULL; + gchar **partstr; + Category *parent = NULL; + Category *retval = NULL; + guint len; - + - DB( g_print("da_cat_get_by_fullname\n") ); + DB( g_print("\nda_cat_get_by_fullname\n") ); - typestr = g_strsplit(fullname, ":", 2); - if( g_strv_length(typestr) == 2 ) + if( rawfullname ) { - ctx.parent = 0; - ctx.name = typestr[0]; - DB( g_print(" [x:x] try to find the parent : '%s'\n", typestr[0]) ); - - Category *parent = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); - if( parent != NULL ) + if( (partstr = da_cat_get_by_fullname_split_clean(rawfullname, &len)) != NULL ) { - ctx.parent = parent->key; - ctx.name = typestr[1]; + if( len >= 1 ) + { + parent = da_cat_get_by_name_find_internal(0, partstr[0]); + retval = parent; + } - + - DB( g_print(" [x:x] and searching sub %d '%s'\n", ctx.parent, ctx.name) ); + if( len == 2 && parent != NULL ) + { + retval = da_cat_get_by_name_find_internal(parent->key, partstr[1]); + } - item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); + g_strfreev(partstr); } } - else - { - ctx.parent = 0; - ctx.name = fullname; - - DB( g_print(" [x] try to '%s'\n", fullname) ); - - item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); - } - - g_strfreev(typestr); - + - DB( g_print(" return value %p\n", item) ); - - return item; + return retval; } @@@ -409,111 -388,54 +391,54 @@@ * */ Category * - da_cat_append_ifnew_by_fullname(gchar *fullname, gboolean imported) + da_cat_append_ifnew_by_fullname(gchar *rawfullname) { - struct fullcatcontext ctx; - gchar **typestr; - Category *newcat, *item, *retval = NULL; - guint32 *new_key; + gchar **partstr; + Category *parent = NULL; + Category *newcat = NULL; + Category *retval = NULL; + guint len; - DB( g_print("da_cat_append_ifnew_by_fullname\n") ); + DB( g_print("\nda_cat_append_ifnew_by_fullname\n") ); - DB( g_print(" -> fullname: '%s' %d\n", fullname, strlen(fullname)) ); - - if( strlen(fullname) > 0 ) + if( rawfullname ) { - typestr = g_strsplit(fullname, ":", 2); - - /* if we have a subcategory : aaaa:bbb */ - if( g_strv_length(typestr) == 2 ) + if( (partstr = da_cat_get_by_fullname_split_clean(rawfullname, &len)) != NULL ) { - ctx.parent = 0; - ctx.name = typestr[0]; - DB( g_print(" try to find the parent:'%s'\n", typestr[0]) ); - - Category *parent = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); - if( parent == NULL ) - { - DB( g_print(" -> not found\n") ); - - // append a new category - new_key = g_new0(guint32, 1); - *new_key = da_cat_get_max_key() + 1; - - newcat = da_cat_malloc(); - newcat->key = *new_key; - newcat->name = g_strdup(typestr[0]); - newcat->imported = imported; - - parent = newcat; - - DB( g_print(" -> insert cat '%s' id: %d\n", newcat->name, newcat->key) ); - - g_hash_table_insert(GLOBALS->h_cat, new_key, newcat); - } - - ctx.parent = parent->key; - ctx.name = typestr[1]; - DB( g_print(" searching %d '%s'\n", ctx.parent, ctx.name) ); - - item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); - if( item == NULL ) + if( len >= 1 ) { - // append a new subcategory - new_key = g_new0(guint32, 1); - *new_key = da_cat_get_max_key() + 1; - - newcat = da_cat_malloc(); - newcat->key = *new_key; - newcat->parent = parent->key; - newcat->name = g_strdup(typestr[1]); - newcat->imported = imported; - - newcat->flags |= GF_SUB; - //#1713413 take parent type into account - if(parent->flags & GF_INCOME) - newcat->flags |= GF_INCOME; - - DB( g_print(" -> insert subcat '%s' id: %d\n", newcat->name, newcat->key) ); - - g_hash_table_insert(GLOBALS->h_cat, new_key, newcat); - - retval = newcat; + parent = da_cat_get_by_name_find_internal(0, partstr[0]); + if( parent == NULL ) + { + parent = da_cat_malloc(); + parent->key = da_cat_get_max_key() + 1; + parent->name = g_strdup(partstr[0]); + da_cat_insert(parent); + } + retval = parent; } - else - retval = item; - } - /* this a single category : aaaa */ - else - { - ctx.parent = 0; - ctx.name = typestr[0]; - DB( g_print(" searching %d '%s'\n", ctx.parent, ctx.name) ); - + - item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx); - if( item == NULL ) + /* if we have a subcategory - xxx:xxx */ + if( len == 2 && parent != NULL ) { - // append a new category - new_key = g_new0(guint32, 1); - *new_key = da_cat_get_max_key() + 1; - - newcat = da_cat_malloc(); - newcat->key = *new_key; - newcat->name = g_strdup(typestr[0]); - newcat->imported = imported; - - DB( g_print(" -> insert cat '%s' id: %d\n", newcat->name, newcat->key) ); - - g_hash_table_insert(GLOBALS->h_cat, new_key, newcat); - + newcat = da_cat_get_by_name_find_internal(parent->key, partstr[1]); + if( newcat == NULL ) + { + newcat = da_cat_malloc(); + newcat->key = da_cat_get_max_key() + 1; + newcat->parent = parent->key; + newcat->name = g_strdup(partstr[1]); + newcat->flags |= GF_SUB; + //#1713413 take parent type into account + if(parent->flags & GF_INCOME) + newcat->flags |= GF_INCOME; + da_cat_insert(newcat); + } retval = newcat; } - else - retval = item; - + + g_strfreev(partstr); } - - g_strfreev(typestr); } return retval; @@@ -565,8 -498,17 +501,17 @@@ gboolean isIncome GLOBALS->changes_count++; } } - - g_strstrip(item->name); + + if( item->name != NULL ) + g_strstrip(item->name); + else + { + item->name = g_strdup("void"); + da_cat_build_fullname(item); + g_warning("category consistency: fixed null name"); + GLOBALS->changes_count++; + } - ++ } @@@ -623,11 -565,11 +568,11 @@@ guint32 retval = 0 } --void ++void category_delete_unused(void) { GList *lcat, *list; -- ++ lcat = list = g_hash_table_get_values(GLOBALS->h_cat); while (list != NULL) { @@@ -642,7 -584,7 +587,7 @@@ } --static void ++static void category_fill_usage_count(guint32 kcat) { Category *cat = da_cat_get (kcat); @@@ -696,16 -638,16 +641,16 @@@ guint i, nbsplit //#1689308 count split as well if( txn->flags & OF_SPLIT ) { - nbsplit = da_splits_count(txn->splits); + nbsplit = da_splits_length(txn->splits); for(i=0;isplits[i]; - + Split *split = da_splits_get(txn->splits, i); - ++ category_fill_usage_count(split->kcat); } } else -- category_fill_usage_count(txn->kcat); ++ category_fill_usage_count(txn->kcat); lnk_txn = g_list_next(lnk_txn); } @@@ -732,11 -674,11 +677,11 @@@ //#1689308 count split as well if( entry->flags & OF_SPLIT ) { - nbsplit = da_splits_count(entry->splits); + nbsplit = da_splits_length(entry->splits); for(i=0;isplits[i]; - + Split *split = da_splits_get(entry->splits, i); - ++ category_fill_usage_count(split->kcat); } } @@@ -778,7 -720,7 +723,7 @@@ guint i, nbsplit while (lnk_txn != NULL) { Transaction *txn = lnk_txn->data; -- ++ if(txn->kcat == key1) { txn->kcat = key2; @@@ -800,7 -742,7 +745,7 @@@ lnk_txn = g_list_next(lnk_txn); } -- ++ lnk_acc = g_list_next(lnk_acc); } g_list_free(lst_acc); @@@ -1131,8 -1057,15 +1060,15 @@@ category_type_get(Category *item } + gchar + category_get_type_char(Category *item) + { + return (item->flags & GF_INCOME) ? '+' : '-'; + } + - static gint category_change_type_eval(Category *item, gboolean isIncome) -static gint ++static gint + category_change_type_eval(Category *item, gboolean isIncome) { if( (item->flags & (GF_INCOME)) && !isIncome ) return 1; @@@ -1140,13 -1073,14 +1076,14 @@@ } - gint category_change_type(Category *item, gboolean isIncome) -gint ++gint + category_change_type(Category *item, gboolean isIncome) { gint changes = 0; GList *lcat, *list; changes += category_change_type_eval(item, isIncome); -- ++ item->flags &= ~(GF_INCOME); //delete flag if(isIncome == TRUE) item->flags |= GF_INCOME; diff --cc src/hb-transaction.c index eb82509,0368946..9665080 --- a/src/hb-transaction.c +++ b/src/hb-transaction.c @@@ -23,11 -23,8 +23,11 @@@ #include "hb-tag.h" #include "hb-split.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ - /* Debug macros */ + /* Debug macro */ /****************************************************************************/ #define MYDEBUG 0 @@@ -140,9 -128,31 +131,31 @@@ Transaction *da_transaction_init_from_t } + Transaction *da_transaction_set_default_template(Transaction *txn) + { + Account *acc; + Archive *arc; + + DB( g_print("da_transaction_set_default_template\n") ); + + acc = da_acc_get(txn->kacc); + if(acc != NULL && acc->karc > 0) + { + arc = da_archive_get(acc->karc); + if( arc ) + { + DB( g_print(" - init with default template\n") ); + da_transaction_init_from_template(txn, arc); + } + } + + return txn; + } + + Transaction *da_transaction_clone(Transaction *src_item) { -Transaction *new_item = g_memdup(src_item, sizeof(Transaction)); +Transaction *new_item = rc_dup(src_item, sizeof(Transaction)); DB( g_print("da_transaction_clone\n") ); @@@ -950,11 -987,8 +993,11 @@@ Account *acc if(newope->paymode == PAYMODE_INTXFER) { - transaction_xfer_search_or_add_child(NULL, newope, FALSE); + transaction_xfer_search_or_add_child(parent, newope, newope->kxferacc); } + + GValue txn_value = G_VALUE_INIT; + ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, newope), NULL); } return newope; diff --cc src/hb-xml.c index da67dad,ae3ea9b..cc99d48 --- a/src/hb-xml.c +++ b/src/hb-xml.c @@@ -1605,42 -1664,35 +1669,38 @@@ gchar *outstr gint retval = XML_OK; GError *error = NULL; + GValue filename_val = G_VALUE_INIT; + ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL); + io = g_io_channel_new_file(filename, "w", &error); - if(io == NULL) + if(error) { - g_message("file error on: %s", filename); - retval = XML_IO_ERROR; - - if(error) - g_print("failed: %s\n", error->message); - + g_warning("unable to save file %s: %s", filename, error->message); g_error_free(error); + return(XML_IO_ERROR); } - else - { - g_io_channel_write_chars(io, "\n", -1, NULL, NULL); - outstr = g_strdup_printf("\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM); - g_io_channel_write_chars(io, outstr, -1, NULL, NULL); - g_free(outstr); + g_io_channel_write_chars(io, "\n", -1, NULL, NULL); - retval = homebank_save_xml_prop(io); - retval = homebank_save_xml_cur(io); - retval = homebank_save_xml_acc(io); - retval = homebank_save_xml_pay(io); - retval = homebank_save_xml_cat(io); - retval = homebank_save_xml_tag(io); - retval = homebank_save_xml_asg(io); - retval = homebank_save_xml_arc(io); - retval = homebank_save_xml_ope(io); + outstr = g_strdup_printf("\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM); + g_io_channel_write_chars(io, outstr, -1, NULL, NULL); + g_free(outstr); - g_io_channel_write_chars(io, "\n", -1, NULL, NULL); + retval = homebank_save_xml_prop(io); + retval = homebank_save_xml_cur(io); + retval = homebank_save_xml_acc(io); + retval = homebank_save_xml_pay(io); + retval = homebank_save_xml_cat(io); + //retval = homebank_save_xml_tag(io); + retval = homebank_save_xml_asg(io); + retval = homebank_save_xml_arc(io); + + retval = homebank_save_xml_ope(io); + + g_io_channel_write_chars(io, "\n", -1, NULL, NULL); + + g_io_channel_unref (io); - g_io_channel_unref (io); - } return retval; } diff --cc src/homebank.c index 60e87c8,f33a1cb..2eff668 --- a/src/homebank.c +++ b/src/homebank.c @@@ -19,9 -19,8 +19,9 @@@ #include "homebank.h" +#include "ext.h" - #include "dsp_mainwindow.h" + #include "dsp-mainwindow.h" #include "hb-preferences.h" #include "language.h" diff --cc src/ui-pref.c index bcee6b1,a5c56eb..c9d435a --- a/src/ui-pref.c +++ b/src/ui-pref.c @@@ -21,11 -21,9 +21,11 @@@ #include "homebank.h" #include "ui-pref.h" - #include "dsp_mainwindow.h" + #include "dsp-mainwindow.h" #include "gtk-chart-colors.h" +#include "ext.h" + #include "ui-currency.h" @@@ -66,24 -69,27 +66,29 @@@ enu static gchar *pref_iconname[PREF_MAX] = { "prf-general", "prf-interface", + "prf-locale", "prf-columns", - "prf-display", -//"prf-display", ++//"prf-display", "prf-import", "prf-report", + "prf-backup", + "prf-folder", "prf-euro", // to be renamed +"prf-plugins", //"prf_charts.svg" }; static gchar *pref_name[PREF_MAX] = { N_("General"), N_("Interface"), + N_("Locale"), N_("Transactions"), - N_("Display format"), N_("Import/Export"), N_("Report"), + N_("Backup"), + N_("Folders"), -N_("Euro minor") +N_("Euro minor"), +N_("Plugins") // }; @@@ -1122,12 -1148,12 +1152,12 @@@ gint crow, row gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + label = make_label_group(_("OFX/QFX options")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); - + row = 1; - label = make_label_widget(_("_Name field:")); + label = make_label_widget(_("OFX _Name:")); //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); widget = make_cycle(label, CYA_IMPORT_OFXNAME); @@@ -1149,67 -1175,32 +1179,32 @@@ gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + label = make_label_group(_("QIF options")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); - + row = 1; - label = make_label_widget(_("Memos:")); - gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); - widget = gtk_check_button_new_with_mnemonic (_("_Import")); + widget = gtk_check_button_new_with_mnemonic (_("_Import memos")); data->CM_dtex_qifmemo = widget; - gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); - widget = gtk_check_button_new_with_mnemonic (_("_Swap with payees")); + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1); + widget = gtk_check_button_new_with_mnemonic (_("_Swap memos with payees")); data->CM_dtex_qifswap = widget; - gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1); - + gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); - // group :: Files folder + // group :: other options group_grid = gtk_grid_new (); gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + - label = make_label_group(_("Files folder")); + label = make_label_group(_("Other options")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); row = 1; - label = make_label_widget(_("_Import:")); - //----------------------------------------- l, r, t, b - gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); - - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_hexpand (hbox, TRUE); - gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1); - - widget = make_string(label); - data->ST_path_import = widget; - gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED); - gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); - - //widget = gtk_button_new_with_label("..."); - widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON); - data->BT_path_import = widget; - gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); - - row++; - label = make_label_widget(_("_Export:")); - //----------------------------------------- l, r, t, b - gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); - - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_set_hexpand (hbox, TRUE); - gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1); - - widget = make_string(label); - data->ST_path_export = widget; - gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED); - gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); + widget = gtk_check_button_new_with_mnemonic (_("Sentence _case memo/payee")); + data->CM_dtex_ucfirst = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1); - + - //widget = gtk_button_new_with_label("..."); - widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON); - data->BT_path_export = widget; - gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); return content_grid; } @@@ -1263,12 -1254,12 +1258,12 @@@ gint crow, row gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + label = make_label_group(_("Initial filter")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); - + row = 1; - label = make_label_widget(_("Date _range:")); + label = make_label_widget(_("_Range:")); //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); widget = make_daterange(label, FALSE); @@@ -1489,8 -1480,8 +1484,8 @@@ gint crow, row gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + - label = make_label_group(_("Date")); + label = make_label_group(_("User interface")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); row = 1; @@@ -1629,6 -1658,27 +1662,27 @@@ gint crow, row data->CM_herit_date = widget; gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + // group :: Memo autocomplete + group_grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); + gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); + gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - ++ + label = make_label_group(_("Memo autocomplete")); + gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); + + row = 1; + widget = gtk_check_button_new_with_mnemonic (_("Active")); + data->CM_memoacp = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + + row++; + widget = make_numeric(NULL, 0, 1460); + data->ST_memoacp_days = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); + label = make_label(_("rolling days"), 0, 0.5); + gtk_grid_attach (GTK_GRID (group_grid), label, 3, row, 1, 1); + // group :: Column list /* group_grid = gtk_grid_new (); @@@ -1734,8 -1785,9 +1789,9 @@@ gint crow, row //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL); + data->GR_colors = hbox; gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1); - + widget = gtk_color_button_new (); data->CP_exp_color = widget; gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); @@@ -1773,8 -1825,8 +1829,8 @@@ gint crow, row gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + - label = make_label_group(_("Program start")); + label = make_label_group(_("Backup")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); row = 1; @@@ -1802,8 -1873,8 +1877,8 @@@ gint crow, row gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + - label = make_label_group(_("Fiscal year")); + label = make_label_group(_("HomeBank files")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); row = 1; @@@ -1825,28 -1901,32 +1905,32 @@@ gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - + - label = make_label_group(_("Main window reports")); + label = make_label_group(_("Exchange files")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); - + row = 1; - label = make_label_widget(_("Date _range:")); + label = make_label_widget(_("_Import:")); + //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); - widget = make_daterange(label, FALSE); - data->CY_daterange_wal = widget; - gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); - // group :: Files folder - group_grid = gtk_grid_new (); - gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); - gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); - gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_hexpand (hbox, TRUE); + gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1); - label = make_label_group(_("Files folder")); - gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); + widget = make_string(label); + data->ST_path_import = widget; + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED); + gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); - row = 1; - label = make_label_widget(_("_Default:")); + //widget = gtk_button_new_with_label("..."); + widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON); + data->BT_path_import = widget; + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + + row++; + label = make_label_widget(_("_Export:")); + //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); @@@ -1860,9 -1940,71 +1944,71 @@@ //widget = gtk_button_new_with_label("..."); widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON); - data->BT_path_hbfile = widget; + data->BT_path_export = widget; gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); + + + return content_grid; + } + + + static GtkWidget *defpref_page_general (struct defpref_data *data) + { + GtkWidget *content_grid, *group_grid, *label, *widget; + gint crow, row; + + content_grid = gtk_grid_new(); + gtk_grid_set_row_spacing (GTK_GRID (content_grid), SPACING_LARGE); + gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL); + + crow = 0; + // group :: Program start + group_grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); + gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); + gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - ++ + label = make_label_group(_("Program start")); + gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); + + row = 1; + widget = gtk_check_button_new_with_mnemonic (_("Show splash screen")); + data->CM_show_splash = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + + row++; + widget = gtk_check_button_new_with_mnemonic (_("Load last opened file")); + data->CM_load_last = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + + row++; + widget = gtk_check_button_new_with_mnemonic (_("Post pending scheduled transactions")); + data->CM_append_scheduled = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + + row++; + widget = gtk_check_button_new_with_mnemonic (_("Update currencies online")); + data->CM_do_update_currency = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); + + + // group :: Main window reports + group_grid = gtk_grid_new (); + gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); + gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); + gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1); - ++ + label = make_label_group(_("Main window reports")); + gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); + + row = 1; + label = make_label(_("_Range:"), 0, 0.5); + gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); + widget = make_daterange(label, FALSE); + data->CY_daterange_wal = widget; + gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); + return content_grid; } @@@ -2314,12 -2267,13 +2470,13 @@@ GtkWidget *hbox, *vbox, *sw, *widget, * //connect all our signals g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window); - g_signal_connect (G_OBJECT (data.BT_clear), "clicked", G_CALLBACK (defpref_clear), NULL); + g_signal_connect (data.CM_bak_is_automatic, "toggled", G_CALLBACK (defpref_backuptoggle), NULL); + - + //path selector - g_signal_connect (data.BT_path_hbfile, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(1)); - g_signal_connect (data.BT_path_import, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(2)); - g_signal_connect (data.BT_path_export, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(3)); + g_signal_connect (data.BT_path_hbfile, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_WALLET)); + g_signal_connect (data.BT_path_import, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_IMPORT)); + g_signal_connect (data.BT_path_export, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_EXPORT)); g_signal_connect (data.CM_custom_colors, "toggled", G_CALLBACK (defpref_colortoggle), NULL); g_signal_connect (data.CY_colors, "changed", G_CALLBACK (defpref_colorpreset), NULL); @@@ -2402,8 -2354,12 +2559,12 @@@ g_free(old_lang); break; + + case 55: + defpref_reset (window, NULL); + break; } - + // cleanup and destroy //defhbfile_cleanup(&data, result); diff --cc src/ui-pref.h index 1ec90ba,19d3876..1ceb457 --- a/src/ui-pref.h +++ b/src/ui-pref.h @@@ -48,12 -67,9 +67,9 @@@ struct defpref_dat GtkWidget *BT_go_up; GtkWidget *BT_go_down; - GtkWidget *NB_fiscyearday; - GtkWidget *CY_fiscyearmonth; -- ++ GtkWidget *CM_runwizard; - GtkWidget *ST_path_hbfile, *BT_path_hbfile; GtkWidget *ST_path_import, *BT_path_import; GtkWidget *ST_path_export, *BT_path_export; @@@ -74,25 -88,24 +88,24 @@@ GtkWidget *CY_daterange_txn; GtkWidget *ST_datefuture_nbdays; GtkWidget *CY_daterange_rep; -- ++ /* currencies */ GtkWidget *LB_default; -- GtkWidget *BT_default; -- ++ GtkWidget *BT_default; ++ GtkWidget *CM_euro_enable; GtkWidget *GRP_currency; GtkWidget *GRP_rate; GtkWidget *GRP_format; -- ++ GtkWidget *CY_euro_preset; GtkWidget *ST_euro_country; GtkWidget *NB_euro_value; GtkWidget *ST_euro_symbol; GtkWidget *CM_euro_isprefix; -- GtkWidget *ST_euro_decimalchar; -- GtkWidget *ST_euro_groupingchar; ++ GtkWidget *ST_euro_decimalchar; ++ GtkWidget *ST_euro_groupingchar; GtkWidget *NB_euro_fracdigits; GtkWidget *LB_numbereuro; @@@ -119,24 -133,10 +133,26 @@@ gint country; + GtkWidget *PI_plugin_columns; }; +enum +{ + PREF_GENERAL, + PREF_INTERFACE, - PREF_TRANSACTIONS, - PREF_DISPLAY_FORMAT, - PREF_IMPORT_EXPORT, ++ PREF_LOCALE, //old DISPLAY ++ PREF_TXN, //old COLUMNS ++ PREF_IMPORT, + PREF_REPORT, - PREF_EURO_MINOR, ++ PREF_BACKUP, ++ PREF_FOLDERS, ++ PREF_EURO, + PREF_PLUGINS, + PREF_MAX +}; -typedef struct + - typedef struct ++typedef struct { gchar *locale; gchar *name; diff --cc themes/hicolor/Makefile.am index 91ced1b,48f5746..fd5bcc9 --- a/themes/hicolor/Makefile.am +++ b/themes/hicolor/Makefile.am @@@ -77,11 -83,12 +83,13 @@@ private_icons = hicolor_status_48x48_prf-general.png \ hicolor_status_48x48_prf-import.png \ hicolor_status_48x48_prf-interface.png \ + hicolor_status_48x48_prf-locale.png \ hicolor_status_48x48_prf-report.png \ + hicolor_status_48x48_prf-plugins.png \ + hicolor_actions_scalable_edit-split-symbolic.svg \ hicolor_actions_scalable_toggle-sign-symbolic.svg \ - hicolor_actions_scalable_btn-collapse-symbolic.svg \ - hicolor_actions_scalable_btn-expand-symbolic.svg \ + hicolor_actions_scalable_list-collapse-all-symbolic.svg \ + hicolor_actions_scalable_list-expand-all-symbolic.svg \ $(NULL)