]> Dogcows Code - chaz/homebank/commitdiff
Merge branch 'master' into ext-perl
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sun, 4 Feb 2018 17:16:29 +0000 (10:16 -0700)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sun, 4 Feb 2018 17:16:29 +0000 (10:16 -0700)
20 files changed:
1  2 
Makefile.am
configure.ac
plugins/hello.pl
src/Makefile.am
src/dsp_mainwindow.c
src/ext-perl.xs
src/hb-account.c
src/hb-archive.c
src/hb-assign.c
src/hb-category.c
src/hb-payee.c
src/hb-preferences.c
src/hb-preferences.h
src/hb-tag.c
src/hb-transaction.c
src/hb-xml.c
src/homebank.c
src/homebank.h
src/ui-pref.c
src/ui-pref.h

diff --combined Makefile.am
index de75d0f3cfbe7415f044a9ac8338a23cec6568b2,e5c6cfec6cbd8e6459ce23702a7de23039a48241..45d1f49f22cf51ba7d7828c84a9bfada8a7f6952
@@@ -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 798e623fd87ef94656bfa36afa343cb580b1ca7b,99db971a60d1c468451c7b0cda8d02d3102ceee6..f1c2dfd33250904f88f5887a5ba7a3ed6d859b72
@@@ -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 9171bb208eb119808ed03ba7973d23b4c2be7ec8,0000000000000000000000000000000000000000..25520b5f43d5ef64440cc3e94fb838d3ae758aef
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
-         print "transaction of amount: ", $xc->amount, "\t", $xc->wording, ", ", $xc->info, ", $num, $date\n";
 +
 +# NAME:     Hello World
 +# VERSION:  0.01
 +# ABSTRACT: This is the "hello world" of HomeBank plugins.
 +# AUTHOR:   Charles McGarvey <chazmcgarvey@brokenzipper.com>
 +# 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->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 484ce27b8a65ad79127df95daac4335f1d554c32,9c7e1936cc8bd4f298b0309c35ef48339f75ffb8..20da8f18246114c77313051187aa34980ea3da4f
@@@ -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 e819137b509e1297fa3809f6fdf2637facf2aebf,2cb2ecd2d5e6c47b7ab8eeb3ecef0ddee12a3d19..c733f4cb730be8c3f443f05f2c3bf5fc3a850152
@@@ -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"
  
  #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") },
    { "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..."), "<control>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 
  "        <separator/>"
  "      <menuitem action='Anonymize'/>"
  "    </menu>"
 +"    <menu action='PluginMenu'>"
 +"      <separator/>"
 +"      <menuitem action='PluginPreferences'/>"
 +"      <separator/>"
 +"    </menu>"
  "    <menu action='HelpMenu'>"
  "      <menuitem action='Contents'/>"
- "        <separator/>"
  "      <menuitem action='Online'/>"
- "      <menuitem action='Translate'/>"
+ "        <separator/>"
+ "      <menuitem action='Updates'/>"
+ "      <menuitem action='ReleaseNotes'/>"
  "      <menuitem action='Problem'/>"
+ "      <menuitem action='Translate'/>"
  "        <separator/>"
  "      <menuitem action='About'/>"
  "    </menu>"
  "    <toolitem action='RBalance'/>"
  "    <toolitem action='RBudget'/>"
  "    <toolitem action='RVehiculeCost'/>"
 +"      <separator/>"
  "  </toolbar>"
  
  "</ui>";
@@@ -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
    };
    };
  */
  
-       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;
        }
  }
  
  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
                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) )
                        {
                                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) )
  
                        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)
                        {
                        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,
                                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,
                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;
  
  
  }
  
  /*
  **
  */
