From: Charles McGarvey Date: Sun, 4 Feb 2018 17:16:29 +0000 (-0700) Subject: Merge branch 'master' into ext-perl X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=35b9973e4de7d69ad8841ead996a2e6cf1d85f08;hp=-c;p=chaz%2Fhomebank Merge branch 'master' into ext-perl --- 35b9973e4de7d69ad8841ead996a2e6cf1d85f08 diff --combined Makefile.am index de75d0f,e5c6cfe..45d1f49 --- a/Makefile.am +++ b/Makefile.am @@@ -1,11 -1,16 +1,18 @@@ # HomeBank Makefile.am +ACLOCAL_AMFLAGS = -I m4 + #SUBDIRS = src -SUBDIRS = src data images mime pixmaps themes po doc +SUBDIRS = src data images mime pixmaps themes po doc plugins + datasdir = $(datadir)/homebank/datas/ + datas_DATA = \ + ChangeLog + + EXTRA_DIST = $(datas_DATA) + + # don't forget to do a 'make check' # to ensure all files are in po/POTFILES.in @@@ -21,8 -26,11 +28,17 @@@ DISTCLEANFILES = ... intltool-extract intltool-update \ po/.intltool-merge-cache - + # we clean every folder under /usr/share/homebank as well on uninstall + uninstall-hook: + -rm -rf $(datadir)/homebank/datas + -rm -rf $(datadir)/homebank/help + -rm -rf $(datadir)/homebank/icons + -rm -rf $(datadir)/homebank/images + #-rmdir $(datadir)/homebank ++ +run: all + PERL5LIB=src src/homebank + +debug: all + PERL5LIB=src gdb src/homebank ++ diff --combined configure.ac index 798e623,99db971..f1c2dfd --- a/configure.ac +++ b/configure.ac @@@ -2,17 -2,13 +2,17 @@@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.52) - AC_INIT([homebank], [5.1.3]) + AC_INIT([homebank], [5.1.7]) #AC_INIT([homebank], [x.x-rc]) AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE([1.9 foreign]) +LT_PREREQ([2.2]) +LT_INIT([dlopen]) +AC_CONFIG_MACRO_DIR([m4]) + # If the source code has changed at all, increment REVISION # If any interfaces have been added, removed, or changed, increment CURRENT, and set REVISION to 0. # If any interfaces have been added since the last public release, then increment AGE. @@@ -26,7 -22,7 +26,7 @@@ AC_PROG_INSTAL AC_PROG_INTLTOOL # Checks for libraries. - PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.12 glib-2.0 >= 2.39 gmodule-2.0 >= 2.39) -PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.16 glib-2.0 >= 2.39) ++PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.16 glib-2.0 >= 2.39 gmodule-2.0 >= 2.39) AC_SUBST(DEPS_CFLAGS) AC_SUBST(DEPS_LIBS) AC_CHECK_LIB(m, pow) @@@ -35,7 -31,7 +35,7 @@@ PKG_CHECK_MODULES(LIBSOUP, [libsoup-2. AC_SUBST(LIBSOUP_CFLAGS) AC_SUBST(LIBSOUP_LIBS) - # release flags + # general usage flags CFLAGS="${CFLAGS} -Wall -Wmissing-prototypes" # disable deprecated warnings @@@ -70,7 -66,7 +70,7 @@@ the then AC_CHECK_LIB(ofx, ofx_set_status_cb, OFX_0_7="-DOFX_ENABLE") DEPS_LIBS="-lofx ${DEPS_LIBS}" - CFLAGS="${CFLAGS} $OFX_0_7" + CPPFLAGS="${CPPFLAGS} $OFX_0_7" else noofx=true AC_MSG_RESULT([Libofx header missing. Check your libofx installation]) @@@ -82,41 -78,6 +82,41 @@@ els fi AM_CONDITIONAL(NOOFX, test x$noofx = xtrue) +AC_ARG_WITH(perl, + [ --with-perl build with perl plug-in support [default=without]], + [build_perl=$withval], + [build_perl=no] +) +if test x$build_perl != xno +then + test x$build_perl != xyes -a -x "$build_perl" && PERL=$build_perl + AC_PATH_PROG(PERL, perl, perl) + AC_MSG_CHECKING(if perl can be embedded) + if $PERL -MExtUtils::Embed -e "use v5.8" >/dev/null 2>&1 + then + AC_MSG_RESULT(yes) + CPPFLAGS="${CPPFLAGS} -DPERL_ENABLE" + PERL_CPPFLAGS="`$PERL -MExtUtils::Embed -e ccopts`" + PERL_OBJS="ext-perl.o perlxsi.o" + PERL_PRIVLIBEXP="`$PERL -MConfig -e 'print $Config{privlibexp}'`" + PERL_SITELIBEXP="`$PERL -MConfig -e 'print $Config{sitelibexp}'`" + DEPS_LIBS="`$PERL -MExtUtils::Embed -e ldopts` ${DEPS_LIBS}" + if test -e "$PERL_SITELIBEXP/ExtUtils/xsubpp" + then + XSUBPP="$PERL $PERL_SITELIBEXP/ExtUtils/xsubpp" + else + XSUBPP="$PERL $PERL_PRIVLIBEXP/ExtUtils/xsubpp" + fi + else + AC_MSG_ERROR([no working perl found, or perl not version >= 5.8]) + fi +fi +AC_SUBST(PERL_CPPFLAGS) +AC_SUBST(PERL_OBJS) +AC_SUBST(PERL_PRIVLIBEXP) +AC_SUBST(PERL_SITELIBEXP) +AC_SUBST(XSUBPP) + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([libintl.h locale.h stdlib.h string.h]) @@@ -153,7 -114,6 +153,7 @@@ themes/hicolor/Makefil po/Makefile.in doc/Makefile doc/images/Makefile +plugins/Makefile ]) AC_OUTPUT @@@ -166,7 -126,6 +166,7 @@@ echo $PACKAGE $VERSIO echo echo Compiler................ : $CC echo Build with OFX support.. : $build_ofx +echo Build with perl support. : $build_perl if test "x$noofx" = "xtrue" ; then echo ........................ : **error** libofx header is missing, ofx feature will be disabled. Check your libofx installation fi diff --combined plugins/hello.pl index 9171bb2,0000000..25520b5 mode 100644,000000..100644 --- a/plugins/hello.pl +++ b/plugins/hello.pl @@@ -1,234 -1,0 +1,234 @@@ + +# NAME: Hello World +# VERSION: 0.01 +# ABSTRACT: This is the "hello world" of HomeBank plugins. +# AUTHOR: Charles McGarvey +# WEBSITE: http://acme.tld/ +# (These comments are read, before the plugin is executed, to provide some +# information to HomeBank and the user about what this plugin is.) + +eval { HomeBank->version } or die "Cannot run outside of HomeBank"; + +use warnings; +use strict; + +use Scalar::Util qw/weaken/; + +#use Moose; + +#has "cool_beans", + #is => 'rw', + #isa => 'Str', + #lazy => 1, + #default => "Booya!!!"; + + +our $counter = 0; +our $temp; + +my $ACC; + +sub new { + my $class = shift; + my $self = $class->SUPER::new(@_); + + $self->on(account_inserted => sub { + my $acc = shift; + print "account inserted: ", Dumper($acc); + print "account name is ", $acc->name, " and balance is ", $acc->bank_balance, "\n"; + #$acc->name("FOOOOBAR!"); + if ($acc->name eq 'Vacation') { + $acc->remove; + $ACC = $acc; + } + print Dumper($acc->is_inserted); + if ($acc->is_inserted) { + print "IT IS INSERTED\n"; + } else { + print "not inserted\n"; + } + print Dumper($acc->transactions); + }); + + #print $self->cool_beans, "\n"; + #$self->cool_beans(123); + #print $self->cool_beans, "\n"; + + $self; +} + +sub on_create_main_window { + my $self = shift; + my $window = shift; + + if (!$window) { + require Gtk3; + $window = HomeBank->main_window; + } + + Dump($window); + print Dumper($window); + $window->set_title("foo bar baz"); + print $window->get_title, "\n"; + + HomeBank->hook("my_hook", $window); +} + +my $test_win; + +sub on_test { + my $self = shift; + require Gtk3; + + my $window = Gtk3::Window->new('toplevel'); + use Devel::Peek; + Dump($window); + print Dumper($window); + $window->set_title("Hello World"); + #$window->signal_connect(delete_event => sub { Gtk3->main_quit }); + $window->signal_connect(delete_event => sub { undef $test_win }); + + my $button = Gtk3::Button->new('Click Me!'); + Dump($button); + print Dumper($button); + $button->signal_connect(clicked => sub { + print "Hello Gtk3-Perl: $counter (perl plugin: $self)\n"; + $counter++; + #if ($temp->is_inserted) { + #print "$temp is inserted\n"; + #} else { + #print "$temp is NOT inserted\n"; + #} + #if ($counter == 5) { + #$temp = undef; + #} + my $acc = HomeBank::Account->get(rand(10)); + print "Changin account named ", $acc->name, " to ", $acc->name($acc), "\n"; + HomeBank->main_window->queue_draw; + + }); + $window->add($button); + + $window->show_all; + $test_win = $window; + + weaken $self; +} + +sub on_enter_main_loop { + my $self = shift; + + use Data::Dumper; + print Dumper(\@_); + my $t = HomeBank::Transaction->new; + print "Transaction:::::::: $t: ", $t->amount, "\n"; + + $temp = HomeBank::Account->get(7); + print "retained account: ", $temp->name, "\n"; + + #require Gtk3; + # + my $txn = HomeBank::Transaction->new; + $txn->amount(12.3456); + print Dumper($txn), $txn->amount, "\n"; + #$txn->open; + + my @ret = HomeBank->hook("my_hook", @_, $temp, [qw/foo bar baz/, $txn], { asf => 42, quux => \1, meh => HomeBank->main_window }); + #my @ret = HomeBank->hook("my_hook", @_, HomeBank->main_window, { + #foo => 'bar', baz => 42 + #}); + print Dumper(\@ret); + + print "adding back account...\n"; + $ACC->name("vacation with a different name"); + $ACC->insert; + HomeBank::Account->compute_balances; + print "account name is ", $ACC->name, " and balance is ", $ACC->balance, "\n"; + print Dumper($ACC->transactions); + + my $cloned = $ACC->clone; + $cloned->name("vacation copy"); + $cloned->insert; + #my $asdf = $cloned->open; + #$asdf->set_title("this is a new friggin account"); + + #my $z = HomeBank::Account->get_by_name('Checking'); + for my $xc (HomeBank::File->transactions) { + use DateTime; + my $num = $xc->date; + my $date = DateTime->new($xc->date)->datetime; - print "transaction of amount: ", $xc->amount, "\t", $xc->wording, ", ", $xc->info, ", $num, $date\n"; ++ print "transaction of amount: ", $xc->amount, "\t", $xc->memo, ", ", $xc->info, ", $num, $date\n"; + } + + HomeBank::File->owner('Billy Murphy'); + #HomeBank::File->anonymize; + print HomeBank::File->owner, "\n"; + + HomeBank::File->baz($ACC); +} + +sub on_deep_hook_recursion { + my $self = shift; + my $level = shift; + print STDERR "recursion is too deep ($level)\n"; + exit -2; +} + +sub on_my_hook { + my $self = shift; + print "This is MY HOOK!!!!!!\n"; + print Dumper(\@_); + + print Dumper($_[2]); + Dump($_[2]); + if ($_[2]) { + print "meh\n"; + } + if ($_[2]->isa('HomeBank::Boolean')) { + print "it is a home;;boolean\n"; + } + if ($_[2]->isa('Types::Serialiser::Boolean')) { + print "it is a types serialiser thingy\n"; + } + if ($_[2]->isa('HomeBank::BooleanBase')) { + print "it is a base bool\n"; + } + + my $win = $_[6]; + if ($win && ref($win) eq 'HASH') { + my $w = $win->{meh}; + if ($w) { + $w->set_title("this is MY HOOK setting a window title"); + } + } + #print Dumper($acc); + #print "transferred account: ", $acc->name, "\n"; + + #my $fff = HomeBank::File->foo({foo => 'asdf', bar => 123456789}); + my $fff = HomeBank::File->meh([qw/hello this is a test 82/, \1, {foo => 'bar'}, 48]); + print Dumper($fff); + + print "my hook done\n"; +} + +sub on_unhandled { + my ($self, $hook) = @_; + warn "Unhandled hook '$hook'\n"; + #HomeBank->warn($hook, 'Hook not handled.'); +} + +sub DESTROY { + my $self = shift; + print "DESTROYING HELLO WORLD!!!!!!\n"; + if ($test_win) { + print "there is a test_win...\n"; + } + $test_win->destroy if $test_win; +} + +sub EXECUTE { + print "the perl plugin is being configured.....\n"; + HomeBank->info("Hello Prefs", "YEEEEEARGGH!!!!!"); +} + +#__PACKAGE__->meta->make_immutable; diff --combined src/Makefile.am index 484ce27,9c7e193..20da8f1 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -1,8 -1,7 +1,8 @@@ common_defines = \ -DSHARE_DIR=\""$(pkgdatadir)"\" \ - -DDATA_DIR=\""$(datadir)"\" + -DDATA_DIR=\""$(datadir)"\" \ + -DPKGLIB_DIR=\""$(pkglibdir)"\" bin_PROGRAMS = homebank @@@ -119,37 -118,16 +119,39 @@@ homebank_SOURCES = ui-split.h \ ui-transaction.c \ ui-transaction.h \ + ui-txn-multi.c \ + ui-txn-multi.h \ 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) \ $(LIBSOUP_CFLAGS) \ $(common_defines) +$(PERL_OBJS): CPPFLAGS += $(PERL_CPPFLAGS) + +ext-perl.c: ext-perl.xs typemap + $(XSUBPP) -typemap $(PERL_PRIVLIBEXP)/ExtUtils/typemap -typemap typemap $< >$@ + +perlxsi.c: Makefile + $(PERL) -MExtUtils::Embed -e xsinit -- -std HomeBank + +CLEANFILES = ext-perl.c perlxsi.c + +pluginsupportdir = $(pkglibdir) +pluginsupport_DATA = HomeBank.pm + diff --combined src/dsp_mainwindow.c index e819137,2cb2ecd..c733f4c --- a/src/dsp_mainwindow.c +++ b/src/dsp_mainwindow.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -22,8 -22,6 +22,8 @@@ #include "dsp_mainwindow.h" +#include "ext.h" + #include "list_account.h" #include "list_upcoming.h" #include "list_topspending.h" @@@ -50,11 -48,17 +50,17 @@@ #include "gtk-chart.h" + //old url prior 2018 //#define HOMEBANK_URL_HELP "http://homebank.free.fr/help/" + //#define HOMEBANK_URL_HELP_ONLINE "https://launchpad.net/homebank/+addquestion" + //#define HOMEBANK_URL_HELP_PROBLEM "https://launchpad.net/homebank/+filebug" + //#define HOMEBANK_URL_HELP_TRANSLATE "https://launchpad.net/homebank/+translations" + #define HOMEBANK_URL_HELP "index.html" - #define HOMEBANK_URL_HELP_ONLINE "https://launchpad.net/homebank/+addquestion" - #define HOMEBANK_URL_HELP_TRANSLATE "https://launchpad.net/homebank/+translations" - #define HOMEBANK_URL_HELP_PROBLEM "https://launchpad.net/homebank/+filebug" + #define HOMEBANK_URL_HELP_ONLINE "http://homebank.free.fr/support.php" + #define HOMEBANK_URL_HELP_UPDATES "http://homebank.free.fr/downloads.php" + #define HOMEBANK_URL_HELP_PROBLEM "http://homebank.free.fr/development.php#bug" + #define HOMEBANK_URL_HELP_TRANSLATE "http://homebank.free.fr/development.php#translate" /****************************************************************************/ @@@ -113,11 -117,11 +119,13 @@@ static void ui_mainwindow_action_export static void ui_mainwindow_action_anonymize(void); static void ui_mainwindow_action_file_statistics(void); +static void ui_mainwindow_action_pluginprefs(void); + static void ui_mainwindow_action_help(void); void ui_mainwindow_action_help_welcome(void); static void ui_mainwindow_action_help_online(void); + static void ui_mainwindow_action_help_updates(void); + static void ui_mainwindow_action_help_releasenotes(void); static void ui_mainwindow_action_help_translate(void); static void ui_mainwindow_action_help_problem(void); static void ui_mainwindow_action_about(void); @@@ -148,8 -152,8 +156,10 @@@ void ui_mainwindow_scheduled_postall(Gt 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[] = { @@@ -171,7 -175,6 +181,7 @@@ static GtkActionEntry entries[] = { "TxnMenu" , NULL, N_("_Transactions"), NULL, NULL, NULL }, { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL }, { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL }, + { "PluginMenu" , NULL, N_("_Plugins"), NULL, NULL, NULL }, { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL }, // { "Import" , NULL, N_("Import") }, @@@ -226,14 -229,14 +236,17 @@@ { "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) }, - { "Translate" , "lpi-translate" , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) }, + + { "Updates" , NULL , N_("Check for updates...") , NULL, N_("Visit HomeBank website to check for update"), G_CALLBACK (ui_mainwindow_action_help_updates) }, + { "ReleaseNotes", NULL , N_("Release Notes") , NULL, N_("Display the release notes"), G_CALLBACK (ui_mainwindow_action_help_releasenotes) }, { "Problem" , "lpi-bug" , N_("Report a Problem...") , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) }, + { "Translate" , "lpi-translate" , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) }, { "About" , ICONNAME_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) }, @@@ -318,17 -321,14 +331,19 @@@ static const gchar *ui_info " " " " " " +" " +" " +" " +" " +" " " " " " - " " " " - " " + " " + " " + " " " " + " " " " " " " " @@@ -355,7 -355,6 +370,7 @@@ " " " " " " +" " " " ""; @@@ -402,9 -401,9 +417,9 @@@ gint result { DB( g_print(" - should revert\n") ); - hbfile_change_filepath(hb_util_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~")); + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~")); ui_mainwindow_open_internal(widget, NULL); - hbfile_change_filepath(hb_util_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); } } @@@ -435,8 -434,7 +450,8 @@@ gchar *version static const gchar *authors[] = { "Lead developer:\n" \ "Maxime DOYEN", - "\nContributor:\n" \ + "\nContributors:\n" \ + "Charles MCGARVEY (Plugin system, Perl support)\n" \ "Ga\xc3\xabtan LORIDANT (Maths formulas for charts)\n", NULL }; @@@ -448,7 -446,7 +463,7 @@@ }; */ - static const gchar *copyright = "Copyright \xc2\xa9 1995-2017 - Maxime DOYEN"; + static const gchar *copyright = "Copyright \xc2\xa9 1995-2018 - Maxime DOYEN"; @@@ -512,9 -510,9 +527,9 @@@ GtkWidget *widget = GLOBALS->mainwindow ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); ui_start_assistant(); - ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); - ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); - ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); + //ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); + //ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); + //ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); } } @@@ -556,25 -554,17 +571,23 @@@ static void ui_mainwindow_action_quit(v { gboolean result; - //gtk_widget_destroy(GLOBALS->mainwindow); - + //emulate the wm close button g_signal_emit_by_name(GLOBALS->mainwindow, "delete-event", NULL, &result); - - //gtk_main_quit(); } + static void ui_mainwindow_action_file_statistics(void) { ui_dialog_file_statistics(); } +static void ui_mainwindow_action_pluginprefs(void) +{ + ui_mainwindow_showprefs(PREF_PLUGINS); +} + + static void ui_mainwindow_action_properties(void) { create_defhbfile_dialog(); @@@ -600,11 -590,14 +613,14 @@@ gchar *secondtext _("_Anonymize") ); - if( result == GTK_RESPONSE_CANCEL ) - return; - - hbfile_anonymize(); - ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); + //#1707201 + //if( result == GTK_RESPONSE_CANCEL ) + // return; + if( result == GTK_RESPONSE_OK ) + { + hbfile_anonymize(); + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); + } } @@@ -684,15 -677,10 +700,15 @@@ static void ui_mainwindow_action_defass 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"); - defpref_dialog_new(); + defpref_dialog_new(page); if(!PREFS->euro_active) { GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"); @@@ -837,6 -825,7 +853,7 @@@ static void ui_mainwindow_action_about( } + static void ui_mainwindow_action_export(void) { gchar *filename; @@@ -848,13 -837,27 +865,27 @@@ } } + static void ui_mainwindow_action_help(void) { gchar *link; link = g_build_filename("file:///", homebank_app_get_help_dir(), HOMEBANK_URL_HELP, NULL ); homebank_util_url_show (link); + g_free(link); + } + + + static void ui_mainwindow_action_help_releasenotes(void) + { + gchar *link; + #ifdef G_OS_WIN32 + link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog.txt", NULL ); + #else + link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog", NULL ); + #endif + homebank_util_url_show (link); g_free(link); } @@@ -977,39 -980,41 +1008,41 @@@ GtkWidget *mainvbox, *widget, *label } + static void ui_mainwindow_action_help_updates(void) + { + const gchar *link = HOMEBANK_URL_HELP_UPDATES; + + homebank_util_url_show (link); + } + static void ui_mainwindow_action_help_online(void) { const gchar *link = HOMEBANK_URL_HELP_ONLINE; homebank_util_url_show (link); - } + static void ui_mainwindow_action_help_translate(void) { const gchar *link = HOMEBANK_URL_HELP_TRANSLATE; homebank_util_url_show (link); - } + static void ui_mainwindow_action_help_problem(void) { const gchar *link = HOMEBANK_URL_HELP_PROBLEM; homebank_util_url_show (link); - } - - /* hbfile functions -------------------- */ - - /* ** */ @@@ -1064,6 -1069,7 +1097,7 @@@ gboolean file_clear = GPOINTER_TO_INT(u 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); hbfile_cleanup(file_clear); hbfile_setup(file_clear); @@@ -1104,7 -1110,7 +1138,7 @@@ gint account, count if( result == GTK_RESPONSE_ADD ) { ope = da_transaction_malloc(); - ope->date = date; + ope->date = date; ope->kacc = account; if( PREFS->heritdate == FALSE ) //fix: 318733 @@@ -1122,7 -1128,7 +1156,7 @@@ if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT) { deftransaction_get(window, NULL); - transaction_add(ope, NULL, ope->kacc); + transaction_add(ope); DB( g_print(" - added 1 transaction to %d\n", ope->kacc) ); @@@ -1160,7 -1166,7 +1194,7 @@@ struct tmpto }; - #define MAX_TOPSPENDING 5 + #define MAX_TOPSPENDING 10 static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2) @@@ -1261,7 -1267,7 +1295,7 @@@ Account *acc { Transaction *ope = list->data; - //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->wording, ope->kcat, filter_test(data->filter, ope)) ); + //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->memo, ope->kcat, filter_test(data->filter, ope)) ); if( !(ope->paymode == PAYMODE_INTXFER) ) { @@@ -1274,7 -1280,7 +1308,7 @@@ if(acc) trn_amount = hb_amount_base(ope->amount, acc->kcur); - if( ope->flags & OF_SPLIT ) + if( ope->flags & OF_SPLIT ) { guint nbsplit = da_splits_count(ope->splits); Split *split; @@@ -1474,7 -1480,7 +1508,7 @@@ Transaction *txn if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT) { deftransaction_get(window, NULL); - transaction_add(txn, NULL, txn->kacc); + transaction_add(txn); GLOBALS->changes_count++; scheduled_date_advance(arc); @@@ -1508,6 -1514,8 +1542,8 @@@ static void ui_mainwindow_scheduled_pos { struct hbfile_data *data = user_data; + DB( g_print("\n[ui-mainwindow] scheduled post\n") ); + Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) ) @@@ -1518,7 -1526,7 +1554,7 @@@ da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, arc->nextdate); - transaction_add(txn, NULL, 0); + transaction_add(txn); GLOBALS->changes_count++; scheduled_date_advance(arc); @@@ -1567,7 -1575,7 +1603,7 @@@ struct hbfile_data *data if(arc) { - DB( g_print("archive is %s\n", arc->wording) ); + 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); @@@ -1679,7 -1687,7 +1715,7 @@@ GDate *date nbdays = arc->nextdate - maxpostdate; nblate = scheduled_get_latepost_count(arc, GLOBALS->today); - DB( g_print(" - append '%s' : %d\n", arc->wording, nbdays) ); + DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) ); if(arc->flags & OF_INCOME) { @@@ -1703,7 -1711,7 +1739,7 @@@ gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_ACCOUNT, acc, - LST_DSPUPC_WORDING, arc->wording, + LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, exp, LST_DSPUPC_INCOME, inc, LST_DSPUPC_REMAINING, nbdays, @@@ -1723,7 -1731,7 +1759,7 @@@ gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_ACCOUNT, acc, - LST_DSPUPC_WORDING, arc->wording, + LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, -inc, LST_DSPUPC_INCOME, -exp, LST_DSPUPC_REMAINING, nbdays, @@@ -1742,18 -1750,42 +1778,42 @@@ gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, NULL, LST_DSPUPC_ACCOUNT, NULL, - LST_DSPUPC_WORDING, _("Total"), + 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; + } /* @@@ -1770,17 -1802,29 +1830,29 @@@ gchar *filename = NULL if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) { - if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename) == TRUE) + if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename) == TRUE ) { - hbfile_change_filepath(filename); + //#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 */ @@@ -1793,10 -1837,10 +1865,10 @@@ gint r data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); - DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) ); - 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; @@@ -1856,6 -1900,7 +1928,7 @@@ } + /* ** */ @@@ -1873,6 -1918,14 +1946,14 @@@ gint r = XML_UNSET 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) @@@ -1882,6 -1935,7 +1963,7 @@@ homebank_backup_current_file(); r = homebank_save_xml(GLOBALS->xhb_filepath); GLOBALS->hbfile_is_new = FALSE; + GLOBALS->hbfile_is_bak = FALSE; } else return; @@@ -1942,7 -1996,12 +2024,12 @@@ 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) @@@ -1950,7 -2009,9 +2037,9 @@@ Account *acc = elt->data; GPtrArray *group; - if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) ) + //#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 ) { @@@ -2015,7 -2076,7 +2104,7 @@@ gpointer key, value gtbank = gttoday = gtfuture = 0; - DB( g_print(" populate listview\n") ); + 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)); @@@ -2026,16 -2087,33 +2115,33 @@@ { GPtrArray *gpa = value; gdouble tbank, ttoday, tfuture; + gint position; if(gpa != NULL) { nbtype++; //1: Header: Bank, Cash, ... - //DB( g_print(" - append type '%s'\n", CYA_ACC_TYPE[i]) ); - DB( g_print("\n - append type '%d'\n", key) ); + 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); @@@ -2054,7 -2132,7 +2160,7 @@@ ttoday += hb_amount_base(acc->bal_today, acc->kcur); tfuture += hb_amount_base(acc->bal_future, acc->kcur); - DB( g_print(" - insert '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) ); + 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, @@@ -2068,7 -2146,7 +2174,7 @@@ if(gpa->len > 1) { - DB( g_print(" - type totals :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); + 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); @@@ -2082,7 -2160,7 +2188,7 @@@ } /* set balance to header to display when collasped */ - DB( g_print(" - enrich totals to header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); + 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, @@@ -2098,7 -2176,7 +2204,7 @@@ } - DB( g_print(" - grand totals :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) ); + DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) ); // Grand total if( nbtype > 1 ) @@@ -2133,7 -2211,7 +2239,7 @@@ void ui_mainwindow_update(GtkWidget *wi struct hbfile_data *data; gint flags; - DB( g_print("\n[ui-mainwindow] refresh_display\n") ); + DB( g_print("\n[ui-mainwindow] update %p\n", user_data) ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //data = INST_DATA(widget); @@@ -2146,7 -2224,7 +2252,7 @@@ gchar *basename; gchar *changed; - DB( g_print(" + 1: wintitle %x\n", data->wintitle) ); + DB( g_print(" 1: wintitle %p\n", data->wintitle) ); basename = g_path_get_basename(GLOBALS->xhb_filepath); @@@ -2172,7 -2250,7 +2278,7 @@@ GtkTreePath *path; gboolean active,sensitive; - DB( g_print(" + 2: disabled, opelist count\n") ); + DB( g_print(" 2: disabled, opelist count\n") ); //#1656531 data->acc = NULL; @@@ -2259,7 -2337,7 +2365,7 @@@ /* update toolbar, list */ if(flags & UF_VISUAL) { - DB( g_print(" + 8: visual\n") ); + DB( g_print(" 8: visual\n") ); if(PREFS->toolbar_style == 0) gtk_toolbar_unset_style(GTK_TOOLBAR(data->toolbar)); @@@ -2304,7 -2382,7 +2410,7 @@@ if(flags & UF_BALANCE) { - DB( g_print(" + 4: balances\n") ); + DB( g_print(" 4: balances\n") ); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); @@@ -2319,7 -2397,7 +2425,7 @@@ if(flags & UF_REFRESHALL) { - DB( g_print(" + 8: refreshall\n") ); + DB( g_print(" 16: refreshall\n") ); ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); @@@ -2362,6 -2440,14 +2468,14 @@@ static voi } } + + static void ui_mainwindow_destroy(GtkTreeView *treeview, gpointer user_data) + { + DB( g_print("\n[ui-mainwindow] destroy\n") ); + + } + + /* ** */ @@@ -2371,10 -2457,7 +2485,10 @@@ struct hbfile_data *data = user_data struct WinGeometry *wg; gboolean retval = FALSE; + GValue widget_value = G_VALUE_INIT; + ext_hook("main_window_disposal", EXT_OBJECT(&widget_value, widget), NULL); + - DB( g_print("\n[ui-mainwindow] dispose\n") ); + DB( g_print("\n[ui-mainwindow] delete-event\n") ); //store position and size wg = &PREFS->wal_wg; @@@ -2398,19 -2481,18 +2512,18 @@@ } else { - DB( g_print(" free wintitle %x\n", data->wintitle) ); - + //todo: retval is useless and below should move to destroy + retval = TRUE; gtk_widget_destroy(data->LV_top); g_free(data->wintitle); da_filter_free(data->filter); g_free(user_data); + gtk_main_quit(); } - - - //delete-event TRUE abort/FALSE destroy + //TRUE:stop other handlers from being invoked for the event | FALSE: propagate return retval; } @@@ -2823,11 -2905,37 +2936,37 @@@ GVariant *old_state, *new_state static const GActionEntry actions[] = { // { "paste", activate_action, NULL, NULL, NULL, {0,0,0} }, - { "showall" , activate_toggle, NULL, "false", NULL, {0,0,0} }, - { "groupby", activate_radio, "s", "'type'", NULL, {0,0,0} } + { "showall", activate_toggle, NULL, "false" , NULL, {0,0,0} }, + { "groupby", activate_radio , "s", "'type'", NULL, {0,0,0} } }; + static void ui_panel_accounts_setup(struct hbfile_data *data) + { + GAction *action; + GVariant *new_state; + + if( !G_IS_SIMPLE_ACTION_GROUP(data->action_group_acc) ) + return; + + action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "showall"); + if( action ) + { + new_state = g_variant_new_boolean (data->showall); + g_simple_action_set_state (G_SIMPLE_ACTION(action), new_state); + } + + action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "groupby"); + if( action ) + { + const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank"; + new_state = g_variant_new_string (value); + g_simple_action_set_state (G_SIMPLE_ACTION (action), new_state); + } + + } + + static GtkWidget *ui_mainwindow_create_youraccounts(struct hbfile_data *data) { GtkWidget *panel, *label, *widget, *sw, *tbar, *hbox, *image; @@@ -2881,16 -2989,6 +3020,6 @@@ GtkToolItem *toolitem //gmenu test (see test folder into gtk) - widget = gtk_menu_button_new(); - gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP); - gtk_widget_set_halign (widget, GTK_ALIGN_END); - image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU); - g_object_set (widget, "image", image, NULL); - - toolitem = gtk_tool_item_new(); - gtk_container_add (GTK_CONTAINER(toolitem), widget); - gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); - GMenu *menu, *section; menu = g_menu_new (); @@@ -2909,15 -3007,21 +3038,21 @@@ GSimpleActionGroup *group = g_simple_action_group_new (); + data->action_group_acc = group; g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), data); - //init radio - GAction *action = g_action_map_lookup_action (G_ACTION_MAP (group), "groupby"); - const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank"; - g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_string (value)); - gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group)); + widget = gtk_menu_button_new(); + gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP); + gtk_widget_set_halign (widget, GTK_ALIGN_END); + image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU); + g_object_set (widget, "image", image, NULL); + toolitem = gtk_tool_item_new(); + gtk_container_add (GTK_CONTAINER(toolitem), widget); + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); + + gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group)); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (widget), G_MENU_MODEL (menu)); return panel; @@@ -3090,7 -3194,7 +3225,7 @@@ GtkAction *action //store our window private data g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data); - DB( g_print(" - new window=%x, inst_data=%0x\n", window, data) ); + DB( g_print(" - new window=%p, inst_data=%p\n", window, data) ); // this is our mainwindow, so store it to GLOBALS data data->window = window; @@@ -3126,21 -3230,16 +3261,16 @@@ GtkWidget *bar, *label gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE); widget = ui_mainwindow_scheduled_create(data); - gtk_paned_pack2 (GTK_PANED(vpaned), widget, FALSE, FALSE); + gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE); widget = ui_mainwindow_create_youraccounts(data); + //gtk_widget_set_size_request (widget, 100, -1); gtk_paned_pack1 (GTK_PANED(hpaned), widget, FALSE, FALSE); widget = ui_mainwindow_create_topspending(data); - gtk_paned_pack2 (GTK_PANED(hpaned), widget, FALSE, FALSE); - - - DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); + //gtk_widget_set_size_request (widget, -1, 100); + gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE); - if(PREFS->wal_hpaned > 0) - gtk_paned_set_position(GTK_PANED(data->hpaned), PREFS->wal_hpaned); - if(PREFS->wal_vpaned > 0) - gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned); //setup, init and show window wg = &PREFS->wal_wg; @@@ -3153,7 -3252,15 +3283,15 @@@ gtk_window_maximize(GTK_WINDOW(window)); gtk_widget_show_all (window); - + + //#1662197/1660910 moved after resize/show + DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); + + if(PREFS->wal_hpaned > 0) + gtk_paned_set_position(GTK_PANED(data->hpaned), PREFS->wal_hpaned); + if(PREFS->wal_vpaned > 0) + gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned); + //todo: move this elsewhere DB( g_print(" - setup stuff\n") ); @@@ -3207,6 -3314,7 +3345,7 @@@ /* GtkWindow events */ g_signal_connect (window, "delete-event", G_CALLBACK (ui_mainwindow_dispose), (gpointer)data); + g_signal_connect (window, "destroy", G_CALLBACK (ui_mainwindow_destroy), NULL); g_signal_connect (window, "screen-changed", diff --combined src/ext-perl.xs index 5aa56b0,0000000..9c7bd8b 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 "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)); + 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* - wording(Transaction* SELF, ...) ++memo(Transaction* SELF, ...) + CODE: + if (1 < items) { - if (SELF->wording) g_free(SELF->wording); - SELF->wording = g_strdup(SvGchar_ptr(ST(1))); ++ if (SELF->memo) g_free(SELF->memo); ++ SELF->memo = g_strdup(SvGchar_ptr(ST(1))); + } - RETVAL = SELF->wording ? SELF->wording : ""; ++ 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)); + 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); + } + 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->wording, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat); ++ SELF->memo, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat); + diff --combined src/hb-account.c index a7c0051,5917e66..ee5055f --- a/src/hb-account.c +++ b/src/hb-account.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -20,9 -20,6 +20,9 @@@ #include "homebank.h" #include "hb-account.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ /* Debug macros */ /****************************************************************************/ @@@ -42,7 -39,7 +42,7 @@@ voi da_acc_free(Account *item) { DB( g_print("da_acc_free\n") ); - if(item != NULL) + if(rc_unref(item)) { DB( g_print(" => %d, %s\n", item->key, item->name) ); @@@ -54,7 -51,7 +54,7 @@@ g_queue_free (item->txn_queue); - g_free(item); + rc_free(item); } } @@@ -65,7 -62,7 +65,7 @@@ da_acc_malloc(void Account *item; DB( g_print("da_acc_malloc\n") ); - item = g_malloc0(sizeof(Account)); + item = rc_alloc(sizeof(Account)); item->txn_queue = g_queue_new (); return item; } @@@ -160,9 -157,6 +160,9 @@@ guint32 *new_key *new_key = item->key; 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; } @@@ -198,10 -192,6 +198,10 @@@ guint32 *new_key DB( g_print(" -> insert id: %d\n", *new_key) ); 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; } } @@@ -628,7 -618,7 +628,7 @@@ GList *lnk_txn gdouble oldamount = txn->amount; txn->amount = hb_amount_to_euro(oldamount); - DB( g_print("%10.6f => %10.6f, %s\n", oldamount, txn->amount, txn->wording) ); + DB( g_print("%10.6f => %10.6f, %s\n", oldamount, txn->amount, txn->memo) ); //todo: sync child xfer lnk_txn = g_list_next(lnk_txn); } diff --combined src/hb-archive.c index e0789de,0e88c48..628e978 --- a/src/hb-archive.c +++ b/src/hb-archive.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -21,9 -21,6 +21,9 @@@ #include "hb-archive.h" #include "hb-split.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ /* Debug macros */ /****************************************************************************/ @@@ -39,43 -36,43 +39,43 @@@ extern struct HomeBank *GLOBALS; - /* = = = = = = = = = = = = = = = = = = = = */ - /* Archive */ - Archive *da_archive_malloc(void) { - return g_malloc0(sizeof(Archive)); + return rc_alloc(sizeof(Archive)); } + Archive *da_archive_clone(Archive *src_item) { -Archive *new_item = g_memdup(src_item, sizeof(Archive)); +Archive *new_item = rc_dup(src_item, sizeof(Archive)); if(new_item) { //duplicate the string - new_item->wording = g_strdup(src_item->wording); - + new_item->memo = g_strdup(src_item->memo); + if( da_splits_clone(src_item->splits, new_item->splits) > 0) new_item->flags |= OF_SPLIT; //Flag that Splits are active } return new_item; } + void da_archive_free(Archive *item) { - if(item != NULL) + if(rc_unref(item)) { - if(item->wording != NULL) - g_free(item->wording); + if(item->memo != NULL) + g_free(item->memo); da_splits_free(item->splits); //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared - g_free(item); + rc_free(item); } } + void da_archive_destroy(GList *list) { GList *tmplist = g_list_first(list); @@@ -89,9 -86,13 +89,13 @@@ g_list_free(list); } + + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + + static gint da_archive_glist_compare_func(Archive *a, Archive *b) { - return hb_string_utf8_compare(a->wording, b->wording); + return hb_string_utf8_compare(a->memo, b->memo); } @@@ -100,11 -101,13 +104,13 @@@ GList *da_archive_sort(GList *list return g_list_sort(list, (GCompareFunc)da_archive_glist_compare_func); } + guint da_archive_length(void) { return g_list_length(GLOBALS->arc_list); } + void da_archive_consistency(Archive *item) { Account *acc; @@@ -151,19 -154,21 +157,21 @@@ Payee *pay Archive *da_archive_init_from_transaction(Archive *arc, Transaction *txn) { + DB( g_print("\n[scheduled] init from txn\n") ); + //fill it arc->amount = txn->amount; arc->kacc = txn->kacc; arc->kxferacc = txn->kxferacc; - arc->paymode = txn->paymode; - arc->flags = txn->flags & (OF_INCOME); + arc->paymode = txn->paymode; + arc->flags = txn->flags & (OF_INCOME); arc->status = txn->status; - arc->kpay = txn->kpay; + arc->kpay = txn->kpay; arc->kcat = txn->kcat; - if(txn->wording != NULL) - arc->wording = g_strdup(txn->wording); + if(txn->memo != NULL) + arc->memo = g_strdup(txn->memo); else - arc->wording = g_strdup(_("(new archive)")); + arc->memo = g_strdup(_("(new archive)")); if( da_splits_clone(txn->splits, arc->splits) > 0) arc->flags |= OF_SPLIT; //Flag that Splits are active @@@ -172,16 -177,16 +180,16 @@@ } - - - static guint32 _sched_date_get_next_post(Archive *arc, guint32 nextdate) + static guint32 _sched_date_get_next_post(GDate *tmpdate, Archive *arc, guint32 nextdate) { - GDate *tmpdate; guint32 nextpostdate = nextdate; - DB( g_print("\n[scheduled] _sched_date_get_next_post\n") ); + //DB( g_print("\n[scheduled] date_get_next_post\n") ); + + g_date_set_julian(tmpdate, nextpostdate); + + //DB( g_print("in : %2d-%2d-%4d\n", g_date_get_day(tmpdate), g_date_get_month (tmpdate), g_date_get_year(tmpdate) ) ); - tmpdate = g_date_new_julian(nextpostdate); switch(arc->unit) { case AUTO_UNIT_DAY: @@@ -198,9 -203,11 +206,11 @@@ break; } + //DB( g_print("out: %2d-%2d-%4d\n", g_date_get_day(tmpdate), g_date_get_month (tmpdate), g_date_get_year(tmpdate) ) ); + + /* get the final post date and free */ nextpostdate = g_date_get_julian(tmpdate); - g_date_free(tmpdate); return nextpostdate; } @@@ -225,7 -232,7 +235,7 @@@ GDateWeekday wday guint32 finalpostdate; gint shift; - DB( g_print("\n[scheduled] scheduled_get_postdate\n") ); + DB( g_print("\n[scheduled] get_postdate\n") ); finalpostdate = postdate; @@@ -236,7 -243,7 +246,7 @@@ { wday = g_date_get_weekday(tmpdate); - DB( g_print(" %s wday=%d\n", arc->wording, wday) ); + DB( g_print(" %s wday=%d\n", arc->memo, wday) ); if( wday >= G_DATE_SATURDAY ) { @@@ -267,10 -274,14 +277,14 @@@ guint32 scheduled_get_latepost_count(Archive *arc, guint32 jrefdate) { - guint32 curdate = jrefdate - arc->nextdate; + GDate *post_date; + guint32 curdate; guint32 nblate = 0; + //DB( g_print("\n[scheduled] get_latepost_count\n") ); + /* + curdate = jrefdate - arc->nextdate; switch(arc->unit) { case AUTO_UNIT_DAY: @@@ -306,16 -317,21 +320,21 @@@ // pre 5.1 way + post_date = g_date_new(); curdate = arc->nextdate; while(curdate <= jrefdate) { - curdate = _sched_date_get_next_post(arc, curdate); + curdate = _sched_date_get_next_post(post_date, arc, curdate); nblate++; // break if over limit or at 11 max (to display +10) if(nblate >= arc->limit || nblate >= 11) break; } + //DB( g_print(" nblate=%d\n", nblate) ); + + g_date_free(post_date); + return nblate; } @@@ -323,8 -339,45 +342,45 @@@ /* return 0 is max number of post is reached */ guint32 scheduled_date_advance(Archive *arc) { - arc->nextdate = _sched_date_get_next_post(arc, arc->nextdate); - + GDate *post_date; + gushort lastday; + + DB( g_print("\n[scheduled] date_advance\n") ); + + DB( g_print(" arc: '%s'\n", arc->memo ) ); + + post_date = g_date_new(); + g_date_set_julian(post_date, arc->nextdate); + // saved the current day number + lastday = g_date_get_day(post_date); + + arc->nextdate = _sched_date_get_next_post(post_date, arc, arc->nextdate); + + DB( g_print(" raw next post date: %2d-%2d-%4d\n", g_date_get_day(post_date), g_date_get_month (post_date), g_date_get_year(post_date) ) ); + + //for day > 28 we might have a gap to compensate later + if( (arc->unit==AUTO_UNIT_MONTH) || (arc->unit==AUTO_UNIT_YEAR) ) + { + if( lastday >= 28 ) + { + DB( g_print(" lastday:%d, daygap:%d\n", lastday, arc->daygap) ); + if( arc->daygap > 0 ) + { + g_date_add_days (post_date, arc->daygap); + arc->nextdate = g_date_get_julian (post_date); + lastday += arc->daygap; + DB( g_print(" adjusted post date: %2d-%2d-%4d\n", g_date_get_day(post_date), g_date_get_month (post_date), g_date_get_year(post_date) ) ); + } + + arc->daygap = CLAMP(lastday - g_date_get_day(post_date), 0, 3); + + DB( g_print(" daygap is %d\n", arc->daygap) ); + } + else + arc->daygap = 0; + } + + //#1556289 /* check limit, update and maybe break */ if(arc->flags & OF_LIMIT) @@@ -336,7 -389,9 +392,9 @@@ arc->nextdate = 0; } } - + + g_date_free(post_date); + return arc->nextdate; } @@@ -402,7 -457,7 +460,7 @@@ Transaction *txn { Archive *arc = list->data; - DB( g_print("\n eval %d for '%s'\n", scheduled_is_postable(arc), arc->wording) ); + DB( g_print("\n eval %d for '%s'\n", scheduled_is_postable(arc), arc->memo) ); if(scheduled_is_postable(arc) == TRUE) { @@@ -415,13 -470,13 +473,13 @@@ while(mydate < maxpostdate) { - DB( hb_print_date(mydate, arc->wording) ); + 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 */ - transaction_add(txn, NULL, 0); + transaction_add(txn); GLOBALS->changes_count++; count++; diff --combined src/hb-assign.c index 495ead2,7989ff9..1a89a45 --- a/src/hb-assign.c +++ b/src/hb-assign.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -20,9 -20,6 +20,9 @@@ #include "homebank.h" #include "hb-assign.h" +#include "ext.h" +#include "refcount.h" + #define MYDEBUG 0 #if MYDEBUG @@@ -41,12 -38,12 +41,12 @@@ voi da_asg_free(Assign *item) { DB( g_print("da_asg_free\n") ); - if(item != NULL) + if(rc_unref(item)) { DB( g_print(" => %d, %s\n", item->key, item->text) ); g_free(item->text); - g_free(item); + rc_free(item); } } @@@ -55,7 -52,7 +55,7 @@@ Assign da_asg_malloc(void) { DB( g_print("da_asg_malloc\n") ); - return g_malloc0(sizeof(Assign)); + return rc_alloc(sizeof(Assign)); } diff --combined src/hb-category.c index f3d43bd,80f7e19..9487886 --- a/src/hb-category.c +++ b/src/hb-category.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -20,9 -20,6 +20,9 @@@ #include "homebank.h" #include "hb-category.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ /* Debug macros */ @@@ -43,7 -40,7 +43,7 @@@ extern struct HomeBank *GLOBALS Category * da_cat_clone(Category *src_item) { -Category *new_item = g_memdup(src_item, sizeof(Category)); +Category *new_item = rc_dup(src_item, sizeof(Category)); DB( g_print("da_cat_clone\n") ); if(new_item) @@@ -59,12 -56,12 +59,12 @@@ voi da_cat_free(Category *item) { DB( g_print("da_cat_free\n") ); - if(item != NULL) + if(rc_unref(item)) { DB( g_print(" => %d, %s\n", item->key, item->name) ); g_free(item->name); - g_free(item); + rc_free(item); } } @@@ -73,7 -70,7 +73,7 @@@ Category da_cat_malloc(void) { DB( g_print("da_cat_malloc\n") ); - return g_malloc0(sizeof(Category)); + return rc_alloc(sizeof(Category)); } @@@ -470,6 -467,9 +470,9 @@@ guint32 *new_key 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) ); @@@ -667,6 -667,7 +670,7 @@@ GList *lcat GList *lst_acc, *lnk_acc; GList *lnk_txn; GList *lpay, *lrul, *list; + guint i, nbsplit; lcat = list = g_hash_table_get_values(GLOBALS->h_cat); while (list != NULL) @@@ -689,7 -690,20 +693,20 @@@ { Transaction *txn = lnk_txn->data; - category_fill_usage_count(txn->kcat); + //#1689308 count split as well + if( txn->flags & OF_SPLIT ) + { + nbsplit = da_splits_count(txn->splits); + for(i=0;isplits[i]; + + category_fill_usage_count(split->kcat); + } + } + else + category_fill_usage_count(txn->kcat); + lnk_txn = g_list_next(lnk_txn); } lnk_acc = g_list_next(lnk_acc); @@@ -712,7 -726,20 +729,20 @@@ { Archive *entry = list->data; - category_fill_usage_count(entry->kcat); + //#1689308 count split as well + if( entry->flags & OF_SPLIT ) + { + nbsplit = da_splits_count(entry->splits); + for(i=0;isplits[i]; + + category_fill_usage_count(split->kcat); + } + } + else + category_fill_usage_count(entry->kcat); + list = g_list_next(list); } diff --combined src/hb-payee.c index e416fcf,896e936..558b76d --- a/src/hb-payee.c +++ b/src/hb-payee.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -20,9 -20,6 +20,9 @@@ #include "homebank.h" #include "hb-payee.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ /* Debug macros */ @@@ -44,12 -41,12 +44,12 @@@ voi da_pay_free(Payee *item) { DB( g_print("da_pay_free\n") ); - if(item != NULL) + if(rc_unref(item)) { DB( g_print(" => %d, %s\n", item->key, item->name) ); g_free(item->name); - g_free(item); + rc_free(item); } } @@@ -58,7 -55,7 +58,7 @@@ Payee da_pay_malloc(void) { DB( g_print("da_pay_malloc\n") ); - return g_malloc0(sizeof(Payee)); + return rc_alloc(sizeof(Payee)); } diff --combined src/hb-preferences.c index 8df0999,db7b3ed..8a9fb60 --- a/src/hb-preferences.c +++ b/src/hb-preferences.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -294,9 -294,6 +294,9 @@@ void homebank_pref_free(void g_free(PREFS->minor_cur.decimal_char); g_free(PREFS->minor_cur.grouping_char); + g_strfreev(PREFS->ext_path); + g_list_free_full(PREFS->ext_whitelist, g_free); + memset(PREFS, 0, sizeof(struct Preferences)); } @@@ -369,7 -366,7 +369,7 @@@ gint i PREFS->lst_ope_columns[i++] = LST_DSPOPE_DATE; PREFS->lst_ope_columns[i++] = LST_DSPOPE_INFO; PREFS->lst_ope_columns[i++] = LST_DSPOPE_PAYEE; - PREFS->lst_ope_columns[i++] = LST_DSPOPE_WORDING; + PREFS->lst_ope_columns[i++] = LST_DSPOPE_MEMO; PREFS->lst_ope_columns[i++] = -LST_DSPOPE_AMOUNT; PREFS->lst_ope_columns[i++] = LST_DSPOPE_EXPENSE; PREFS->lst_ope_columns[i++] = LST_DSPOPE_INCOME; @@@ -387,7 -384,7 +387,7 @@@ PREFS->lst_ope_columns[i++] = LST_DSPOPE_EXPENSE; PREFS->lst_ope_columns[i++] = LST_DSPOPE_INCOME; PREFS->lst_ope_columns[i++] = LST_DSPOPE_BALANCE; - PREFS->lst_ope_columns[i++] = LST_DSPOPE_WORDING; + PREFS->lst_ope_columns[i++] = LST_DSPOPE_MEMO; PREFS->lst_ope_sort_id = LST_DSPOPE_DATE; PREFS->lst_ope_sort_order = GTK_SORT_ASCENDING; @@@ -434,23 -431,6 +434,23 @@@ PREFS->vehicle_unit_ismile = FALSE; PREFS->vehicle_unit_isgal = FALSE; + gchar** plugin_path = g_new0(gchar*, 4); + i = 0; + const gchar* env = g_getenv("HOMEBANK_PLUGINS"); + if (env) { + if (g_path_is_absolute(env)) { + plugin_path[i++] = g_strdup(env); + } else { + gchar* cur = g_get_current_dir(); + plugin_path[i++] = g_build_filename(cur, env, NULL); + g_free(cur); + } + } + plugin_path[i++] = g_build_filename(homebank_app_get_config_dir(), "plugins", NULL); + plugin_path[i++] = g_build_filename(homebank_app_get_pkglib_dir(), "plugins", NULL); + PREFS->ext_path = plugin_path; + PREFS->ext_whitelist = NULL; + _homebank_pref_init_measurement_units(); } @@@ -565,7 -545,9 +565,9 @@@ gchar *string string = g_key_file_get_string(key_file, group_name, key, NULL); if( string != NULL ) { - *storage = g_strdup(string); + //*storage = g_strdup(string); + //leak + *storage = string; //already a new allocated string //DB( g_print(" store '%s' for %s at %x\n", string, key, *storage) ); } @@@ -785,6 -767,10 +787,10 @@@ GError *error = NULL DB( g_print(" - copying column width from pref file\n") ); memcpy(PREFS->lst_ope_col_size, src, length*sizeof(gint)); } + + //leak + g_free(src); + } homebank_pref_get_integer(keyfile, group, "OpeSortId", &PREFS->lst_ope_sort_id); @@@ -949,6 -935,7 +955,7 @@@ DB( g_print(" -> ** Exchange\n") ); //homebank_pref_get_boolean(keyfile, group, "DoIntro", &PREFS->dtex_nointro); + homebank_pref_get_integer(keyfile, group, "DateFmt", &PREFS->dtex_datefmt); homebank_pref_get_integer(keyfile, group, "OfxName", &PREFS->dtex_ofxname); homebank_pref_get_integer(keyfile, group, "OfxMemo", &PREFS->dtex_ofxmemo); @@@ -960,27 -947,6 +967,27 @@@ //PREFS->chart_legend = g_key_file_get_boolean (keyfile, group, "Legend", NULL); + group = "Plugins"; + { + DB( g_print(" -> ** Plugins\n") ); + + gchar** strv = g_key_file_get_string_list(keyfile, group, "Path", NULL, NULL); + if (strv) { + g_strfreev(PREFS->ext_path); + PREFS->ext_path = strv; + } + + strv = g_key_file_get_string_list(keyfile, group, "Whitelist", NULL, NULL); + if (strv) { + gchar** it; + for (it = strv; it && *it; ++it) { + PREFS->ext_whitelist = g_list_append(PREFS->ext_whitelist, g_strdup(*it)); + } + g_strfreev(strv); + } + } + + /* #if MYDEBUG == 1 gsize length; @@@ -1044,6 -1010,8 +1051,8 @@@ gsize length g_key_file_set_integer (keyfile, group, "BarStyle", PREFS->toolbar_style); //g_key_file_set_integer (keyfile, group, "BarImageSize", PREFS->image_size); + + g_key_file_set_boolean (keyfile, group, "CustomColors", PREFS->custom_colors); g_key_file_set_string (keyfile, group, "ColorExp" , PREFS->color_exp); g_key_file_set_string (keyfile, group, "ColorInc" , PREFS->color_inc); @@@ -1056,6 -1024,9 +1065,9 @@@ homebank_pref_set_string (keyfile, group, "ExportPath" , PREFS->path_export); //g_key_file_set_string (keyfile, group, "NavigatorPath", PREFS->path_navigator); + + + g_key_file_set_boolean (keyfile, group, "ShowSplash", PREFS->showsplash); g_key_file_set_boolean (keyfile, group, "LoadLast", PREFS->loadlast); g_key_file_set_boolean (keyfile, group, "AppendScheduled", PREFS->appendscheduled); @@@ -1119,7 -1090,7 +1131,7 @@@ group = "Filter"; g_key_file_set_integer (keyfile, group, "DateRangeWal", PREFS->date_range_wal); g_key_file_set_integer (keyfile, group, "DateRangeTxn", PREFS->date_range_txn); - g_key_file_set_integer (keyfile, group, "DateFutureNbdays", PREFS->date_future_nbdays); + g_key_file_set_integer (keyfile, group, "DateFutureNbDays", PREFS->date_future_nbdays); g_key_file_set_integer (keyfile, group, "DateRangeRep", PREFS->date_range_rep); DB( g_print(" -> ** euro\n") ); @@@ -1156,6 -1127,7 +1168,7 @@@ group = "Exchange"; //g_key_file_set_boolean (keyfile, group, "DoIntro", PREFS->dtex_nointro); + g_key_file_set_integer (keyfile, group, "DateFmt", PREFS->dtex_datefmt); g_key_file_set_integer (keyfile, group, "OfxName", PREFS->dtex_ofxname); g_key_file_set_integer (keyfile, group, "OfxMemo", PREFS->dtex_ofxmemo); @@@ -1166,21 -1138,6 +1179,21 @@@ //group = "Chart"; //g_key_file_set_boolean (keyfile, group, "Legend", PREFS->chart_legend); + group = "Plugins"; + { + g_key_file_set_string_list(keyfile, group, "Path", (const gchar* const*)PREFS->ext_path, g_strv_length(PREFS->ext_path)); + + gsize len = g_list_length(PREFS->ext_whitelist); + gchar** strv = g_new0(gchar*, len + 1); + guint i; + + for (i = 0; i < len; ++i) { + strv[i] = g_list_nth_data(PREFS->ext_whitelist, i); + } + g_key_file_set_string_list(keyfile, group, "Whitelist", (const gchar* const*)strv, len); + g_free(strv); + } + //g_key_file_set_string (keyfile, group, "", PREFS->); //g_key_file_set_boolean (keyfile, group, "", PREFS->); //g_key_file_set_integer (keyfile, group, "", PREFS->); diff --combined src/hb-preferences.h index 69bb44e,cf7e1a3..1223888 --- a/src/hb-preferences.h +++ b/src/hb-preferences.h @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -151,10 -151,6 +151,10 @@@ struct Preference gchar *vehicle_unit_100; gchar *vehicle_unit_distbyvol; + // plugins + gchar** ext_path; + GList* ext_whitelist; + }; diff --combined src/hb-tag.c index 8a93bab,13065ed..96cb5bf --- a/src/hb-tag.c +++ b/src/hb-tag.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -20,9 -20,6 +20,9 @@@ #include "homebank.h" #include "hb-tag.h" +#include "ext.h" +#include "refcount.h" + #define MYDEBUG 0 #if MYDEBUG @@@ -40,12 -37,12 +40,12 @@@ extern struct HomeBank *GLOBALS void da_tag_free(Tag *item) { DB( g_print("da_tag_free\n") ); - if(item != NULL) + if(rc_unref(item)) { DB( g_print(" => %d, %s\n", item->key, item->name) ); g_free(item->name); - g_free(item); + rc_free(item); } } @@@ -53,7 -50,7 +53,7 @@@ Tag *da_tag_malloc(void) { DB( g_print("da_tag_malloc\n") ); - return g_malloc0(sizeof(Tag)); + return rc_alloc(sizeof(Tag)); } diff --combined src/hb-transaction.c index 5f77203,29812d9..eb82509 --- a/src/hb-transaction.c +++ b/src/hb-transaction.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -23,9 -23,6 +23,9 @@@ #include "hb-tag.h" #include "hb-split.h" +#include "ext.h" +#include "refcount.h" + /****************************************************************************/ /* Debug macros */ /****************************************************************************/ @@@ -49,10 -46,10 +49,10 @@@ da_transaction_clean(Transaction *item { if(item != NULL) { - if(item->wording != NULL) + if(item->memo != NULL) { - g_free(item->wording); - item->wording = NULL; + g_free(item->memo); + item->memo = NULL; } if(item->info != NULL) { @@@ -78,14 -75,13 +78,13 @@@ } - void da_transaction_free(Transaction *item) { - if(item != NULL) + if(rc_unref(item)) { da_transaction_clean(item); - g_free(item); + rc_free(item); } } @@@ -93,7 -89,7 +92,7 @@@ Transaction * da_transaction_malloc(void) { - return g_malloc0(sizeof(Transaction)); + return rc_alloc(sizeof(Transaction)); } @@@ -106,7 -102,7 +105,7 @@@ Transaction *da_transaction_copy(Transa memmove(dst_txn, src_txn, sizeof(Transaction)); //duplicate the string - dst_txn->wording = g_strdup(src_txn->wording); + dst_txn->memo = g_strdup(src_txn->memo); dst_txn->info = g_strdup(src_txn->info); //duplicate tags @@@ -132,7 -128,7 +131,7 @@@ Transaction *da_transaction_init_from_t txn->kpay = arc->kpay; txn->kcat = arc->kcat; txn->kxferacc = arc->kxferacc; - txn->wording = g_strdup(arc->wording); + txn->memo = g_strdup(arc->memo); txn->info = NULL; if( da_splits_clone(arc->splits, txn->splits) > 0) txn->flags |= OF_SPLIT; //Flag that Splits are active @@@ -143,14 -139,14 +142,14 @@@ 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") ); if(new_item) { //duplicate the string - new_item->wording = g_strdup(src_item->wording); + new_item->memo = g_strdup(src_item->memo); new_item->info = g_strdup(src_item->info); //duplicate tags @@@ -238,16 -234,19 +237,19 @@@ GList *da_transaction_sort(GList *list } - static void da_transaction_insert_memo(Transaction *item) + gboolean da_transaction_insert_memo(Transaction *item) { + gboolean retval = FALSE; + // append the memo if new - if( item->wording != NULL ) + if( item->memo != NULL ) { - if( g_hash_table_lookup(GLOBALS->h_memo, item->wording) == NULL ) + if( g_hash_table_lookup(GLOBALS->h_memo, item->memo) == NULL ) { - g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->wording), NULL); + retval = g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->memo), NULL); } } + return retval; } @@@ -285,8 -284,11 +287,11 @@@ gboolean da_transaction_prepend(Transac Account *acc; acc = da_acc_get(item->kacc); - if(acc) - item->kcur = acc->kcur; + //#1661279 + if(!acc) + return FALSE; + + item->kcur = acc->kcur; g_queue_push_tail(acc->txn_queue, item); da_transaction_insert_memo(item); return TRUE; @@@ -335,7 -337,12 +340,12 @@@ guint32 max_key = 0 static void da_transaction_goto_orphan(Transaction *txn) { const gchar *oatn = "orphaned transactions"; - Account *acc; + Account *ori_acc, *acc; + gboolean found; + + DB( g_print("\n[transaction] goto orphan\n") ); + + g_warning("txn consistency: moving to orphan %d '%s' %.2f", txn->date, txn->memo, txn->amount); acc = da_acc_get_by_name((gchar *)oatn); if(acc == NULL) @@@ -343,8 -350,21 +353,21 @@@ acc = da_acc_malloc(); acc->name = g_strdup(oatn); da_acc_append(acc); + DB( g_print(" - created orphan acc %d\n", acc->key) ); + } + + ori_acc = da_acc_get(txn->kacc); + if( ori_acc ) + { + found = g_queue_remove(ori_acc->txn_queue, txn); + DB( g_print(" - found in origin ? %d\n", found) ); + if(found) + { + txn->kacc = acc->key; + da_transaction_insert_sorted (txn); + DB( g_print("moved txn to %d\n", txn->kacc) ); + } } - txn->kacc = acc->key; } @@@ -355,6 -375,8 +378,8 @@@ Category *cat Payee *pay; gint nbsplit; + DB( g_print("\n[transaction] consistency\n") ); + // ensure date is between range item->date = CLAMP(item->date, HB_MINDATE, HB_MAXDATE); @@@ -399,7 -421,27 +424,27 @@@ // reset dst acc for non xfer transaction if( item->paymode != PAYMODE_INTXFER ) + { + item->kxfer = 0; item->kxferacc = 0; + } + + // check dst account exists + if( item->paymode == PAYMODE_INTXFER ) + { + gint tak = item->kxferacc; + + item->kxferacc = ABS(tak); //I crossed negative here one day + acc = da_acc_get(item->kxferacc); + if(acc == NULL) + { + g_warning("txn consistency: fixed invalid dst_acc %d", item->kxferacc); + da_transaction_goto_orphan(item); + item->kxfer = 0; + item->paymode = PAYMODE_XFER; + GLOBALS->changes_count++; + } + } //#1628678 tags for internal xfer should be checked as well @@@ -437,8 -479,9 +482,9 @@@ gchar swap child->amount = -child->amount; child->flags ^= (OF_INCOME); // invert flag - //#1268026 - child->status = TXN_STATUS_NONE; + //#1268026 #1690555 + if( child->status != TXN_STATUS_REMIND ) + child->status = TXN_STATUS_NONE; //child->flags &= ~(OF_VALID); // delete reconcile state swap = child->kacc; @@@ -469,9 -512,6 +515,9 @@@ account_balances_add (child); + GValue txn_value = G_VALUE_INIT; + ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, child), NULL); + } } @@@ -539,7 -579,7 +585,7 @@@ GList *list, *matchlist = NULL if( transaction_xfer_child_might(ope, item, 0) == TRUE ) { - //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) ); + //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) ); matchlist = g_list_append(matchlist, item); } list = g_list_previous(list); @@@ -610,7 -650,7 +656,7 @@@ GList *list if( !dstacc || src->kxfer <= 0 ) return NULL; - DB( g_print(" - search: %d %s %f %d=>%d - %d\n", src->date, src->wording, src->amount, src->kacc, src->kxferacc, src->kxfer) ); + DB( g_print(" - search: %d %s %f %d=>%d - %d\n", src->date, src->memo, src->amount, src->kacc, src->kxferacc, src->kxfer) ); list = g_queue_peek_tail_link(dstacc->txn_queue); while (list != NULL) @@@ -625,7 -665,7 +671,7 @@@ && item->kxfer == src->kxfer && item != src ) { - DB( g_print(" - found : %d %s %f %d=>%d - %d\n", item->date, item->wording, item->amount, item->kacc, item->kxferacc, src->kxfer) ); + DB( g_print(" - found : %d %s %f %d=>%d - %d\n", item->date, item->memo, item->amount, item->kacc, item->kxferacc, src->kxfer) ); return item; } list = g_list_previous(list); @@@ -668,10 -708,24 +714,24 @@@ Account *dstacc } - void transaction_xfer_sync_child(Transaction *s_txn, Transaction *child) + void transaction_xfer_child_sync(Transaction *s_txn, Transaction *child) { + Account *acc; - DB( g_print("\n[transaction] xfer_sync_child\n") ); + DB( g_print("\n[transaction] xfer_child_sync\n") ); + + if( child == NULL ) + { + DB( g_print(" - no child found\n") ); + return; + } + + DB( g_print(" - found do sync\n") ); + + /* update acc flags */ + acc = da_acc_get( child->kacc); + if(acc != NULL) + acc->flags |= AF_CHANGED; account_balances_sub (child); @@@ -684,19 -738,29 +744,29 @@@ child->flags |= (OF_INCOME); child->kpay = s_txn->kpay; child->kcat = s_txn->kcat; - if(child->wording) - g_free(child->wording); - child->wording = g_strdup(s_txn->wording); + if(child->memo) + g_free(child->memo); + child->memo = g_strdup(s_txn->memo); if(child->info) g_free(child->info); child->info = g_strdup(s_txn->info); + account_balances_add (child); + //#1252230 sync account also - child->kacc = s_txn->kxferacc; - child->kxferacc = s_txn->kacc; + //#1663789 idem after 5.1 + //source changed: update child key (move of s_txn is done in external_edit) + if( s_txn->kacc != child->kxferacc ) + { + child->kxferacc = s_txn->kacc; + } + + //dest changed: move child & update child key + if( s_txn->kxferacc != child->kacc ) + { + transaction_acc_move(child, child->kacc, s_txn->kxferacc); + } - account_balances_add (child); - //synchronise tags since 5.1 if(child->tags) g_free(child->tags); @@@ -712,20 -776,26 +782,26 @@@ Transaction *dst DB( g_print("\n[transaction] xfer_remove_child\n") ); dst = transaction_xfer_child_strong_get( src ); - - DB( g_print(" -> return is %s, %p\n", dst->wording, dst) ); - if( dst != NULL ) { Account *acc = da_acc_get(dst->kacc); - DB( g_print("deleting...") ); - src->kxfer = 0; - src->kxferacc = 0; - account_balances_sub(dst); - g_queue_remove(acc->txn_queue, dst); - da_transaction_free (dst); + if( acc != NULL ) + { + DB( g_print("deleting...") ); + account_balances_sub(dst); + g_queue_remove(acc->txn_queue, dst); + //#1419304 we keep the deleted txn to a trash stack + //da_transaction_free (dst); + g_trash_stack_push(&GLOBALS->txn_stk, dst); + + //#1691992 + acc->flags |= AF_CHANGED; + } } + + src->kxfer = 0; + src->kxferacc = 0; } @@@ -737,31 -807,34 +813,34 @@@ GList *list DB( g_print("\n[transaction] get_child_transfer\n") ); - //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) ); + //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->memo, src->amount, src->account, src->kxferacc) ); acc = da_acc_get(src->kxferacc); - list = g_queue_peek_head_link(acc->txn_queue); - while (list != NULL) + if( acc != NULL ) { - Transaction *item = list->data; + list = g_queue_peek_head_link(acc->txn_queue); + while (list != NULL) + { + Transaction *item = list->data; - // no need to go higher than src txn date - if(item->date > src->date) - break; + // no need to go higher than src txn date + if(item->date > src->date) + break; - if( item->paymode == PAYMODE_INTXFER) - { - if( src->date == item->date && - src->kacc == item->kxferacc && - src->kxferacc == item->kacc && - ABS(src->amount) == ABS(item->amount) ) + if( item->paymode == PAYMODE_INTXFER) { - //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->account, item->kxferacc) ); + if( src->date == item->date && + src->kacc == item->kxferacc && + src->kxferacc == item->kacc && + ABS(src->amount) == ABS(item->amount) ) + { + //DB( g_print(" found : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) ); - return item; + return item; + } } + list = g_list_next(list); } - list = g_list_next(list); } DB( g_print(" not found...\n") ); @@@ -773,7 -846,30 +852,30 @@@ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - void transaction_add(Transaction *ope, GtkWidget *treeview, guint32 accnum) + void transaction_remove(Transaction *ope) + { + Account *acc; + + //controls accounts valid (archive scheduled maybe bad) + acc = da_acc_get(ope->kacc); + if(acc == NULL) return; + + account_balances_sub(ope); + + if( ope->paymode == PAYMODE_INTXFER ) + { + transaction_xfer_remove_child( ope ); + } + + g_queue_remove(acc->txn_queue, ope); + acc->flags |= AF_CHANGED; + //#1419304 we keep the deleted txn to a trash stack + //da_transaction_free(entry); + g_trash_stack_push(&GLOBALS->txn_stk, ope); + } + + + Transaction *transaction_add(Transaction *ope) { Transaction *newope; Account *acc; @@@ -782,7 -878,7 +884,7 @@@ //controls accounts valid (archive scheduled maybe bad) acc = da_acc_get(ope->kacc); - if(acc == NULL) return; + if(acc == NULL) return NULL; DB( g_print(" acc is '%s' %d\n", acc->name, acc->key) ); @@@ -791,7 -887,7 +893,7 @@@ if(ope->paymode == PAYMODE_INTXFER) { acc = da_acc_get(ope->kxferacc); - if(acc == NULL) return; + if(acc == NULL) return NULL; // delete any splits da_splits_free(ope->splits); @@@ -818,16 -914,19 +920,19 @@@ /* get the active account and the corresponding cheque number */ acc = da_acc_get( newope->kacc); - cheque = atol(newope->info); - - //DB( g_print(" -> should store cheque number %d to %d", cheque, newope->account) ); - if( newope->flags & OF_CHEQ2 ) + if( acc != NULL ) { - acc->cheque2 = MAX(acc->cheque2, cheque); - } - else - { - acc->cheque1 = MAX(acc->cheque1, cheque); + cheque = atol(newope->info); + + //DB( g_print(" -> should store cheque number %d to %d", cheque, newope->account) ); + if( newope->flags & OF_CHEQ2 ) + { + acc->cheque2 = MAX(acc->cheque2, cheque); + } + else + { + acc->cheque1 = MAX(acc->cheque1, cheque); + } } } @@@ -841,50 -940,15 +946,18 @@@ //da_transaction_append(newope); da_transaction_insert_sorted(newope); - if(treeview != NULL) - transaction_add_treeview(newope, treeview, accnum); - account_balances_add(newope); if(newope->paymode == PAYMODE_INTXFER) { transaction_xfer_search_or_add_child(NULL, newope, FALSE); } + + GValue txn_value = G_VALUE_INIT; + ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, newope), NULL); } - } - - - void transaction_add_treeview(Transaction *ope, GtkWidget *treeview, guint32 accnum) - { - GtkTreeModel *model; - GtkTreeIter iter; - //GtkTreePath *path; - //GtkTreeSelection *sel; - - DB( g_print("\n[transaction] add_treeview\n") ); - - if(ope->kacc == accnum) - { - model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); - gtk_list_store_append (GTK_LIST_STORE(model), &iter); - - gtk_list_store_set (GTK_LIST_STORE(model), &iter, - LST_DSPOPE_DATAS, ope, - -1); - - //activate that new line - //path = gtk_tree_model_get_path(model, &iter); - //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path); - - //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - //gtk_tree_selection_select_iter(sel, &iter); - - //gtk_tree_path_free(path); - - } + + return newope; } @@@ -894,21 -958,29 +967,29 @@@ Account *oacc, *nacc DB( g_print("\n[transaction] acc_move\n") ); + if( okacc == nkacc ) + return TRUE; + oacc = da_acc_get(okacc); nacc = da_acc_get(nkacc); if( oacc && nacc ) { + account_balances_sub(txn); if( g_queue_remove(oacc->txn_queue, txn) ) { g_queue_push_tail(nacc->txn_queue, txn); txn->kacc = nacc->key; txn->kcur = nacc->kcur; nacc->flags |= AF_CHANGED; + account_balances_add(txn); return TRUE; } else + { //ensure to keep txn into current account txn->kacc = okacc; + account_balances_add(txn); + } } return FALSE; } @@@ -924,7 -996,7 +1005,7 @@@ gboolean match = FALSE if(text == NULL) return FALSE; - //DB( g_print("search %s in %s\n", rul->name, ope->wording) ); + //DB( g_print("search %s in %s\n", rul->name, ope->memo) ); if( searchtext != NULL ) { if( exact == TRUE ) @@@ -985,7 -1057,7 +1066,7 @@@ GList *list Assign *rul = list->data; gchar *text; - text = txn->wording; + text = txn->memo; if(rul->field == 1) //payee { Payee *pay = da_pay_get(txn->kpay); @@@ -1061,7 -1133,7 +1142,7 @@@ gint changes = 0 Transaction *ope = l_ope->data; gboolean changed = FALSE; - DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope->wording, ope->kacc, ope->kpay, ope->kcat) ); + DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope->memo, ope->kacc, ope->kpay, ope->kcat) ); //#1215521: added kacc == 0 if( (kacc == ope->kacc || kacc == 0) ) diff --combined src/hb-xml.c index 6476fd8,c55db99..da67dad --- a/src/hb-xml.c +++ b/src/hb-xml.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -23,8 -23,6 +23,8 @@@ #include "hb-transaction.h" #include "hb-xml.h" +#include "ext.h" + #include "ui-dialogs.h" /****************************************************************************/ @@@ -319,6 -317,8 +319,8 @@@ GList *list // v0.6 to v0.7 : assign a default currency static void homebank_upgrade_to_v12(void) { + DB( g_print("\n[hb-xml] homebank_upgrade_to_v12\n") ); + // set a base currency to the hbfile if not DB( g_print("GLOBALS->kcur %d\n", GLOBALS->kcur) ); @@@ -326,6 -326,34 +328,34 @@@ } + static void homebank_upgrade_to_v12_7(void) + { + GList *lst_acc, *lnk_acc; + + DB( g_print("\n[hb-xml] homebank_upgrade_to_v12\n") ); + + //#1674045 exclude closed account from everywhere to + //keep continuity for user that don't want to change this + lst_acc = g_hash_table_get_values(GLOBALS->h_acc); + lnk_acc = g_list_first(lst_acc); + while (lnk_acc != NULL) + { + Account *acc = lnk_acc->data; + + if( acc->flags & AF_CLOSED ) + { + if( !(acc->flags & AF_NOSUMMARY) ) + acc->flags |= AF_NOSUMMARY; + if( !(acc->flags & AF_NOBUDGET) ) + acc->flags |= AF_NOBUDGET; + if( !(acc->flags & AF_NOREPORT) ) + acc->flags |= AF_NOREPORT; + } + lnk_acc = g_list_next(lnk_acc); + } + g_list_free(lst_acc); + } + // lower v0.6 : we must assume categories/payee exists // and strong link to xfer @@@ -545,7 -573,8 +575,8 @@@ gint i { //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); - if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + if(!strcmp (attribute_names[i], "key" )) { entry->key = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "name" )) { entry->name = g_strdup(attribute_values[i]); } else if(!strcmp (attribute_names[i], "iso" )) { entry->iso_code = g_strdup(attribute_values[i]); } else if(!strcmp (attribute_names[i], "symb" )) { entry->symbol = g_strdup(attribute_values[i]); } @@@ -595,6 -624,7 +626,7 @@@ gint i { //DB( g_print(" att='%s' val='%s'\n", attribute_names[i], attribute_values[i]) ); + if(!strcmp (attribute_names[i], "amount" )) { entry->amount = g_ascii_strtod(attribute_values[i], NULL); } else if(!strcmp (attribute_names[i], "account" )) { entry->kacc = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "dst_account")) { entry->kxferacc = atoi(attribute_values[i]); } @@@ -603,12 -633,20 +635,20 @@@ else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); } + + + + + + + else if(!strcmp (attribute_names[i], "nextdate" )) { entry->nextdate = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "every" )) { entry->every = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "unit" )) { entry->unit = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "limit" )) { entry->limit = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "weekend" )) { entry->weekend = atoi(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "gap" )) { entry->daygap = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "scat" )) { scat = (gchar *)attribute_values[i]; split = TRUE; } else if(!strcmp (attribute_names[i], "samt" )) { samt = (gchar *)attribute_values[i]; split = TRUE; } else if(!strcmp (attribute_names[i], "smem" )) { smem = (gchar *)attribute_values[i]; split = TRUE; } @@@ -650,7 -688,7 +690,7 @@@ gint i else if(!strcmp (attribute_names[i], "flags" )) { entry->flags = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "payee" )) { entry->kpay = atoi(attribute_values[i]); } else if(!strcmp (attribute_names[i], "category" )) { entry->kcat = atoi(attribute_values[i]); } - else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->wording = g_strdup(attribute_values[i]); } + else if(!strcmp (attribute_names[i], "wording" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->memo = g_strdup(attribute_values[i]); } else if(!strcmp (attribute_names[i], "info" )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->info = g_strdup(attribute_values[i]); } else if(!strcmp (attribute_names[i], "tags" )) { @@@ -678,7 -716,7 +718,7 @@@ } //all attribute loaded: append - // we use prepend here, the list will be reversed later for perf reason + // for perf reason we use prepend here, the list will be reversed later da_transaction_prepend(entry); } @@@ -746,6 -784,7 +786,7 @@@ ParseContext *ctx = user_data homebank_load_xml_tag(ctx, attribute_names, attribute_values); } } + break; case 'f': { @@@ -838,9 -877,6 +879,9 @@@ gboolean rc DB( g_print("\n[hb-xml] homebank_load_xml\n") ); + GValue filename_val = G_VALUE_INIT; + ext_hook("load_file", EXT_STRING(&filename_val, filename), NULL); + retval = XML_OK; if (!g_file_get_contents (filename, &buffer, &length, &error)) { @@@ -898,52 -934,63 +939,63 @@@ DB( g_timer_destroy (t) ); /* file upgrade / bugfix */ - if( ctx.file_version <= 0.1 ) - homebank_upgrade_to_v02(); - if( ctx.file_version <= 0.2 ) - homebank_upgrade_to_v03(); - if( ctx.file_version <= 0.3 ) - homebank_upgrade_to_v04(); - if( ctx.file_version <= 0.4 ) - homebank_upgrade_to_v05(); - if( ctx.file_version <= 0.5 ) - { - homebank_upgrade_to_v06(); - homebank_upgrade_lower_v06(); - } - if( ctx.file_version <= 0.6 ) + // group a test for very old version + if( ctx.file_version <= 1.0 ) { - homebank_upgrade_to_v07(); - hbfile_sanity_check(); - } - if( ctx.file_version <= 0.7 ) // <= 4.5 - { - homebank_upgrade_to_v08(); - } - if( ctx.file_version <= 0.8 ) // <= 4.6 - { - hbfile_sanity_check(); - } - if( ctx.file_version <= 0.9 ) // <= 4.6.3 - { - hbfile_sanity_check(); - homebank_upgrade_to_v10(); - } - if( ctx.file_version <= 1.0 ) // <= 5.0.0 - { - hbfile_sanity_check(); - homebank_upgrade_to_v11(); - } + if( ctx.file_version <= 0.1 ) + homebank_upgrade_to_v02(); + if( ctx.file_version <= 0.2 ) + homebank_upgrade_to_v03(); + if( ctx.file_version <= 0.3 ) + homebank_upgrade_to_v04(); + if( ctx.file_version <= 0.4 ) + homebank_upgrade_to_v05(); + if( ctx.file_version <= 0.5 ) + { + homebank_upgrade_to_v06(); + homebank_upgrade_lower_v06(); + } + if( ctx.file_version <= 0.6 ) + { + homebank_upgrade_to_v07(); + hbfile_sanity_check(); + } + if( ctx.file_version <= 0.7 ) // <= 4.5 + { + homebank_upgrade_to_v08(); + } + if( ctx.file_version <= 0.8 ) // <= 4.6 + { + hbfile_sanity_check(); + } + if( ctx.file_version <= 0.9 ) // <= 4.6.3 + { + hbfile_sanity_check(); + homebank_upgrade_to_v10(); + } + if( ctx.file_version <= 1.0 ) // <= 5.0.0 + { + hbfile_sanity_check(); + homebank_upgrade_to_v11(); + } + } + //starting 5.0.4 data upgrade is done without changing file_version - if( ctx.data_version < 050005 ) // <= 5.0.5 + //file version is changed only when the structure change + //don't start number below with 0 to avoid octal interpretation + if( ctx.data_version <= 50005 ) // <= 5.0.5 { hbfile_sanity_check(); } - if( ctx.file_version <= 1.1 ) // <= 5.1.0 + if( ctx.file_version <= 1.1 ) // <= 5.1.0 { hbfile_sanity_check(); homebank_upgrade_to_v12(); } + if( ctx.data_version <= 50106 ) // < 5.1.6 + { + homebank_upgrade_to_v12_7(); + } // next ? @@@ -954,7 -1001,6 +1006,6 @@@ } - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* @@@ -1123,8 -1169,9 +1174,9 @@@ gint retval = XML_OK Currency *item = list->data; tmpstr = g_markup_printf_escaped( - "\n", + "\n", item->key, + item->flags, item->iso_code, item->name, item->symbol, @@@ -1413,12 -1460,13 +1465,13 @@@ GError *error = NULL hb_xml_append_int(node, "flags", item->flags); hb_xml_append_int(node, "payee", item->kpay); hb_xml_append_int(node, "category", item->kcat); - hb_xml_append_txt(node, "wording", item->wording); + hb_xml_append_txt(node, "wording", item->memo); hb_xml_append_int(node, "nextdate", item->nextdate); hb_xml_append_int(node, "every", item->every); hb_xml_append_int(node, "unit", item->unit); hb_xml_append_int(node, "limit", item->limit); hb_xml_append_int(node, "weekend", item->weekend); + hb_xml_append_int(node, "gap", item->daygap); if(da_splits_count(item->splits) > 0) { @@@ -1494,13 -1542,13 +1547,13 @@@ GError *error = NULL hb_xml_append_int(node, "flags", item->flags); hb_xml_append_int(node, "payee", item->kpay); hb_xml_append_int(node, "category", item->kcat); - hb_xml_append_txt(node, "wording", item->wording); + hb_xml_append_txt(node, "wording", item->memo); hb_xml_append_txt(node, "info", item->info); hb_xml_append_txt(node, "tags", tagstr); hb_xml_append_int(node, "kxfer", item->kxfer); - if(da_splits_count(item->splits) > 0) - { + if(da_splits_count(item->splits) > 0) + { gchar *cats, *amounts, *memos; da_splits_tostring(item->splits, &cats, &amounts, &memos); @@@ -1552,9 -1600,6 +1605,9 @@@ 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) { diff --combined src/homebank.c index 9a9e915,3b65ca1..60e87c8 --- a/src/homebank.c +++ b/src/homebank.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -17,21 -17,21 +17,22 @@@ * along with this program. If not, see . */ + #include "homebank.h" +#include "ext.h" #include "dsp_mainwindow.h" #include "hb-preferences.h" #include "language.h" - #ifdef G_OS_WIN32 #include #endif #define APPLICATION_NAME "HomeBank" + /****************************************************************************/ /* Debug macros */ /****************************************************************************/ @@@ -55,7 -55,6 +56,7 @@@ static gchar *pixmaps_dir = NULL static gchar *locale_dir = NULL; static gchar *help_dir = NULL; static gchar *datas_dir = NULL; +static gchar *pkglib_dir = NULL; //#define MARKUP_STRING "%s" @@@ -108,7 -107,7 +109,7 @@@ static gint csvtype[7] = { g_io_channel_set_encoding(io, NULL, NULL); /* set to binary mode */ - for(i=0;i<4;i++) + for(i=0;i<25;i++) { if( retval != FILETYPE_UNKNOW ) break; @@@ -142,7 -141,7 +143,7 @@@ g_str_has_prefix(tmpstr, "!option") || g_str_has_prefix(tmpstr, "!Account") || g_str_has_prefix(tmpstr, "!account") - ) + ) { DB( g_print(" type is QIF\n") ); retval = FILETYPE_QIF; @@@ -150,7 -149,10 +151,10 @@@ else /* is it OFX ? */ - if( g_strstr_len(tmpstr, 10, "OFX") != NULL) + if( g_strstr_len(tmpstr, -1, "") != NULL + || g_strstr_len(tmpstr, -1, "") != NULL + /*|| strcasestr(tmpstr, "") != NULL*/ + ) { DB( g_print(" type is OFX\n") ); retval = FILETYPE_OFX; @@@ -201,7 -203,7 +205,7 @@@ void homebank_file_ensure_xhb(gchar *fi { gchar *newfilename; - newfilename = hb_util_filename_new_with_extension(filename, "xhb"); + newfilename = hb_filename_new_with_extension(filename, "xhb"); hbfile_change_filepath(newfilename); DB( g_print(" - changed to: '%s'\n", GLOBALS->xhb_filepath) ); } @@@ -213,13 -215,15 +217,15 @@@ } - static gboolean homebank_copy_file(gchar *srcfile, gchar *dstfile) + static gboolean homebank_file_copy(gchar *srcfile, gchar *dstfile) { gchar *buffer; gsize length; //GError *error = NULL; gboolean retval = FALSE; + DB( g_print("\n[homebank] file copy\n") ); + if (g_file_get_contents (srcfile, &buffer, &length, NULL)) { if(g_file_set_contents(dstfile, buffer, length, NULL)) @@@ -228,32 -232,46 +234,46 @@@ } g_free(buffer); } + + DB( g_print(" - copied '%s' => '%s' :: %d\n", srcfile, dstfile, retval) ); return retval; } - void homebank_backup_current_file(void) + static gboolean homebank_file_delete_existing(gchar *filepath) { - gchar *bakfilename; + gboolean retval = FALSE; - DB( g_print("\n[homebank] backup_current_file\n") ); + DB( g_print("\n[homebank] file delete existing\n") ); - bakfilename = hb_util_filename_new_with_extension (GLOBALS->xhb_filepath, "xhb~"); - if( g_file_test(bakfilename, G_FILE_TEST_EXISTS) ) + if( g_file_test(filepath, G_FILE_TEST_EXISTS) ) { - DB( g_print(" - delete existing: '%s'\n", bakfilename) ); - g_remove(bakfilename); + g_remove(filepath); + retval = TRUE; } - DB( g_print(" - copy '%s' => '%s'\n", GLOBALS->xhb_filepath, bakfilename) ); + DB( g_print(" - deleted: '%s' :: %d\n", filepath, retval) ); + return retval; + } + + void homebank_backup_current_file(void) + { + gchar *bakfilename; + + DB( g_print("\n[homebank] backup_current_file\n") ); + + //do normal linux backup file + DB( g_print(" normal backup with ~\n") ); + bakfilename = hb_filename_new_with_extension (GLOBALS->xhb_filepath, "xhb~"); + homebank_file_delete_existing(bakfilename); //#512046 copy file not to broke potential links //retval = g_rename(pathname, newname); - homebank_copy_file (GLOBALS->xhb_filepath, bakfilename); - + homebank_file_copy (GLOBALS->xhb_filepath, bakfilename); g_free(bakfilename); } + /* = = = = = = = = = = = = = = = = = = = = */ /* url open */ @@@ -332,43 -350,29 +352,29 @@@ homebank_util_url_show (const gchar *ur /* ** load lastopenedfiles from homedir/.homebank */ - gboolean homebank_lastopenedfiles_load(void) + gchar *homebank_lastopenedfiles_load(void) { GKeyFile *keyfile; - gboolean retval = FALSE; - gchar *group, *filename, *lastfilename; + gchar *group, *filename, *tmpfilename; + gchar *lastfilename = NULL; DB( g_print("\n[homebank] lastopenedfiles load\n") ); keyfile = g_key_file_new(); if(keyfile) { - filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL ); - - DB( g_print(" - filename: %s\n", filename) ); - if(g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)) { group = "HomeBank"; - DB( g_print(" - load keyfile ok\n") ); - if(g_key_file_has_key(keyfile, group, "LastOpenedFile", NULL)) { - DB( g_print(" - keyfile has key ok\n") ); - - lastfilename = g_key_file_get_string (keyfile, group, "LastOpenedFile", NULL); - - DB( g_print(" - lastfile loaded: %s\n", lastfilename ) ); + tmpfilename = g_key_file_get_string (keyfile, group, "LastOpenedFile", NULL); // #593082 - if (g_file_test (lastfilename, G_FILE_TEST_EXISTS) != FALSE) + if (g_file_test (tmpfilename, G_FILE_TEST_EXISTS) != FALSE) { - DB( g_print(" - file exists\n") ); - - hbfile_change_filepath(lastfilename); - - retval = TRUE; + lastfilename = tmpfilename; } } } @@@ -376,9 -380,7 +382,7 @@@ g_key_file_free (keyfile); } - DB( g_print(" - return: %d\n", retval) ); - - return retval; + return lastfilename; } @@@ -561,12 -563,6 +565,12 @@@ homebank_app_get_datas_dir (void return datas_dir; } +const gchar * +homebank_app_get_pkglib_dir (void) +{ + return pkglib_dir; +} + /* build package paths at runtime */ static void @@@ -583,7 -579,6 +587,7 @@@ build_package_paths (void pixmaps_dir = g_build_filename (prefix, "share", PACKAGE, "icons", NULL); help_dir = g_build_filename (prefix, "share", PACKAGE, "help", NULL); datas_dir = g_build_filename (prefix, "share", PACKAGE, "datas", NULL); + pkglib_dir = g_build_filename (prefix, "lib", PACKAGE, NULL); #ifdef PORTABLE_APP DB( g_print(" - app is portable under windows\n") ); config_dir = g_build_filename(prefix, "config", NULL); @@@ -597,7 -592,6 +601,7 @@@ pixmaps_dir = g_build_filename (DATA_DIR, PACKAGE, "icons", NULL); help_dir = g_build_filename (DATA_DIR, PACKAGE, "help", NULL); datas_dir = g_build_filename (DATA_DIR, PACKAGE, "datas", NULL); + pkglib_dir = g_build_filename (PKGLIB_DIR, NULL); config_dir = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL); //#870023 Ubuntu packages the help files in "/usr/share/doc/homebank-data/help/" for some strange reason @@@ -614,7 -608,6 +618,7 @@@ DB( g_print(" - locale_dir : %s\n", locale_dir) ); DB( g_print(" - help_dir : %s\n", help_dir) ); DB( g_print(" - datas_dir : %s\n", datas_dir) ); + DB( g_print(" - pkglib_dir : %s\n", pkglib_dir) ); } @@@ -756,7 -749,6 +760,7 @@@ static void homebank_cleanup( g_free (pixmaps_dir); g_free (locale_dir); g_free (help_dir); + g_free (pkglib_dir); } @@@ -887,7 -879,7 +891,7 @@@ homebank_init_i18n (void int -main (int argc, char *argv[]) +main (int argc, char *argv[], char *env[]) { GOptionContext *option_context; GOptionGroup *option_group; @@@ -959,22 -951,6 +963,22 @@@ gboolean openlast /* change the locale if a language is specified */ language_init (PREFS->language); + DB( g_print(" - loading plugins\n") ); + ext_init(&argc, &argv, &env); + + GList* it; + for (it = PREFS->ext_whitelist; it; it = g_list_next(it)) { + ext_load_plugin(it->data); + } + + gchar** plugins = ext_list_plugins(); + gchar** plugins_it; + for (plugins_it = plugins; *plugins_it; ++plugins_it) { + gboolean loaded = ext_is_plugin_loaded(*plugins_it); + g_print("found plugin: %s, loaded: %d\n", *plugins_it, loaded); + } + g_strfreev(plugins); + if( PREFS->showsplash == TRUE ) { splash = homebank_construct_splash(); @@@ -993,9 -969,6 +997,9 @@@ mainwin = (GtkWidget *)create_hbfile_window (NULL); + GValue mainwin_val = G_VALUE_INIT; + ext_hook("create_main_window", EXT_OBJECT(&mainwin_val, mainwin), NULL); + if(mainwin) { @@@ -1069,28 -1042,44 +1073,51 @@@ if( openlast ) { - if( homebank_lastopenedfiles_load() == TRUE ) + gchar *lastfilepath; + + lastfilepath = homebank_lastopenedfiles_load(); + if( lastfilepath != NULL ) + { + //#1710955 test for backup open + if( hbfile_file_isbackup(lastfilepath) ) + { + if( ui_mainwindow_open_backup_check_confirm(lastfilepath) == TRUE ) + { + GLOBALS->hbfile_is_bak = TRUE; + } + else + { + g_free(lastfilepath); + goto nobak; + } + } + + hbfile_change_filepath(lastfilepath); ui_mainwindow_open_internal(mainwin, NULL); + + } } /* -- hack to generate a big file -- */ - + nobak: /* update the mainwin display */ ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL)); + ext_hook("enter_main_loop", NULL); + - DB( g_print(" - gtk_main()\n" ) ); - + DB( g_print(" - gtk_main()\n" ) ); gtk_main (); - + + ext_hook("exit_main_loop", NULL); ++ + DB( g_print(" - call destroy mainwin\n" ) ); + gtk_widget_destroy(mainwin); } + DB( g_print(" - unloading plugins\n") ); + ext_term(); + } diff --combined src/homebank.h index e540237,81cc7fa..bc69153 --- a/src/homebank.h +++ b/src/homebank.h @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -68,19 -68,19 +68,19 @@@ /* = = = = = = = = = = = = = = = = */ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/ - #define HB_UNSTABLE FALSE + #define HB_UNSTABLE FALSE #define HB_UNSTABLE_SHOW FALSE #define HB_VERSION_MAJOR 5 #define HB_VERSION_MINOR 1 - #define HB_VERSION_MICRO 3 + #define HB_VERSION_MICRO 7 - #define HB_VERSION "5.1.3" + #define HB_VERSION "5.1.7" #define HB_VERSION_NUM (HB_VERSION_MAJOR*10000) + (HB_VERSION_MINOR*100) + HB_VERSION_MICRO #define FILE_VERSION 1.2 - #define PREF_VERSION 513 + #define PREF_VERSION 517 #if HB_UNSTABLE == FALSE #define PROGNAME "HomeBank" @@@ -156,6 -156,7 +156,7 @@@ typedef enu * GTK_ICON_SIZE_DIALOG 48 */ + /* -------- named icons (Standard Icon Name) -------- */ #define ICONNAME_NEW "document-new" #define ICONNAME_OPEN "document-open" @@@ -183,8 -184,7 +184,7 @@@ #define ICONNAME_LIST_ADD "list-add-symbolic" #define ICONNAME_LIST_REMOVE "list-remove-symbolic" - //#define ICONNAME_HB_SCHED_SKIP "media-skip-forward" - //#define ICONNAME_HB_SCHED_POST "media-playback-start" + #define ICONNAME_CHANGES_PREVENT "changes-prevent-symbolic" // custom or gnome not found #define ICONNAME_HB_BUTTON_MENU "open-menu-symbolic" @@@ -275,6 -275,7 +275,7 @@@ struct HomeBan // hbfile (unsaved properties) guint changes_count; gboolean hbfile_is_new; + gboolean hbfile_is_bak; gchar *xhb_filepath; gboolean xhb_hasbak; //file has backup (*.xhb~) used for revert menu sensitivity @@@ -297,7 -298,7 +298,7 @@@ gchar *homebank_filename_without_extent void homebank_file_ensure_xhb(gchar *filename); void homebank_backup_current_file(void); gboolean homebank_util_url_show (const gchar *url); - gboolean homebank_lastopenedfiles_load(void); + gchar *homebank_lastopenedfiles_load(void); gboolean homebank_lastopenedfiles_save(void); @@@ -309,7 -310,6 +310,7 @@@ const gchar *homebank_app_get_pixmaps_d const gchar *homebank_app_get_locale_dir (void); const gchar *homebank_app_get_help_dir (void); const gchar *homebank_app_get_datas_dir (void); +const gchar *homebank_app_get_pkglib_dir (void); guint32 homebank_app_date_get_julian(void); /* - - - - obsolete things - - - - */ diff --combined src/ui-pref.c index 1597d68,7da069f..bcee6b1 --- a/src/ui-pref.c +++ b/src/ui-pref.c @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -24,8 -24,6 +24,8 @@@ #include "dsp_mainwindow.h" #include "gtk-chart-colors.h" +#include "ext.h" + #include "ui-currency.h" @@@ -52,21 -50,17 +52,14 @@@ enum LST_PREF_MAX }; - enum - { - COLUMN_VISIBLE, - COLUMN_NAME, - COLUMN_ID, - NUM_COLUMNS - }; enum { - PREF_GENERAL, - PREF_INTERFACE, - PREF_COLUMNS, - PREF_DISPLAY, - PREF_IMPORT, - PREF_REPORT, - PREF_EURO, - PREF_MAX + EXT_COLUMN_ENABLED = 0, + EXT_COLUMN_LABEL, + EXT_COLUMN_TOOLTIP, + EXT_COLUMN_PLUGIN_NAME, + EXT_NUM_COLUMNS }; @@@ -78,7 -72,6 +71,7 @@@ static gchar *pref_iconname[PREF_MAX] "prf-import", "prf-report", "prf-euro", // to be renamed +"prf-plugins", //"prf_charts.svg" }; @@@ -89,8 -82,7 +82,8 @@@ N_("Transactions") N_("Display format"), N_("Import/Export"), N_("Report"), -N_("Euro minor") +N_("Euro minor"), +N_("Plugins") // }; @@@ -146,20 -138,7 +139,7 @@@ NUL extern gchar *CYA_CHART_COLORSCHEME[]; extern gchar *CYA_MONTHS[]; - typedef struct - { - gshort id; - gchar *iso; - gchar *name; - gdouble value; - //gchar *prefix_symbol; /* max symbol is 3 digits in unicode */ - //gchar *suffix_symbol; /* but mostly is 1 digit */ - gchar *symbol; - gboolean sym_prefix; - gchar *decimal_char; - gchar *grouping_char; - gshort frac_digits; - } EuroParams; + /* @@@ -206,29 -185,14 +186,17 @@@ static EuroParams euro_params[] }; - GtkWidget *pref_list_create(void); - GtkWidget *list_txn_colprefcreate(void); - - static void list_txn_colpref_get(GtkTreeView *treeview, gboolean *columns); - +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns); + + - - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/ - typedef struct - { - gchar *locale; - gchar *name; - - } LangName; + static LangName languagenames[] = { --// af ar ast be bg ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl he hr hu id is it ++// af ar ast be bg ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl he hr hu id is it //ja ka ko lt lv ms nb nds nl oc pl pt_BR pt pt_PT ro ru si sk sl sr sv tr uk vi zh_CN zh_TW -- ++ { "aa", "Afar" }, { "ab", "Abkhazian" }, { "ae", "Avestan" }, @@@ -420,6 -384,9 +388,9 @@@ }; + static GtkWidget *pref_list_create(void); + + static gint ui_language_combobox_compare_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata) { @@@ -433,7 -400,7 +404,7 @@@ gchar *name1, *name2 //keep system laguage on top if(code1 == NULL) name1 = NULL; if(code2 == NULL) name2 = NULL; -- ++ retval = hb_string_utf8_compare(name1, name2); g_free(name2); @@@ -482,7 -449,7 +453,7 @@@ const gchar *lang g_warning(" locale name not found '%s'", locale); lang = locale; } -- ++ } return lang; @@@ -497,7 -464,7 +468,7 @@@ GtkTreeIter iter model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox)); gtk_list_store_append (GTK_LIST_STORE(model), &iter); -- gtk_list_store_set (GTK_LIST_STORE(model), &iter, ++ gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, NULL, 1, _("System Language"), -1); @@@ -520,13 -487,13 +491,13 @@@ const gchar *dirname { const gchar *lang; gchar *label; -- ++ gtk_list_store_append (GTK_LIST_STORE(model), &iter); lang = ui_language_combobox_get_name(dirname); label = g_strdup_printf ("%s [%s]", lang, dirname); -- gtk_list_store_set (GTK_LIST_STORE(model), &iter, ++ gtk_list_store_set (GTK_LIST_STORE(model), &iter, 0, dirname, 1, label, -1); @@@ -563,7 -530,7 +534,7 @@@ GtkCellRenderer *renderer gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, "text", 1, NULL); gtk_combo_box_set_id_column( GTK_COMBO_BOX(combobox), 0); -- ++ g_object_unref(store); if(label) @@@ -572,7 -539,7 +543,7 @@@ ui_language_combobox_populate(combobox); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); -- ++ return combobox; } @@@ -740,7 -707,7 +711,7 @@@ gchar buf[128] cur.frac_digits = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits)); da_cur_initformat (&cur); -- ++ DB( g_print("fmt: %s\n", cur.format) ); g_ascii_formatd(formatd_buf, sizeof (formatd_buf), cur.format, HB_NUMBER_SAMPLE); @@@ -780,11 -747,11 +751,11 @@@ struct defpref_data *data EuroParams *euro; gchar *buf; gint active; -- ++ DB( g_print("\n[ui-pref] eurosetcurrency\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); -- ++ active = ui_euro_combobox_id_to_active(country); euro = &euro_params[active]; buf = g_strdup_printf("%s - %s", euro->iso, euro->name); @@@ -899,7 -866,7 +870,7 @@@ struct defpref_data *data data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); gtk_widget_queue_draw (data->DA_colors); -- ++ } @@@ -932,99 -899,88 +903,88 @@@ GdkRGBA rgba DB( g_print("\n[ui-pref] set\n") ); + // general + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_show_splash), PREFS->showsplash); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_load_last), PREFS->loadlast); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_append_scheduled), PREFS->appendscheduled); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_do_update_currency), PREFS->do_update_currency); + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_daterange_wal), PREFS->date_range_wal); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_fiscyearday), PREFS->fisc_year_day ); + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_fiscyearmonth), PREFS->fisc_year_month - 1); + + // files/backup + gtk_entry_set_text(GTK_ENTRY(data->ST_path_hbfile), PREFS->path_hbfile); + + + + // interface if(PREFS->language != NULL) gtk_combo_box_set_active_id(GTK_COMBO_BOX(data->CY_language), PREFS->language); else gtk_combo_box_set_active (GTK_COMBO_BOX(data->CY_language), 0); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_toolbar), PREFS->toolbar_style); //gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_image_size), PREFS->image_size); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_custom_colors), PREFS->custom_colors); - gdk_rgba_parse(&rgba, PREFS->color_exp); gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(data->CP_exp_color), &rgba); - gdk_rgba_parse(&rgba, PREFS->color_inc); gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(data->CP_inc_color), &rgba); - gdk_rgba_parse(&rgba, PREFS->color_warn); gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(data->CP_warn_color), &rgba); - //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_ruleshint), PREFS->rules_hint); gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_gridlines), PREFS->grid_lines); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_fiscyearday), PREFS->fisc_year_day ); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_fiscyearmonth), PREFS->fisc_year_month - 1); - - gtk_entry_set_text(GTK_ENTRY(data->ST_path_hbfile), PREFS->path_hbfile); - gtk_entry_set_text(GTK_ENTRY(data->ST_path_import), PREFS->path_import); - gtk_entry_set_text(GTK_ENTRY(data->ST_path_export), PREFS->path_export); - //gtk_entry_set_text(GTK_ENTRY(data->ST_path_navigator), PREFS->path_navigator); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_load_last), PREFS->loadlast); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_append_scheduled), PREFS->appendscheduled); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_do_update_currency), PREFS->do_update_currency); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_show_splash), PREFS->showsplash); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_herit_date), PREFS->heritdate); + // transactions + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_daterange_txn), PREFS->date_range_txn); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_datefuture_nbdays), PREFS->date_future_nbdays); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_hide_reconciled), PREFS->hidereconciled); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_show_remind), PREFS->showremind); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_herit_date), PREFS->heritdate); - /* display */ + // display format gtk_entry_set_text(GTK_ENTRY(data->ST_datefmt), PREFS->date_format); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_unitismile), PREFS->vehicle_unit_ismile); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_unitisgal), PREFS->vehicle_unit_isgal); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_daterange_wal), PREFS->date_range_wal); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_daterange_txn), PREFS->date_range_txn); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_datefuture_nbdays), PREFS->date_future_nbdays); + // import/export + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_datefmt), PREFS->dtex_datefmt); + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_ofxname), PREFS->dtex_ofxname); + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_ofxmemo), PREFS->dtex_ofxmemo); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifmemo), PREFS->dtex_qifmemo); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifswap), PREFS->dtex_qifswap); + gtk_entry_set_text(GTK_ENTRY(data->ST_path_import), PREFS->path_import); + gtk_entry_set_text(GTK_ENTRY(data->ST_path_export), PREFS->path_export); + + // report gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_daterange_rep), PREFS->date_range_rep); + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_color_scheme), PREFS->report_color_scheme); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_byamount), PREFS->stat_byamount); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_showrate), PREFS->stat_showrate); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_showdetail), PREFS->stat_showdetail); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_budg_showdetail), PREFS->budg_showdetail); /* euro */ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_enable), PREFS->euro_active); //gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_euro_preset), PREFS->euro_country); data->country = PREFS->euro_country; defpref_eurosetcurrency(data->window, data->country); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_value), PREFS->euro_value); - ui_gtk_entry_set_text(data->ST_euro_symbol, PREFS->minor_cur.symbol); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_isprefix), PREFS->minor_cur.sym_prefix); ui_gtk_entry_set_text(data->ST_euro_decimalchar, PREFS->minor_cur.decimal_char); ui_gtk_entry_set_text(data->ST_euro_groupingchar, PREFS->minor_cur.grouping_char); gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits), PREFS->minor_cur.frac_digits); - //gtk_entry_set_text(GTK_ENTRY(data->ST_euro_symbol), PREFS->euro_symbol); //gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_nbdec), PREFS->euro_nbdec); //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_thsep), PREFS->euro_thsep); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_byamount), PREFS->stat_byamount); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_showrate), PREFS->stat_showrate); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_stat_showdetail), PREFS->stat_showdetail); - - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_budg_showdetail), PREFS->budg_showdetail); - - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_color_scheme), PREFS->report_color_scheme); - - /* import */ - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_datefmt), PREFS->dtex_datefmt); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_ofxname), PREFS->dtex_ofxname); - gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_ofxmemo), PREFS->dtex_ofxmemo); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifmemo), PREFS->dtex_qifmemo); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifswap), PREFS->dtex_qifswap); - - } /* ** get :: fill PREFS structure from widgets */ - #define RGBA_TO_INT(x) (int)(x*255) static gchar *gdk_rgba_to_hex(GdkRGBA *rgba) @@@ -1040,6 -996,21 +1000,21 @@@ const gchar *lang DB( g_print("\n[ui-pref] get\n") ); + // general + PREFS->showsplash = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_show_splash)); + PREFS->loadlast = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_load_last)); + PREFS->appendscheduled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_append_scheduled)); + PREFS->do_update_currency = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_do_update_currency)); + PREFS->date_range_wal = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_wal)); + PREFS->fisc_year_day = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_fiscyearday)); + PREFS->fisc_year_month = 1 + gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_fiscyearmonth)); + + // files/backup + g_free(PREFS->path_hbfile); + PREFS->path_hbfile = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_path_hbfile))); + + + g_free(PREFS->language); PREFS->language = NULL; lang = gtk_combo_box_get_active_id(GTK_COMBO_BOX(data->CY_language)); @@@ -1047,94 -1018,67 +1022,69 @@@ { PREFS->language = g_strdup(lang); } -- ++ PREFS->toolbar_style = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_toolbar)); //PREFS->image_size = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_image_size)); PREFS->custom_colors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_custom_colors)); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(data->CP_exp_color), &rgba); g_free(PREFS->color_exp); PREFS->color_exp = gdk_rgba_to_hex(&rgba); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(data->CP_inc_color), &rgba); g_free(PREFS->color_inc); PREFS->color_inc = gdk_rgba_to_hex(&rgba); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(data->CP_warn_color), &rgba); g_free(PREFS->color_warn); PREFS->color_warn = gdk_rgba_to_hex(&rgba); - //PREFS->rules_hint = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_ruleshint)); PREFS->grid_lines = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_gridlines)); + //list_txn_colpref_get(GTK_TREE_VIEW(data->LV_opecolumns), PREFS->lst_ope_columns); - PREFS->fisc_year_day = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_fiscyearday)); - PREFS->fisc_year_month = 1 + gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_fiscyearmonth)); - - list_txn_colpref_get(GTK_TREE_VIEW(data->LV_opecolumns), PREFS->lst_ope_columns); - - g_free(PREFS->path_hbfile); - PREFS->path_hbfile = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_path_hbfile))); - - ui_gtk_entry_replace_text(data->ST_path_import, &PREFS->path_import); - - ui_gtk_entry_replace_text(data->ST_path_export, &PREFS->path_export); - - PREFS->loadlast = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_load_last)); - PREFS->appendscheduled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_append_scheduled)); - PREFS->do_update_currency = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_do_update_currency)); - - PREFS->showsplash = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_show_splash)); - PREFS->heritdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_herit_date)); - // transaction ++ // transaction + PREFS->date_range_txn = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_txn)); + PREFS->date_future_nbdays = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_datefuture_nbdays)); PREFS->hidereconciled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_hide_reconciled)); PREFS->showremind = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_show_remind)); + PREFS->heritdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_herit_date)); - //g_free(PREFS->path_navigator); - //PREFS->path_navigator = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_path_navigator))); - + // display format g_free(PREFS->date_format); PREFS->date_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_datefmt))); - PREFS->vehicle_unit_ismile = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_unitismile)); PREFS->vehicle_unit_isgal = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_unitisgal)); - PREFS->date_range_wal = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_wal)); - PREFS->date_range_txn = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_txn)); - PREFS->date_future_nbdays = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_datefuture_nbdays)); + // import/export + PREFS->dtex_datefmt = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_datefmt)); + PREFS->dtex_ofxname = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxname)); + PREFS->dtex_ofxmemo = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxmemo)); + PREFS->dtex_qifmemo = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifmemo)); + PREFS->dtex_qifswap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifswap)); + ui_gtk_entry_replace_text(data->ST_path_import, &PREFS->path_import); + ui_gtk_entry_replace_text(data->ST_path_export, &PREFS->path_export); + + // report PREFS->date_range_rep = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_rep)); + PREFS->report_color_scheme = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_color_scheme)); + PREFS->stat_byamount = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_byamount)); + PREFS->stat_showrate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showrate)); + PREFS->stat_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showdetail)); + PREFS->budg_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_budg_showdetail)); + // euro minor PREFS->euro_active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_euro_enable)); - PREFS->euro_country = data->country; PREFS->euro_value = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_value)); //strcpy(PREFS->euro_symbol, gtk_entry_get_text(GTK_ENTRY(data->ST_euro_symbol))); //PREFS->euro_nbdec = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_nbdec)); //PREFS->euro_thsep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_euro_thsep)); - ui_gtk_entry_replace_text(data->ST_euro_symbol, &PREFS->minor_cur.symbol); PREFS->minor_cur.sym_prefix = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_euro_isprefix)); ui_gtk_entry_replace_text(data->ST_euro_decimalchar, &PREFS->minor_cur.decimal_char); ui_gtk_entry_replace_text(data->ST_euro_groupingchar, &PREFS->minor_cur.grouping_char); PREFS->minor_cur.frac_digits = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits)); - - PREFS->stat_byamount = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_byamount)); - PREFS->stat_showrate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showrate)); - PREFS->stat_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showdetail)); - - PREFS->budg_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_budg_showdetail)); - - PREFS->report_color_scheme = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_color_scheme)); - - /* import */ - PREFS->dtex_datefmt = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_datefmt)); - PREFS->dtex_ofxname = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxname)); - PREFS->dtex_ofxmemo = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxmemo)); - PREFS->dtex_qifmemo = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifmemo)); - PREFS->dtex_qifswap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifswap)); - //PREFS->chart_legend = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_chartlegend)); + + list_ext_colpref_get(GTK_TREE_VIEW(data->PI_plugin_columns), &(PREFS->ext_whitelist)); } @@@ -1153,10 -1097,10 +1103,10 @@@ 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 options")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); -- ++ row = 1; label = make_label_widget(_("Date order:")); //----------------------------------------- l, r, t, b @@@ -1172,10 -1116,10 +1122,10 @@@ 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:")); //----------------------------------------- l, r, t, b @@@ -1199,10 -1143,10 +1149,10 @@@ 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); @@@ -1219,10 -1163,10 +1169,10 @@@ 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")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); -- ++ row = 1; label = make_label_widget(_("_Import:")); //----------------------------------------- l, r, t, b @@@ -1280,7 -1224,7 +1230,7 @@@ gint i, x, y index = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_color_scheme)); colorscheme_init(&scheme, index); -- ++ gtk_widget_get_size_request (widget, &w, &h); x = y = 0; for(i=0;iCM_stat_byamount = widget; @@@ -1381,10 -1325,10 +1331,10 @@@ 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(_("Budget options")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); -- ++ row = 1; widget = gtk_check_button_new_with_mnemonic (_("Show _details")); data->CM_budg_showdetail = widget; @@@ -1409,7 -1353,7 +1359,7 @@@ 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(_("General")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1424,7 -1368,7 +1374,7 @@@ 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(_("Currency")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 4, 1); @@@ -1444,7 -1388,7 +1394,7 @@@ //gtk_grid_attach (GTK_GRID (group_grid), data->CY_option[FILTER_DATE], 1, 2, row, row+1); gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1); -- ++ // group :: Exchange rate group_grid = gtk_grid_new (); data->GRP_rate = group_grid; @@@ -1469,7 -1413,7 +1419,7 @@@ 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(_("Format")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1486,7 -1430,7 +1436,7 @@@ gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL); gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM); gtk_container_add (GTK_CONTAINER (expander), group_grid); -- ++ row = 0; label = make_label_widget(_("_Symbol:")); gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); @@@ -1539,7 -1483,7 +1489,7 @@@ 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")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1569,7 -1513,7 +1519,7 @@@ widget = gtk_image_new_from_icon_name (ICONNAME_INFO, GTK_ICON_SIZE_BUTTON); gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1); -- ++ gtk_widget_set_tooltip_text(widget, _("%a locale's abbreviated weekday name.\n" "%A locale's full weekday name. \n" @@@ -1597,7 -1541,7 +1547,7 @@@ 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(_("Measurement units")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1617,7 -1561,7 +1567,7 @@@ static GtkWidget *defpref_page_transactions (struct defpref_data *data) { - GtkWidget *content_grid, *group_grid, *sw, *label, *widget; + GtkWidget *content_grid, *group_grid, *label, *widget; gint crow, row; content_grid = gtk_grid_new(); @@@ -1630,7 -1574,7 +1580,7 @@@ 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(_("Transaction window")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1647,7 -1591,7 +1597,7 @@@ //----------------------------------------- l, r, t, b gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); widget = make_numeric(NULL, 0, 366); -- ++ data->ST_datefuture_nbdays = widget; gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); @@@ -1670,7 -1614,7 +1620,7 @@@ 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(_("Multiple add")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1680,11 -1624,12 +1630,12 @@@ gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1); // group :: Column list + /* 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(_("Column list")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1699,6 -1644,7 +1650,7 @@@ gtk_widget_set_vexpand (sw, TRUE); gtk_grid_attach (GTK_GRID (group_grid), sw, 1, row, 2, 1); gtk_widget_set_tooltip_text(widget, _("Drag & drop to change the order")); + */ return content_grid; } @@@ -1720,7 -1666,7 +1672,7 @@@ 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(_("General")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1730,7 -1676,7 +1682,7 @@@ widget = ui_language_combobox_new(label); data->CY_language = widget; gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1); -- ++ row++; label = make_label_widget(_("_Toolbar:")); gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); @@@ -1753,7 -1699,7 +1705,7 @@@ 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(_("Amount colors")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1783,11 -1729,11 +1735,11 @@@ gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL); 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); -- ++ label = make_label_widget(_("_Income:")); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); @@@ -1821,7 -1767,7 +1773,7 @@@ 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")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1873,7 -1819,7 +1825,7 @@@ 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); @@@ -1889,7 -1835,7 +1841,7 @@@ 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")); gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1); @@@ -1914,202 -1860,6 +1866,202 @@@ return content_grid; } + +void plugin_execute_action(GtkTreeView* treeview, GtkTreePath* path, GtkTreeViewColumn* col, gpointer userdata); + +static void +toggle_plugin(GtkCellRendererToggle *cell, gchar* path_str, gpointer data) +{ + GtkTreeModel *model = (GtkTreeModel*)data; + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_path_new_from_string(path_str); + + const gchar* plugin; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, EXT_COLUMN_PLUGIN_NAME, &plugin, -1); + + gboolean enabled = ext_is_plugin_loaded(plugin); + if (enabled) { + ext_unload_plugin(plugin); + enabled = FALSE; + } else { + enabled = (ext_load_plugin(plugin) == 0); + if (!enabled) { + ext_run_modal(_("Plugin Error"), _("The plugin failed to load properly."), "error"); + } + } + + /* set new value */ + gtk_list_store_set(GTK_LIST_STORE (model), &iter, EXT_COLUMN_ENABLED, enabled, -1); + + /* clean up */ + gtk_tree_path_free(path); +} + + +void plugin_execute_action(GtkTreeView* treeview, GtkTreePath* path, GtkTreeViewColumn* col, gpointer userdata) +{ + GtkTreeModel* model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + + if (gtk_tree_model_get_iter(model, &iter, path)) { + gchar* plugin_filename; + gtk_tree_model_get(model, &iter, EXT_COLUMN_PLUGIN_NAME, &plugin_filename, -1); + ext_execute_action(plugin_filename); + g_free(plugin_filename); + } +} + +static GtkWidget *defpref_page_plugins (struct defpref_data *data) +{ + GtkWidget *container; + GtkListStore *store; + GtkTreeIter it; + GtkWidget* view; + + container = gtk_vbox_new(FALSE, 0); + + store = gtk_list_store_new(EXT_NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + gchar** plugins = ext_list_plugins(); + gchar** plugins_it; + for (plugins_it = plugins; *plugins_it; ++plugins_it) { + + gboolean enabled = ext_is_plugin_loaded(*plugins_it); + GHashTable* metadata = ext_read_plugin_metadata(*plugins_it); + if (!metadata) { + metadata = g_hash_table_new(g_str_hash, g_str_equal); + } + + gchar* tmp = NULL; + + // NAME + gchar* name = g_hash_table_lookup(metadata, "name"); + if (!name || *name == '\0') { + name = *plugins_it; + } + name = g_markup_escape_text(name, -1); + gchar* label = g_strdup_printf("%s", name); + gchar* tooltip = g_strdup_printf("%s", name); + g_free(name); + + // VERSION + gchar* version = g_hash_table_lookup(metadata, "version"); + if (version) { + version = g_markup_escape_text(version, -1); + tmp = label; + label = g_strdup_printf("%s %s", tmp, version); + g_free(tmp); + tmp = tooltip; + tooltip = g_strdup_printf("%s %s", tmp, version); + g_free(tmp); + g_free(version); + } + + // ABSTRACT + gchar* abstract = g_hash_table_lookup(metadata, "abstract"); + if (abstract) { + abstract = g_markup_escape_text(abstract, -1); + tmp = label; + label = g_strdup_printf("%s\n%s", tmp, abstract); + g_free(tmp); + g_free(abstract); + } + + // AUTHOR + gchar* author = g_hash_table_lookup(metadata, "author"); + if (author) { + author = g_markup_escape_text(author, -1); + tmp = tooltip; + tooltip = g_strdup_printf("%s\n%s", tmp, author); + g_free(tmp); + g_free(author); + } + + // WEBSITE + gchar* website = g_hash_table_lookup(metadata, "website"); + if (website) { + website = g_markup_escape_text(website, -1); + tmp = tooltip; + tooltip = g_strdup_printf("%s\n%s: %s", tmp, _("Website"), website); + g_free(tmp); + g_free(website); + } + + // FILEPATH + tmp = ext_find_plugin(*plugins_it); + gchar* full = g_markup_escape_text(tmp, -1); + g_free(tmp); + tmp = tooltip; + tooltip = g_strdup_printf("%s\n%s: %s", tmp, _("File"), full); + g_free(tmp); + g_free(full); + + g_hash_table_unref(metadata); + + gtk_list_store_append(store, &it); + gtk_list_store_set(store, &it, + EXT_COLUMN_ENABLED, enabled, + EXT_COLUMN_LABEL, label, + EXT_COLUMN_TOOLTIP, tooltip, + EXT_COLUMN_PLUGIN_NAME, *plugins_it, + -1); + + g_free(label); + g_free(tooltip); + } + g_strfreev(plugins); + + view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); + g_object_unref(store); + + g_signal_connect(view, "row-activated", (GCallback)plugin_execute_action, NULL); + + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE); + gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(view), EXT_COLUMN_TOOLTIP); + + + GtkTreeViewColumn *col; + GtkCellRenderer *renderer; + + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, _("Enabled")); + gtk_tree_view_column_set_sort_column_id(col, EXT_COLUMN_ENABLED); + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + + renderer = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "active", 0); + g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_plugin), store); + + col = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(col, _("Plugin")); + gtk_tree_view_column_set_sort_column_id(col, EXT_COLUMN_LABEL); + gtk_tree_view_column_set_expand(col, TRUE); + /*gtk_tree_view_column_set_sort_order(col, GTK_SORT_ASCENDING);*/ + gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); + + renderer = gtk_cell_renderer_text_new(); + g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start(col, renderer, TRUE); + gtk_tree_view_column_add_attribute(col, renderer, "markup", EXT_COLUMN_LABEL); + + data->PI_plugin_columns = view; + + GtkWidget* sw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_container_add(GTK_CONTAINER(sw), view); + + gtk_box_pack_start(GTK_BOX(container), sw, TRUE, TRUE, 0); + + return(container); +} + + static void defpref_selection(GtkTreeSelection *treeselection, gpointer user_data) { struct defpref_data *data; @@@ -2204,12 -1954,12 +2156,12 @@@ gint result homebank_pref_setdefault(); defpref_set(data); } -- ++ } // the window creation -GtkWidget *defpref_dialog_new (void) +GtkWidget *defpref_dialog_new (gint initial_selection) { struct defpref_data data; GtkWidget *window, *content, *mainvbox; @@@ -2225,7 -1975,7 +2177,7 @@@ GtkWidget *hbox, *vbox, *sw, *widget, * NULL); data.window = window; -- ++ //store our window private data g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data); @@@ -2243,7 -1993,7 +2195,7 @@@ //left part vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING_SMALL); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); -- ++ //list sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); @@@ -2257,7 -2007,7 +2209,7 @@@ data.BT_clear = gtk_button_new_with_mnemonic(_("_Reset")); gtk_box_pack_start (GTK_BOX (vbox), data.BT_clear, FALSE, TRUE, 0); -- ++ //right part : notebook vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); @@@ -2272,11 -2022,11 +2224,11 @@@ #else GtkCssProvider *provider; provider = gtk_css_provider_new (); -- gtk_css_provider_load_from_data (provider, ++ gtk_css_provider_load_from_data (provider, "#hbebox { color: @theme_selected_fg_color; background-color: @theme_selected_bg_color; }" , -1, NULL); gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER(provider), G_MAXUINT); -- ++ // gtk_style_context_set_state(context, GTK_STATE_FLAG_SELECTED); #endif @@@ -2351,10 -2101,6 +2303,10 @@@ page = defpref_page_euro(&data); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); + //plugins + page = defpref_page_plugins(&data); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL); + //todo:should move this gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data.CM_euro_enable), PREFS->euro_active); @@@ -2363,7 -2109,7 +2315,7 @@@ 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); -- ++ //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)); @@@ -2373,7 -2119,7 +2325,7 @@@ g_signal_connect (data.CY_colors, "changed", G_CALLBACK (defpref_colorpreset), NULL); -- ++ g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_page)), "changed", G_CALLBACK (defpref_selection), notebook); g_signal_connect (data.CM_euro_enable, "toggled", G_CALLBACK (defpref_eurotoggle), NULL); @@@ -2410,8 -2156,7 +2362,8 @@@ //select first row - GtkTreePath *path = gtk_tree_path_new_first (); + GtkTreePath *path = gtk_tree_path_new_from_indices(initial_selection, -1); + gtk_tree_selection_select_path (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_page)), path); @@@ -2420,7 -2165,6 +2372,7 @@@ gtk_tree_path_free(path); gtk_widget_show_all (window); + gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), initial_selection); gint result; gchar *old_lang; @@@ -2438,20 -2182,20 +2390,20 @@@ ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_BALANCE+UF_VISUAL)); DB( g_print("old='%s' new='%s'\n", old_lang, PREFS->language) ); -- ++ if(g_ascii_strncasecmp(old_lang == NULL ? "" : old_lang, PREFS->language == NULL ? "" : PREFS->language, -1) != 0) { ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_INFO, _("Info"), _("You will have to restart HomeBank\nfor the language change to take effect.") ); -- ++ } g_free(old_lang); break; } -- ++ // cleanup and destroy //defhbfile_cleanup(&data, result); @@@ -2463,7 -2207,7 +2415,7 @@@ // ------------------------------- - GtkWidget *pref_list_create(void) + static GtkWidget *pref_list_create(void) { GtkListStore *store; GtkWidget *view; @@@ -2518,7 -2262,7 +2470,7 @@@ gint i /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/ - + /* extern gchar *list_txn_column_label[]; @@@ -2532,17 -2276,17 +2484,17 @@@ GtkTreeIter iter GtkTreePath *path = gtk_tree_path_new_from_string (path_str); gboolean fixed; - /* get toggled iter */ - // get toggled iter ++ // get toggled iter gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_get (model, &iter, COLUMN_VISIBLE, &fixed, -1); - /* do something with the value */ + // do something with the value fixed ^= 1; - /* set new value */ + // set new value gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_VISIBLE, fixed, -1); - /* clean up */ + // clean up gtk_tree_path_free (path); } @@@ -2556,8 -2300,7 +2508,7 @@@ gboolean visible gint i, id; DB( g_print("[lst_txn-colpref] store column order \n") ); - + - model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); i = 0; @@@ -2572,13 -2315,10 +2523,10 @@@ // start at index 2 (status, date always displayed columns[i+2] = visible == TRUE ? id : -id; - /* Make iter point to the next row in the list store */ + // Make iter point to the next row in the list store valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); i++; } - - - } @@@ -2594,7 -2334,7 +2542,7 @@@ gint i DB( g_print("[lst_txn-colpref] create\n") ); - /* create list store */ + // create list store store = gtk_list_store_new( 3, G_TYPE_BOOLEAN, @@@ -2602,23 -2342,23 +2550,23 @@@ G_TYPE_UINT ); - /* populate */ + // populate for(i=0 ; i < NUM_LST_DSPOPE-1; i++ ) //-1 cause account column avoid { gint id; gboolean visible; DB( g_print("eval %d, %s\n", i, list_txn_column_label[i]) ); -- ++ if(i <= LST_DSPOPE_DATE) // status, date always displayed continue; //[i-1] here because lst_ope_columns[] do not store LST_DSPOPE_DATAS -- id = ABS(PREFS->lst_ope_columns[i-1]); ++ id = ABS(PREFS->lst_ope_columns[i-1]); if(id == 0) id = i; //if we pass here, new column or weird into pref file visible = (PREFS->lst_ope_columns[i-1] > 0) ? TRUE : FALSE; -- ++ DB( g_print(" - pos=%2d, id=%2d - %d '%s'\n", i, id, visible, list_txn_column_label[id]) ); gtk_list_store_append (store, &iter); @@@ -2627,7 -2367,7 +2575,7 @@@ COLUMN_NAME, _(list_txn_column_label[id]), COLUMN_ID , id, -1); -- ++ } //treeview @@@ -2646,7 -2386,7 +2594,7 @@@ g_signal_connect (renderer, "toggled", G_CALLBACK (list_txn_colpref_toggled_cell_data_function), store); -- ++ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes (_("Column"), renderer, @@@ -2659,33 -2399,5 +2607,34 @@@ return(view); } + */ + +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + g_list_free_full(*columns, g_free); + *columns = NULL; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + + gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); + while (valid) { + gboolean enabled = FALSE; + const gchar* name; + + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, + EXT_COLUMN_ENABLED, &enabled, + EXT_COLUMN_PLUGIN_NAME, &name, + -1); + + if (enabled) { + *columns = g_list_append(*columns, g_strdup(name)); + } + + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); + } +} + diff --combined src/ui-pref.h index 51799d3,d272be6..1ec90ba --- a/src/ui-pref.h +++ b/src/ui-pref.h @@@ -1,5 -1,5 +1,5 @@@ /* HomeBank -- Free, easy, personal accounting for everyone. - * Copyright (C) 1995-2017 Maxime DOYEN + * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * @@@ -119,26 -119,36 +119,50 @@@ struct defpref_dat gint country; + GtkWidget *PI_plugin_columns; +}; + +enum +{ + PREF_GENERAL, + PREF_INTERFACE, + PREF_TRANSACTIONS, + PREF_DISPLAY_FORMAT, + PREF_IMPORT_EXPORT, + PREF_REPORT, + PREF_EURO_MINOR, + PREF_PLUGINS, + PREF_MAX }; + typedef struct + { + gchar *locale; + gchar *name; + } LangName; + + + typedef struct + { + gshort id; + gchar *iso; + gchar *name; + gdouble value; + //gchar *prefix_symbol; /* max symbol is 3 digits in unicode */ + //gchar *suffix_symbol; /* but mostly is 1 digit */ + gchar *symbol; + gboolean sym_prefix; + gchar *decimal_char; + gchar *grouping_char; + gshort frac_digits; + } EuroParams; + + + void free_pref_icons(void); void load_pref_icons(void); -GtkWidget *defpref_dialog_new (void); +GtkWidget *defpref_dialog_new (gint initial_selection); #endif