@@@ -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)
                        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)
        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));
        {
        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);
                                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,
  
                        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);
                        }
  
                        /* 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,
  
        }
  
-       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);
        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);
  
        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;
        /* 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));
        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));
  
  
        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;
  
-       DB( g_print("\n[ui-mainwindow] dispose\n") );
 +      GValue widget_value = G_VALUE_INIT;
 +      ext_hook("main_window_disposal", EXT_OBJECT(&widget_value, widget), NULL);
 +
+       DB( g_print("\n[ui-mainwindow] delete-event\n") );
  
        //store position and size
        wg = &PREFS->wal_wg;
        }
        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 ();
  
  
        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;
                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") );
  
  
        /* 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 5aa56b01df5480491909eb647b4d6ae6b48696b5,0000000000000000000000000000000000000000..9c7bd8bc11aac03f1098fbeb4049def0a77a90cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1043 -1,0 +1,1043 @@@
- wording(Transaction* SELF, ...)
 +
 +#include <EXTERN.h>
 +#include <perl.h>
 +#include <XSUB.h>
 +
 +#include <string.h>
 +
 +#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*
-                       if (SELF->wording) g_free(SELF->wording);
-                       SELF->wording = g_strdup(SvGchar_ptr(ST(1)));
++memo(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
-               RETVAL = SELF->wording ? SELF->wording : "";
++                      if (SELF->memo) g_free(SELF->memo);
++                      SELF->memo = g_strdup(SvGchar_ptr(ST(1)));
 +              }
-                       SELF->wording, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
++              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->memo, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
 +
diff --combined src/hb-account.c
index a7c0051c11e474a45de0b22a3b16243f1b640edc,5917e669cfd97a8d782a7e9bb6f21351d609b68c..ee5055f954374c75a4f6ecfbd4f6e2c32b5ddc87
@@@ -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 e0789de31bb5f7c45e08f32b1640a002bab1147f,0e88c48549f243252fb63d64c87738d249ff8291..628e978a9ce7c0ec4125909f3cc16d7a54e04ad4
@@@ -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                                                             */
  /****************************************************************************/
  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);
        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
  }
  
  
- 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:
                        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;
        {
                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 )
                {
  
  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:
        
  
        // 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;
  }
  
  /* 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)
                        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)
                {
  
                                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 495ead2da698a2dccd39dbb52dbef7088ead46b6,7989ff9961fda8b5f011d322161a91eaa569570b..1a89a45fc5a9a358aa8ff88299330004815b2ece
@@@ -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 f3d43bd549c28af3953c9e114a6f8558324ee43b,80f7e19b62e0540df4239a4046d909220b218b2e..948788649f591bcd242a47e0c898993beff7ce08
@@@ -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)
                {
                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;i<nbsplit;i++)
+                               {
+                               Split *split = txn->splits[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);
        {
        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;i<nbsplit;i++)
+                       {
+                       Split *split = entry->splits[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 e416fcf9324671ad5e7b38fe80d8b0c76a9652c6,896e9360057443c46d40eafbcde67b092c5014cd..558b76dd526c364a4a4af2b65c81c1757527a9bf
@@@ -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 8df09995cd89a75f877ff8749ec317a266156f61,db7b3ed5a2adffbf11420f18a57f87a4d7e026d0..8a9fb60e810199ca61f6430609098f44b76295bb
@@@ -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;
        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;
        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);
                                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);
                        //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);
                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);
                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") );
  
                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);
                //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 69bb44e4d27b7a3c16d7404d30a7819da6855c85,cf7e1a30da518d5d557ad9b23d4fb03accab09fc..1223888a34a2549d86782f14c77ff4507a70588e
@@@ -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 8a93babbdfb071ee2854596fec190057f0f7f014,13065edb8d13d9ad6ae2966773ae0e463ec76a83..96cb5bf496dd7d518ae02e12a61b3f342e847975
@@@ -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 5f77203fed1a988218a6945bb1dd5ca272b78562,29812d9ce5e1050640b55f05998c512d66a95c0a..eb825093e8b674239d7c4a3c4a326cde61e1d7bd
@@@ -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)
                {
  }
  
  
  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
  
  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)
                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);
  
  
        // 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;
  
                        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)
                 && 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);
  
          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") );
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  
- 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;
  
        //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) );
  
        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);
  
                /* 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);
+                       }
                }
        }
  
                //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 6476fd8e0c3f327a009d1b4cef851ebfbf2ab712,c55db990e29686e604b2033b1dd9e39fcb0b280d..da67dad488e9b9a95a3c5b901d6140914e56736b
@@@ -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) );
  
  }
  
  
+ 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]); }
                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"       ))
                {
        }
        
        //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))
        {
                        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 ?
                        
  }
  
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  /*
@@@ -1123,8 -1169,9 +1174,9 @@@ gint retval = XML_OK
        Currency *item = list->data;
  
                tmpstr = g_markup_printf_escaped(
-                   "<cur key=\"%d\" iso=\"%s\" name=\"%s\" symb=\"%s\" syprf=\"%d\" dchar=\"%s\" gchar=\"%s\" frac=\"%d\" rate=\"%s\" mdate=\"%d\" />\n",
+                   "<cur key=\"%d\" flags=\"%d\" iso=\"%s\" name=\"%s\" symb=\"%s\" syprf=\"%d\" dchar=\"%s\" gchar=\"%s\" frac=\"%d\" rate=\"%s\" mdate=\"%d\"/>\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 9a9e9157a89fafca1252bebe915f3f3da711d634,3b65ca1e57043713de1d2195a37be971e29c03ae..60e87c88650dbc4ccc7bc0329cec3e07db271bf4
@@@ -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.
   *
   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #include "homebank.h"
 +#include "ext.h"
  
  #include "dsp_mainwindow.h"
  #include "hb-preferences.h"
  #include "language.h"
  
  
  #ifdef G_OS_WIN32
  #include <windows.h>
  #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 "<span size='small'>%s</span>"
@@@ -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;
                                            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;
                                        else
  
                                        /* is it OFX ? */
-                                       if( g_strstr_len(tmpstr, 10, "OFX") != NULL)
+                                       if( g_strstr_len(tmpstr, -1, "<OFX>") != NULL 
+                                        || g_strstr_len(tmpstr, -1, "<ofx>") != NULL
+                                        /*||   strcasestr(tmpstr, "<OFC>") != 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) );
        }
  }
  
  
- 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))
                }
                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;
                                }
                        }
                }
                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);
        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
        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();
  
                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)
                {
  
  
                        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));
  
-               DB( g_print(" - gtk_main()\n" ) );
 +                      ext_hook("enter_main_loop", NULL);
 +
+                       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 e54023743e9bb4c3f1869e910ab6b19bf51c4629,81cc7fa7e03fe7d2765ef9bc6368db8c1216b54f..bc69153e0718f79991dea2885b7fe9919e38b566
@@@ -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.
   *
  /* = = = = = = = = = = = = = = = = */
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  
- #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"
  #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 1597d688aa3f055501c127f3f61df3568245d41f,7da069f50719083bab1878da9480ff5dbb65dceb..bcee6b1848e09e19df8a61921583935c0496a3a9
@@@ -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" },
  };
  
  
+ 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)
        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));
        {
                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
        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
        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);
        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;i<scheme.nb_cols;i++)
@@@ -1313,10 -1257,10 +1263,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(_("Initial filter"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Date _range:"));
        //----------------------------------------- l, r, t, b
        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(_("Charts options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Color scheme:"));
        //----------------------------------------- l, r, t, b
        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(_("Statistics options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        widget = gtk_check_button_new_with_mnemonic (_("Show by _amount"));
        data->CM_stat_byamount = widget;
        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);
  
        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);
  
        //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;
        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);
  
        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);
  
        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"
        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);
  
  
  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();
        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);
  
        //----------------------------------------- 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);
  
        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);
  
        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);
  
        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);
  
        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);
        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);
  
        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);
  
        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);
  
        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);
  
        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("<b>%s</b>", name);
 +              gchar* tooltip = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>", 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<b>%s:</b> %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<b>%s:</b> %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);
  
        //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);
        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);
        #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
  
        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);
        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));
      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);
  
  
        //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);
  
        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;
                                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);
  // -------------------------------
  
  
- 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;
                // 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,
                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);
                        COLUMN_NAME, _(list_txn_column_label[id]),
                        COLUMN_ID  , id,
                        -1);
--              
++
        }
  
        //treeview
        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,
  
        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 51799d3baf804647bfcc58a7f6b41a7b2cc8eaac,d272be615b2b2b031371594f11dd8a14286966bb..1ec90ba22a200f429b973224e147b932f3ba6251
@@@ -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
This page took 0.195483 seconds and 4 git commands to generate.