]> Dogcows Code - chaz/homebank/commitdiff
Merge branch 'master' into ext-perl
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Thu, 25 Apr 2019 05:07:35 +0000 (23:07 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Thu, 25 Apr 2019 05:07:35 +0000 (23:07 -0600)
19 files changed:
1  2 
configure.ac
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
themes/hicolor/Makefile.am

diff --combined configure.ac
index f1c2dfd33250904f88f5887a5ba7a3ed6d859b72,12933ffa32c9066a8cbf52b5fc196ffd8aba268f..869c694afc9411405524f6be150cb51761e586e8
@@@ -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.7])
+ AC_INIT([homebank], [5.2.4])
  #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.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)
@@@ -42,7 -38,7 +42,7 @@@ CFLAGS="${CFLAGS} -Wall -Wmissing-proto
  CFLAGS="${CFLAGS} -Wno-deprecated-declarations"
  
  # extended flags
- #CFLAGS="${CFLAGS} -Wextra -Wno-unused-parameter"
+ #CFLAGS="${CFLAGS} -Wextra -Wno-unused-parameter -Wno-cast-function-type"
  
  # profiling valgrind/gprof flags
  #CFLAGS="${CFLAGS} -g -O0 -pg"
@@@ -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])
@@@ -131,7 -92,7 +131,7 @@@ AC_C_VOLATIL
  AC_CHECK_FUNCS([floor localeconv memset modf pow setlocale sqrt strcasecmp strtoul])
  
  # International support
- ALL_LINGUAS="af ar ast be bg br ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr gl he hr hu id is it ja ko lt lv mr 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" 
+ ALL_LINGUAS="af ar ast be bg br ca ckb cs cy da de el en_AU en_CA en_GB es et eu fa fi fr 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" 
  
  AM_GLIB_GNU_GETTEXT
  
@@@ -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 src/Makefile.am
index 20da8f18246114c77313051187aa34980ea3da4f,9e4fd20426d55c6f41e1d895f77f79f3822e0e2e..7acfc873883dffc4ec74c3778e3d6841d5f13d44
@@@ -1,8 -1,7 +1,8 @@@
  
  common_defines = \
        -DSHARE_DIR=\""$(pkgdatadir)"\" \
 -      -DDATA_DIR=\""$(datadir)"\"
 +      -DDATA_DIR=\""$(datadir)"\" \
 +      -DPKGLIB_DIR=\""$(pkglibdir)"\"
  
  
  bin_PROGRAMS = homebank
@@@ -15,17 -14,17 +15,17 @@@ USER_INTERFACE 
        
  
  homebank_SOURCES =  \
-       dsp_account.c \
-       dsp_account.h \
-       dsp_mainwindow.c \
-       dsp_mainwindow.h \
+       dsp-account.c \
+       dsp-account.h \
+       dsp-mainwindow.c \
+       dsp-mainwindow.h \
        enums.h \
        gtk-chart.c \
        gtk-chart.h \
        gtk-chart-colors.c \
        gtk-chart-colors.h \
-       gtk-chart-stack.c \
-       gtk-chart-stack.h \
+       gtk-chart-progress.c \
+       gtk-chart-progress.h \
        gtk-dateentry.c \
        gtk-dateentry.h \
        hb-account.c \
        hb-xml.h \
        homebank.c \
        homebank.h \
+       hub-account.c \
+       hub-account.h \
+       hub-scheduled.c \
+       hub-scheduled.h \
+       hub-spending.c \
+       hub-spending.h \
+       hub-transaction.c \
+       hub-transaction.h \
        language.c \
        language.h \
-       list_account.c \
-       list_account.h \
-       list_operation.c \
-       list_operation.h \
-       list_topspending.c \
-       list_topspending.h \
-       list_upcoming.c \
-       list_upcoming.h \
-       rep_balance.c \
-       rep_balance.h \
-       rep_budget.c \
-       rep_budget.h \
-       rep_stats.c \
-       rep_stats.h \
-       rep_time.c \
-       rep_time.h \
-       rep_vehicle.c \
-       rep_vehicle.h \
+       list-account.c \
+       list-account.h \
+       list-operation.c \
+       list-operation.h \
+       list-scheduled.c \
+       list-scheduled.h \
+       rep-balance.c \
+       rep-balance.h \
+       rep-budget.c \
+       rep-budget.h \
+       rep-stats.c \
+       rep-stats.h \
+       rep-time.c \
+       rep-time.h \
+       rep-vehicle.c \
+       rep-vehicle.h \
        ui-account.c \
        ui-account.h \
        ui-archive.c \
        ui-pref.h \
        ui-split.c \
        ui-split.h \
+       ui-tag.c \
+       ui-tag.h \
        ui-transaction.c \
        ui-transaction.h \
        ui-txn-multi.c \
        ui-txn-multi.h \
+       ui-widgets-data.c \
        ui-widgets.c \
 -      ui-widgets.h
 +      ui-widgets.h \
 +      refcount.h \
 +      ext.c \
 +      ext.h \
 +      ext-value.c \
 +      ext-value.h \
 +      ext-native.c \
 +      ext-perl.xs
 +
 +EXTRA_homebank_DEPENDENCIES = $(PERL_OBJS)
  
  homebank_LDADD = $(DEPS_LIBS) \
 -      $(LIBSOUP_LIBS)
 +      $(LIBSOUP_LIBS) \
 +      $(PERL_OBJS)
  
  AM_CPPFLAGS = \
        $(DEPS_CFLAGS) \
        $(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 c733f4cb730be8c3f443f05f2c3bf5fc3a850152,1f53410322aea8c6b5a33953f9ad1f7d86eb8c68..0b21f9d701093801db9dde295f65c50a1ee13a75
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  
  #include "homebank.h"
  
- #include "dsp_mainwindow.h"
+ #include "dsp-mainwindow.h"
  
- #include "list_account.h"
- #include "list_upcoming.h"
- #include "list_topspending.h"
 +#include "ext.h"
 +
+ #include "list-account.h"
  
- #include "dsp_account.h"
+ #include "hub-account.h"
+ #include "hub-scheduled.h"
+ #include "hub-spending.h"
+ #include "hub-transaction.h"
+ #include "dsp-account.h"
  #include "ui-assist-import.h"
  #include "ui-assist-start.h"
  #include "ui-account.h"
  #include "ui-pref.h"
  #include "ui-hbfile.h"
  #include "ui-transaction.h"
+ #include "ui-tag.h"
  
- #include "rep_balance.h"
- #include "rep_budget.h"
- #include "rep_stats.h"
- #include "rep_time.h"
- #include "rep_vehicle.h"
+ #include "rep-balance.h"
+ #include "rep-budget.h"
+ #include "rep-stats.h"
+ #include "rep-time.h"
+ #include "rep-vehicle.h"
  
  #include "gtk-chart.h"
  
- //old url prior 2018
+ //old url prior 2019
  //#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"
@@@ -86,6 -88,7 +90,7 @@@ static void ui_mainwindow_action_open(v
  static void ui_mainwindow_action_save(void);
  static void ui_mainwindow_action_saveas(void);
  static void ui_mainwindow_action_revert(void);
+ static void ui_mainwindow_action_openbak(void);
  static void ui_mainwindow_action_properties(void);
  static void ui_mainwindow_action_close(void);
  static void ui_mainwindow_action_quit(void);
@@@ -97,6 -100,7 +102,7 @@@ static void ui_mainwindow_action_defcat
  static void ui_mainwindow_action_defarchive(void);
  static void ui_mainwindow_action_defbudget(void);
  static void ui_mainwindow_action_defassign(void);
+ static void ui_mainwindow_action_deftag(void);
  static void ui_mainwindow_action_preferences(void);
  
  static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action);
@@@ -105,6 -109,8 +111,8 @@@ static void ui_mainwindow_action_toggle
  static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action);
  
  static void ui_mainwindow_action_showtransactions(void);
+ static void ui_mainwindow_action_showalltransactions(void);
  static void ui_mainwindow_action_addtransactions(void);
  static void ui_mainwindow_action_checkscheduled(void);
  
@@@ -119,8 -125,6 +127,8 @@@ 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);
@@@ -133,8 -137,6 +141,6 @@@ static void ui_mainwindow_action_about(
  
  static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager);
  
- static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_open(GtkWidget *widget, gpointer user_data);
  
  void ui_mainwindow_save(GtkWidget *widget, gpointer user_data);
@@@ -143,45 -145,26 +149,28 @@@ void ui_mainwindow_action(GtkWidget *wi
  void ui_mainwindow_toggle_minor(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data);
  
- gboolean ui_dialog_msg_savechanges(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_update(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
  
- static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data);
- static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data);
- void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
  
 +static void ui_mainwindow_showprefs(gint page);
  
- static void ui_panel_accounts_setup(struct hbfile_data *data);
- extern gchar *CYA_ACC_TYPE[];
- gchar *CYA_CATSUBCAT[] = { 
-       N_("Category"), 
-       N_("Subcategory"), 
-       NULL
- };
  static GtkActionEntry entries[] = {
  
    /* name, icon-name, label */
  
    { "FileMenu"   , NULL, N_("_File"), NULL, NULL, NULL },
-   { "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL },
+   //{ "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL },
+   { "RecentMenu" , NULL, N_("Open _Recent"), NULL, NULL, NULL },
    { "EditMenu"   , NULL, N_("_Edit"), NULL, NULL, NULL },
    { "ViewMenu"   , NULL, N_("_View"), NULL, NULL, NULL },
    { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL },
    { "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") },
        /* name, icon-name, label, accelerator, tooltip */
  
    /* FileMenu */
-   { "New"        , ICONNAME_NEW            , N_("_New")          , "<control>N", N_("Create a new file"),    G_CALLBACK (ui_mainwindow_action_new) },
-   { "Open"       , ICONNAME_OPEN           , N_("_Open...")      , "<control>O", N_("Open a file"),    G_CALLBACK (ui_mainwindow_action_open) },
-   { "Save"       , ICONNAME_SAVE           , N_("_Save")         , "<control>S", N_("Save the current file"),    G_CALLBACK (ui_mainwindow_action_save) },
+   { "New"        , ICONNAME_HB_FILE_NEW    , N_("_New")          , "<control>N", N_("Create a new file"),    G_CALLBACK (ui_mainwindow_action_new) },
+   { "Open"       , ICONNAME_HB_FILE_OPEN   , N_("_Open...")      , "<control>O", N_("Open a file"),    G_CALLBACK (ui_mainwindow_action_open) },
+   { "Save"       , ICONNAME_HB_FILE_SAVE   , N_("_Save")         , "<control>S", N_("Save the current file"),    G_CALLBACK (ui_mainwindow_action_save) },
    { "SaveAs"     , ICONNAME_SAVE_AS        , N_("Save _As...")    , "<shift><control>S", N_("Save the current file with a different name"),    G_CALLBACK (ui_mainwindow_action_saveas) },
    { "Revert"     , ICONNAME_REVERT         , N_("Revert")        , NULL, N_("Revert to a saved version of this file"),    G_CALLBACK (ui_mainwindow_action_revert) },
+   { "OpenBak"    , NULL                   , N_("Restore backup") , NULL, N_("Restore from a backup file"),    G_CALLBACK (ui_mainwindow_action_openbak) },
  
    { "Properties" , ICONNAME_PROPERTIES     , N_("Properties..."), NULL, N_("Configure the file"),    G_CALLBACK (ui_mainwindow_action_properties) },
    { "Close"      , ICONNAME_CLOSE          , N_("_Close")        , "<control>W", N_("Close the current file"),    G_CALLBACK (ui_mainwindow_action_close) },
    { "Quit"       , ICONNAME_QUIT           , N_("_Quit")         , "<control>Q", N_("Quit HomeBank"),    G_CALLBACK (ui_mainwindow_action_quit) },
  
    /* Exchange */
-   { "ImportQIF" , ICONNAME_HB_FILE_IMPORT  , N_("QIF file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
-   { "ImportOFX" , ICONNAME_HB_FILE_IMPORT  , N_("OFX/QFX file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
-   { "ImportCSV" , ICONNAME_HB_FILE_IMPORT  , N_("CSV file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
-       
-   { "ExportQIF" , ICONNAME_HB_FILE_EXPORT  , N_("Export QIF file...")     , NULL, N_("Export all account in a QIF file"),    G_CALLBACK (ui_mainwindow_action_export) },
+   { "Import" , ICONNAME_HB_FILE_IMPORT  , N_("Import...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+   //{ "ImportQIF" , ICONNAME_HB_FILE_IMPORT  , N_("QIF file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+   //{ "ImportOFX" , ICONNAME_HB_FILE_IMPORT  , N_("OFX/QFX file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+   //{ "ImportCSV" , ICONNAME_HB_FILE_IMPORT  , N_("CSV file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
 -      
++
+   { "ExportQIF" , ICONNAME_HB_FILE_EXPORT  , N_("Export as QIF...")     , NULL, N_("Export all account in a QIF file"),    G_CALLBACK (ui_mainwindow_action_export) },
  
    /* EditMenu */
    { "Preferences", ICONNAME_PREFERENCES    , N_("Preferences..."), NULL,    N_("Configure HomeBank"),    G_CALLBACK (ui_mainwindow_action_preferences) },
    { "Archive"    , ICONNAME_HB_ARCHIVE     , N_("Scheduled/Template...")  , NULL,    N_("Configure the scheduled/template transactions"),    G_CALLBACK (ui_mainwindow_action_defarchive) },
    { "Budget"     , ICONNAME_HB_BUDGET      , N_("Budget...")     , NULL,    N_("Configure the budget"),    G_CALLBACK (ui_mainwindow_action_defbudget) },
    { "Assign"     , ICONNAME_HB_ASSIGN      , N_("Assignments..."), NULL,    N_("Configure the automatic assignments"),    G_CALLBACK (ui_mainwindow_action_defassign) },
+   { "Tag"        , NULL                    , N_("Tags..."),        NULL,    N_("Configure the tags"),    G_CALLBACK (ui_mainwindow_action_deftag) },
  
    /* TxnMenu */
-   { "ShowOpe"     , ICONNAME_HB_OPE_SHOW   , N_("Show...")             , NULL, N_("Shows selected account transactions"),    G_CALLBACK (ui_mainwindow_action_showtransactions) },
-   { "AddOpe"      , ICONNAME_HB_OPE_ADD    , N_("Add...")              , NULL, N_("Add transactions"),    G_CALLBACK (ui_mainwindow_action_addtransactions) },
+   { "AddTxn"      , ICONNAME_HB_OPE_ADD    , N_("Add...")              , NULL, N_("Add transactions"),    G_CALLBACK (ui_mainwindow_action_addtransactions) },
+   { "ShowTxn"     , ICONNAME_HB_OPE_SHOW   , N_("Show...")             , NULL, N_("Shows selected account transactions"),    G_CALLBACK (ui_mainwindow_action_showtransactions) },
+   { "ShowAllTxn"  , ICONNAME_HB_OPE_SHOW   , N_("Show all...")         , NULL, N_("Shows all account transactions"),    G_CALLBACK (ui_mainwindow_action_showalltransactions) },
    { "Scheduler"   , NULL                   , N_("Set scheduler...")    , NULL, N_("Configure the transaction scheduler"),    G_CALLBACK (ui_mainwindow_action_properties) },
    { "AddScheduled", NULL                   , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"),    G_CALLBACK (ui_mainwindow_action_checkscheduled) },
  
    { "Welcome"     , NULL              , N_("Show welcome dialog...")  , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) },
    { "FileStats"   , NULL              , N_("File statistics...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_file_statistics) },
    { "Anonymize"   , NULL              , N_("Anonymize...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_anonymize) },
--      
++
 +  /* Plugins */
 +  { "PluginPreferences", "prf-plugins", N_("_Plugins..."), "<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) },
@@@ -258,7 -243,7 +252,7 @@@ static GtkToggleActionEntry toggle_entr
  /*  name         , icon-name, label, accelerator, tooltip, callback, is_active */
    { "Toolbar"    , NULL                 , N_("_Toolbar")  , NULL,    NULL,    G_CALLBACK (ui_mainwindow_action_toggle_toolbar), TRUE },
    { "Spending"   , NULL                 , N_("_Top spending") , NULL,    NULL,    G_CALLBACK (ui_mainwindow_action_toggle_topspending), TRUE },
-   { "Upcoming"   , NULL                 , N_("_Scheduled list") , NULL,    NULL,    G_CALLBACK (ui_mainwindow_action_toggle_upcoming), TRUE },
+   { "BottomLists", NULL                 , N_("_Bottom Lists") , NULL,    NULL,    G_CALLBACK (ui_mainwindow_action_toggle_upcoming), TRUE },
    { "AsMinor"    , NULL                 , N_("Euro minor"), "<control>M",    NULL,    G_CALLBACK (ui_mainwindow_action_toggle_minor), FALSE },
  };
  
@@@ -272,21 -257,24 +266,24 @@@ static const gchar *ui_info 
  "    <menu action='FileMenu'>"
  "      <menuitem action='New'/>"
  "      <menuitem action='Open'/>"
+ "      <menuitem action='RecentMenu'/>"
  "        <separator/>"
  "      <menuitem action='Save'/>"
  "      <menuitem action='SaveAs'/>"
- "      <menuitem action='Revert'/>"
- "        <separator/>"
- "      <menuitem action='Properties'/>"
  "        <separator/>"
- "        <menu action='ImportMenu'>"
+ "      <menuitem action='Import'/>"
+ /*"        <menu action='ImportMenu'>"
  "          <menuitem action='ImportQIF'/>"
  "          <menuitem action='ImportOFX'/>"
  "          <menuitem action='ImportCSV'/>"
- "        </menu>"
+ "        </menu>"*/
  "      <menuitem action='ExportQIF'/>"
- //"        <separator/>"
- // print to come here
+ //     future: print to come here
+ "        <separator/>"
+ "      <menuitem action='Revert'/>"
+ "      <menuitem action='OpenBak'/>"
+ "        <separator/>"
+ "      <menuitem action='Properties'/>"
  "        <separator/>"
  "      <menuitem action='Close'/>"
  "      <menuitem action='Quit'/>"
  "      <menuitem action='Toolbar'/>"
  "        <separator/>"
  "      <menuitem action='Spending'/>"
- "      <menuitem action='Upcoming'/>"
+ "      <menuitem action='BottomLists'/>"
  "        <separator/>"
  "      <menuitem action='AsMinor'/>"
  "    </menu>"
  "      <menuitem action='Budget'/>"
  "      <menuitem action='Assign'/>"
  "      <menuitem action='Currency'/>"
+ "      <menuitem action='Tag'/>"
  "    </menu>"
  "    <menu action='TxnMenu'>"
- "      <menuitem action='ShowOpe'/>"
- "      <menuitem action='AddOpe'/>"
+ "      <menuitem action='AddTxn'/>"
+ "      <menuitem action='ShowTxn'/>"
+ "      <menuitem action='ShowAllTxn'/>"
  "        <separator/>"
  "      <menuitem action='Scheduler'/>"
  "      <menuitem action='AddScheduled'/>"
  "        <separator/>"
  "      <menuitem action='Anonymize'/>"
  "    </menu>"
 +"    <menu action='PluginMenu'>"
 +"      <separator/>"
 +"      <menuitem action='PluginPreferences'/>"
 +"      <separator/>"
 +"    </menu>"
  "    <menu action='HelpMenu'>"
  "      <menuitem action='Contents'/>"
  "      <menuitem action='Online'/>"
  "    <toolitem action='Assign'/>"
  "    <toolitem action='Currency'/>"
  "      <separator/>"
- "    <toolitem action='ShowOpe'/>"
- "    <toolitem action='AddOpe'/>"
+ "    <toolitem action='ShowTxn'/>"
+ "    <toolitem action='AddTxn'/>"
  "      <separator/>"
  "    <toolitem action='RStatistics'/>"
  "    <toolitem action='RTrendTime'/>"
  "    <toolitem action='RBalance'/>"
  "    <toolitem action='RBudget'/>"
  "    <toolitem action='RVehiculeCost'/>"
 +"      <separator/>"
  "  </toolbar>"
  
  "</ui>";
@@@ -399,7 -383,7 +398,7 @@@ gint result
        title = g_strdup_printf (
                _("Revert unsaved changes to file '%s'?"), basename);
  
--      secondtext = 
++      secondtext =
                _("- Changes made to the file will be permanently lost\n"
                "- File will be reloaded from the last save (.xhb~)");
  
        if( result == GTK_RESPONSE_OK )
        {
                DB( g_print(" - should revert\n") );
--              
++
                hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~"));
                ui_mainwindow_open_internal(widget, NULL);
                hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb"));
@@@ -431,7 -415,7 +430,7 @@@ activate_url (GtkAboutDialog *about
              gpointer        data)
  {
        DB( g_print("activate url %s\n", link) );
--      
++
        homebank_util_url_show (link);
  }
  
@@@ -450,8 -434,7 +449,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-2018 - Maxime DOYEN";
+       static const gchar *copyright = "Copyright \xc2\xa9 1995-2019 - Maxime DOYEN";
  
  
  
                                                       gtk_get_major_version (),
                                                       gtk_get_minor_version (),
                                                       gtk_get_micro_version ());
--      
++
        dialog = gtk_about_dialog_new();
  
        gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(GLOBALS->mainwindow));
        gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
--      
++
        gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), g_get_application_name ());
        gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version);
        gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright);
        gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Free, easy, personal accounting for everyone"));
        gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0);
--      
++
        //gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(dialog), );
        gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://homebank.free.fr");
        gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Visit the HomeBank website");
                gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
                g_object_unref (pixbuf);
        }
--      
++
        gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors);
        gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artists);
        //gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(dialog), );
        gtk_widget_destroy (dialog);
  
        g_free(version);
--      
++
  }
  
  
@@@ -527,15 -510,20 +526,20 @@@ 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_hub_account_populate(GLOBALS->mainwindow, NULL);
+               //ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL);
+               //ui_hub_spending_populate(GLOBALS->mainwindow, NULL);
        }
  }
  
  static void ui_mainwindow_action_open(void)
  {
-       ui_mainwindow_open(GLOBALS->mainwindow, NULL);
+       ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
+ }
+ static void ui_mainwindow_action_openbak(void)
+ {
+       ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
  }
  
  static void ui_mainwindow_action_save(void)
@@@ -582,12 -570,6 +586,12 @@@ static void ui_mainwindow_action_file_s
  }
  
  
 +static void ui_mainwindow_action_pluginprefs(void)
 +{
 +      ui_mainwindow_showprefs(PREF_PLUGINS);
 +}
 +
 +
  static void ui_mainwindow_action_properties(void)
  {
        create_defhbfile_dialog();
@@@ -602,7 -584,7 +606,7 @@@ gchar *secondtext
  
        title = _("Are you sure you want to anonymize the file?");
  
--      secondtext = 
++      secondtext =
                _("Proceeding will anonymize any text, \n"
                "like 'account x', 'payee y', 'memo z', ...");
  
  
        //#1707201
        //if( result == GTK_RESPONSE_CANCEL )
--      //      return; 
++      //      return;
        if( result == GTK_RESPONSE_OK )
        {
                hbfile_anonymize();
@@@ -638,7 -620,7 +642,7 @@@ static void ui_mainwindow_action_defacc
        //our global list has changed, so update the treeview
        //todo: optimize this, should not call compute balance here
        account_compute_balances ();
-       ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
+       ui_hub_account_populate(GLOBALS->mainwindow, NULL);
  
        ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE));
  }
@@@ -654,24 -636,25 +658,25 @@@ static void ui_mainwindow_action_defcat
        ui_cat_manage_dialog();
        //todo:why refresh upcoming here??
        //ui_mainwindow_populate_upcoming(GLOBALS->mainwindow, NULL);
-       ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
+       ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
  }
  
  
- static void ui_mainwindow_defarchive(Archive *arc)
+ //TODO: not ideal to do this
+ void ui_mainwindow_defarchive(Archive *arc)
  {
  struct hbfile_data *data;
  GtkTreeModel *model;
  
        data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
  
-       // upcoming list have direct pointer to the arc (which may have changed)
+       // upcoming list have direct pointer to the arc (which may change during edit)
        model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc));
        gtk_list_store_clear (GTK_LIST_STORE(model));
  
        ui_arc_manage_dialog(arc);
  
-       ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
+       ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL);
  
        ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
  }
@@@ -699,16 -682,20 +704,25 @@@ static void ui_mainwindow_action_defass
  }
  
  
+ static void ui_mainwindow_action_deftag(void)
+ {
+       ui_tag_manage_dialog();
+       //ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
+ }
  static void ui_mainwindow_action_preferences(void)
 +{
 +      ui_mainwindow_showprefs(PREF_GENERAL);
 +}
 +
 +static void ui_mainwindow_showprefs(gint page)
  {
  struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
  
 -      defpref_dialog_new();
 +      defpref_dialog_new(page);
        if(!PREFS->euro_active)
        {
        GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor");
@@@ -756,8 -743,8 +770,8 @@@ struct hbfile_data *data = g_object_get
  
        // top spending
        gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor);
--      
-       ui_panel_topspending_update(data->window, data);
++
+       ui_hub_spending_update(data->window, data);
  
  }
  
@@@ -771,19 -758,37 +785,37 @@@ GtkWidget *window
        {
                if( data->acc->window == NULL )
                {
-                       window = register_panel_window_new(data->acc->key, data->acc);
+                       window = register_panel_window_new(data->acc);
                        register_panel_window_init(window, NULL);
                }
                else
                {
                        if(GTK_IS_WINDOW(data->acc->window))
-                               gtk_window_present(data->acc->window);
+                               gtk_window_present(GTK_WINDOW(data->acc->window));
  
                }
        }
  }
  
  
+ static void ui_mainwindow_action_showalltransactions(void)
+ {
+ GtkWidget *window;
+       if( GLOBALS->alltxnwindow == NULL )
+       {
+               window = register_panel_window_new(NULL);
+               register_panel_window_init(window, NULL);
+       }
+       else
+       {
+               if(GTK_IS_WINDOW(GLOBALS->alltxnwindow))
+                       gtk_window_present(GTK_WINDOW(GLOBALS->alltxnwindow));
+       }
+ }
  static void ui_mainwindow_action_addtransactions(void)
  {
        ui_mainwindow_addtransactions(GLOBALS->mainwindow, NULL);
  
  static void ui_mainwindow_action_checkscheduled(void)
  {
-       ui_mainwindow_scheduled_postall(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
+       ui_hub_scheduled_postall(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
  }
  
  static void ui_mainwindow_action_statistic(void)
  static void ui_mainwindow_action_trendtime(void)
  {
  struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
--      
++
        ui_reptime_window_new(data->acc != NULL ? data->acc->key : 0);
  }
  
@@@ -825,8 -830,8 +857,8 @@@ static void ui_mainwindow_action_vehicl
  
  static void ui_mainwindow_action_import(GtkAction *action)
  {
- const gchar *name;
- gint filetype = FILETYPE_UNKNOW;
/*const gchar *name;
+ gint filetype = FILETYPE_UNKNOWN;
  
        name = gtk_action_get_name(action);
  
           filetype= FILETYPE_OFX;
        else
        if( g_str_has_suffix (name, "CSV"))
-          filetype= FILETYPE_CSV_HB;
+          filetype= FILETYPE_CSV_HB;*/
  
-       DB( g_print("action %s type=%d\n", name, filetype) );
+       //DB( g_print("action %s type=%d\n", name, filetype) );
  
-       ui_import_assistant_new(filetype);
+       ui_import_assistant_new(NULL);
  
  }
  
@@@ -930,7 -935,7 +962,7 @@@ GtkWidget *mainvbox, *widget, *label
                        NULL);
  
        content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
--      
++
        mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
        gtk_box_pack_start (GTK_BOX (content_area), mainvbox, FALSE, FALSE, 0);
        gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM);
        widget = gtk_button_new_with_mnemonic(_("Read HomeBank _Manual"));
        gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
        g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome1), dialog);
--      
++
        widget = gtk_button_new_with_mnemonic(_("Configure _preferences"));
        gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
        g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome2), dialog);
--      
++
        widget = gtk_button_new_with_mnemonic(_("Create a _new file"));
        gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
        g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome3), dialog);
@@@ -1095,10 -1100,10 +1127,10 @@@ gboolean file_clear = GPOINTER_TO_INT(u
        gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc))));
        gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc))));
        gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top))));
--      
++
        data->showall = FALSE;
-       ui_panel_accounts_setup(data);
-       
+       ui_hub_account_setup(data);
 -      
++
        hbfile_cleanup(file_clear);
        hbfile_setup(file_clear);
  
@@@ -1128,14 -1133,14 +1160,14 @@@ gint account, count
        if(data->acc != NULL)
                account = data->acc->key;
  
-       window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, FALSE);
+       window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, FALSE, account);
        count = 0;
-       while(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ADDKEEP)
+       while(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP)
        {
        Transaction *ope;
  
                /* fill in the transaction */
-               if( result == GTK_RESPONSE_ADD )
+               if( result == HB_RESPONSE_ADD )
                {
                        ope = da_transaction_malloc();
                        ope->date = date;
  
                        if( PREFS->heritdate == FALSE ) //fix: 318733
                                ope->date = GLOBALS->today;
 -                      
++
+                       da_transaction_set_default_template(ope);
                }
  
                // normally we can't be in addkeep without initialized ope with add
  
                DB( g_print(" - dialog result is %d\n", result) );
  
-               if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT)
+               if(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT)
                {
                        deftransaction_get(window, NULL);
-                       transaction_add(ope);
+                       transaction_add(GTK_WINDOW(GLOBALS->mainwindow), ope);
  
                        DB( g_print(" - added 1 transaction to %d\n", ope->kacc) );
  
-                       ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
-                       
+                       ui_hub_account_populate(GLOBALS->mainwindow, NULL);
 -                      
++
                        count++;
                        //todo: still usefull ? store last date
                        date = ope->date;
                }
  
-               if( result == GTK_RESPONSE_ADD )
+               if( result == HB_RESPONSE_ADD )
                {
                        da_transaction_free(ope);
                        ope = NULL;
        }
  }
  
- struct tmptop
- {
-       guint32         key;
-       gdouble         value;
- };
- #define MAX_TOPSPENDING 10
- static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2)
- {
-       return tt1->value > tt2->value ? 1 : -1;
- }
  
static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data)
gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath)
  {
- struct hbfile_data *data;
- GtkTreeModel *model;
- gchar *title;
- gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE];
-       DB( g_print("\n[ui-mainwindow] topspending_update\n") );
+ gboolean retval = FALSE;
+ gchar *basename, *secondtext;
+ gboolean result;
  
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
+       basename = g_path_get_basename(filepath);
+       secondtext = g_strdup_printf (
 -      _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename);             
++      _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename);
  
-       hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, data->toptotal, GLOBALS->kcur, GLOBALS->minor);        
-       //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor);
-       title = g_strdup_printf("%s %s", _("Top spending"), strbuffer);
+       result = ui_dialog_msg_confirm_alert(
+               GTK_WINDOW(GLOBALS->mainwindow),
+               _("Open the backup file ?"),
+               secondtext,
+               _("_Open backup")
 -      );      
++      );
  
-       model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top));
-       
-       gtk_chart_set_color_scheme(GTK_CHART(data->RE_pie), PREFS->report_color_scheme);
-       gtk_chart_set_currency(GTK_CHART(data->RE_pie), GLOBALS->kcur);
-       gtk_chart_set_datas(GTK_CHART(data->RE_pie), model, LST_TOPSPEND_AMOUNT, title, NULL);
+       g_free(secondtext);
+       g_free(basename);
  
-       g_free(title);
+       if( result == GTK_RESPONSE_OK )
+               retval = TRUE;
 -      
 +
-       //future usage
-       gchar *fu = _("Top %d spending"); title = fu;
+       return retval;
  }
  
  
- static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data)
+ /*
+ **
+ */
+ void ui_mainwindow_open(GtkWidget *widget, gpointer user_data)
  {
- struct hbfile_data *data;
- GtkTreeModel *model;
- GtkTreeIter  iter;
- GList *list;
- gint type, range;
- guint n_result, i, n_items;
- GArray *garray;
- gdouble total, other;
- Account *acc;
-       
-       DB( g_print("\n[ui-mainwindow] populate_topspending\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       type = radio_get_active(GTK_CONTAINER(data->RA_type));
-       range = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_range));
-       DB( g_print(" - type=%d, range=%d\n", type, range) );
-       DB( g_print(" - pref range=%d\n", PREFS->date_range_wal) );
+ //struct hbfile_data *data;
+ gboolean bakmode = GPOINTER_TO_INT(user_data);;
+ gboolean doopen = TRUE;
+ gchar *filename = NULL;
  
-       if(range == FLT_RANGE_OTHER)
-               return;
-       
-       filter_preset_daterange_set(data->filter, range, 0);
-       
-       
-       n_result = da_cat_get_max_key() + 1;
-       total = 0.0;
+       DB( g_print("\n[ui-mainwindow] open\n") );
  
-       DB( g_print(" - max key is %d\n", n_result) );
+       //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
  
-       /* allocate some memory */
-       garray = g_array_sized_new(FALSE, FALSE, sizeof(struct tmptop), n_result);
+       //#1791554 do ask for save confirm
+       if( bakmode != TRUE )
+               doopen = ui_dialog_msg_savechanges(widget,NULL);
  
-       if(garray)
+       if( doopen == TRUE )
        {
-       struct tmptop zero = { .key=0, .value=0.0 };
-       GQueue *txn_queue;
-               
-               //DB( g_print(" - array length=%d\n", garray->len) );
-               for(i=0 ; i<n_result ; i++)
-               {
-                       g_array_append_vals(garray, &zero, 1);
-                       //g_array_insert_vals(garray, i, &zero, 1);
-                       //struct tmptop *tt = &g_array_index (garray, struct tmptop, i);
-                       //DB( g_print("%4d, %4d %f\n", i, tt->key, tt->value) );
-               }
-               //DB( g_print("\n - end array length=%d\n", garray->len) );
-               //todo: not ideal, has ot force to get_acc for each txn below
-               txn_queue = hbfile_transaction_get_partial(data->filter->mindate, data->filter->maxdate);
-               /* compute the results */
-               list = g_queue_peek_head_link(txn_queue);
-               while (list != NULL)
+               if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename, bakmode) == TRUE )
                {
-               Transaction *ope = list->data;
-                       //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) )
+                       //#1710955 test for backup open
+                       if( hbfile_file_isbackup(filename) )
                        {
-                       guint32 pos = 0;
-                       gdouble trn_amount;
-                               //todo: optimize here
-                               trn_amount = ope->amount;
-                               acc = da_acc_get(ope->kacc);
-                               if(acc)
-                                       trn_amount = hb_amount_base(ope->amount, acc->kcur);
-                               if( ope->flags & OF_SPLIT )
+                               if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE )
                                {
-                               guint nbsplit = da_splits_count(ope->splits);
-                               Split *split;
-                               struct tmptop *item;
-                               
-                                       for(i=0;i<nbsplit;i++)
-                                       {
-                                               split = ope->splits[i];
-                                               pos = category_report_id(split->kcat, type);
-                                               trn_amount = hb_amount_base(split->amount, acc->kcur);
-                                               //trn_amount = split->amount;
-                                               //#1297054 if( trn_amount < 0 ) {
-                                                       item = &g_array_index (garray, struct tmptop, pos);
-                                                       item->key = pos;
-                                                       item->value += trn_amount;
-                                                       //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos)  );
-                                               //}
-                                       }
+                                       GLOBALS->hbfile_is_bak = TRUE;
                                }
                                else
                                {
-                               struct tmptop *item;
-                                       pos = category_report_id(ope->kcat, type);
-       
-                                       //#1297054 if( trn_amount < 0 ) {
-                                               item = &g_array_index (garray, struct tmptop, pos);
-                                               item->key = pos;
-                                               item->value += trn_amount;
-                                               //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos)  );
-                                       //}
+                                       g_free(filename);
+                                       return;
                                }
-                       }
-                       list = g_list_next(list);
-               }
-               g_queue_free (txn_queue);
-               
-               // we need to sort this and limit before
-               g_array_sort(garray, (GCompareFunc)tmptop_compare_func);
-               n_items = MIN(garray->len,MAX_TOPSPENDING);
-               other = 0;
-               for(i=0 ; i<garray->len ; i++)
-               {
-               struct tmptop *item;
-               
-                       item = &g_array_index (garray, struct tmptop, i);
-                       if(item->value < 0)
-                       {
-                               total += item->value;
-                               if(i >= n_items)
-                                       other += item->value;
-                               DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i, item->key, item->value, total) );
 -                      }                       
 +                      }
-               }
  
-               model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top));
-               gtk_list_store_clear (GTK_LIST_STORE(model));
-               g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
-               gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), NULL); /* Detach model from view */
-               /* insert into the treeview */
-               for(i=0 ; i<MIN(garray->len,MAX_TOPSPENDING) ; i++)
-               {
-               gchar *name;
-               Category *entry;
-               struct tmptop *item;
-               gdouble value;
-               
-                       item = &g_array_index (garray, struct tmptop, i);
-                       if(!item->value) continue;
-                       value = hb_amount_round(item->value, 2);
-                       entry = da_cat_get(item->key);
-                       if(entry == NULL) continue;
-                       name = entry->key == 0 ? _("(no category)") : da_cat_get_fullname(entry);
-                       // append test
-                       gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-                       gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                                 LST_TOPSPEND_ID, i,
-                                 LST_TOPSPEND_KEY, 0,
-                                 LST_TOPSPEND_NAME, name,
-                                 LST_TOPSPEND_AMOUNT, value,
-                                 //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5),
-                                 -1);
-               }
-               // append test
-               if(ABS(other) > 0)
-               {
-                       gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-                       gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                                 LST_TOPSPEND_ID, n_items,
-                                 LST_TOPSPEND_KEY, 0,
-                                 LST_TOPSPEND_NAME, _("Other"),
-                                 LST_TOPSPEND_AMOUNT, other,
-                                 //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5),
-                                 -1);
-               }
-                       
-               /* Re-attach model to view */
-               gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model);
-               g_object_unref(model);
-               
-               
-               // update chart and widgets
-               {
-               gchar *daterange;
-                       data->toptotal = total;
-                       ui_panel_topspending_update(widget, data);
-                       
-                       daterange = filter_daterange_text_get(data->filter);
-                       gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange);
-                       g_free(daterange);
+                       hbfile_change_filepath(filename);
+                       ui_mainwindow_open_internal(widget, NULL);
                }
        }
-       
-       /* free our memory */
-       g_array_free (garray, TRUE);
  }
  
  
- /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
- /* scheduled */
- /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
- static Archive *
- ui_mainwindow_scheduled_get_selected_item(GtkTreeView *treeview)
+ /*
+  *    open the file stored in GLOBALS->xhb_filepath
+  */
+ void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data)
  {
- GtkTreeSelection *treeselection;
- GtkTreeModel           *model;
- GtkTreeIter                    iter;
-       treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
-       if( gtk_tree_selection_get_selected(treeselection, &model, &iter) )
-       {
-       Archive *arc;
+ struct hbfile_data *data;
+ gint r;
  
-               gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1);
-               return arc;
-       }
+       DB( g_print("\n[ui-mainwindow] open internal\n") );
  
-       return NULL;
- }
+       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
  
+       if( GLOBALS->xhb_filepath != NULL )
+       {
+               DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) );
  
- static void ui_mainwindow_scheduled_onRowActivated (GtkTreeView        *treeview,
-                        GtkTreePath        *path,
-                        GtkTreeViewColumn  *col,
-                        gpointer            userdata)
- {
- //struct hbfile_data *data;
- Archive *arc;
+               ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
+               GLOBALS->hbfile_is_new = FALSE;
  
-       DB( g_print ("\n[ui-mainwindow] A scheduled row has been double-clicked!\n") );
+               r = homebank_load_xml(GLOBALS->xhb_filepath);
+               if( r == XML_OK )
+               {
+                       DB( g_print(" - file loaded ok : rcode=%d\n", r) );
  
-       //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data");
+                       GLOBALS->xhb_timemodified = hbfile_file_get_time_modified(GLOBALS->xhb_filepath);
+                       hbfile_file_hasrevert(GLOBALS->xhb_filepath);
 -                      
 +
-       arc = ui_mainwindow_scheduled_get_selected_item(treeview);
-       ui_mainwindow_defarchive(arc);
- }
+                       if(PREFS->appendscheduled)
+                               scheduled_post_all_pending();
  
+                       if(PREFS->do_update_currency)
+                               ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow));
  
- static void ui_mainwindow_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data)
- {
- struct hbfile_data *data = user_data;
- GtkWidget *window;
- gint result;
- Transaction *txn;
+                       homebank_lastopenedfiles_save();
  
-       window =  create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE);
+                       //todo: delete this after computing done at xml read
+                       account_compute_balances();
  
-       /* fill in the transaction */
-       txn = da_transaction_malloc();
-       da_transaction_init_from_template(txn, arc);
-       txn->date = scheduled_get_postdate(arc, arc->nextdate);
+                       ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath);
+               }
+               else
+               {
+               gchar *msg = _("Unknown error");
  
-       deftransaction_set_transaction(window, txn);
+                       switch(r)
+                       {
+                               case XML_IO_ERROR:
+                                       msg = _("I/O error for file '%s'.");
+                                       break;
+                               case XML_FILE_ERROR:
+                                       msg = _("The file '%s' is not a valid HomeBank file.");
+                                       break;
 -                              case XML_VERSION_ERROR: 
++                              case XML_VERSION_ERROR:
+                                       msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version.");
+                                       break;
+                       }
  
-       result = gtk_dialog_run (GTK_DIALOG (window));
+                       ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
+                               _("File error"),
+                               msg,
+                               GLOBALS->xhb_filepath
+                               );
  
-       DB( g_print(" - dialog result is %d\n", result) );
+                       ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
  
-       if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT)
-       {
-               deftransaction_get(window, NULL);
-               transaction_add(txn);
-               GLOBALS->changes_count++;
+               }
  
-               scheduled_date_advance(arc);
+               ui_hub_account_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_spending_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_transaction_populate(data);
 -      
 +
-               DB( g_print(" - added 1 transaction to %d\n", txn->kacc) );
+               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
        }
  
-       da_transaction_free(txn);
-       deftransaction_dispose(window, NULL);
-       gtk_widget_destroy (window);
  
  }
  
  
- static void ui_mainwindow_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data)
+ /*
+ **
+ */
+ void ui_mainwindow_save(GtkWidget *widget, gpointer user_data)
  {
- struct hbfile_data *data = user_data;
-       Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
-       if( (arc != NULL) )
-       {
-               ui_mainwindow_scheduled_do_post(arc, TRUE, data);
-               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL));
-       }
- }
+ struct hbfile_data *data;
+ gboolean saveas = GPOINTER_TO_INT(user_data);
+ gchar *filename = NULL;
+ gint r = XML_UNSET;
  
+       DB( g_print("\n[ui-mainwindow] save\n") );
  
- static void ui_mainwindow_scheduled_post_cb(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data = user_data;
+       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
  
-       DB( g_print("\n[ui-mainwindow] scheduled post\n") );
+       if( GLOBALS->hbfile_is_new == TRUE )
+               saveas = 1;
  
-       Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
+       //#1710955 test for backup open
+       if( GLOBALS->hbfile_is_bak == TRUE )
+       {
+               //todo: later for backup, should also remove datetime and .bak
+               hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb"));
+               saveas = 1;
+       }
  
-       if( (arc != NULL) )
+       if(saveas == 1)
        {
-               if( scheduled_is_postable(arc) )
+               if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename, FALSE) == TRUE)
                {
-               Transaction *txn = da_transaction_malloc ();
-                       da_transaction_init_from_template(txn, arc);
-                       txn->date = scheduled_get_postdate(arc, arc->nextdate);
-                       transaction_add(txn);
-                       GLOBALS->changes_count++;
-                       scheduled_date_advance(arc);
-                       da_transaction_free (txn);
+                       DB( g_print(" + should save as '%s'\n", filename) );
+                       homebank_file_ensure_xhb(filename);
+                       homebank_backup_current_file();
+                       r = homebank_save_xml(GLOBALS->xhb_filepath);
+                       GLOBALS->hbfile_is_new = FALSE;
+                       GLOBALS->hbfile_is_bak = FALSE;
                }
                else
-               {
-                       ui_mainwindow_scheduled_do_post(arc, FALSE, data);
-               }
-               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL));
+                       return;
        }
- }
+       else
+       {
+       guint64 time_modified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath);
+       gint result = GTK_RESPONSE_OK;
  
+               DB( g_print(" + should quick save '%s'\n + time: open=%lu :: now=%lu\n", GLOBALS->xhb_filepath, GLOBALS->xhb_timemodified, time_modified) );
  
- static void ui_mainwindow_scheduled_skip_cb(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data = user_data;
-       Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
-       if( (arc != NULL) && (arc->flags & OF_AUTO) )
-       {
-               GLOBALS->changes_count++;
-               scheduled_date_advance(arc);
-               ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
-       }
- }
- static void ui_mainwindow_scheduled_update(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
- //gint filter;
-       DB( g_print("\n[ui-mainwindow] scheduled update\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter));
-       Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
-       if(arc)
-       {
-               DB( g_print("archive is %s\n", arc->memo) );
-               
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE);
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE);
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE);
-       }
-       else
-       {
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE);
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE);
-               gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE);
-       }
- }
- static void ui_mainwindow_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data)
- {
-       
-       ui_mainwindow_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE));
- }
- /*
- ** called after load, importamiga, on demand
- */
- void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data)
- {
- //struct hbfile_data *data;
- gint count;
- gint usermode = GPOINTER_TO_INT(user_data);
-       DB( g_print("\n[ui-mainwindow] check scheduled\n") );
-       //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       count = scheduled_post_all_pending();
-       //inform the user
-       if(usermode == TRUE)
-       {
-       gchar *txt;
-               //#125534
-               if( count > 0 )
-               {
-                       ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL));
-               }
-               
-               if(count == 0)
-                       txt = _("No transaction to add");
-               else
-                       txt = _("transaction added: %d");
-               ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO,
-                       _("Check scheduled transactions result"),
-                       txt,
-                       count);
-       }
- }
- static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
- GtkTreeModel *model;
- GtkTreeIter  iter;
- GList *list;
- gdouble totexp = 0;
- gdouble totinc = 0;
- gint count = 0;
- gchar buffer[256];
- guint32 maxpostdate;
- GDate *date;
- //Account *acc;
-       DB( g_print("\n[ui-mainwindow] scheduled populate list\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc));
-       gtk_list_store_clear (GTK_LIST_STORE(model));
-       homebank_app_date_get_julian();
-       maxpostdate = scheduled_date_get_post_max();
-       date = g_date_new_julian (maxpostdate);
-       g_date_strftime (buffer, 256-1, PREFS->date_format, date);
-       g_date_free(date);
-       gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer);
-       
-       list = g_list_first(GLOBALS->arc_list);
-       while (list != NULL)
-       {
-       Archive *arc = list->data;
-       Account *acc;
-       gdouble inc, exp;
-       guint nbdays, nblate;
-               if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0)
-               {
-                       count++;
-                       nbdays = arc->nextdate - maxpostdate;
-                       nblate = scheduled_get_latepost_count(arc, GLOBALS->today);
-                       
-                       DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) );
-                       if(arc->flags & OF_INCOME)
-                       {
-                               inc = arc->amount;
-                               exp = 0.0;
-                       }
-                       else
-                       {
-                               exp = arc->amount;
-                               inc = 0.0;
-                       }
-                       /* insert normal txn */
-                       acc = da_acc_get(arc->kacc);
-                       if( acc)
-                       {
-                               totinc += hb_amount_base(inc, acc->kcur);
-                               totexp += hb_amount_base(exp, acc->kcur);
-                       }
-                       gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-                       gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                                 LST_DSPUPC_DATAS, arc,
-                                 LST_DSPUPC_ACCOUNT, acc,
-                             LST_DSPUPC_MEMO, arc->memo,
-                             LST_DSPUPC_EXPENSE, exp,
-                             LST_DSPUPC_INCOME, inc,
-                                 LST_DSPUPC_REMAINING, nbdays,
-                             LST_DSPUPC_NB_LATE, nblate,
-                                 -1);
-                       /* insert internal xfer txn : 1378836 */
-                       if(arc->paymode == PAYMODE_INTXFER)
-                       {
-                               acc = da_acc_get(arc->kxferacc);
-                               if( acc)
-                               {
-                                       totinc += hb_amount_base(-inc, acc->kcur);
-                                       totexp += hb_amount_base(-exp, acc->kcur);
-                               }
-                               gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-                               gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                                         LST_DSPUPC_DATAS, arc,
-                                         LST_DSPUPC_ACCOUNT, acc,
-                                         LST_DSPUPC_MEMO, arc->memo,
-                                         LST_DSPUPC_EXPENSE, -inc,
-                                         LST_DSPUPC_INCOME, -exp,
-                                         LST_DSPUPC_REMAINING, nbdays,
-                                         LST_DSPUPC_NB_LATE, nblate,
-                                         -1);
-                       }
-               }
-               list = g_list_next(list);
-       }
-       // insert total
-       if(count > 0 )
-       {
-               gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-               gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                         LST_DSPUPC_DATAS, NULL,
-                         LST_DSPUPC_ACCOUNT, NULL,
-                         LST_DSPUPC_MEMO, _("Total"),
-                         LST_DSPUPC_EXPENSE, totexp,
-                     LST_DSPUPC_INCOME, totinc,
-                 -1);
-       }
-       ui_mainwindow_scheduled_update(widget, NULL);
-       
- }
- gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath)
- {
- gboolean retval = FALSE;
- gchar *basename, *secondtext;
- gboolean result;
-       basename = g_path_get_basename(filepath);
-       secondtext = g_strdup_printf (
-       _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename);             
-       result = ui_dialog_msg_confirm_alert(
-               GTK_WINDOW(GLOBALS->mainwindow),
-               _("Open a backup file ?"),
-               secondtext,
-               _("_Open backup")
-       );      
-       g_free(secondtext);
-       g_free(basename);
-       if( result == GTK_RESPONSE_OK )
-               retval = TRUE;
-       
-       return retval;
- }
- /*
- **
- */
- void ui_mainwindow_open(GtkWidget *widget, gpointer user_data)
- {
- //struct hbfile_data *data;
- gchar *filename = NULL;
-       DB( g_print("\n[ui-mainwindow] open\n") );
-       //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       if( ui_dialog_msg_savechanges(widget,NULL) == TRUE )
-       {
-               if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename) == TRUE )
-               {
-                       //#1710955 test for backup open
-                       if( hbfile_file_isbackup(filename) )
-                       {
-                               if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE )
-                               {
-                                       GLOBALS->hbfile_is_bak = TRUE;
-                               }
-                               else
-                               {
-                                       g_free(filename);
-                                       return;
-                               }
-                       }                       
-                       hbfile_change_filepath(filename);
-                       ui_mainwindow_open_internal(widget, NULL);
-               }
-       }
- }
- /*
-  *    open the file stored in GLOBALS->xhb_filepath
-  */
- void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
- gint r;
-       DB( g_print("\n[ui-mainwindow] open internal\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       if( GLOBALS->xhb_filepath != NULL )
-       {
-               DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) );
-               ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
-               GLOBALS->hbfile_is_new = FALSE;
-               r = homebank_load_xml(GLOBALS->xhb_filepath);
-               if( r == XML_OK )
-               {
-                       DB( g_print(" - file loaded ok : rcode=%d\n", r) );
-                       
-                       hbfile_file_hasbackup(GLOBALS->xhb_filepath);
-                       
-                       if(PREFS->appendscheduled)
-                               scheduled_post_all_pending();
-                       if(PREFS->do_update_currency)
-                               ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow));
-                       homebank_lastopenedfiles_save();
-                       //todo: delete this after computing done at xml read
-                       account_compute_balances();
-                       ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath);
-               }
-               else
-               {
-               gchar *msg = _("Unknow error");
-                       switch(r)
-                       {
-                               case XML_IO_ERROR:
-                                       msg = _("I/O error for file '%s'.");
-                                       break;
-                               case XML_FILE_ERROR:
-                                       msg = _("The file '%s' is not a valid HomeBank file.");
-                                       break;
-                               case XML_VERSION_ERROR: 
-                                       msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version.");
-                                       break;
-                       }
-                       ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
-                               _("File error"),
-                               msg,
-                               GLOBALS->xhb_filepath
-                               );
-                       ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
-               }
-               ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
-       }
- }
- /*
- **
- */
- void ui_mainwindow_save(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
- gboolean saveas = GPOINTER_TO_INT(user_data);
- gchar *filename = NULL;
- gint r = XML_UNSET;
-       DB( g_print("\n[ui-mainwindow] save\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       if( GLOBALS->hbfile_is_new == TRUE )
-               saveas = 1;
-       //#1710955 test for backup open
-       if( GLOBALS->hbfile_is_bak == TRUE )
-       {
-               //todo: later for backup, should also remove datetime and .bak
-               hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb"));
-               saveas = 1;
-       }
-       if(saveas == 1)
-       {
-               if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename) == TRUE)
-               {
-                       DB( g_print(" + should save as '%s'\n", filename) );
-                       homebank_file_ensure_xhb(filename);
-                       homebank_backup_current_file();
-                       r = homebank_save_xml(GLOBALS->xhb_filepath);
-                       GLOBALS->hbfile_is_new = FALSE;
-                       GLOBALS->hbfile_is_bak = FALSE;
-               }
-               else
-                       return;
-       }
-       else
-       {
-               DB( g_print(" + should quick save %s\n", GLOBALS->xhb_filepath) );
-               homebank_file_ensure_xhb(NULL);
-               homebank_backup_current_file();
-               r = homebank_save_xml(GLOBALS->xhb_filepath);
-       }
-       if(r == XML_OK)
-       {
-               GLOBALS->changes_count = 0;
-               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
-       }
-       else
-       {
-       gchar *msg = _("I/O error for file '%s'.");
-               ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
-                       _("File error"),
-                       msg,
-                       GLOBALS->xhb_filepath
-                       );
-       }
- }
- static void ui_panel_accounts_expand_all(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc));
- }
- static void ui_panel_accounts_collapse_all(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_acc));
- }
- static GHashTable *ui_panel_accounts_groups_get(GList *lacc, gint groupby, gboolean showall)
- {
- GHashTable *hash;
- GList *elt;
- gchar *groupname;
- gint nballoc;
-       DB( g_print("\n[ui-mainwindow] accounts_groups_get\n") );
-       nballoc = da_acc_length ();
-       
-       DB( g_print(" %d accounts\n", nballoc) );
-       
-       hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
-       elt = g_list_first(lacc);
-       while (elt != NULL)
-       {
-       Account *acc = elt->data;
-       GPtrArray *group;
-       
-               //#1674045 ony rely on nosummary
-               //if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) )
-               if( showall || !(acc->flags & AF_NOSUMMARY) )
-               {
-                       if( groupby == DSPACC_GROUP_BY_BANK )
-                       {
-                               groupname = _("(no institution)");
-                               if( (acc->bankname != NULL) && strlen(acc->bankname) > 0 ) 
-                                       groupname = acc->bankname;
-                       }
-                       else
-                       {
-                               //pre 5.1.3 historical by type display
-                               groupname = _(CYA_ACC_TYPE[acc->type]);
-                       }
-                       
-                       if( g_hash_table_contains(hash, groupname) == FALSE )
-                       {
-                               g_hash_table_insert(hash, g_strdup(groupname), g_ptr_array_sized_new(nballoc) );
-                               //DB( g_print(" - type hash insert '%s' = %d\n", groupname, inserted) );
-                       }
-                       group = g_hash_table_lookup(hash, groupname);
-                       if( group != NULL )
-                       {
-                               g_ptr_array_add(group, (gpointer)acc);
-                               DB( g_print(" -- add '%s' to group '%s'\n", acc->name, groupname) );
-                       }
-               }
-               elt = g_list_next(elt);
-       }
-       return hash;
- }
- void ui_mainwindow_populate_accounts(GtkWidget *widget, gpointer user_data)
- {
- struct hbfile_data *data;
- GtkTreeModel *model;
- GtkTreeIter  iter1, child_iter;
- GList *lacc, *elt;
- Account *acc;
- guint j, nbtype;
- gdouble gtbank, gttoday, gtfuture;
- GHashTable *h_group;
- GHashTableIter grp_iter;
- gpointer key, value;
-       DB( g_print("\n[ui-mainwindow] populate accounts\n") );
-       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       /* here we create a count and a list of every account pointer by type */
-       lacc = elt = g_hash_table_get_values(GLOBALS->h_acc);
-       
-       h_group = ui_panel_accounts_groups_get(lacc, PREFS->pnl_acc_show_by, data->showall);
-       g_list_free(lacc);
-       gtbank = gttoday = gtfuture = 0;
-       DB( g_print(" - populate listview, %d group(s)\n", g_hash_table_size(h_group)) );
-       model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc));
-       gtk_tree_store_clear (GTK_TREE_STORE(model));
-       nbtype = 0;
-       g_hash_table_iter_init (&grp_iter, h_group);
-       while (g_hash_table_iter_next (&grp_iter, &key, &value))
-       {
-       GPtrArray *gpa = value;
-       gdouble tbank, ttoday, tfuture;
-       gint position;
-               if(gpa != NULL)
+               if( GLOBALS->xhb_timemodified != time_modified )
                {
-                       nbtype++;
-                       //1: Header: Bank, Cash, ...
-                       DB( g_print(" - add group '%s'\n", (gchar *)key) );
-                       //#1663399 keep type position like in dropdown
-                       position = 0;
-                       if( PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE )
-                       {
-                       gint t = 0;     
-                               while(CYA_ACC_TYPE[t] != NULL && t < 15)
-                               {
-                                       if( !strcmp(CYA_ACC_TYPE[t], key) )
-                                               break;
-                                       t++;
-                               }
-                               position = t;
-                       }
-                       gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL);
-                       gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
-                                         LST_DSPACC_POS, position,
-                                         LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER,
-                                         LST_DSPACC_NAME, key,
-                                         -1);
-                       tbank = ttoday = tfuture = 0;
-                       //2: Accounts for real
-                       for(j=0;j<gpa->len;j++)
-                       {
-                               acc = g_ptr_array_index(gpa, j);
-                               //tbank += acc->bal_bank;
-                               //ttoday += acc->bal_today;
-                               //tfuture += acc->bal_future;
-                               tbank += hb_amount_base(acc->bal_bank, acc->kcur);
-                               ttoday += hb_amount_base(acc->bal_today, acc->kcur);
-                               tfuture += hb_amount_base(acc->bal_future, acc->kcur);
-                               DB( g_print(" - add account '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) );
-                               gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1);
-                               gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter,
-                                               LST_DSPACC_DATAS, acc,
-                                               LST_DSPACC_DATATYPE, DSPACC_TYPE_NORMAL,
-                                               LST_DSPACC_BANK, acc->bal_bank,
-                                               LST_DSPACC_TODAY, acc->bal_today,
-                                               LST_DSPACC_FUTURE, acc->bal_future,
-                                         -1);
-                       }
-                       if(gpa->len > 1)
-                       {
-                               DB( g_print(" - group total :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) );
-                               // insert the total line
-                               gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1);
-                               gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter,
-                                               LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL,
-                                               LST_DSPACC_NAME, _("Total"),
-                                               LST_DSPACC_BANK, tbank,
-                                               LST_DSPACC_TODAY, ttoday,
-                                               LST_DSPACC_FUTURE, tfuture,
-                                                 -1);
-                       }
-                       /* set balance to header to display when collasped */
-                       DB( g_print(" - enrich group total header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) );
-                       gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
-                                       LST_DSPACC_BANK, tbank,
-                                       LST_DSPACC_TODAY, ttoday,
-                                       LST_DSPACC_FUTURE, tfuture,
-                                         -1);
-                       /* add to grand total */
-                       gtbank += tbank;
-                       gttoday += ttoday;
-                       gtfuture += tfuture;
+                       result = ui_dialog_msg_confirm_alert(
+                                       GTK_WINDOW(GLOBALS->mainwindow),
+                                       _("The file has been modified since reading it."),
+                                       _("If you save it, all the external changes could be lost. Save it anyway?"),
+                                       _("S_ave Anyway")
+                               );
 -                              
 +
+                       if( result != GTK_RESPONSE_OK )
+                               return;
                }
  
+               DB( g_print(" + saving...\n") );
+               homebank_file_ensure_xhb(NULL);
+               homebank_backup_current_file();
+               r = homebank_save_xml(GLOBALS->xhb_filepath);
        }
  
-       DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) );
-       // Grand total
-       if( nbtype > 1 )
+       if(r == XML_OK)
        {
-               gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL);
-               gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
-                                       LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL,
-                                       LST_DSPACC_NAME, _("Grand total"),
-                                       LST_DSPACC_BANK, gtbank,
-                                       LST_DSPACC_TODAY, gttoday,
-                                       LST_DSPACC_FUTURE, gtfuture,
-                                 -1);
+               DB( g_print(" + OK...\n") );
+               GLOBALS->changes_count = 0;
+               GLOBALS->xhb_timemodified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath);
+               ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
        }
-       gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc));
-       DB( g_print(" - free ressources\n") );
-       g_hash_table_iter_init (&grp_iter, h_group);
-       while (g_hash_table_iter_next (&grp_iter, &key, &value))
+       else
        {
-               g_ptr_array_free (value, TRUE);
-       }
-       g_hash_table_destroy (h_group);  
+       gchar *msg = _("I/O error for file '%s'.");
  
+               ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
+                       _("File error"),
+                       msg,
+                       GLOBALS->xhb_filepath
+                       );
+       }
  }
  
  
@@@ -2262,8 -1457,12 +1484,12 @@@ gint flags
  
                changed = (GLOBALS->changes_count > 0) ? "*" : "";
  
+ #if MYDEBUG == 1
+               data->wintitle = g_strdup_printf("%s%s (%d)- %s - " PROGNAME, changed, basename, GLOBALS->changes_count, GLOBALS->owner);
+ #else
                data->wintitle = g_strdup_printf("%s%s - %s - " PROGNAME, changed, basename, GLOBALS->owner);
 -              
+ #endif
 +
            gtk_window_set_title (GTK_WINDOW (gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), data->wintitle);
  
                g_free(basename);
                                active = FALSE;
                }
  
-               // no change: disable save
                DB( g_print(" changes %d - new %d\n", GLOBALS->changes_count, GLOBALS->hbfile_is_new) );
  
+       // save
                sensitive = (GLOBALS->changes_count != 0 ) ? TRUE : FALSE;
-               //gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/SaveAs"), sensitive);
-               //if(sensitive == TRUE && GLOBALS->hbfile_is_new == TRUE) sensitive = FALSE;
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Save"), sensitive);
-               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Revert"), GLOBALS->xhb_hasbak);
  
+       // backup
+               sensitive = ( (GLOBALS->changes_count != 0) && GLOBALS->xhb_hasrevert ) ? TRUE : FALSE;
+               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Revert"), sensitive);
+               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/OpenBak"), sensitive);
  
        // define off ?
                sensitive = GLOBALS->define_off == 0 ? TRUE : FALSE;
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Account"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Payee"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Category"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/EditMenu/Preferences"), sensitive);
  
-       // empty account list: disable Import, Archives, Edit, Filter, Add, Statistics, Overdrawn, Car Cost
+       // empty account list: disable Archives, Edit, Filter, Add, Statistics, Overdrawn, Car Cost
                sensitive = da_acc_length() > 0 ? TRUE : FALSE;
-               //gtk_action_set_sensitive(gtk_ui_manager_get_action(data-data->manager, "/MenuBar/FileMenu/Import"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Close"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Archive"), sensitive);
-               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddOpe"), sensitive);
-               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowOpe"), sensitive);
+               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddTxn"), sensitive);
+               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RStatistics"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RTrendTime"), sensitive);
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBudget"), sensitive);
  
        // empty archive list: disable scheduled check
                sensitive = g_list_length(GLOBALS->arc_list) > 0 ? TRUE : FALSE;
                gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddScheduled"), sensitive);
  
        // no active account: disable Edit, Over
                sensitive = (active == TRUE ) ? TRUE : FALSE;
                if(data->acc && data->acc->window != NULL)
                        sensitive = FALSE;
-               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowOpe"), sensitive);
+               gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive);
        }
  
        /* update toolbar, list */
                        gtk_widget_hide(GTK_WIDGET(data->GR_top));
  
  
--              
++
                DB( g_print(" - show upcoming=%d\n", PREFS->wal_upcoming) );
                if(PREFS->wal_upcoming)
                        gtk_widget_show(GTK_WIDGET(data->GR_upc));
        {
                DB( g_print(" 16: refreshall\n") );
  
-               ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL);
-               ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_account_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_spending_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_scheduled_populate(GLOBALS->mainwindow, NULL);
+               ui_hub_transaction_populate(data);
        }
  
  
@@@ -2485,9 -1677,6 +1704,9 @@@ struct hbfile_data *data = user_data
  struct WinGeometry *wg;
  gboolean retval = FALSE;
  
 +      GValue widget_value = G_VALUE_INIT;
 +      ext_hook("main_window_disposal", EXT_OBJECT(&widget_value, widget), NULL);
 +
        DB( g_print("\n[ui-mainwindow] delete-event\n") );
  
        //store position and size
        GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget));
        GdkWindowState state = gdk_window_get_state(gdk_window);
        wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0;
-       
        DB( g_print(" window: l=%d, t=%d, w=%d, h=%d s=%d, state=%d\n", wg->l, wg->t, wg->w, wg->h, wg->s, state & GDK_WINDOW_STATE_MAXIMIZED) );
  
        PREFS->wal_vpaned = gtk_paned_get_position(GTK_PANED(data->vpaned));
        PREFS->wal_hpaned = gtk_paned_get_position(GTK_PANED(data->hpaned));
        DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) );
  
 -      
+       if(PREFS->pnl_list_tab)
+               g_free(PREFS->pnl_list_tab);
+       PREFS->pnl_list_tab = g_strdup(gtk_stack_get_visible_child_name(GTK_STACK(data->stack)));
++
        //todo
        if(ui_dialog_msg_savechanges(widget, NULL) == FALSE)
        {
                gtk_widget_destroy(data->LV_top);
  
                g_free(data->wintitle);
-               da_filter_free(data->filter);
+               da_flt_free(data->filter);
                g_free(user_data);
--              
++
                gtk_main_quit();
        }
  
@@@ -2565,31 -1756,6 +1786,6 @@@ static void ui_mainwindow_recent_choose
  }
  
  
- static void ui_mainwindow_window_screen_changed_cb (GtkWidget *widget,
-                             GdkScreen *old_screen,
-                             struct hbfile_data *data)
- {
-       DB( g_print("\n[ui-mainwindow] screen_changed_cb\n") );
-       data->recent_manager = gtk_recent_manager_get_default ();
-       gtk_menu_detach (GTK_MENU (data->recent_menu));
-       g_object_unref (G_OBJECT (data->recent_menu));
-       data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager);
-       g_signal_connect (data->recent_menu,
-                         "item-activated",
-                         G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb),
-                         data);
-       //menu_item = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/OpenRecent");
-       //gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), data->recent_menu);
- }
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path)
  {
        GtkRecentData *recent_data;
@@@ -2656,8 -1822,9 +1852,9 @@@ static void ui_mainwindow_drag_data_rec
  {
  gchar **uris, **str;
  gchar *newseldata;
- gint filetype, slen;
+ gint n_uris, filetype, slen;
+ GError *error = NULL;
 -      
 +
        if (info != TARGET_URI_LIST)
                return;
  
        newseldata = g_new (gchar, slen + 1);
        memcpy (newseldata, gtk_selection_data_get_data(selection_data), slen);
        newseldata[slen] = 0;
 -      
+       //DB( g_print(" - seldata ='%s'\n", gtk_selection_data_get_data(selection_data) ) );
+       //DB( g_print(" - newseldata ='%s'\n", newseldata ) );
 +
        uris = g_uri_list_extract_uris (newseldata);
+       n_uris = g_strv_length(uris);
+       DB( g_print(" - dragged %d files (len=%d)\n", n_uris, slen ) );
  
-       DB( g_print(" - dragged %d %d files\n", slen, g_strv_length(uris) ) );
+       g_free(newseldata);
  
-       str = uris;
-       //for (str = uris; *str; str++)
-       if( *str )
+       //single file: check for xhb
+       if(n_uris == 1)
 -      {               
 +      {
-               GError *error = NULL;
-               gchar *path = g_filename_from_uri (*str, NULL, &error);
+               filetype = hb_filename_type_get_by_extension(*uris);
  
-               if (path)
-               {
-                       filetype = homebank_alienfile_recognize(path);
+               DB( g_print(" - filetype is homebank (%d)\n", filetype) );
  
-                       DB( g_print(" - dragged %s, type is %d\n", path, filetype ) );
+               if( filetype == FILETYPE_HOMEBANK )
+               {
+               gchar *path = g_filename_from_uri (*uris, NULL, &error);
  
-                       if( filetype == FILETYPE_HOMEBANK)
+                       if( path != NULL )
                        {
+                               DB( g_print(" - path is '%s'\n", path) );
                                hbfile_change_filepath(g_strdup(path));
                                ui_mainwindow_open_internal(GTK_WIDGET(window), NULL);
+                               goto end_drop;
                        }
                        else
                        {
-                               //todo: future here to implement import for other filetype
-                               //      ui_import_assistant_new();
-                               // + write a method into assistant to catch other filename
-                               ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR,
+                               g_warning ("Could not convert uri to local path: %s", error->message);
+                               g_error_free (error);
+                       }
+                       g_free (path);
+               }
+               /* we no more manage error here
+               ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR,
                                        _("File error"),
                                        _("The file %s is not a valid HomeBank file."),
-                                       path
-                                       );
+                                       path);
+               */
+       }
  
-                       }
+       //collect known filetype to import
+       DB( g_print(" - collect %d files\n", n_uris) );
 -      
 +
-               }
-               else
+       gchar **paths = g_new (gchar *, n_uris + 1);
+       slen = 0;
+       for (str = uris; *str; str++)
+       {
+               filetype = hb_filename_type_get_by_extension(*str);
+               if( filetype != FILETYPE_HOMEBANK && filetype != FILETYPE_UNKNOWN )
                {
-                       g_warning ("Could not convert uri to local path: %s", error->message);
+               gchar *path = g_filename_from_uri (*str, NULL, NULL);
  
-                       g_error_free (error);
+                       if( path != NULL )
+                       {
+                               DB( g_print(" - append %d '%s'\n", slen, path ) );
+                               paths[slen++] = path;
+                       }
 -              }   
 +              }
-               g_free (path);
        }
 -      
 -      
+       paths[slen] = NULL;
+       if( slen > 0 )
+       {
+               ui_import_assistant_new( paths );
+       }
++
++
+ end_drop:
        g_strfreev (uris);
-       
-       g_free(newseldata);
  }
  
  
  static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager)
  {
- GtkWidget *toolbar_recent_menu;
+ GtkWidget *recent_menu;
  GtkRecentFilter *filter;
  
-       toolbar_recent_menu = gtk_recent_chooser_menu_new_for_manager (manager);
-       gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (toolbar_recent_menu),
-                                       FALSE);
-       gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (toolbar_recent_menu),
-                                       GTK_RECENT_SORT_MRU);
+       recent_menu = gtk_recent_chooser_menu_new_for_manager (manager);
+       gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (recent_menu), FALSE);
+       gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), GTK_RECENT_SORT_MRU);
        //todo: add a user pref for this
-       gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER (toolbar_recent_menu),
-                                       10);
-       //gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (toolbar_recent_menu), FALSE);
-       //gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (toolbar_recent_menu), TRUE);
+       gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER (recent_menu), 10);
+       gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (recent_menu), FALSE);
+       //gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (recent_menu), TRUE);
  
        filter = gtk_recent_filter_new ();
        //gtk_recent_filter_add_application (filter, g_get_application_name());
        gtk_recent_filter_add_pattern (filter, "*.[Xx][Hh][Bb]");
-       gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (toolbar_recent_menu), filter);
+       gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (recent_menu), filter);
  
-       return toolbar_recent_menu;
+       return recent_menu;
  }
  
  
@@@ -2804,10 -1984,10 +2014,10 @@@ GError *error = NULL
        action = gtk_action_group_get_action(actions, "Budget");
        g_object_set(action, "short_label", _("Budget"), NULL);
  
-       action = gtk_action_group_get_action(actions, "ShowOpe");
+       action = gtk_action_group_get_action(actions, "ShowTxn");
        g_object_set(action, "short_label", _("Show"), NULL);
  
-       action = gtk_action_group_get_action(actions, "AddOpe");
+       action = gtk_action_group_get_action(actions, "AddTxn");
        g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL);
  
        action = gtk_action_group_get_action(actions, "RStatistics");
                g_error_free (error);
        }
  
-       //todo: this generate a warning
+       data->recent_manager = gtk_recent_manager_get_default ();
        data->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar");
        gtk_box_pack_start (GTK_BOX (mainvbox),
                            data->menubar,
                            FALSE,
                            0);
  
-       data->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
-       gtk_box_pack_start (GTK_BOX (mainvbox),
-                           data->toolbar,
-                           FALSE,
-                           FALSE,
-                           0);
        /* recent files menu */
-       data->recent_manager = gtk_recent_manager_get_default ();
        data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager);
  
        g_signal_connect (data->recent_menu,
                          G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb),
                          data);
  
- /*
-       widget = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/OpenRecent");
+       GtkWidget *widget = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/RecentMenu");
        gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), data->recent_menu);
- */
  
-       /* test */
-       /* add the custom Open button to the toolbar */
-       GtkWidget *image = gtk_image_new_from_icon_name (ICONNAME_OPEN, GTK_ICON_SIZE_BUTTON);
  
-       GtkToolItem *open_button = gtk_menu_tool_button_new(image, _("_Open"));
-       gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button), data->recent_menu);
+       data->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
+       gtk_box_pack_start (GTK_BOX (mainvbox),
+                           data->toolbar,
+                           FALSE,
+                           FALSE,
+                           0);
  
+       /* add the custom Open button to the toolbar */
+       GtkWidget *image = gtk_image_new_from_icon_name (ICONNAME_HB_FILE_OPEN, GTK_ICON_SIZE_BUTTON);
+       GtkToolItem *open_button = gtk_menu_tool_button_new(image, _("_Open"));
        gtk_tool_item_set_tooltip_text (open_button, _("Open a file"));
+       GtkWidget *recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager);
+       gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button), recent_menu);
        gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button), _("Open a recently used file"));
  
+       g_signal_connect (recent_menu,
+                         "item-activated",
+                         G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb),
+                         data);
        action = gtk_action_group_get_action (data->actions, "Open");
        g_object_set (action, "short_label", _("Open"), NULL);
        //gtk_action_connect_proxy (action, GTK_WIDGET (open_button));
        gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button), action);
  
        gtk_toolbar_insert (GTK_TOOLBAR (data->toolbar), open_button, 1);
-       /* end test */
- }
- /* Callback function for the undo action */
- /*static void
- activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
- {
-   g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action)));
- }*/
- static void
- activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
- {
- struct hbfile_data *data = user_data;
-   GVariant *old_state, *new_state;
-   old_state = g_action_get_state (G_ACTION (action));
-   new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
-   DB( g_print ("Toggle action %s activated, state changes from %d to %d\n",
-            g_action_get_name (G_ACTION (action)),
-            g_variant_get_boolean (old_state),
-            g_variant_get_boolean (new_state)) );
-       data->showall = g_variant_get_boolean (new_state);
-       ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
-   g_simple_action_set_state (action, new_state);
-   g_variant_unref (old_state);
- }
- static void
- activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
- {
- //struct hbfile_data *data = user_data;
- GVariant *old_state, *new_state;
-   old_state = g_action_get_state (G_ACTION (action));
-   new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
-   DB( g_print ("Radio action %s activated, state changes from %s to %s\n",
-            g_action_get_name (G_ACTION (action)),
-            g_variant_get_string (old_state, NULL),
-            g_variant_get_string (new_state, NULL)) );
-       PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_TYPE;
-       if( !strcmp("bank", g_variant_get_string(new_state, NULL)) )
-               PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_BANK;
-       ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
-   g_simple_action_set_state (action, new_state);
-   g_variant_unref (old_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} }
- };
- 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;
- GtkToolItem *toolitem;
-       panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
-       sw = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
-       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0);
-       widget = (GtkWidget *)create_list_account();
-       data->LV_acc = widget;
-       gtk_container_add (GTK_CONTAINER (sw), widget);
-       //list toolbar
-       tbar = gtk_toolbar_new();
-       gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
-       gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
-       gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
-       gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0);
-       label = make_label_group(_("Your accounts"));
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), label);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       toolitem = gtk_separator_tool_item_new ();
-       gtk_tool_item_set_expand (toolitem, TRUE);
-       gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), hbox);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       
-               widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all"));
-               data->BT_expandall = widget;
-               gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-               widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all"));
-               data->BT_collapseall = widget;
-               gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-       toolitem = gtk_separator_tool_item_new ();
-       gtk_tool_item_set_expand (toolitem, FALSE);
-       gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       //gmenu test (see test folder into gtk)
- GMenu *menu, *section;
-       menu = g_menu_new ();
-       //g_menu_append (menumodel, "About", "actions.undo");
-       //g_menu_append (menumodel, "Test", "actions.redo");
-       section = g_menu_new ();
-       g_menu_append (section, _("Show all"), "actions.showall");
-       g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
-       g_object_unref (section);
-       section = g_menu_new ();
-       g_menu_append (section, _("By type"), "actions.groupby::type");
-       g_menu_append (section, _("By institition"), "actions.groupby::bank");
-       g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
-       g_object_unref (section);
-       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);
-       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;
- }
- static GtkWidget *ui_mainwindow_create_topspending(struct hbfile_data *data)
- {
- GtkWidget *panel, *hbox, *tbar;
- GtkWidget *label, *widget;
- GtkToolItem *toolitem;
-       widget = (GtkWidget *)create_list_topspending();
-       data->LV_top = widget;
-       panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
-       data->GR_top = panel;
  
-       /* chart + listview */
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_box_pack_start (GTK_BOX (panel), hbox, TRUE, TRUE, 0);
-       widget = gtk_chart_new(CHART_TYPE_PIE);
-       data->RE_pie = widget;
-       gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.symbol);
-       gtk_chart_show_legend(GTK_CHART(data->RE_pie), TRUE, TRUE);
-       gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
-       //list toolbar
-       tbar = gtk_toolbar_new();
-       gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
-       gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
-       gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
-       gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0);
-       label = make_label_group(_("Where your money goes"));
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), label);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       toolitem = gtk_separator_tool_item_new ();
-       gtk_tool_item_set_expand (toolitem, TRUE);
-       gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       /* total + date range */
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), hbox);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       
-       data->CY_range = make_daterange(label, FALSE);
-       gtk_box_pack_end (GTK_BOX (hbox), data->CY_range, FALSE, FALSE, 0);
-       widget = make_radio(CYA_CATSUBCAT, TRUE, GTK_ORIENTATION_HORIZONTAL);
-       data->RA_type = widget;
-       gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-       return panel;
- }
- static GtkWidget *ui_mainwindow_scheduled_create(struct hbfile_data *data)
- {
- GtkWidget *panel, *hbox, *vbox, *bbox, *sw, *tbar;
- GtkWidget *label, *widget;
- GtkToolItem *toolitem;
-       
-       panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
-       data->GR_upc = panel;
-       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       //gtk_widget_set_margin_top(GTK_WIDGET(vbox), 0);
-       //gtk_widget_set_margin_bottom(GTK_WIDGET(vbox), SPACING_SMALL);
-       //gtk_widget_set_margin_start(GTK_WIDGET(vbox), 2*SPACING_SMALL);
-       //gtk_widget_set_margin_end(GTK_WIDGET(vbox), SPACING_SMALL);
-       gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
-       sw = gtk_scrolled_window_new (NULL, NULL);
-       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
-       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-       gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
-       
-       widget = (GtkWidget *)create_list_upcoming();
-       data->LV_upc = widget;
-       gtk_container_add (GTK_CONTAINER (sw), widget);
-       tbar = gtk_toolbar_new();
-       gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
-       gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
-       gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
-       gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0);
-       label = make_label_group(_("Scheduled transactions"));
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), label);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       toolitem = gtk_separator_tool_item_new ();
-       gtk_tool_item_set_expand (toolitem, FALSE);
-       gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), bbox);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-               widget = gtk_button_new_with_label(_("Skip"));
-               data->BT_sched_skip = widget;
-               gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
-               widget = gtk_button_new_with_label(_("Edit & Post"));
-               data->BT_sched_editpost = widget;
-               gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
-               //TRANSLATORS: Posting a scheduled transaction is the action to materialize it into its target account.
-               //TRANSLATORS: Before that action the automated transaction occurrence is pending and not yet really existing.
-               widget = gtk_button_new_with_label (_("Post"));
-               data->BT_sched_post = widget;
-               gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
-       toolitem = gtk_separator_tool_item_new ();
-       gtk_tool_item_set_expand (toolitem, FALSE);
-       gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-       hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
-       gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER);
-       toolitem = gtk_tool_item_new();
-       gtk_container_add (GTK_CONTAINER(toolitem), hbox);
-       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
-               label = make_label(_("maximum post date"), 0.0, 0.7);
-               gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
-               gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
-               gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-               label = make_label(NULL, 0.0, 0.7);
-               data->LB_maxpostdate = label;
-               gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
-               gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
-               gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-       return panel;
  }
  
  
@@@ -3211,8 -2070,8 +2100,8 @@@ GtkWidget *create_hbfile_window(GtkWidg
  {
  struct hbfile_data *data;
  struct WinGeometry *wg;
- GtkWidget *mainvbox, *vbox, *vpaned, *hpaned;
- GtkWidget *widget;
+ GtkWidget *mainvbox, *vbox, *box, *vpaned, *hpaned, *sidebar, *stack;
+ GtkWidget *widget, *page;
  GtkWidget *window;
  GtkAction *action;
  
@@@ -3246,7 -2105,7 +2135,7 @@@ GtkWidget *bar, *label
        gtk_label_set_markup (GTK_LABEL(label), "Unstable Development Version");
        gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0);
  #endif
--      
++
        /* Add the main area */
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
      //gtk_container_set_border_width (GTK_CONTAINER(vbox), SPACING_MEDIUM);
        data->vpaned = vpaned;
      gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0);
  
-               hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
-               data->hpaned = hpaned;
-               gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE);
-               widget = ui_mainwindow_scheduled_create(data);
-               gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE);
+       hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
+       data->hpaned = hpaned;
+       gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE);
  
-               widget = ui_mainwindow_create_youraccounts(data);
+               widget = ui_hub_account_create(data);
                //gtk_widget_set_size_request (widget, 100, -1);
                gtk_paned_pack1 (GTK_PANED(hpaned), widget, FALSE, FALSE);
  
-               widget = ui_mainwindow_create_topspending(data);
+               widget = ui_hub_spending_create(data);
                //gtk_widget_set_size_request (widget, -1, 100);
                gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE);
  
 -      
+       box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+       data->GR_upc = box;
+       gtk_paned_pack2 (GTK_PANED(vpaned), box, TRUE, FALSE);
+       sidebar = gtk_stack_sidebar_new ();
+       gtk_box_pack_start (GTK_BOX (box), sidebar, FALSE, FALSE, 0);
+       stack = gtk_stack_new ();
+       //gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN);
+       gtk_stack_sidebar_set_stack (GTK_STACK_SIDEBAR (sidebar), GTK_STACK (stack));
+       data->stack = stack;
+     gtk_box_pack_start (GTK_BOX (box), stack, TRUE, TRUE, 0);
 -      
++
+               page = ui_hub_scheduled_create(data);
+               gtk_stack_add_titled (GTK_STACK (stack), page, "sched", _("Scheduled"));
+               //gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE);
+               page = ui_hub_transaction_create(data, HUB_TXN_TYPE_FUTURE);
+               gtk_stack_add_titled (GTK_STACK (stack), page, "futur", _("Future"));
+               page = ui_hub_transaction_create(data, HUB_TXN_TYPE_REMIND);
+               gtk_stack_add_titled (GTK_STACK (stack), page, "remin", _("Remind"));
++
  
        //setup, init and show window
        wg = &PREFS->wal_wg;
        if(PREFS->wal_vpaned > 0)
                gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned);
  
 -      
+       if( PREFS->pnl_list_tab != NULL )
+               gtk_stack_set_visible_child_name (GTK_STACK(data->stack), PREFS->pnl_list_tab);
++
        //todo: move this elsewhere
        DB( g_print(" - setup stuff\n") );
  
-       data->filter = da_filter_malloc();
-       filter_default_all_set(data->filter);
+       data->filter = da_flt_malloc();
+       filter_reset(data->filter);
        gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal);
  
        action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Toolbar");
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_toolbar);
        action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Spending");
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_spending);
-       action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Upcoming");
+       action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/BottomLists");
        gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_upcoming);
  
        /* Drag and drop support, set targets to NULL because we add the
        g_signal_connect (G_OBJECT (window), "drag-data-received",
                          G_CALLBACK (ui_mainwindow_drag_data_received), window);
  
        //connect all our signals
        DB( g_print(" - connect signals\n") );
  
        g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)), "changed", G_CALLBACK (ui_mainwindow_selection), NULL);
        g_signal_connect (GTK_TREE_VIEW(data->LV_acc    ), "row-activated", G_CALLBACK (ui_mainwindow_onRowActivated), GINT_TO_POINTER(2));
-       g_signal_connect (G_OBJECT (data->BT_expandall  ), "clicked"      , G_CALLBACK (ui_panel_accounts_expand_all), NULL);
-       g_signal_connect (G_OBJECT (data->BT_collapseall), "clicked"      , G_CALLBACK (ui_panel_accounts_collapse_all), NULL);
-       g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_upc)), "changed", G_CALLBACK (ui_mainwindow_scheduled_selection_cb), NULL);
-       g_signal_connect (GTK_TREE_VIEW(data->LV_upc), "row-activated", G_CALLBACK (ui_mainwindow_scheduled_onRowActivated), NULL);
-       g_signal_connect (G_OBJECT (data->BT_sched_skip), "clicked", G_CALLBACK (ui_mainwindow_scheduled_skip_cb), data);
-       g_signal_connect (G_OBJECT (data->BT_sched_editpost), "clicked", G_CALLBACK (ui_mainwindow_scheduled_editpost_cb), data);
-       g_signal_connect (G_OBJECT (data->BT_sched_post), "clicked", G_CALLBACK (ui_mainwindow_scheduled_post_cb), data);
-       
-       widget = radio_get_nth_widget(GTK_CONTAINER(data->RA_type), 1);
-       if(widget)
-               g_signal_connect (widget, "toggled", G_CALLBACK (ui_mainwindow_populate_topspending), &data);
-       g_signal_connect (data->CY_range, "changed", G_CALLBACK (ui_mainwindow_populate_topspending), NULL);
  
        /* 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",
-                         G_CALLBACK (ui_mainwindow_window_screen_changed_cb),
-                         data);
        //gtk_action_group_set_sensitive(data->actions, FALSE);
  
-       
        return window;
  }
  
diff --combined src/ext-perl.xs
index 4890db85a56e2c7cd4b91548dc5009f6fa083ada,0000000000000000000000000000000000000000..c8e1f25b5a4f82e4435cbac1658583c4e2ac2bff
mode 100644,000000..100644
--- /dev/null
@@@ -1,1043 -1,0 +1,1043 @@@
- #include "dsp_mainwindow.h"
- #include "dsp_account.h"
 +
 +#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;
-               RETVAL = G_OBJECT(register_panel_window_new(SELF->key, SELF));
++#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(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE));
++              RETVAL = G_OBJECT(register_panel_window_new(SELF));
 +      OUTPUT:
 +              RETVAL
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::Transaction
 +
 +Transaction*
 +new(void)
 +      CODE:
 +              RETVAL = da_transaction_malloc();
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +DESTROY(Transaction* SELF)
 +      CODE:
 +              da_transaction_free(SELF);
 +
 +gdouble
 +amount(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->amount = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->amount;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kacc;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +paired_account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kxferacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kxferacc;
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +date(Transaction* SELF, ...)
 +      PPCODE:
 +              if (1 < items) {
 +                      SELF->date = SvIV(ST(1));
 +              }
 +              if (GIMME_V == G_ARRAY) {
 +                      GDate* d = g_date_new_julian(SELF->date);
 +                      mXPUSHp("day", 3);
 +                      mXPUSHi(g_date_get_day(d));
 +                      mXPUSHp("month", 5);
 +                      mXPUSHi(g_date_get_month(d));
 +                      mXPUSHp("year", 4);
 +                      mXPUSHi(g_date_get_year(d));
 +                      g_date_free(d);
 +                      XSRETURN(6);
 +              } else {
 +                      XSRETURN_IV(SELF->date);
 +              }
 +
 +const gchar*
 +memo(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      if (SELF->memo) g_free(SELF->memo);
 +                      SELF->memo = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->memo ? SELF->memo : "";
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +info(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      if (SELF->info) g_free(SELF->info);
 +                      SELF->info = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->info ? SELF->info : "";
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +open(Transaction* SELF)
 +      CODE:
-                       other = ui_dialog_transaction_xfer_select_child(SELF, list);
++              RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE, 0));
 +              deftransaction_set_transaction(GTK_WIDGET(RETVAL), SELF);
 +      OUTPUT:
 +              RETVAL
 +
 +Transaction*
 +pair_with(Transaction* SELF, Transaction* other, ...)
 +      PREINIT:
 +              int i;
 +              GList* list = NULL;
 +      CODE:
 +              if (2 < items) {
 +                      list = g_list_append(list, other);
 +                      for (i = 2; i < items; ++i) {
 +                              Transaction* ptr = NULL;
 +                              SV* sv = ST(i);
 +                              EXT_P2C_OBJECT("HomeBank::Transaction", sv, ptr, Transaction*);
 +                              list = g_list_append(list, ptr);
 +                      }
++                      ui_dialog_transaction_xfer_select_child(NULL, SELF, list, &other);
 +              }
 +              if (other) {
 +                      transaction_xfer_change_to_child(SELF, other);
 +                      SELF->paymode = PAYMODE_INTXFER;
 +              }
 +              RETVAL = other;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_list_free(list);
 +
 +void
 +dump(Transaction* SELF)
 +      CODE:
 +              g_print("txn: %p (%s) at %u (%d/%d) flags:%d, paymode:%d, kpay:%d, kcat:%d", SELF,
 +                      SELF->memo, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
 +
diff --combined src/hb-account.c
index ee5055f954374c75a4f6ecfbd4f6e2c32b5ddc87,b6888c9144f2838ca7f9eb1886d3f6643511fa53..2ecbb6f93c5aa42ba6a1f14b5d8eff39c458328e
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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,19 -39,18 +42,18 @@@ 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) );
  
-               g_free(item->imp_name);
                g_free(item->name);
                g_free(item->number);
                g_free(item->bankname);
                g_free(item->notes);
--              
++
                g_queue_free (item->txn_queue);
--              
 -              g_free(item);
++
 +              rc_free(item);
        }
  }
  
@@@ -65,7 -61,8 +64,8 @@@ da_acc_malloc(void
  Account *item;
  
        DB( g_print("da_acc_malloc\n") );
 -      item = g_malloc0(sizeof(Account));
 +      item = rc_alloc(sizeof(Account));
+       item->kcur = GLOBALS->kcur;
        item->txn_queue = g_queue_new ();
        return item;
  }
@@@ -88,30 -85,7 +88,7 @@@ da_acc_new(void
  
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
- static void da_acc_max_key_ghfunc(gpointer key, Account *item, guint32 *max_key)
- {
-       *max_key = MAX(*max_key, item->key);
- }
  
- static gboolean da_acc_name_grfunc(gpointer key, Account *item, gchar *name)
- {
-       if( name && item->name )
-       {
-               if(!strcasecmp(name, item->name))
-                       return TRUE;
-       }
-       return FALSE;
- }
- static gboolean da_acc_imp_name_grfunc(gpointer key, Account *item, gchar *name)
- {
-       if( name && item->imp_name )
-       {
-               if(!strcasecmp(name, item->imp_name))
-                       return TRUE;
-       }
-       return FALSE;
- }
  
  /**
   * da_acc_length:
@@@ -125,6 -99,30 +102,30 @@@ da_acc_length(void
  }
  
  
+ static void da_acc_max_key_ghfunc(gpointer key, Account *item, guint32 *max_key)
+ {
+       *max_key = MAX(*max_key, item->key);
+ }
+ /**
+  * da_acc_get_max_key:
+  *
+  * Get the biggest key from the GHashTable
+  *
+  * Return value: the biggest key value
+  *
+  */
+ guint32
+ da_acc_get_max_key(void)
+ {
+ guint32 max_key = 0;
+       g_hash_table_foreach(GLOBALS->h_acc, (GHFunc)da_acc_max_key_ghfunc, &max_key);
+       return max_key;
+ }
  /**
   * da_acc_remove:
   *
@@@ -160,9 -158,6 +161,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;
  }
  
@@@ -179,31 -174,16 +180,20 @@@ gboolea
  da_acc_append(Account *item)
  {
  Account *existitem;
- guint32 *new_key;
  
        DB( g_print("da_acc_append\n") );
  
-       /* ensure no duplicate */
-       g_strstrip(item->name);
-       if(item->name != NULL)
+       existitem = da_acc_get_by_name( item->name );
+       if( existitem == NULL )
        {
-               existitem = da_acc_get_by_name( item->name );
-               if( existitem == NULL )
-               {
-                       new_key = g_new0(guint32, 1);
-                       *new_key = da_acc_get_max_key() + 1;
-                       item->key = *new_key;
-                       item->pos = da_acc_length() + 1;
+               item->key = da_acc_get_max_key() + 1;
+               item->pos = da_acc_length() + 1;
+               da_acc_insert(item);
 +
-                       DB( g_print(" -> insert id: %d\n", *new_key) );
++              GValue item_val = G_VALUE_INIT;
++              ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
 +
-                       g_hash_table_insert(GLOBALS->h_acc, new_key, item);
-                       GValue item_val = G_VALUE_INIT;
-                       ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
-                       return TRUE;
-               }
+               return TRUE;
        }
  
        DB( g_print(" -> %s already exist: %d\n", item->name, item->key) );
        return FALSE;
  }
  
- /**
-  * da_acc_get_max_key:
-  *
-  * Get the biggest key from the GHashTable
-  *
-  * Return value: the biggest key value
-  *
-  */
- guint32
- da_acc_get_max_key(void)
- {
- guint32 max_key = 0;
  
-       g_hash_table_foreach(GLOBALS->h_acc, (GHFunc)da_acc_max_key_ghfunc, &max_key);
-       return max_key;
+ static gboolean da_acc_name_grfunc(gpointer key, Account *item, gchar *name)
+ {
+       if( name && item->name )
+       {
+               if(!strcasecmp(name, item->name))
+                       return TRUE;
+       }
+       return FALSE;
  }
  
  /**
   * da_acc_get_by_name:
   *
   *
   */
  Account *
- da_acc_get_by_name(gchar *name)
+ da_acc_get_by_name(gchar *rawname)
  {
+ Account *retval = NULL;
+ gchar *stripname;
        DB( g_print("da_acc_get_by_name\n") );
  
-       return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_name_grfunc, name);
- }
+       if( rawname )
+       {
+               stripname = g_strdup(rawname);
+               g_strstrip(stripname);
+               if( strlen(stripname) > 0 )
+                       retval = g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_name_grfunc, stripname);
  
- Account *
- da_acc_get_by_imp_name(gchar *name)
- {
-       DB( g_print("da_acc_get_by_imp_name\n") );
+               g_free(stripname);
+       }
  
-       return g_hash_table_find(GLOBALS->h_acc, (GHRFunc)da_acc_imp_name_grfunc, name);
 -      return retval; 
++      return retval;
  }
  
  
@@@ -369,14 -345,14 +355,14 @@@ gboolean retval
        while (lnk_acc != NULL)
        {
        Account *acc = lnk_acc->data;
--      
++
                if(acc->key != key)
                {
                        lnk_txn = g_queue_peek_head_link(acc->txn_queue);
                        while (lnk_txn != NULL)
                        {
                        Transaction *entry = lnk_txn->data;
--                      
++
                                if( key == entry->kxferacc)
                                {
                                        retval = TRUE;
@@@ -439,21 -415,24 +425,24 @@@ account_rename(Account *item, gchar *ne
  Account *existitem;
  gchar *stripname = account_get_stripname(newname);
  
-       existitem = da_acc_get_by_name(stripname);
-       if( existitem == NULL )
+       if( strlen(stripname) > 0 )
        {
-               g_free(item->name);
-               item->name = g_strdup(stripname);
-               return TRUE;
-       }
+               existitem = da_acc_get_by_name(stripname);
+               if( existitem == NULL )
+               {
+                       g_free(item->name);
+                       item->name = g_strdup(stripname);
+                       return TRUE;
+               }
  
-       g_free(stripname);
+               g_free(stripname);
+       }
 -      
 +
        return FALSE;
  }
  
  
--/* 
++/*
   * change the account currency
   * change every txn to currency
   * ensure dst xfer transaction account will be set to same currency
@@@ -474,7 -453,7 +463,7 @@@ guint32 maxkey, i
        }
  
        DB( g_print(" - set for '%s'\n", acc->name)  );
-               
        maxkey = da_acc_get_max_key () + 1;
        xfer_list = g_malloc0(sizeof(gboolean) * maxkey );
        DB( g_print(" - alloc for %d account\n", da_acc_length() ) );
  
        acc->kcur = kcur;
        DB( g_print(" - '%s'\n", acc->name) );
--      
++
        for(i=1;i<maxkey;i++)
        {
                DB( g_print(" - %d '%d'\n", i, xfer_list[i]) );
@@@ -589,25 -568,25 +578,25 @@@ GList *lnk_txn
        while (lnk_acc != NULL)
        {
        Account *acc = lnk_acc->data;
--      
++
                /* set initial amount */
                acc->bal_bank = acc->initial;
                acc->bal_today = acc->initial;
                acc->bal_future = acc->initial;
--              
++
                /* add every txn */
                lnk_txn = g_queue_peek_head_link(acc->txn_queue);
                while (lnk_txn != NULL)
                {
                Transaction *txn = lnk_txn->data;
--              
++
                        if(!(txn->status == TXN_STATUS_REMIND))
                        {
                                account_balances_add_internal(acc, txn);
                        }
                        lnk_txn = g_list_next(lnk_txn);
                }
--              
++
                lnk_acc = g_list_next(lnk_acc);
        }
        g_list_free(lst_acc);
diff --combined src/hb-archive.c
index 628e978a9ce7c0ec4125909f3cc16d7a54e04ad4,890cd7f5c15bae7fb397a3f4884b68bcbfef3433..db3b10188739f87895cadb4e58bef5d746c8c9ca
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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                                                             */
  /****************************************************************************/
@@@ -41,20 -38,31 +41,31 @@@ extern struct HomeBank *GLOBALS
  
  Archive *da_archive_malloc(void)
  {
-       return rc_alloc(sizeof(Archive));
+ Archive *item;
 -      item = g_malloc0(sizeof(Archive));
++      item = rc_alloc(sizeof(Archive));
+       item->key = 1;
+       return item;
  }
  
  
  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->memo = g_strdup(src_item->memo);
  
-               if( da_splits_clone(src_item->splits, new_item->splits) > 0)
+               //duplicate tags
+               //no g_free here to avoid free the src tags (memdup copie dthe ptr)
+               new_item->tags = tags_clone(src_item->tags);
+               //duplicate splits
+               //no g_free here to avoid free the src tags (memdup copie dthe ptr)
+               new_item->splits = da_splits_clone(src_item->splits);
+               if( da_splits_length (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->memo != NULL)
                        g_free(item->memo);
-               da_splits_free(item->splits);
-               //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared            
-               
+               if(item->splits != NULL)
+                       da_split_destroy(item->splits);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -111,11 -117,70 +120,70 @@@ guint da_archive_length(void
  }
  
  
 -              max_key = MAX(item->key, max_key);              
+ /* append a fav with an existing key (from xml file only) */
+ gboolean
+ da_archive_append(Archive *item)
+ {
+       GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item);
+       return TRUE;
+ }
+ gboolean
+ da_archive_append_new(Archive *item)
+ {
+       item->key = da_archive_get_max_key() + 1;
+       GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, item);
+       return TRUE;
+ }
+ guint32
+ da_archive_get_max_key(void)
+ {
+ GList *tmplist = g_list_first(GLOBALS->arc_list);
+ guint32 max_key = 0;
+       while (tmplist != NULL)
+       {
+       Archive *item = tmplist->data;
 -      
++              max_key = MAX(item->key, max_key);
+               tmplist = g_list_next(tmplist);
+       }
++
+       return max_key;
+ }
+ Archive *
+ da_archive_get(guint32 key)
+ {
+ GList *tmplist;
+ Archive *retval = NULL;
+       tmplist = g_list_first(GLOBALS->arc_list);
+       while (tmplist != NULL)
+       {
+       Archive *item = tmplist->data;
+               if(item->key == key)
+               {
+                       retval = item;
+                       break;
+               }
+               tmplist = g_list_next(tmplist);
+       }
+       return retval;
+ }
  void da_archive_consistency(Archive *item)
  {
  Account *acc;
  Category *cat;
  Payee *pay;
+ guint nbsplit;
  
        // check category exists
        cat = da_cat_get(item->kcat);
                item->kcat = 0;
                GLOBALS->changes_count++;
        }
-       
-       split_cat_consistency(item->splits);
-       
 -      //#1340142 check split category         
++      //#1340142 check split category
+       if( item->splits != NULL )
+       {
+               nbsplit = da_splits_consistency(item->splits);
+               //# 1416624 empty category when split
+               if(nbsplit > 0 && item->kcat > 0)
+               {
+                       g_warning("txn consistency: fixed invalid cat on split txn");
+                       item->kcat = 0;
+                       GLOBALS->changes_count++;
+               }
+       }
 -      
++
        // check payee exists
        pay = da_pay_get(item->kpay);
        if(pay == NULL)
@@@ -169,13 -245,15 +248,15 @@@ Archive *da_archive_init_from_transacti
        arc->kpay               = txn->kpay;
        arc->kcat               = txn->kcat;
        if(txn->memo != NULL)
-               arc->memo       = g_strdup(txn->memo);
+               arc->memo = g_strdup(txn->memo);
        else
-               arc->memo       = g_strdup(_("(new archive)"));
+               arc->memo = g_strdup(_("(new archive)"));
  
-       if( da_splits_clone(txn->splits, arc->splits) > 0)
+       arc->tags    = tags_clone(txn->tags);
+       arc->splits  = da_splits_clone(txn->splits);
+       if( da_splits_length (arc->splits) > 0 )
                arc->flags |= OF_SPLIT; //Flag that Splits are active
--      
++
        return arc;
  }
  
@@@ -211,7 -289,7 +292,7 @@@ guint32 nextpostdate = nextdate
  
        /* get the final post date and free */
        nextpostdate = g_date_get_julian(tmpdate);
--      
++
        return nextpostdate;
  }
  
@@@ -239,7 -317,7 +320,7 @@@ gint shift
  
  
        finalpostdate = postdate;
--      
++
        tmpdate = g_date_new_julian(finalpostdate);
        /* manage weekend exception */
        if( arc->weekend > 0 )
                        }
                }
        }
--      
++
        /* get the final post date and free */
        finalpostdate = g_date_get_julian(tmpdate);
        g_date_free(tmpdate);
--      
++
        return finalpostdate;
  }
  
@@@ -314,10 -392,10 +395,10 @@@ guint32 nblate = 0
  
        if(arc->flags & OF_LIMIT)
                nblate = MIN(nblate, arc->limit);
--      
++
        nblate = MIN(nblate, 11);
        */
--      
++
  
        // pre 5.1 way
        post_date = g_date_new();
                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)
+               if( nblate >= 11 || ( (arc->flags & OF_LIMIT) && (nblate >= arc->limit) ) )
                        break;
        }
  
@@@ -373,7 -451,7 +454,7 @@@ gushort lastday
                        }
  
                        arc->daygap = CLAMP(lastday - g_date_get_day(post_date), 0, 3);
--              
++
                        DB( g_print(" daygap is %d\n", arc->daygap) );
                }
                else
@@@ -410,10 -488,10 +491,10 @@@ GDate *today, *maxdate
        DB( g_print("\n[scheduled] date_get_post_max\n") );
  
        //add until xx of the next month (excluded)
--      if(GLOBALS->auto_smode == 0)    
++      if(GLOBALS->auto_smode == 0)
        {
                DB( g_print(" - max is %d of next month\n", GLOBALS->auto_weekday) );
--              
++
                today = g_date_new_julian(GLOBALS->today);
  
                //we compute user xx weekday of next month
                g_date_set_day(maxdate, GLOBALS->auto_weekday);
                if(g_date_get_day (today) >= GLOBALS->auto_weekday)
                        g_date_add_months(maxdate, 1);
--              
++
                nbdays = g_date_days_between(today, maxdate);
--      
++
                g_date_free(maxdate);
                g_date_free(today);
        }
@@@ -454,7 -532,7 +535,7 @@@ Transaction *txn
        maxpostdate = scheduled_date_get_post_max();
  
        txn = da_transaction_malloc();
--      
++
        list = g_list_first(GLOBALS->arc_list);
        while (list != NULL)
        {
                                while(mydate < maxpostdate)
                                {
                                        DB( hb_print_date(mydate, arc->memo) );
--                                      
++
                                        da_transaction_init_from_template(txn, arc);
                                        txn->date = scheduled_get_postdate(arc, mydate);
                                        /* todo: ? fill in cheque number */
  
-                                       transaction_add(txn);
+                                       transaction_add(NULL, txn);
                                        GLOBALS->changes_count++;
                                        count++;
  
@@@ -500,7 -578,7 +581,7 @@@ nextarchive
        }
  
        da_transaction_free (txn);
--      
++
        return count;
  }
  
diff --combined src/hb-assign.c
index 1a89a45fc5a9a358aa8ff88299330004815b2ece,3d3f2a943a54152448311a4116cdf95bf0550eb1..21a88fdaef3ad08b922505b8df24636707c4e7f6
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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 948788649f591bcd242a47e0c898993beff7ce08,3dc34e402c382dd06e66772dd6d3714399e628b6..e26b2b8117d8ca687b4b1321bc202d852004b089
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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,13 -40,14 +43,14 @@@ 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)
        {
                //duplicate the string
-               new_item->name          = g_strdup(src_item->name);
+               new_item->name = g_strdup(src_item->name);
+               new_item->fullname = g_strdup(src_item->fullname);
        }
        return new_item;
  }
@@@ -59,12 -57,13 +60,13 @@@ 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);
+               g_free(item->fullname);
 +              rc_free(item);
        }
  }
  
@@@ -73,7 -72,7 +75,7 @@@ Category 
  da_cat_malloc(void)
  {
        DB( g_print("da_cat_malloc\n") );
 -      return g_malloc0(sizeof(Category));
 +      return rc_alloc(sizeof(Category));
  }
  
  
@@@ -95,7 -94,9 +97,9 @@@ Category *item
  
        // insert our 'no category'
        item = da_cat_malloc();
+       item->key = 0;
        item->name = g_strdup("");
+       item->fullname = g_strdup("");
        da_cat_insert(item);
  }
  
@@@ -114,15 -115,30 +118,30 @@@ da_cat_length(void
  }
  
  
+ static void
+ da_cat_max_key_ghfunc(gpointer key, Category *cat, guint32 *max_key)
+ {
+       *max_key = MAX(*max_key, cat->key);
+ }
  
  /**
-  * da_cat_remove_grfunc:
+  * da_cat_get_max_key:
   *
-  * GRFunc to get the max id
+  * Get the biggest key from the GHashTable
   *
-  * Return value: TRUE if the key/value must be deleted
+  * Return value: the biggest key value
   *
   */
+ guint32
+ da_cat_get_max_key(void)
+ {
+ guint32 max_key = 0;
+       g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)da_cat_max_key_ghfunc, &max_key);
+       return max_key;
+ }
  static gboolean
  da_cat_remove_grfunc(gpointer key, Category *cat, guint32 *remkey)
  {
  guint
  da_cat_remove(guint32 key)
  {
-       DB( g_print("da_cat_remove %d\n", key) );
+       DB( g_print("\nda_cat_remove %d\n", key) );
  
        return g_hash_table_foreach_remove(GLOBALS->h_cat, (GHRFunc)da_cat_remove_grfunc, &key);
  }
  
 -      
+ static void
+ da_cat_build_fullname(Category *item)
+ {
+ Category *parent;
+       g_free(item->fullname);
+       if( item->parent == 0 )
+               item->fullname = g_strdup(item->name);
+       else
+       {
+               parent = da_cat_get(item->parent);
+               if( parent != NULL )
+                       item->fullname = g_strconcat(parent->name, ":", item->name, NULL);
+       }
 -      
++
+       DB( g_print("- updated %d:'%s' fullname='%s'\n", item->key, item->name, item->fullname) );
+ }
+ static void
+ da_cat_rename(Category *item, gchar *newname)
+ {
+       DB( g_print("- renaming %s' => '%s'\n", item->name, newname) );
 -      
++
+       g_free(item->name);
+       item->name = g_strdup(newname);
+       da_cat_build_fullname(item);
 -              
++
+       if( item->parent == 0 )
+       {
+       GHashTableIter iter;
+       gpointer value;
+               DB( g_print("- updating subcat fullname\n") );
 -                      
++
+               g_hash_table_iter_init (&iter, GLOBALS->h_cat);
+               while (g_hash_table_iter_next (&iter, NULL, &value))
+               {
+               Category *subcat = value;
++
+                       if( subcat->parent == item->key )
+                               da_cat_build_fullname(subcat);
+               }
+       }
+ }
  /**
   * da_cat_insert:
   *
@@@ -162,12 -229,16 +232,16 @@@ da_cat_insert(Category *item
  {
  guint32 *new_key;
  
-       DB( g_print("da_cat_insert\n") );
+       DB( g_print("\nda_cat_insert\n") );
+       DB( g_print("- '%s'\n", item->name) );
 -      
 +
        new_key = g_new0(guint32, 1);
        *new_key = item->key;
        g_hash_table_insert(GLOBALS->h_cat, new_key, item);
  
 -      
+       da_cat_build_fullname(item);
++
        return TRUE;
  }
  
   * Return value: TRUE if inserted
   *
   */
+ // used only to add cat/subcat from ui_category with the 2 inputs
  gboolean
  da_cat_append(Category *cat)
  {
  Category *existitem;
- guint32 *new_key;
- gchar *fullname;
-       DB( g_print("da_cat_append\n") );
-       if( cat->name != NULL)
-       {
-               fullname = da_cat_get_fullname(cat);
-               existitem = da_cat_get_by_fullname( fullname );
-               g_free(fullname);
  
-               if( existitem == NULL )
-               {
-                       new_key = g_new0(guint32, 1);
-                       *new_key = da_cat_get_max_key() + 1;
-                       cat->key = *new_key;
-                       DB( g_print(" -> insert id: %d\n", *new_key) );
+       DB( g_print("\nda_cat_append\n") );
  
-                       g_hash_table_insert(GLOBALS->h_cat, new_key, cat);
-                       return TRUE;
-               }
+       if( !cat->fullname )
+               da_cat_build_fullname(cat);
 -      
 +
+       existitem = da_cat_get_by_fullname( cat->fullname );
+       if( existitem == NULL )
+       {
+               cat->key = da_cat_get_max_key() + 1;
+               da_cat_insert(cat);
+               return TRUE;
        }
  
        DB( g_print(" -> %s already exist\n", cat->name) );
        return FALSE;
  }
  
  
- /**
-  * da_cat_max_key_ghfunc:
-  *
-  * GHFunc for biggest key
-  *
-  */
- static void
- da_cat_max_key_ghfunc(gpointer key, Category *cat, guint32 *max_key)
- {
-       *max_key = MAX(*max_key, cat->key);
- }
- /**
-  * da_cat_get_max_key:
-  *
-  * Get the biggest key from the GHashTable
-  *
-  * Return value: the biggest key value
-  *
-  */
- guint32
- da_cat_get_max_key(void)
- {
- guint32 max_key = 0;
  
-       g_hash_table_foreach(GLOBALS->h_cat, (GHFunc)da_cat_max_key_ghfunc, &max_key);
-       return max_key;
- }
  
- /**
-  * da_cat_get_fullname:
-  *
-  * Get category the fullname 'xxxx:yyyyy'
-  *
-  * Return value: the category fullname (free it with g_free)
-  *
-  */
- gchar *
- da_cat_get_fullname(Category *cat)
+ /* fullname i.e. car:refuel */
+ struct fullcatcontext
  {
- Category *parent;
-       if( cat->parent == 0 )
-               return g_strdup(cat->name);
-       else
-       {
-               parent = da_cat_get(cat->parent);
-               if( parent )
-               {
-                       return g_strdup_printf("%s:%s", parent->name, cat->name);
-               }
-       }
-       return NULL;
- }
+       guint32 parent;
+       gchar   *name;
+ };
  
  
- /**
-  * da_cat_name_grfunc:
-  *
-  * GRFunc to get the max id
-  *
-  * Return value: TRUE if the key/value pair match our name
-  *
-  */
  static gboolean
- da_cat_name_grfunc(gpointer key, Category *cat, gchar *name)
+ da_cat_fullname_grfunc(gpointer key, Category *item, struct fullcatcontext *ctx)
  {
  
//    DB( g_print("%s == %s\n", name, cat->name) );
-       if( name && cat->name)
      //DB( g_print("'%s' == '%s'\n", ctx->name, item->name) );
+       if( item->parent == ctx->parent )
        {
-               if(!strcasecmp(name, cat->name))
-                       return TRUE;
+               if( ctx->name && item->name )
+                       if(!strcasecmp(ctx->name, item->name))
+                               return TRUE;
        }
        return FALSE;
  }
  
- /**
-  * da_cat_get_key_by_name:
-  *
-  * Get a category key by its name
-  *
-  * Return value: the category key or -1 if not found
-  *
-  */
- guint32
- da_cat_get_key_by_name(gchar *name)
- {
- Category *cat;
-       DB( g_print("da_cat_get_key_by_name\n") );
-       cat = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_name_grfunc, name);
-       if( cat == NULL)
-               return -1;
-       return cat->key;
- }
  
- /**
-  * da_cat_get_by_name:
-  *
-  * Get a category structure by its name
-  *
-  * Return value: Category * or NULL if not found
-  *
-  */
- Category *
- da_cat_get_by_name(gchar *name)
+ static Category *da_cat_get_by_name_find_internal(guint32 parent, gchar *name)
  {
      DB( g_print("da_cat_get_by_name\n") );
struct fullcatcontext ctx;
  
-       return g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_name_grfunc, name);
+       ctx.parent = parent;
+       ctx.name   = name;
+       DB( g_print("- searching %s %d '%s'\n", (parent == 0) ? "lv1cat" : "lv2cat", parent, name) );
+       return g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
  }
  
  
- /* fullname i.e. car:refuel */
- struct fullcatcontext
+ static gchar **da_cat_get_by_fullname_split_clean(gchar *rawfullname, guint *outlen)
  {
      guint   parent;
      gchar   *name;
};
gchar **partstr = g_strsplit(rawfullname, ":", 2);
guint len = g_strv_length(partstr);
gboolean valid = TRUE;
  
+       DB( g_print("- spliclean '%s' - %d parts\n", rawfullname, g_strv_length(partstr)) );
  
- static gboolean
- da_cat_fullname_grfunc(gpointer key, Category *item, struct fullcatcontext *ctx)
- {
+       if( outlen != NULL )
+               *outlen = len;
 -      
 +
-       //DB( g_print("'%s' == '%s'\n", ctx->name, item->name) );
-       if( item->parent == ctx->parent )
+       if(len >= 1)
        {
-               if(!strcasecmp(ctx->name, item->name))
-                       return TRUE;
+               g_strstrip(partstr[0]);
+               if( strlen(partstr[0]) == 0 )
+                  valid = FALSE;
+               if(len == 2)
+               {
+                       g_strstrip(partstr[1]);
+                       if( strlen(partstr[1]) == 0 )
+                          valid = FALSE;
+          }
        }
-       return FALSE;
+       if(valid == TRUE)
+               return partstr;
+       DB( g_print("- is invalid\n") );
+       g_strfreev(partstr);
+       return NULL;
  }
  
  Category *
- da_cat_get_by_fullname(gchar *fullname)
+ da_cat_get_by_fullname(gchar *rawfullname)
  {
- struct fullcatcontext ctx;
- gchar **typestr;
- Category *item = NULL;
+ gchar **partstr;
+ Category *parent = NULL;
+ Category *retval = NULL;
+ guint len;
 -      
 +
-       DB( g_print("da_cat_get_by_fullname\n") );
+       DB( g_print("\nda_cat_get_by_fullname\n") );
  
-       typestr = g_strsplit(fullname, ":", 2);
-       if( g_strv_length(typestr) == 2 )
+       if( rawfullname )
        {
-               ctx.parent = 0;
-               ctx.name = typestr[0];
-               DB( g_print(" [x:x] try to find the parent : '%s'\n", typestr[0]) );
-               Category *parent = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
-               if( parent != NULL )
+               if( (partstr = da_cat_get_by_fullname_split_clean(rawfullname, &len)) != NULL )
                {
-                       ctx.parent = parent->key;
-                       ctx.name = typestr[1];
+                       if( len >= 1 )
+                       {
+                               parent = da_cat_get_by_name_find_internal(0, partstr[0]);
+                               retval = parent;
+                       }
 -                      
 +
-                       DB( g_print(" [x:x] and searching sub %d '%s'\n", ctx.parent, ctx.name) );
+                       if( len == 2 && parent != NULL )
+                       {
+                               retval = da_cat_get_by_name_find_internal(parent->key, partstr[1]);
+                       }
  
-                       item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
+                       g_strfreev(partstr);
                }
        }
-       else
-       {
-               ctx.parent = 0;
-               ctx.name = fullname;
-               DB( g_print(" [x] try to '%s'\n", fullname) );
-               item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
-       }
-       g_strfreev(typestr);
 -              
 +
-       DB( g_print(" return value %p\n", item) );
-       return item;
+       return retval;
  }
  
  
   *
   */
  Category *
- da_cat_append_ifnew_by_fullname(gchar *fullname, gboolean imported)
+ da_cat_append_ifnew_by_fullname(gchar *rawfullname)
  {
- struct fullcatcontext ctx;
- gchar **typestr;
- Category *newcat, *item, *retval = NULL;
- guint32 *new_key;
+ gchar **partstr;
+ Category *parent = NULL;
+ Category *newcat = NULL;
+ Category *retval = NULL;
+ guint len;
  
-       DB( g_print("da_cat_append_ifnew_by_fullname\n") );
+       DB( g_print("\nda_cat_append_ifnew_by_fullname\n") );
  
-       DB( g_print(" -> fullname: '%s' %d\n", fullname, strlen(fullname)) );
-       if( strlen(fullname) > 0 )
+       if( rawfullname )
        {
-               typestr = g_strsplit(fullname, ":", 2);
-               /* if we have a subcategory : aaaa:bbb */
-               if( g_strv_length(typestr) == 2 )
+               if( (partstr = da_cat_get_by_fullname_split_clean(rawfullname, &len)) != NULL )
                {
-                       ctx.parent = 0;
-                       ctx.name = typestr[0];
-                       DB( g_print(" try to find the parent:'%s'\n", typestr[0]) );
-                       Category *parent = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
-                       if( parent == NULL )
-                       {
-                               DB( g_print(" -> not found\n") );
-                               // append a new category
-                               new_key = g_new0(guint32, 1);
-                               *new_key = da_cat_get_max_key() + 1;
-                               newcat = da_cat_malloc();
-                               newcat->key = *new_key;
-                               newcat->name = g_strdup(typestr[0]);
-                               newcat->imported = imported;
-                               parent = newcat;
-                               DB( g_print(" -> insert cat '%s' id: %d\n", newcat->name, newcat->key) );
-                               g_hash_table_insert(GLOBALS->h_cat, new_key, newcat);
-                       }
-                       ctx.parent = parent->key;
-                       ctx.name = typestr[1];
-                       DB( g_print(" searching %d '%s'\n", ctx.parent, ctx.name) );
-                       item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
-                       if( item == NULL )
+                       if( len >= 1 )
                        {
-                               // append a new subcategory
-                               new_key = g_new0(guint32, 1);
-                               *new_key = da_cat_get_max_key() + 1;
-                               newcat = da_cat_malloc();
-                               newcat->key = *new_key;
-                               newcat->parent = parent->key;
-                               newcat->name = g_strdup(typestr[1]);
-                               newcat->imported = imported;
-                               newcat->flags |= GF_SUB;
-                               //#1713413 take parent type into account
-                               if(parent->flags & GF_INCOME)
-                                       newcat->flags |= GF_INCOME;
-                               DB( g_print(" -> insert subcat '%s' id: %d\n", newcat->name, newcat->key) );
-                               g_hash_table_insert(GLOBALS->h_cat, new_key, newcat);
-                               retval = newcat;
+                               parent = da_cat_get_by_name_find_internal(0, partstr[0]);
+                               if( parent == NULL )
+                               {
+                                       parent = da_cat_malloc();
+                                       parent->key = da_cat_get_max_key() + 1;
+                                       parent->name = g_strdup(partstr[0]);
+                                       da_cat_insert(parent);
+                               }
+                               retval = parent;
                        }
-                       else
-                               retval = item;
-               }
-               /* this a single category : aaaa */
-               else
-               {
-                       ctx.parent = 0;
-                       ctx.name = typestr[0];
-                       DB( g_print(" searching %d '%s'\n", ctx.parent, ctx.name) );
 -                              
 +
-                       item = g_hash_table_find(GLOBALS->h_cat, (GHRFunc)da_cat_fullname_grfunc, &ctx);
-                       if( item == NULL )
+                       /* if we have a subcategory - xxx:xxx */
+                       if( len == 2 && parent != NULL )
                        {
-                               // append a new category
-                               new_key = g_new0(guint32, 1);
-                               *new_key = da_cat_get_max_key() + 1;
-                               newcat = da_cat_malloc();
-                               newcat->key = *new_key;
-                               newcat->name = g_strdup(typestr[0]);
-                               newcat->imported = imported;
-                               DB( g_print(" -> insert cat '%s' id: %d\n", newcat->name, newcat->key) );
-                               g_hash_table_insert(GLOBALS->h_cat, new_key, newcat);
+                               newcat = da_cat_get_by_name_find_internal(parent->key, partstr[1]);
+                               if( newcat == NULL )
+                               {
+                                       newcat = da_cat_malloc();
+                                       newcat->key = da_cat_get_max_key() + 1;
+                                       newcat->parent = parent->key;
+                                       newcat->name = g_strdup(partstr[1]);
+                                       newcat->flags |= GF_SUB;
+                                       //#1713413 take parent type into account
+                                       if(parent->flags & GF_INCOME)
+                                               newcat->flags |= GF_INCOME;
+                                       da_cat_insert(newcat);
+                               }
                                retval = newcat;
                        }
-                       else
-                               retval = item;
 -                                 
 +
+                       g_strfreev(partstr);
                }
-               g_strfreev(typestr);
        }
  
        return retval;
  }
  
  
  /**
   * da_cat_get:
   *
@@@ -538,6 -459,18 +462,18 @@@ da_cat_get(guint32 key
  }
  
  
+ gchar *da_cat_get_name(Category *item)
+ {
+ gchar *name = NULL;
+       if(item != NULL)
+       {
+               name = item->key == 0 ? _("(no category)") : item->fullname;
+       }
+       return name;
+ }
  void da_cat_consistency(Category *item)
  {
  gboolean isIncome;
                //check for existing parent
                if( da_cat_get(item->parent) == NULL )
                {
-               Category *parent = da_cat_append_ifnew_by_fullname ("orphaned", FALSE);
+               Category *parent = da_cat_append_ifnew_by_fullname ("orphaned");
  
                        item->parent = parent->key;
-                       
+                       da_cat_build_fullname(item);
                        g_warning("category consistency: fixed missing parent %d", item->parent);
                }
        }
                        GLOBALS->changes_count++;
                }
        }
-       
-       g_strstrip(item->name);
+       if( item->name != NULL )
+               g_strstrip(item->name);
+       else
+       {
+               item->name = g_strdup("void");
+               da_cat_build_fullname(item);
+               g_warning("category consistency: fixed null name");
+               GLOBALS->changes_count++;
+       }
 -      
++
  }
  
  
@@@ -603,31 -545,31 +548,31 @@@ da_cat_debug_list(void
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  guint32 category_report_id(guint32 key, gboolean subcat)
  {
- Category *catentry = da_cat_get(key);
  guint32 retval = 0;
  
-       if(catentry)
+       if(subcat == FALSE)
        {
-               if(subcat == FALSE)
-               {
+       Category *catentry = da_cat_get(key);
+               if(catentry)
                        retval = (catentry->flags & GF_SUB) ? catentry->parent : catentry->key;
-               }
-               else
-               {
-                       retval = catentry->key;
-               }
        }
+       else
+       {
+               retval = key;
+       }
+       //DB( g_print("- cat '%s' reportid = %d\n", catentry->name, retval) );
        return retval;
  }
  
  
--void 
++void
  category_delete_unused(void)
  {
  GList *lcat, *list;
--      
++
        lcat = list = g_hash_table_get_values(GLOBALS->h_cat);
        while (list != NULL)
        {
  }
  
  
--static void 
++static void
  category_fill_usage_count(guint32 kcat)
  {
  Category *cat = da_cat_get (kcat);
@@@ -696,16 -638,16 +641,16 @@@ guint i, nbsplit
                        //#1689308 count split as well
                        if( txn->flags & OF_SPLIT )
                        {
-                               nbsplit = da_splits_count(txn->splits);
+                               nbsplit = da_splits_length(txn->splits);
                                for(i=0;i<nbsplit;i++)
                                {
-                               Split *split = txn->splits[i];
-                                       
+                               Split *split = da_splits_get(txn->splits, i);
 -                                      
++
                                        category_fill_usage_count(split->kcat);
                                }
                        }
                        else
--                              category_fill_usage_count(txn->kcat);           
++                              category_fill_usage_count(txn->kcat);
  
                        lnk_txn = g_list_next(lnk_txn);
                }
                //#1689308 count split as well
                if( entry->flags & OF_SPLIT )
                {
-                       nbsplit = da_splits_count(entry->splits);
+                       nbsplit = da_splits_length(entry->splits);
                        for(i=0;i<nbsplit;i++)
                        {
-                       Split *split = entry->splits[i];
-                               
+                       Split *split = da_splits_get(entry->splits, i);
 -                              
++
                                category_fill_usage_count(split->kcat);
                        }
                }
@@@ -778,7 -720,7 +723,7 @@@ guint i, nbsplit
                while (lnk_txn != NULL)
                {
                Transaction *txn = lnk_txn->data;
--              
++
                        if(txn->kcat == key1)
                        {
                                txn->kcat = key2;
                        }
  
                        // move split category #1340142
-                       nbsplit = da_splits_count(txn->splits);
+                       nbsplit = da_splits_length(txn->splits);
                        for(i=0;i<nbsplit;i++)
                        {
-                       Split *split = txn->splits[i];
+                       Split *split = da_splits_get(txn->splits, i);
  
                                if( split->kcat == key1 )
                                {
  
                        lnk_txn = g_list_next(lnk_txn);
                }
--              
++
                lnk_acc = g_list_next(lnk_acc);
        }
        g_list_free(lst_acc);
@@@ -841,7 -783,7 +786,7 @@@ gchar *fullname = NULL
  gchar *stripname;
  gboolean retval;
  
-       DB( g_print("(category) rename\n") );
+       DB( g_print("\n(category) rename\n") );
  
        stripname = g_strdup(newname);
        g_strstrip(stripname);
  
        if( existitem != NULL && existitem->key != item->key)
        {
-               DB( g_print("error, same name already exist with other key %d <> %d\n",existitem->key, item->key) );
+               DB( g_print("error, same name already exist with other key %d <> %d\n",existitem->key, item->key) );
                retval = FALSE;
        }
        else
        {
-               DB( g_print(" -renaming\n") );
+               DB( g_print("renaming\n") );
  
-               g_free(item->name);
-               item->name = g_strdup(stripname);
+               da_cat_rename (item, stripname);
                retval = TRUE;
        }
  
  }
  
  
- static gint category_glist_name_compare_func(Category *c1, Category *c2)
+ static gint
+ category_glist_name_compare_func(Category *c1, Category *c2)
  {
- gchar *name1, *name2;
  gint retval = 0;
  
        if( c1 != NULL && c2 != NULL )
        {
-               name1 = da_cat_get_fullname(c1);
-               name2 = da_cat_get_fullname(c2);
-               retval = hb_string_utf8_compare(name1, name2);
-               g_free(name2);
-               g_free(name1);
+               retval = hb_string_utf8_compare(c1->fullname, c2->fullname);
        }
        return retval;
  }
  
  
- static gint category_glist_key_compare_func(Category *a, Category *b)
+ static gint
+ category_glist_key_compare_func(Category *a, Category *b)
  {
  gint ka, kb, retval = 0;
  
  }
  
  
- GList *category_glist_sorted(gint column)
+ GList *
+ category_glist_sorted(gint column)
  {
  GList *list = g_hash_table_get_values(GLOBALS->h_cat);
  
@@@ -964,16 -901,13 +904,13 @@@ gint type = 0
  const gchar *encoding;
  
        encoding = homebank_file_getencoding(filename);
-                       DB( g_print(" -> encoding should be %s\n", encoding) );
+       DB( g_print(" -> encoding should be %s\n", encoding) );
  
        retval = TRUE;
        *error = NULL;
        io = g_io_channel_new_file(filename, "r", NULL);
        if(io != NULL)
        {
                if( encoding != NULL )
                {
                        g_io_channel_set_encoding(io, encoding, NULL);
                                                        fullcatname = g_strdup_printf("%s:%s", lastcatname, str_array[2]);
                                                }
  
-                                               DB( g_print(" + fullcatname %s\n", fullcatname) );
-                                               item = da_cat_append_ifnew_by_fullname(fullcatname, FALSE);
+                                               item = da_cat_append_ifnew_by_fullname(fullcatname);
                                                DB( g_print(" + item %p\n", item) );
  
                                                if( item != NULL)
                                                g_strfreev (str_array);
                                        }
                                }
                        }
                        g_free(tmpstr);
                }
                g_io_channel_unref (io);
        }
  
        g_free(lastcatname);
  }
  
  
  gboolean
  category_save_csv(gchar *filename, gchar **error)
  {
@@@ -1076,7 -1002,6 +1005,6 @@@ GIOChannel *io
  gchar *outstr;
  GList *lcat, *list;
  
        io = g_io_channel_new_file(filename, "w", NULL);
        if(io != NULL)
        {
                g_io_channel_unref (io);
        }
  
        return retval;
  }
  
- gint category_type_get(Category *item)
+ gint
+ category_type_get(Category *item)
  {
        if( (item->flags & (GF_INCOME)) )
                return 1;
  }
  
  
+ gchar
+ category_get_type_char(Category *item)
+ {
+       return (item->flags & GF_INCOME) ? '+' : '-';
+ }
  
- static gint category_change_type_eval(Category *item, gboolean isIncome)
 -static gint 
++static gint
+ category_change_type_eval(Category *item, gboolean isIncome)
  {
        if( (item->flags & (GF_INCOME)) && !isIncome )
                return 1;
  }
  
  
- gint category_change_type(Category *item, gboolean isIncome)
 -gint 
++gint
+ category_change_type(Category *item, gboolean isIncome)
  {
  gint changes = 0;
  GList *lcat, *list;
  
        changes += category_change_type_eval(item, isIncome);
--      
++
        item->flags &= ~(GF_INCOME);    //delete flag
        if(isIncome == TRUE)
                item->flags |= GF_INCOME;
  }
  
  
  /**
   * category_find_preset:
   *
   * Return value: a pathname to the file or NULL
   *
   */
- gchar *category_find_preset(gchar **lang)
+ gchar *
+ category_find_preset(gchar **lang)
  {
  gchar **langs;
  gchar *filename;
@@@ -1220,4 -1152,3 +1155,3 @@@ guint i
        return NULL;
  }
  
diff --combined src/hb-payee.c
index 558b76dd526c364a4a4af2b65c81c1757527a9bf,fa49406810fa077dd56bb8cc5fb109ad9448f62c..fc1829b00b8588e32fc55bde4ba6507864b08707
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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                                                                                */
@@@ -40,16 -37,20 +40,20 @@@ extern struct HomeBank *GLOBALS
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
+ //Payee *
+ //da_pay_clone
  void
  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 -59,7 +62,7 @@@ Payee 
  da_pay_malloc(void)
  {
        DB( g_print("da_pay_malloc\n") );
 -      return g_malloc0(sizeof(Payee));
 +      return rc_alloc(sizeof(Payee));
  }
  
  
@@@ -86,20 -87,6 +90,6 @@@ Payee *item
  
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
- static void da_pay_max_key_ghfunc(gpointer key, Payee *item, guint32 *max_key)
- {
-       *max_key = MAX(*max_key, item->key);
- }
- static gboolean da_pay_name_grfunc(gpointer key, Payee *item, gchar *name)
- {
-       if( name && item->name )
-       {
-               if(!strcasecmp(name, item->name))
-                       return TRUE;
-       }
-       return FALSE;
- }
  
  /**
   * da_pay_length:
@@@ -112,29 -99,30 +102,30 @@@ da_pay_length(void
        return g_hash_table_size(GLOBALS->h_pay);
  }
  
- /*
- gboolean
- da_pay_create_none(void)
- {
- Payee *pay;
- guint32 *new_key;
-       DB( g_print("da_pay_insert none\n") );
  
-       pay = da_pay_malloc();
-       new_key = g_new0(guint32, 1);
-       *new_key = 0;
-       pay->key = 0;
-       pay->name = g_strdup("");
-       DB( g_print(" -> insert id: %d\n", *new_key) );
+ static void 
+ da_pay_max_key_ghfunc(gpointer key, Payee *item, guint32 *max_key)
+ {
+       *max_key = MAX(*max_key, item->key);
+ }
  
-       g_hash_table_insert(GLOBALS->h_pay, new_key, pay);
  
+ /**
+  * da_pay_get_max_key:
+  *
+  * Get the biggest key from the GHashTable
+  *
+  * Return value: the biggest key value
+  *
+  */
+ guint32
+ da_pay_get_max_key(void)
+ {
+ guint32 max_key = 0;
  
-       return TRUE;
+       g_hash_table_foreach(GLOBALS->h_pay, (GHFunc)da_pay_max_key_ghfunc, &max_key);
+       return max_key;
  }
- */
  
  
  /**
@@@ -153,6 -141,7 +144,7 @@@ da_pay_remove(guint32 key
        return g_hash_table_remove(GLOBALS->h_pay, &key);
  }
  
  /**
   * da_pay_insert:
   *
@@@ -188,51 -177,59 +180,59 @@@ gboolea
  da_pay_append(Payee *item)
  {
  Payee *existitem;
- guint32 *new_key;
  
        DB( g_print("da_pay_append\n") );
  
-       /* ensure no duplicate */
-       //g_strstrip(item->name);
-       if( item->name != NULL )
+       existitem = da_pay_get_by_name( item->name );
+       if( existitem == NULL )
        {
-               existitem = da_pay_get_by_name( item->name );
-               if( existitem == NULL )
-               {
-                       new_key = g_new0(guint32, 1);
-                       *new_key = da_pay_get_max_key() + 1;
-                       item->key = *new_key;
-                       DB( g_print(" -> append id: %d\n", *new_key) );
-                       g_hash_table_insert(GLOBALS->h_pay, new_key, item);
-                       return TRUE;
-               }
+               item->key = da_pay_get_max_key() + 1;
+               da_pay_insert(item);
+               return TRUE;
        }
  
        DB( g_print(" -> %s already exist: %d\n", item->name, item->key) );
        return FALSE;
  }
  
  /**
-  * da_pay_get_max_key:
+  * da_pay_append_if_new:
   *
-  * Get the biggest key from the GHashTable
+  * append a new payee into the GHashTable
   *
-  * Return value: the biggest key value
+  * Return value: existing or new payee
   *
   */
- guint32
- da_pay_get_max_key(void)
+ Payee *
+ da_pay_append_if_new(gchar *rawname)
  {
guint32 max_key = 0;
Payee *retval = NULL;
  
-       g_hash_table_foreach(GLOBALS->h_pay, (GHFunc)da_pay_max_key_ghfunc, &max_key);
-       return max_key;
+       retval = da_pay_get_by_name(rawname);
+       if(retval == NULL)
+       {
+               retval = da_pay_malloc();
+               retval->key = da_pay_get_max_key() + 1;
+               retval->name = g_strdup(rawname);
+               g_strstrip(retval->name);
+               da_pay_insert(retval);
+       }
+       return retval;
  }
  
  
+ static gboolean
+ da_pay_name_grfunc(gpointer key, Payee *item, gchar *name)
+ {
+       if( name && item->name )
+       {
+               if(!strcasecmp(name, item->name))
+                       return TRUE;
+       }
+       return FALSE;
+ }
  
  
  /**
   *
   */
  Payee *
- da_pay_get_by_name(gchar *name)
+ da_pay_get_by_name(gchar *rawname)
  {
+ Payee *retval = NULL;
+ gchar *stripname;
        DB( g_print("da_pay_get_by_name\n") );
  
-       return g_hash_table_find(GLOBALS->h_pay, (GHRFunc)da_pay_name_grfunc, name);
+       if( rawname )
+       {
+               stripname = g_strdup(rawname);
+               g_strstrip(stripname);
+               if( strlen(stripname) == 0 )
+                       retval = da_pay_get(0);
+               else
+                       retval = g_hash_table_find(GLOBALS->h_pay, (GHRFunc)da_pay_name_grfunc, stripname);
+               g_free(stripname);
+       }
+       return retval;
  }
  
  
  /**
   * da_pay_get:
   *
@@@ -273,6 -282,9 +285,9 @@@ da_pay_get(guint32 key
  void da_pay_consistency(Payee *item)
  {
        g_strstrip(item->name);
+       //5.2.4 we drop internal xfer here as it will disapear 
+       if( item->paymode == PAYMODE_INTXFER )
+               item->paymode = PAYMODE_XFER;
  }
  
  
@@@ -454,62 -466,30 +469,30 @@@ payee_rename(Payee *item, const gchar *
  {
  Payee *existitem;
  gchar *stripname;
+ gboolean retval = FALSE;
  
        stripname = g_strdup(newname);
        g_strstrip(stripname);
  
        existitem = da_pay_get_by_name(stripname);
  
-       if( existitem != NULL )
+       if( existitem != NULL && existitem->key != item->key)
        {
-               if( existitem->key == item->key )
-                       return TRUE;
+               DB( g_print("- error, same name already exist with other key %d <> %d\n",existitem->key, item->key) );
+               g_free(stripname);
        }
        else
        {
+               DB( g_print("- renaming\n") );
                g_free(item->name);
-               item->name = g_strdup(stripname);
-               return TRUE;
-       }
-       g_free(stripname);
-       return FALSE;
- }
- /**
-  * payee_append_if_new:
-  *
-  * append a new payee into the GHashTable
-  *
-  * Return value: true/false + new payee
-  *
-  */
- gboolean
- payee_append_if_new(gchar *name, Payee **newpayee)
- {
- gboolean retval = FALSE;
- gchar *stripname = g_strdup(name);
- Payee *item;
-       g_strstrip(stripname);
-       item = da_pay_get_by_name(stripname);
-       if(item == NULL)
-       {
-               item = da_pay_malloc();
-               item->name = g_strdup(stripname);
-               da_pay_append(item);
+               item->name = stripname;
                retval = TRUE;
        }
-       if( newpayee != NULL )
-               *newpayee = item;
-       g_free(stripname);
  
        return retval;
  }
  
  static gint
  payee_glist_name_compare_func(Payee *a, Payee *b)
  {
@@@ -524,7 -504,8 +507,8 @@@ payee_glist_key_compare_func(Payee *a, 
  }
  
  
- GList *payee_glist_sorted(gint column)
+ GList *
+ payee_glist_sorted(gint column)
  {
  GList *list = g_hash_table_get_values(GLOBALS->h_pay);
  
  }
  
  
  gboolean
  payee_load_csv(gchar *filename, gchar **error)
  {
@@@ -548,13 -528,13 +531,13 @@@ const gchar *encoding
  gint nbcol;
  
        encoding = homebank_file_getencoding(filename);
+       DB( g_print(" -> encoding should be %s\n", encoding) );
  
        retval = TRUE;
        *error = NULL;
        io = g_io_channel_new_file(filename, "r", NULL);
        if(io != NULL)
        {
-               DB( g_print(" -> encoding should be %s\n", encoding) );
                if( encoding != NULL )
                {
                        g_io_channel_set_encoding(io, encoding, NULL);
                                        }
                                        else
                                        {
-                                       gboolean added;
                                        Payee *pay = NULL;
-                                       
+                                       Category *cat = NULL;
                                                if( nbcol >= 1 )
                                                {
                                                        DB( g_print(" add pay:'%s' ?\n", str_array[0]) );
-                                                       added = payee_append_if_new(str_array[0], &pay);
-                                                       if(     added )
+                                                       pay = da_pay_append_if_new(str_array[0]);
+                                                       DB( g_print(" pay: %p\n", pay) );
+                                                       if(     pay != NULL )
                                                        {                               
-                                                               DB( g_print(" added: %p\n", pay) );
                                                                GLOBALS->changes_count++;
                                                        }
                                                }
  
                                                if( nbcol == 2 )
                                                {
-                                               Category *cat;
-                                               
                                                        DB( g_print(" add cat:'%s'\n", str_array[1]) );
-                                                       cat = da_cat_append_ifnew_by_fullname(str_array[1], FALSE);
+                                                       cat = da_cat_append_ifnew_by_fullname(str_array[1]);
                                                        
                                                        DB( g_print(" cat: %p %p\n", cat, pay) );
                                                        if( cat != NULL )
@@@ -657,7 -635,7 +638,7 @@@ gchar *outstr
                                        
                                        if( cat != NULL )
                                        {
-                                               fullcatname = da_cat_get_fullname (cat);
+                                               fullcatname = cat->fullname;
                                        }
                                }
  
  
                g_io_channel_unref (io);
        }
  }
  
diff --combined src/hb-preferences.c
index 8a9fb60e810199ca61f6430609098f44b76295bb,7933e34f6ec50d2b68f4fa5ec7a1e5fb85433a26..ec6ce1595a151a544bbf07aa6b8ba2361ed4dfe7
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -289,14 -289,12 +289,15 @@@ void homebank_pref_free(void
  
        g_free(PREFS->language);
  
+       g_free(PREFS->pnl_list_tab);
  
        g_free(PREFS->minor_cur.symbol);
        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));
  }
  
@@@ -323,9 -321,15 +324,15 @@@ gint i
        PREFS->appendscheduled = FALSE;
        PREFS->do_update_currency = FALSE;
  
+       PREFS->bak_is_automatic = TRUE;
+       PREFS->bak_max_num_copies = 5;
        PREFS->heritdate = FALSE;
        PREFS->hidereconciled = FALSE;
        PREFS->showremind = TRUE;
+       //#1673048
+       PREFS->txn_memoacp = TRUE;
+       PREFS->txn_memoacp_days = 365;
  
        PREFS->toolbar_style = 4;       //text beside icons
        PREFS->custom_colors = TRUE;
        PREFS->pnl_upc_col_pay_width = -1;
        PREFS->pnl_upc_col_mem_width = -1;
  
+       i = 0;
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_DATE;         //always displayed
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_MEMO;
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_AMOUNT;
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_INFO;
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_PAYEE;
+       PREFS->lst_impope_columns[i++] = LST_DSPOPE_CATEGORY;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_TAGS;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_CLR;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_STATUS;  //always displayed
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_EXPENSE;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_INCOME;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_BALANCE;
+       PREFS->lst_impope_columns[i++] = -LST_DSPOPE_ACCOUNT;
  
        i = 0;
-       /* prior v4.5
-       PREFS->lst_ope_columns[i++] = LST_DSPOPE_STATUS;
-       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_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_CATEGORY;
-       PREFS->lst_ope_columns[i++] = LST_DSPOPE_TAGS;
-       */
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_STATUS;  //always displayed
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_DATE;    //always displayed
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_INFO;
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_INCOME;
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_BALANCE;
        PREFS->lst_ope_columns[i++] = LST_DSPOPE_MEMO;
+       PREFS->lst_ope_columns[i++] = -LST_DSPOPE_ACCOUNT;
  
        PREFS->lst_ope_sort_id    = LST_DSPOPE_DATE;
        PREFS->lst_ope_sort_order = GTK_SORT_ASCENDING;
  
        for( i=0;i<NUM_LST_DSPOPE;i++)
-               PREFS->lst_ope_col_size[i] = -1;
+               PREFS->lst_ope_col_width[i] = -1;
  
        //PREFS->base_cur.nbdecimal = 2;
        //PREFS->base_cur.separator = TRUE;
  
-       PREFS->date_range_wal = FLT_RANGE_LASTMONTH;
-       PREFS->date_range_txn = FLT_RANGE_LAST12MONTHS;
+       //PREFS->date_range_wal = FLT_RANGE_LASTMONTH;
+       //PREFS->date_range_txn = FLT_RANGE_LAST12MONTHS;
+       //PREFS->date_range_rep = FLT_RANGE_THISYEAR;
+       //v5.2 change to let the example file show things
+       PREFS->date_range_wal = FLT_RANGE_ALLDATE;
+       PREFS->date_range_txn = FLT_RANGE_ALLDATE;
+       PREFS->date_range_rep = FLT_RANGE_ALLDATE;
        PREFS->date_future_nbdays = 0;
-       PREFS->date_range_rep = FLT_RANGE_THISYEAR;
  
        //import/export
        PREFS->dtex_nointro = TRUE;
+       PREFS->dtex_ucfirst = FALSE;
        //PREFS->dtex_datefmt
        PREFS->dtex_ofxname = 1;
        PREFS->dtex_ofxmemo = 2;
        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();
  
  }
@@@ -491,10 -487,12 +507,12 @@@ static void homebank_pref_get_boolean
      const gchar *key,
        gboolean *storage)
  {
+       DB( g_print(" search %s in %s\n", key, group_name) );
  
        if( g_key_file_has_key(key_file, group_name, key, NULL) )
        {
                *storage = g_key_file_get_boolean(key_file, group_name, key, NULL);
+               DB( g_print(" stored boolean %d for %s at %x\n", *storage, key, *storage) );
        }
  }
  
@@@ -504,15 -502,12 +522,12 @@@ static void homebank_pref_get_integer
      const gchar *key,
        gint *storage)
  {
        DB( g_print(" search %s in %s\n", key, group_name) );
  
        if( g_key_file_has_key(key_file, group_name, key, NULL) )
        {
                *storage = g_key_file_get_integer(key_file, group_name, key, NULL);
-               DB( g_print(" store integer %d for %s at %x\n", *storage, key, *storage) );
+               DB( g_print(" stored integer %d for %s at %x\n", *storage, key, *storage) );
        }
  }
  
@@@ -522,10 -517,12 +537,12 @@@ static void homebank_pref_get_guint32
      const gchar *key,
        guint32 *storage)
  {
+       DB( g_print(" search %s in %s\n", key, group_name) );
  
        if( g_key_file_has_key(key_file, group_name, key, NULL) )
        {
                *storage = g_key_file_get_integer(key_file, group_name, key, NULL);
+               DB( g_print(" stored guint32 %d for %s at %x\n", *storage, key, *storage) );
        }
  }
  
@@@ -535,10 -532,12 +552,12 @@@ static void homebank_pref_get_short
      const gchar *key,
        gshort *storage)
  {
+       DB( g_print(" search %s in %s\n", key, group_name) );
  
        if( g_key_file_has_key(key_file, group_name, key, NULL) )
        {
                *storage = (gshort)g_key_file_get_integer(key_file, group_name, key, NULL);
+               DB( g_print(" stored short %d for %s at %x\n", *storage, key, *storage) );
        }
  }
  
@@@ -608,6 -607,7 +627,7 @@@ GKeyFile *keyfile
  gboolean retval = FALSE;
  gchar *group, *filename;
  guint32 version;
+ gboolean loaded;
  GError *error = NULL;
  
        DB( g_print("\n[preferences] pref load\n") );
  
                DB( g_print(" - filename: %s\n", filename) );
  
-               if(g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL))
+               error = NULL;
+               loaded = g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error);
+               if( error )
+               {
+                       g_warning("unable to load file %s: %s", filename, error->message);
+                       g_error_free (error);
+               }
+                       
+               if( loaded == TRUE )
                {
  
                        group = "General";
                                homebank_pref_get_boolean(keyfile, group, "AppendScheduled", &PREFS->appendscheduled);
                                homebank_pref_get_boolean(keyfile, group, "UpdateCurrency", &PREFS->do_update_currency);        
  
+                               homebank_pref_get_boolean(keyfile, group, "BakIsAutomatic", &PREFS->bak_is_automatic);
+                               homebank_pref_get_short(keyfile, group, "BakMaxNumCopies", &PREFS->bak_max_num_copies);
                                homebank_pref_get_boolean(keyfile, group, "HeritDate", &PREFS->heritdate);
                                homebank_pref_get_boolean(keyfile, group, "HideReconciled", &PREFS->hidereconciled);
                                homebank_pref_get_boolean(keyfile, group, "ShowRemind", &PREFS->showremind);
+                               homebank_pref_get_boolean(keyfile, group, "TxnMemoAcp", &PREFS->txn_memoacp);
+                               homebank_pref_get_short(keyfile, group, "TxnMemoAcpDays", &PREFS->txn_memoacp_days);
  
                                if( g_key_file_has_key(keyfile, group, "ColumnsOpe", NULL) )
                                {
  
                                        if(version <= 2)        //retrieve old 0.1 or 0.2 visibility boolean
                                        {
-                                               bsrc = g_key_file_get_boolean_list(keyfile, group, "ColumnsOpe", &length, &error);
+                                               bsrc = g_key_file_get_boolean_list(keyfile, group, "ColumnsOpe", &length, NULL);
                                                if( length == NUM_LST_DSPOPE-1 )
                                                {
                                                        //and convert
                                        }
                                        else
                                        {
-                                               src = g_key_file_get_integer_list(keyfile, group, "ColumnsOpe", &length, &error);
+                                               src = g_key_file_get_integer_list(keyfile, group, "ColumnsOpe", &length, NULL);
  
                                                DB( g_print(" - length %d (max=%d)\n", length, NUM_LST_DSPOPE) );
  
-                                               if( length == NUM_LST_DSPOPE-1 )
+                                               if( length == NUM_LST_DSPOPE )
                                                {
                                                        DB( g_print(" - copying column order from pref file\n") );
                                                        memcpy(PREFS->lst_ope_columns, src, length*sizeof(gint));
                                gint *src;
                                gsize length;
  
-                                       src = g_key_file_get_integer_list(keyfile, group, "ColumnsOpeWidth", &length, &error);
+                                       src = g_key_file_get_integer_list(keyfile, group, "ColumnsOpeWidth", &length, NULL);
  
                                        DB( g_print(" - length %d (max=%d)\n", length, NUM_LST_DSPOPE) );
  
-                                       if( length == NUM_LST_DSPOPE-1 )
+                                       if( length == NUM_LST_DSPOPE )
                                        {
                                                DB( g_print(" - copying column width from pref file\n") );
-                                               memcpy(PREFS->lst_ope_col_size, src, length*sizeof(gint));
+                                               memcpy(PREFS->lst_ope_col_width, src, length*sizeof(gint));
                                        }
  
                                        //leak
                                homebank_pref_get_short(keyfile, group, "UpcColPayW", &PREFS->pnl_upc_col_pay_width);
                                homebank_pref_get_short(keyfile, group, "UpcColMemW", &PREFS->pnl_upc_col_mem_width);
  
+                               homebank_pref_get_string(keyfile, group, "PnlLstTab", &PREFS->pnl_list_tab);
  
                        group = "Format";
  
  
                                DB( g_print(" -> ** Exchange\n") );
  
-                               //homebank_pref_get_boolean(keyfile, group, "DoIntro", &PREFS->dtex_nointro);
+                               homebank_pref_get_boolean(keyfile, group, "DoIntro", &PREFS->dtex_nointro);
+                               homebank_pref_get_boolean(keyfile, group, "UcFirst", &PREFS->dtex_ucfirst);
                                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;
        return retval;
  }
  
  static void homebank_pref_set_string(
        GKeyFile *key_file,
      const gchar *group_name,
@@@ -1033,6 -1027,7 +1068,7 @@@ GKeyFile *keyfile
  gboolean retval = FALSE;
  gchar *group, *filename;
  gsize length;
+ GError *error = NULL;
  
        DB( g_print("\n[preferences] pref save\n") );
  
                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, "BakIsAutomatic", PREFS->bak_is_automatic);
+               g_key_file_set_integer (keyfile, group, "BakMaxNumCopies", PREFS->bak_max_num_copies);
  
                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, "HeritDate", PREFS->heritdate);
                g_key_file_set_boolean (keyfile, group, "HideReconciled", PREFS->hidereconciled);
                g_key_file_set_boolean (keyfile, group, "ShowRemind", PREFS->showremind);
+               g_key_file_set_boolean (keyfile, group, "TxnMemoAcp", PREFS->txn_memoacp);
+               g_key_file_set_integer (keyfile, group, "TxnMemoAcpDays" , PREFS->txn_memoacp_days);
  
-               g_key_file_set_integer_list(keyfile, group, "ColumnsOpe", PREFS->lst_ope_columns, NUM_LST_DSPOPE-1);
-               g_key_file_set_integer_list(keyfile, group, "ColumnsOpeWidth", PREFS->lst_ope_col_size, NUM_LST_DSPOPE-1);
+               g_key_file_set_integer_list(keyfile, group, "ColumnsOpe", PREFS->lst_ope_columns, NUM_LST_DSPOPE);
+               g_key_file_set_integer_list(keyfile, group, "ColumnsOpeWidth", PREFS->lst_ope_col_width, NUM_LST_DSPOPE);
                g_key_file_set_integer     (keyfile, group, "OpeSortId" , PREFS->lst_ope_sort_id);
                g_key_file_set_integer     (keyfile, group, "OpeSortOrder" , PREFS->lst_ope_sort_order);
  
                g_key_file_set_integer(keyfile, group, "UpcColPayW", PREFS->pnl_upc_col_pay_width);
                g_key_file_set_integer(keyfile, group, "UpcColMemW", PREFS->pnl_upc_col_mem_width);
  
+               homebank_pref_set_string  (keyfile, group, "PnlLstTab", PREFS->pnl_list_tab);
  
                DB( g_print(" -> ** format\n") );
  
  
  
                group = "Exchange";
-               //g_key_file_set_boolean (keyfile, group, "DoIntro", PREFS->dtex_nointro);
+               g_key_file_set_boolean (keyfile, group, "DoIntro", PREFS->dtex_nointro);
+               g_key_file_set_boolean (keyfile, group, "UcFirst", PREFS->dtex_ucfirst);
                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->);
  
                DB( g_print(" -> filename: %s\n", filename) );
  
-               g_file_set_contents(filename, contents, length, NULL);
+               g_file_set_contents(filename, contents, length, &error);
+               if( error )
+               {
+                       g_warning("unable to save file %s: %s", filename, error->message);
+                       g_error_free (error);
+                       error = NULL;
+               }
+               
                DB( g_print(" -> contents: %s\n", contents) );
  
                DB( g_print(" -> freeing filename\n") );
diff --combined src/hb-preferences.h
index 1223888a34a2549d86782f14c77ff4507a70588e,1cf7e6f441e32e083d93753dc49bfe7b6e84f466..751896162abfc591a7f2b5ff2a6fd9518e1828c8
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -22,6 -22,7 +22,7 @@@
  
  #include "hb-currency.h"
  
  #define DEFAULT_FORMAT_DATE                   "%x"
  
  #define MAX_FRAC_DIGIT                6
@@@ -58,47 -59,42 +59,42 @@@ struct Preference
        gboolean        loadlast;
        gboolean        appendscheduled;
        gboolean        do_update_currency;
-       gshort          fisc_year_day;
-       gshort          fisc_year_month;
        gint            date_range_wal;
-       gchar           *path_hbfile;
  
        //interface
-       gchar           *language;
        gshort          toolbar_style;
-       //gboolean      rules_hint;
+       gboolean        icon_symbolic;
        gshort          grid_lines;
        gboolean        custom_colors;
        gchar           *color_exp;
        gchar           *color_inc;
        gchar           *color_warn;
  
+       //locale
+       gchar           *language;
+       gchar           *date_format;
+       gshort          fisc_year_day;
+       gshort          fisc_year_month;
+       gboolean        vehicle_unit_ismile;    // true if unit is mile, default Km
+       gboolean        vehicle_unit_isgal;             // true if unit is gallon, default Liter
        //transactions
        gint            date_range_txn;
        gint            date_future_nbdays;
        gboolean        hidereconciled;
        gboolean    showremind;
        gboolean        heritdate;
-       gint            lst_ope_columns[NUM_LST_DSPOPE+1];
-       gint            lst_ope_col_size[NUM_LST_DSPOPE+1];
-       gint            lst_ope_sort_id;        // -- implicit --
-       gint            lst_ope_sort_order; // -- implicit --
+       gboolean        txn_memoacp;
+       gshort          txn_memoacp_days;
  
-       //display format
-       gchar           *date_format;
-       gchar       IntCurrSymbol[8];
-       gboolean        vehicle_unit_ismile;    // true if unit is mile, default Km
-       gboolean        vehicle_unit_isgal;             // true if unit is gallon, default Liter
-       //data exchange options
-       gboolean        dtex_nointro;
+       //import/export
        gint            dtex_datefmt;
        gint            dtex_ofxname;
        gint            dtex_ofxmemo;
        gboolean        dtex_qifmemo;
        gboolean        dtex_qifswap;
-       gchar           *path_import;
-       gchar           *path_export;
+       gboolean        dtex_ucfirst;
  
        //report options
        gint            date_range_rep;
        gboolean        stat_byamount;
        gboolean        stat_showrate;
        gboolean        stat_showdetail;
-       gboolean        budg_showdetail;
+       gboolean        budg_showdetail;        
+       //backup option
+       gboolean        bak_is_automatic;
+       gshort          bak_max_num_copies;
+       //folders
+       gchar           *path_hbfile;
+       gchar           *path_import;
+       gchar           *path_export;
+       gchar           *path_attach;
  
        //euro zone
        gboolean        euro_active;
        gdouble         euro_value;
        Currency        minor_cur;
  
-       //chart options
-       //gboolean      chart_legend;
  
+       //---- others data -----
+       gboolean        dtex_nointro;
+       gchar       IntCurrSymbol[8];
+       gint            lst_impope_columns[NUM_LST_DSPOPE+1];
+       gint            lst_ope_columns[NUM_LST_DSPOPE+1];
+       gint            lst_ope_col_width[NUM_LST_DSPOPE+1];
+       gint            lst_ope_sort_id;        // -- implicit --
+       gint            lst_ope_sort_order; // -- implicit --
+       
        /* windows/dialogs size an position */
        struct WinGeometry      wal_wg;
        struct WinGeometry      acc_wg;
        gshort          pnl_acc_show_by;
        gshort          pnl_upc_col_pay_width;
        gshort          pnl_upc_col_mem_width;
-       
+       gchar           *pnl_list_tab;
  
        //vehiclecost units (mile/gal or km/liters)
        
        gchar      *vehicle_unit_100;
        gchar      *vehicle_unit_distbyvol;
  
 +      // plugins
 +      gchar** ext_path;
 +      GList* ext_whitelist;
 +
  };
  
  
diff --combined src/hb-tag.c
index 96cb5bf496dd7d518ae02e12a61b3f342e847975,781a439a0e9f0adf3c14998fa5697354960bc3d0..ebe1fa6f6d3c5b1ef3c7f5d8b1877e79e3a79bf0
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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));
  }
  
  
@@@ -189,8 -186,6 +189,6 @@@ guint32 max_key = 0
  }
  
  
  /**
   * da_tag_get_by_name:
   *
@@@ -224,11 -219,146 +222,146 @@@ Tag *da_tag_get(guint32 key
  }
  
  
+ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+ guint
+ tags_count(guint32 *tags)
+ {
+ guint count = 0;
+       DB( g_print("\n[tags] count\n") );
+       if( tags == NULL )
+               return 0;
+       while(*tags++ != 0 && count < 32)
+               count++;
+       return count;
+ }
+ guint32 *tags_clone(guint32 *tags)
+ {
+ guint32 *newtags = NULL;
+ guint count;
+       count = tags_count(tags);
+       if(count > 0)
+       {
+               //1501962: we must also copy the final 0
+               newtags = g_memdup(tags, (count+1)*sizeof(guint32));
+       }
+       return newtags; 
+ }
+ static gboolean
+ tags_key_exists(guint32 *tags, guint32 key)
+ {
+ guint count = 0;
+       while(*tags != 0 && count < 32)
+       {
+               if( *tags == key )
+                       return TRUE;
+               tags++;
+               count++;
+       }
+       return FALSE;
+ }
+ guint32 *
+ tags_parse(const gchar *tagstring)
+ {
+ gchar **str_array;
+ guint32 *tags = NULL;
+ guint32 *ptags;
+ guint count, i;
+ Tag *tag;
+       DB( g_print("\n[tags] parse\n") );
+       if( tagstring )
+       {
+               str_array = g_strsplit (tagstring, " ", 0);
+               count = g_strv_length( str_array );
+               DB( g_print("- %d tags '%s'\n", count, tagstring) );
+               if( count > 0 )
+               {
+                       tags = g_new0(guint32, count + 1);
+                       ptags = tags;
+                       for(i=0;i<count;i++)
+                       {
+                               //5.2.3 fixed empty tag
+                               if( strlen(str_array[i]) == 0 )
+                                       continue;
+                               DB( g_print("- %d search '%s'\n", i, str_array[i]) );
+                               tag = da_tag_get_by_name(str_array[i]);
+                               if(tag == NULL)
+                               {
+                               Tag *newtag = da_tag_malloc();
+                                       newtag->name = g_strdup(str_array[i]);
+                                       da_tag_append(newtag);
+                                       tag = da_tag_get_by_name(str_array[i]);
+                               }
+                               DB( g_print("- array add %d '%s'\n", tag->key, tag->name) );
+                               //5.3 fixed duplicate tag in same tags
+                               if( tags_key_exists(tags, tag->key) == FALSE )
+                                       *ptags++ = tag->key;
+                       }
+                       *ptags = 0;
+               }
+               g_strfreev (str_array);
+       }
+       return tags;
+ }
+ gchar *
+ tags_tostring(guint32 *tags)
+ {
+ guint count, i;
+ gchar **str_array, **tptr;
+ gchar *tagstring;
+ Tag *tag;
  
+       DB( g_print("\n[tags] tostring\n") );
+       if( tags == NULL )
+       {
+               return NULL;
+       }
+       else
+       {
+               count = tags_count(tags);
+               str_array = g_new0(gchar*, count+1);
+               tptr = str_array;
+               for(i=0;i<count;i++)
+               {
+                       tag = da_tag_get(tags[i]);
+                       if( tag )
+                       {
+                               *tptr++ = tag->name;
+                       }
+               }
+               *tptr = NULL;
+               
+               tagstring = g_strjoinv(" ", str_array);
+               g_free (str_array);
+       }
+       return tagstring;
+ }
  
  
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  #if MYDEBUG
  
  static void
@@@ -258,6 -388,34 +391,34 @@@ da_tag_debug_list(void
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  
+ gboolean
+ tag_rename(Tag *item, const gchar *newname)
+ {
+ Tag *existitem;
+ gchar *stripname;
+ gboolean retval = FALSE;
+       stripname = g_strdup(newname);
+       g_strstrip(stripname);
+       existitem = da_tag_get_by_name(stripname);
+       if( existitem != NULL && existitem->key != item->key)
+       {
+               DB( g_print("- error, same name already exist with other key %d <> %d\n",existitem->key, item->key) );
+               g_free(stripname);
+       }
+       else
+       {
+               DB( g_print("- renaming\n") );
+               g_free(item->name);
+               item->name = stripname;
+               retval = TRUE;
+       }
+       return retval;
+ }
  
  
  static gint
diff --combined src/hb-transaction.c
index eb825093e8b674239d7c4a3c4a326cde61e1d7bd,0368946f9fbb4267bb383d7ace7200f70f03a6a2..966508092798840858a0a77cd74c814860eb9b59
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  #include "hb-tag.h"
  #include "hb-split.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  /****************************************************************************/
- /* Debug macros                                                                                                       */
+ /* Debug macro                                                                    */
  /****************************************************************************/
  #define MYDEBUG 0
  
@@@ -66,8 -63,12 +66,12 @@@ da_transaction_clean(Transaction *item
                        item->tags = NULL;
                }
  
-               da_splits_free(item->splits);
-               item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
+               if(item->splits != NULL)
+               {
+                       da_split_destroy(item->splits);
+                       item->splits = NULL;
+                       item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
+               }
  
                if(item->same != NULL)
                {
  void
  da_transaction_free(Transaction *item)
  {
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                da_transaction_clean(item);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
  Transaction *
  da_transaction_malloc(void)
  {
 -      return g_malloc0(sizeof(Transaction));
 +      return rc_alloc(sizeof(Transaction));
  }
  
  
- Transaction *da_transaction_copy(Transaction *src_txn, Transaction *dst_txn)
- {
-       DB( g_print("da_transaction_copy\n") );
-       da_transaction_clean (dst_txn);
-       memmove(dst_txn, src_txn, sizeof(Transaction));
-       
-       //duplicate the string
-       dst_txn->memo = g_strdup(src_txn->memo);
-       dst_txn->info = g_strdup(src_txn->info);
-       //duplicate tags
-       transaction_tags_clone(src_txn, dst_txn);
-       if (da_splits_clone(src_txn->splits, dst_txn->splits) > 0)
-               dst_txn->flags |= OF_SPLIT; //Flag that Splits are active
-       return dst_txn;
- }
  Transaction *da_transaction_init_from_template(Transaction *txn, Archive *arc)
  {
+       DB( g_print("da_transaction_init_from_template\n") );
        //txn->date             = 0;
        txn->amount     = arc->amount;
        //#1258344 keep the current account if tpl is empty
        txn->kpay               = arc->kpay;
        txn->kcat               = arc->kcat;
        txn->kxferacc   = arc->kxferacc;
-       txn->memo       = g_strdup(arc->memo);
+       txn->memo           = g_strdup(arc->memo);
        txn->info               = NULL;
-       if( da_splits_clone(arc->splits, txn->splits) > 0)
+       //copy tags (with free previous here)
+       g_free(txn->tags);
+       txn->tags = tags_clone(arc->tags);
+       da_split_destroy (txn->splits);
+       txn->splits = da_splits_clone(arc->splits);
+       if( da_splits_length (txn->splits) > 0 )
                txn->flags |= OF_SPLIT; //Flag that Splits are active
  
        return txn;
  }
  
  
+ Transaction *da_transaction_set_default_template(Transaction *txn)
+ {
+ Account *acc;
+ Archive *arc;
+       DB( g_print("da_transaction_set_default_template\n") );
+       acc = da_acc_get(txn->kacc);
+       if(acc != NULL && acc->karc > 0)
+       {
+               arc = da_archive_get(acc->karc);
+               if( arc )
+               {
+                       DB( g_print(" - init with default template\n") );
+                       da_transaction_init_from_template(txn, arc);
+               }
+       }
+       return txn;
+ }
  Transaction *da_transaction_clone(Transaction *src_item)
  {
 -Transaction *new_item = g_memdup(src_item, sizeof(Transaction));
 +Transaction *new_item = rc_dup(src_item, sizeof(Transaction));
  
        DB( g_print("da_transaction_clone\n") );
  
                new_item->memo = g_strdup(src_item->memo);
                new_item->info = g_strdup(src_item->info);
  
-               //duplicate tags
-               transaction_tags_clone(src_item, new_item);
+               //duplicate tags/splits
+               //no g_free here to avoid free the src tags (memdup copied the ptr)
+               new_item->tags = tags_clone(src_item->tags);
                
-               if( da_splits_clone(src_item->splits, new_item->splits) > 0)
+               new_item->splits = da_splits_clone(src_item->splits);
+               if( da_splits_length (new_item->splits) > 0 )
                        new_item->flags |= OF_SPLIT; //Flag that Splits are active
  
        }
@@@ -241,12 -253,15 +256,15 @@@ gboolean da_transaction_insert_memo(Tra
  {
  gboolean retval = FALSE;
  
-       // append the memo if new
        if( item->memo != NULL )
        {
-               if( g_hash_table_lookup(GLOBALS->h_memo, item->memo) == NULL )
+               //# 1673048 add filter on status and date obsolete
+               if( (PREFS->txn_memoacp == TRUE) && (item->date >= (GLOBALS->today - PREFS->txn_memoacp_days)) )
                {
-                       retval = g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->memo), NULL);
+                       if( g_hash_table_lookup(GLOBALS->h_memo, item->memo) == NULL )
+                       {
+                               retval = g_hash_table_insert(GLOBALS->h_memo, g_strdup(item->memo), NULL);
+                       }
                }
        }
        return retval;
@@@ -376,7 -391,7 +394,7 @@@ void da_transaction_consistency(Transac
  Account *acc;
  Category *cat;
  Payee *pay;
- gint nbsplit;
+ guint nbsplit;
  
        DB( g_print("\n[transaction] consistency\n") );
  
                GLOBALS->changes_count++;
        }
  
-       // check split category #1340142
-       split_cat_consistency(item->splits);
-       //# 1416624 empty category when split
-       nbsplit = da_splits_count(item->splits);
-       if(nbsplit > 0 && item->kcat > 0)
+       //#1340142 check split category 
+       if( item->splits != NULL )
        {
-               g_warning("txn consistency: fixed invalid cat on split txn");
-               item->kcat = 0;
-               GLOBALS->changes_count++;
+               nbsplit = da_splits_consistency(item->splits);
+               //# 1416624 empty category when split
+               if(nbsplit > 0 && item->kcat > 0)
+               {
+                       g_warning("txn consistency: fixed invalid cat on split txn");
+                       item->kcat = 0;
+                       GLOBALS->changes_count++;
+               }
        }
        
        // check payee exists
        }
  
        //#1628678 tags for internal xfer should be checked as well
+       //#1787826 intxfer should not have split
  
        //#1295877 ensure income flag is correctly set
        item->flags &= ~(OF_INCOME);
@@@ -515,9 -531,6 +534,9 @@@ gchar swap
  
                        account_balances_add (child);
  
 +                      GValue txn_value = G_VALUE_INIT;
 +                      ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, child), NULL);
 +
                }
        }
  
@@@ -559,12 -572,14 +578,14 @@@ gboolean retval = FALSE
  }
  
  
- static GList *transaction_xfer_child_might_list_get(Transaction *ope)
+ static GList *transaction_xfer_child_might_list_get(Transaction *ope, guint32 kdstacc)
  {
  GList *lst_acc, *lnk_acc;
  GList *list, *matchlist = NULL;
  
-       //DB( g_print("\n[transaction] xfer_child_might_list_get\n") );
+       DB( g_print("\n[transaction] xfer_child_might_list_get\n") );
+       DB( g_print(" - kdstacc:%d\n", kdstacc) );
  
        lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
        lnk_acc = g_list_first(lst_acc);
        {
        Account *acc = lnk_acc->data;
  
-               if( !(acc->flags & AF_CLOSED) && (acc->key != ope->kacc) )
+               if( !(acc->flags & AF_CLOSED) && (acc->key != ope->kacc) && ( (acc->key == kdstacc) || kdstacc == 0 ) )
                {
                        list = g_queue_peek_tail_link(acc->txn_queue);
                        while (list != NULL)
                
                                if( transaction_xfer_child_might(ope, item, 0) == TRUE )
                                {
-                                       //DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->account, item->kxferacc) );
+                                       DB( g_print(" - match : %d %s %f %d=>%d\n", item->date, item->memo, item->amount, item->kacc, item->kxferacc) );
                                        matchlist = g_list_append(matchlist, item);
                                }
                                list = g_list_previous(list);
  }
  
  
- void transaction_xfer_search_or_add_child(GtkWindow *parentwindow, Transaction *ope, gboolean manual)
+ void transaction_xfer_search_or_add_child(GtkWindow *parent, Transaction *ope, guint32 kdstacc)
  {
  GList *matchlist;
  gint count;
  
        DB( g_print("\n[transaction] xfer_search_or_add_child\n") );
  
-       matchlist = transaction_xfer_child_might_list_get(ope);
+       matchlist = transaction_xfer_child_might_list_get(ope, kdstacc);
        count = g_list_length(matchlist);
  
        DB( g_print(" - found %d might match, switching\n", count) );
                        break;
  
                //todo: maybe with just 1 match the user must choose ?
-               //#942346: bad idea so to no let the user confirm, so let hil confirm
+               //#942346: bad idea so to no let the user confirm, so let him confirm
                /*
                case 1:         //transform the transaction to a child transfer
                {
  
                default:        //the user must choose himself
                {
+               gint result;
                Transaction *child;
  
-                       child = ui_dialog_transaction_xfer_select_child(ope, matchlist);
-                       if(child == NULL)
-                               transaction_xfer_create_child(ope);
-                       else
+                       result = ui_dialog_transaction_xfer_select_child(parent, ope, matchlist, &child);
+                       if( result == GTK_RESPONSE_ACCEPT )
+                       {
                                transaction_xfer_change_to_child(ope, child);
+                       }
+                       else //GTK_RESPONSE_CANCEL
+                       {
+                               ope->paymode = PAYMODE_NONE;
+                               ope->kxfer = 0;
+                               ope->kxferacc = 0;
+                       }
                }
        }
  
@@@ -768,9 -790,8 +796,8 @@@ Account *acc
        }
  
        //synchronise tags since 5.1
-       if(child->tags)
-               g_free(child->tags);
-       transaction_tags_clone (s_txn, child);
+       g_free(child->tags);
+       child->tags = tags_clone (s_txn->tags);
  
  }
  
@@@ -875,7 -896,22 +902,22 @@@ Account *acc
  }
  
  
- Transaction *transaction_add(Transaction *ope)
+ void transaction_changed(Transaction *txn)
+ {
+ Account *acc;
+       if( txn == NULL )
+               return;
+       acc = da_acc_get(txn->kacc);
+       if(acc == NULL)
+               return; 
+       acc->flags |= AF_CHANGED;
+ }
+ Transaction *transaction_add(GtkWindow *parent, Transaction *ope)
  {
  Transaction *newope;
  Account *acc;
                if(acc == NULL) return NULL;
                
                // delete any splits
-               da_splits_free(ope->splits);
+               da_split_destroy(ope->splits);
+               ope->splits = NULL;
                ope->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
        }
  
  
                if(newope->paymode == PAYMODE_INTXFER)
                {
-                       transaction_xfer_search_or_add_child(NULL, newope, FALSE);
+                       transaction_xfer_search_or_add_child(parent, newope, newope->kxferacc);
                }
 +
 +              GValue txn_value = G_VALUE_INIT;
 +              ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, newope), NULL);
        }
        
        return newope;
@@@ -1012,7 -1046,7 +1055,7 @@@ gboolean match = FALSE
                {
                        if( g_strrstr(text, searchtext) != NULL )
                        {
-                               DB( g_print(" found case '%s'\n", searchtext) );
+                               DB( g_print("-- found case '%s'\n", searchtext) );
                                match = TRUE;
                        }
                }
  
                        if( g_strrstr(word, needle) != NULL )
                        {
-                               DB( g_print(" found nocase '%s'\n", searchtext) );
+                               DB( g_print("-- found nocase '%s'\n", searchtext) );
                                match = TRUE;
                        }
                        g_free(word);
@@@ -1041,30 -1075,26 +1084,26 @@@ gboolean match = FALSE
        if(text == NULL)
                return FALSE;
        
-       DB( g_print("- match RE %s in %s\n", searchtext, text) );
+       DB( g_print("-- match RE %s in %s\n", searchtext, text) );
        if( searchtext != NULL )
        {
                match = g_regex_match_simple(searchtext, text, ((exact == TRUE)?0:G_REGEX_CASELESS) | G_REGEX_OPTIMIZE, G_REGEX_MATCH_NOTEMPTY );
-               if (match == TRUE) { DB( g_print(" found pattern '%s'\n", searchtext) ); }
+               if (match == TRUE) { DB( g_print("-- found pattern '%s'\n", searchtext) ); }
        }
        return match;
  }
  
  
- static Assign *transaction_auto_assign_eval_txn(GList *l_rul, Transaction *txn)
+ static GList *transaction_auto_assign_eval_txn(GList *l_rul, Transaction *txn)
  {
Assign *rule = NULL;
GList *ret_list = NULL;
  GList *list;
-       DB( g_print("\n[transaction] auto_assign_eval_txn\n") );
-       DB( g_print("- eval every rules, and return the last that match\n") );
+ gchar *text;
  
        list = g_list_first(l_rul);
        while (list != NULL)
        {
        Assign *rul = list->data;
-       gchar *text;
  
                text = txn->memo;
                if(rul->field == 1) //payee
                if( !(rul->flags & ASGF_REGEX) )
                {
                        if( misc_text_match(text, rul->text, rul->flags & ASGF_EXACT) )
-                               rule = rul;
+                               ret_list = g_list_append(ret_list, rul);
                }
                else
                {
                        if( misc_regex_match(text, rul->text, rul->flags & ASGF_EXACT) )
-                               rule = rul;
+                               ret_list = g_list_append(ret_list, rul);
                }
  
                list = g_list_next(list);
        }
  
-       return rule;
+       DB( g_print("- evaluated txn '%s'=> %d match\n", text, g_list_length (ret_list)) );
+       
+       return ret_list;
  }
  
  
- static Assign *transaction_auto_assign_eval(GList *l_rul, gchar *text)
+ static GList *transaction_auto_assign_eval(GList *l_rul, gchar *text)
  {
Assign *rule = NULL;
GList *ret_list = NULL;
  GList *list;
  
-       DB( g_print("\n[transaction] auto_assign_eval\n") );
-       
-       DB( g_print("- eval every rules, and return the last that match\n") );
        list = g_list_first(l_rul);
        while (list != NULL)
        {
                        if( !(rul->flags & ASGF_REGEX) )
                        {
                                if( misc_text_match(text, rul->text, rul->flags & ASGF_EXACT) )
-                                       rule = rul;
+                                       ret_list = g_list_append(ret_list, rul);
                        }
                        else
                        {
                                if( misc_regex_match(text, rul->text, rul->flags & ASGF_EXACT) )
-                                       rule = rul;
+                                       ret_list = g_list_append(ret_list, rul);
                        }
                }
                list = g_list_next(list);
        }
  
-       return rule;
+       DB( g_print("- evaluated split '%s' => %d match\n", text, g_list_length (ret_list)) );
+       
+       return ret_list;
  }
  
  
- gint transaction_auto_assign(GList *ope_list, guint32 kacc)
+ guint transaction_auto_assign(GList *ope_list, guint32 kacc)
  {
  GList *l_ope;
  GList *l_rul;
- gint changes = 0;
+ GList *l_match, *l_tmp;
+ guint changes = 0;
  
        DB( g_print("\n[transaction] auto_assign\n") );
  
        Transaction *ope = l_ope->data;
        gboolean changed = FALSE; 
  
-               DB( g_print("- eval ope '%s' : acc=%d, pay=%d, cat=%d\n", ope->memo, ope->kacc, ope->kpay, ope->kcat) );
+               DB( g_print("\n- work on txn '%s' : acc=%d, pay=%d, cat=%d, %s\n", ope->memo, ope->kacc, ope->kpay, ope->kcat, (ope->flags & OF_SPLIT) ? "is_split" : "" ) );
  
                //#1215521: added kacc == 0
                if( (kacc == ope->kacc || kacc == 0) )
                {
-               Assign *rul;
-                       rul = transaction_auto_assign_eval_txn(l_rul, ope);
-                       if( rul != NULL )
+                       if( !(ope->flags & OF_SPLIT) )
                        {
-                               if( (ope->kpay == 0 && (rul->flags & ASGF_DOPAY)) || (rul->flags & ASGF_OVWPAY) )
+                               l_match = l_tmp = transaction_auto_assign_eval_txn(l_rul, ope);
+                               while( l_tmp != NULL )
                                {
-                                       if(ope->kpay != rul->kpay) { changed = TRUE; }
-                                       ope->kpay = rul->kpay;
-                               }
+                               Assign *rul = l_tmp->data;
+                                       
+                                       if( (ope->kpay == 0 && (rul->flags & ASGF_DOPAY)) || (rul->flags & ASGF_OVWPAY) )
+                                       {
+                                               if(ope->kpay != rul->kpay) { changed = TRUE; }
+                                               ope->kpay = rul->kpay;
+                                       }
  
-                               if( !(ope->flags & OF_SPLIT) )
-                               {
                                        if( (ope->kcat == 0 && (rul->flags & ASGF_DOCAT)) || (rul->flags & ASGF_OVWCAT) )
                                        {
                                                if(ope->kcat != rul->kcat) { changed = TRUE; }
                                                ope->kcat = rul->kcat;
                                        }
-                               }
  
-                               if( (ope->paymode == 0 && (rul->flags & ASGF_DOMOD)) || (rul->flags & ASGF_OVWMOD) )
-                               {
-                                       //ugly hack - don't allow modify intxfer
-                                       if(ope->paymode != PAYMODE_INTXFER && rul->paymode != PAYMODE_INTXFER) 
+                                       if( (ope->paymode == 0 && (rul->flags & ASGF_DOMOD)) || (rul->flags & ASGF_OVWMOD) )
                                        {
-                                               if(ope->paymode != rul->paymode) { changed = TRUE; }
-                                               ope->paymode = rul->paymode;
+                                               //ugly hack - don't allow modify intxfer
+                                               if(ope->paymode != PAYMODE_INTXFER && rul->paymode != PAYMODE_INTXFER) 
+                                               {
+                                                       if(ope->paymode != rul->paymode) { changed = TRUE; }
+                                                       ope->paymode = rul->paymode;
+                                               }
                                        }
+                                       l_tmp = g_list_next(l_tmp);
                                }
+                               g_list_free(l_match);
                        }
-                       if( ope->flags & OF_SPLIT )
+                       else
                        {
-                       guint i, nbsplit = da_splits_count(ope->splits);
+                       guint i, nbsplit = da_splits_length(ope->splits);
+                               
                                for(i=0;i<nbsplit;i++)
                                {
-                               Split *split = ope->splits[i];
+                               Split *split = da_splits_get(ope->splits, i);
                                        
                                        DB( g_print("- eval split '%s'\n", split->memo) );
  
-                                       rul = transaction_auto_assign_eval(l_rul, split->memo);
-                                       if( rul != NULL )
+                                       l_match = l_tmp = transaction_auto_assign_eval(l_rul, split->memo);
+                                       while( l_tmp != NULL )
                                        {
+                                       Assign *rul = l_tmp->data;
                                                //#1501144: check if user wants to set category in rule
                                                if( (split->kcat == 0 || (rul->flags & ASGF_OVWCAT)) && (rul->flags & ASGF_DOCAT) )
                                                {
                                                        if(split->kcat != rul->kcat) { changed = TRUE; }
                                                        split->kcat = rul->kcat;
                                                }
-                                       }
+                                               l_tmp = g_list_next(l_tmp);
+                                       }       
+                                       g_list_free(l_match);
                                }
                        }
  
  }
  
  
- /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
- guint
- transaction_tags_count(Transaction *ope)
+ static gboolean transaction_similar_match(Transaction *stxn, Transaction *dtxn, guint32 daygap)
  {
- guint count = 0;
- guint32 *ptr = ope->tags;
-       //DB( g_print("\n[transaction] tags_count\n") );
-       
-       if( ope->tags == NULL )
-               return 0;
+ gboolean retval = FALSE;
  
-       while(*ptr++ != 0 && count < 32)
-               count++;
+       if(stxn == dtxn)
+               return FALSE;
  
-       return count;
+       DB( g_print(" date: %d - %d = %d\n", stxn->date, dtxn->date, stxn->date - dtxn->date) );
+       
+       if( stxn->kcur == dtxn->kcur
+        &&     stxn->amount == dtxn->amount
+        && ( (stxn->date - dtxn->date) <= daygap )
+        //todo: at import we also check payee, but maybe too strict here
+        && (hb_string_compare(stxn->memo, dtxn->memo) == 0)
+         )
+       {
+               retval = TRUE;
+       }
+       return retval;
  }
  
  
- void transaction_tags_clone(Transaction *src_txn, Transaction *dst_txn)
+ void transaction_similar_unmark(Account *acc)
  {
guint count;
GList *lnk_txn;
  
-       dst_txn->tags = NULL;
-       count = transaction_tags_count(src_txn);
-       if(count > 0)
+       lnk_txn = g_queue_peek_tail_link(acc->txn_queue);
+       while (lnk_txn != NULL)
        {
-               //1501962: we must also copy the final 0
-               dst_txn->tags = g_memdup(src_txn->tags, (count+1)*sizeof(guint32));
+       Transaction *stxn = lnk_txn->data;
+               stxn->marker = TXN_MARK_NONE;
+               lnk_txn = g_list_previous(lnk_txn);
        }
  }
  
- guint
transaction_tags_parse(Transaction *ope, const gchar *tagstring)
gint transaction_similar_mark(Account *acc, guint32 daygap)
  {
gchar **str_array;
- guint count, i;
Tag *tag;
GList *lnk_txn, *list2;
+ gint nball = 0;
gint nbdup = 0;
  
-       DB( g_print("\n[transaction] tags_parse\n") );
+       //warning the list must be sorted by date then amount
+       //ideally (easier to parse) we shoudl get a list sorted by amount, then date
+       DB( g_print("\n[transaction] check duplicate\n") );
  
-       DB( g_print(" - tagstring='%s'\n", tagstring) );
+       DB( g_print("\n - account:'%s' gap:%d\n", acc->name, daygap) );
  
-       str_array = g_strsplit (tagstring, " ", 0);
-       count = g_strv_length( str_array );
+       #if MYDEBUG == 1
+       GTimer *t = g_timer_new();
+       g_print(" - start parse\n");
+       #endif
  
-       g_free(ope->tags);
-       ope->tags = NULL;
  
-       DB( g_print(" -> reset storage %p\n", ope->tags) );
+       /*
+       llast = g_list_last(old ope list);
+       DB( g_print("- end last : %f sec\n", g_timer_elapsed(t, NULL)) );
+       g_timer_reset(t);
  
+       ltxn = llast->data;
+       g_date_clear(&gd, 1);
+       g_date_set_julian(&gd, ltxn->date);
+       g_print(" - last julian=%u %02d-%02d-%04d\n", ltxn->date, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd));
  
-       if( count > 0 )
-       {
+       minjulian = ltxn->date - (366*2);
+       g_date_clear(&gd, 1);
+       g_date_set_julian(&gd, minjulian);
+       g_print(" - min julian=%u %02d-%02d-%04d\n", minjulian, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd));
+       */
+       transaction_similar_unmark(acc);
  
-               ope->tags = g_new0(guint32, count + 1);
+       //mark duplicate
+       lnk_txn = g_queue_peek_tail_link(acc->txn_queue);
+       while (lnk_txn != NULL)
+       {
+       Transaction *stxn = lnk_txn->data;
  
-               DB( g_print(" -> storage %p\n", ope->tags) );
+               //if(stxn->date < minjulian)
+               //      break;
+               DB( g_print("------\n eval src: %d, '%s', '%s', %.2f\n", stxn->date, stxn->info, stxn->memo, stxn->amount) );
  
-               for(i=0;i<count;i++)
+               list2 = g_list_previous(lnk_txn);
+               while (list2 != NULL)
                {
-                       tag = da_tag_get_by_name(str_array[i]);
-                       if(tag == NULL)
-                       {
-                       Tag *newtag = da_tag_malloc();
+               Transaction *dtxn = list2->data;
  
-                               newtag->name = g_strdup(str_array[i]);
-                               da_tag_append(newtag);
-                               tag = da_tag_get_by_name(str_array[i]);
-                       }
+                       DB( g_print(" + with dst: %d, '%s', '%s', %.2f\n", dtxn->date, dtxn->info, dtxn->memo, dtxn->amount) );
  
-                       DB( g_print(" -> storing %d=>%s at tags pos %d\n", tag->key, tag->name, i) );
+                       if( (stxn->date - dtxn->date) > daygap )
+                       {
+                               DB( g_print(" break %d %d\n", (dtxn->date - daygap) , (stxn->date - daygap)) );
+                               break;
+                       }
+                               
+                       if( dtxn->marker == TXN_MARK_NONE )
+                       {
+                               if( transaction_similar_match(stxn, dtxn, daygap) )
+                               {
+                                       stxn->marker = TXN_MARK_DUPSRC;
+                                       dtxn->marker = TXN_MARK_DUPDST;
+                                       DB( g_print(" = dtxn marker=%d\n", dtxn->marker) );
+                                       nball++;
+                               }
+                       }
+                       else
+                       {
+                               DB( g_print(" already marked %d\n", dtxn->marker) );
+                       }
  
-                       ope->tags[i] = tag->key;
+                       
+                       list2 = g_list_previous(list2);
                }
-               ope->tags[i] = 0;
+       
+               DB( g_print(" = stxn marker=%d\n", stxn->marker) );
+               if( stxn->marker == TXN_MARK_DUPSRC )
+                       nbdup++;
+               
+               lnk_txn = g_list_previous(lnk_txn);
        }
  
-       //hex_dump(ope->tags, sizeof(guint32*)*count+1);
+       DB( g_print(" - end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
+       DB( g_timer_destroy (t) );
  
-       g_strfreev (str_array);
+       DB( g_print(" - found: %d/%d dup\n", nbdup, nball ) );
  
-       return count;
+       return nbdup;
  }
  
- gchar *
- transaction_tags_tostring(Transaction *ope)
+ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+ /* = = experimental = = */
+ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
+ /*
+ probably add a structure hosted into a glist here
+ with kind of problem: duplicate, child xfer, orphan xfer      
+ and collect all that with target txn
+ */
+ /*void future_transaction_test_account(Account *acc)
  {
- guint count, i;
- gchar **str_array;
- gchar *tagstring;
- Tag *tag;
+ GList *lnk_txn, *list2;
+ gint nball = 0;
+ gint nbdup = 0;
+ gint nbxfer = 0;
+ GPtrArray *array;
  
-       DB( g_print("\n[transaction] tags_tostring\n") );
+ //future
+ gint gapday = 0, i;
  
-       DB( g_print(" -> tags at=%p\n", ope->tags) );
+       //warning the list must be sorted by date then amount
+       //ideally (easier to parse) we shoudl get a list sorted by amount, then date
  
-       if( ope->tags == NULL )
-       {
+       DB( g_print("\n[transaction] check duplicate\n") );
  
-               return NULL;
-       }
-       else
-       {
-               count = transaction_tags_count(ope);
  
-               DB( g_print(" -> tags at=%p, nbtags=%d\n", ope->tags, count) );
  
-               str_array = g_new0(gchar*, count+1);
+       DB( g_print("\n - account:'%s'\n", acc->name) );
+       GTimer *t = g_timer_new();
+       g_print(" - start parse\n");
  
-               DB( g_print(" -> str_array at %p\n", str_array) );
+       llast = g_list_last(old ope list);
+       DB( g_print("- end last : %f sec\n", g_timer_elapsed(t, NULL)) );
+       g_timer_reset(t);
  
-               //hex_dump(ope->tags, sizeof(guint32*)*(count+1));
+       ltxn = llast->data;
+       g_date_clear(&gd, 1);
+       g_date_set_julian(&gd, ltxn->date);
+       g_print(" - last julian=%u %02d-%02d-%04d\n", ltxn->date, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd));
  
-               for(i=0;i<count;i++)
+       minjulian = ltxn->date - (366*2);
+       g_date_clear(&gd, 1);
+       g_date_set_julian(&gd, minjulian);
+       g_print(" - min julian=%u %02d-%02d-%04d\n", minjulian, g_date_get_day (&gd), g_date_get_month (&gd), g_date_get_year(&gd));
+       array = g_ptr_array_sized_new (25);
+       lnk_txn = g_queue_peek_tail_link(acc->txn_queue);
+       while (lnk_txn != NULL)
+       {
+       Transaction *stxn = lnk_txn->data;
+               //if(stxn->date < minjulian)
+               //      break;
+               DB( g_print("------\n eval src: %d, '%s', '%s', %2.f\n", stxn->date, stxn->info, stxn->memo, stxn->amount) );
+               stxn->marker = 0;
+               list2 = g_list_previous(lnk_txn);
+               while (list2 != NULL)
                {
-                       DB( g_print(" -> try to get tag %d\n", ope->tags[i]) );
+               Transaction *dtxn = list2->data;
+                       stxn->marker = 0;
+                       if( (dtxn->date + gapday) < (stxn->date + gapday) )
+                               break;
+                       DB( g_print(" + with dst: %d, '%s', '%s', %2.f\n", dtxn->date, dtxn->info, dtxn->memo, dtxn->amount) );
  
-                       tag = da_tag_get(ope->tags[i]);
-                       if( tag )
+                       if( transaction_similar_match(stxn, dtxn, gapday) )
                        {
-                               DB( g_print(" -> get %s at %d\n", tag->name, i) );
-                               str_array[i] = tag->name;
+                               g_ptr_array_add (array, stxn);
+                               g_ptr_array_add (array, dtxn);
+                               nbdup++;
+                               DB( g_print(" + dst=1 src=1\n") );
                        }
-                       else
-                               str_array[i] = NULL;
  
+                       nball++;
+                       list2 = g_list_previous(list2);
                }
  
-               tagstring = g_strjoinv(" ", str_array);
+               lnk_txn = g_list_previous(lnk_txn);
+       }
  
-               g_free (str_array);
+       DB( g_print(" - end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
+       DB( g_timer_destroy (t) );
  
+       for(i=0;i<array->len;i++)
+       {
+       Transaction *txn = g_ptr_array_index(array, i);
+               txn->marker = 1;
        }
  
-       return tagstring;
+       g_ptr_array_free(array, TRUE);
+       DB( g_print(" - found: %d/%d dup, %d xfer\n", nbdup, nball, nbxfer ) );
  }
  
+ //todo: add a limitation, no need to go through all txn
+ // 1 year in th past, or abolute number ?
+ gint future_transaction_test_notification(void)
+ {
+ GList *lst_acc, *lnk_acc;
+       DB( g_print("\ntransaction_test_notification\n") );
+       
+       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;
+               transaction_similar_mark(acc);
+               lnk_acc = g_list_next(lnk_acc);
+       }
+       g_list_free(lst_acc);
+       
+       return 0;
+ }
+ */
diff --combined src/hb-xml.c
index da67dad488e9b9a95a3c5b901d6140914e56736b,ae3ea9b6635321de51c6416dae674d4b71733442..cc99d48e44cab33ca9d54a23b2e21e94d2d7ab53
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 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"
  
  /****************************************************************************/
@@@ -357,6 -355,27 +357,27 @@@ GList *lst_acc, *lnk_acc
  }
  
  
+ static void homebank_upgrade_to_v13(void)
+ {
+ GList *tmplist;
+ guint32 newkey;
+       DB( g_print("\n[hb-xml] homebank_upgrade_to_v13\n") );
+       //#1008629 assign a key to each archive
+       newkey = 1;
+       tmplist = g_list_first(GLOBALS->arc_list);
+       while (tmplist != NULL)
+       {
+       Archive *item = tmplist->data;
+               
+               item->key = newkey++;
+               tmplist = g_list_next(tmplist);
+       }
+ }
  // lower v0.6 : we must assume categories/payee exists
  // and strong link to xfer
  // #632496
@@@ -407,14 -426,14 +428,14 @@@ GList *lrul, *list
                cat = da_cat_get(entry->kcat);
                if(cat == NULL)
                {
-                       DB( g_print(" !! fixing cat for rul: %d is unknow\n", entry->kcat) );
+                       DB( g_print(" !! fixing cat for rul: %d is unknown\n", entry->kcat) );
                        entry->kcat = 0;
                }
  
                pay = da_pay_get(entry->kpay);
                if(pay == NULL)
                {
-                       DB( g_print(" !! fixing pay for rul: %d is unknow\n", entry->kpay) );
+                       DB( g_print(" !! fixing pay for rul: %d is unknown\n", entry->kpay) );
                        entry->kpay = 0;
                }
  
@@@ -451,6 -470,7 +472,7 @@@ gint i
                else if(!strcmp (attribute_names[i], "cheque1" )) { entry->cheque1 = atoi(attribute_values[i]); }
                else if(!strcmp (attribute_names[i], "cheque2" )) { entry->cheque2 = atoi(attribute_values[i]); }
                else if(!strcmp (attribute_names[i], "notes"   )) { if(strcmp(attribute_values[i],"(null)") && attribute_values[i] != NULL) entry->notes = g_strdup(attribute_values[i]); }
+               else if(!strcmp (attribute_names[i], "tpl" )) { entry->karc = atoi(attribute_values[i]); }
        }
  
        //all attribute loaded: append
@@@ -594,7 -614,7 +616,7 @@@ gint i
  }
  
  
- static void homebank_load_xml_tag(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
/*static void homebank_load_xml_tag(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
  {
  Tag *entry = da_tag_malloc();
  gint i;
  
        //all attribute loaded: append
        da_tag_insert(entry);
- }
+ }*/
  
  
  static void homebank_load_xml_fav(ParseContext *ctx, const gchar **attribute_names, const gchar **attribute_values)
@@@ -626,8 -646,8 +648,8 @@@ 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); }
+                    if(!strcmp (attribute_names[i], "key"        )) { entry->key = atoi(attribute_values[i]); }
+               else 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], "paymode"    )) { entry->paymode = 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->memo = g_strdup(attribute_values[i]); }
+               else if(!strcmp (attribute_names[i], "tags"       ))
+               {
+                       if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
+                       {
+                               entry->tags = tags_parse(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]); }
  
        if(split == TRUE)
        {
+               entry->splits = da_split_new ();
                if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
                {
                        entry->flags |= OF_SPLIT; //Flag that Splits are active
        }
  
        //all attribute loaded: append
-       GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry);
+       //GLOBALS->arc_list = g_list_append(GLOBALS->arc_list, entry);
+       da_archive_append(entry);
  }
  
  
@@@ -696,7 -718,7 +720,7 @@@ gint i
                {
                        if(attribute_values[i] != NULL && strlen(attribute_values[i]) > 0 && strcmp(attribute_values[i],"(null)") != 0 )
                        {
-                               transaction_tags_parse(entry, attribute_values[i]);
+                               entry->tags = tags_parse(attribute_values[i]);
                        }
                }
                else if(!strcmp (attribute_names[i], "kxfer"    )) { entry->kxfer = atoi(attribute_values[i]); }
  
        if(split == TRUE)
        {
+               entry->splits = da_split_new ();
                if (da_splits_parse(entry->splits, scat, samt, smem) > 0)
                {
                        entry->flags |= OF_SPLIT; //Flag that Splits are active
@@@ -736,7 -759,7 +761,7 @@@ start_element_handler (GMarkupParseCont
  ParseContext *ctx = user_data;
  //GtkUIManager *self = ctx->self;
  
-       //DB( g_print("** start element: %s\n", element_name) );
+       //DB( g_print("** start element: '%s'\n", element_name) );
  
        switch(element_name[0])
        {
                }
                break;
  
                case 'c':
                {
                        if(!strcmp (element_name, "cat"))
                }
                break;
  
-               case 't':
+               //TODO: < 5.2 misstyped here, should be tag without a s
+               //commented > 5.2 useless not loaded, but no side effect
+               /*case 't':
                {
                        if(!strcmp (element_name, "tags"))
                        {
                                homebank_load_xml_tag(ctx, attribute_names, attribute_values);
                        }
                }
-               break;
+               break;*/
  
                case 'f':
                {
@@@ -879,15 -913,15 +915,18 @@@ 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))
        {
-               //g_message ("%s", error->message);
-               retval = XML_IO_ERROR;
-               g_error_free (error);
+               if(error)
+               {
+                       g_warning("unable to load file %s: %s", filename, error->message);
+                       g_error_free(error);
+                       retval = XML_IO_ERROR;
+               }
        }
        else
        {
                        rc = g_markup_parse_context_parse (context, buffer, length, &error);
  
                        if( error )
+                       {
                                g_print("failed: %s\n", error->message);
+                               g_error_free (error);
+                       }
  
+                               
                        if( rc == FALSE )
                        {
                                error = NULL;
                                g_markup_parse_context_end_parse(context, &error);
  
                                if( error )
+                               {
                                        g_print("failed: %s\n", error->message);
+                                       g_error_free (error);
+                               }
                        }
  
                        g_markup_parse_context_free (context);
                        {
                                homebank_upgrade_to_v12_7();
                        }
+                       if( ctx.file_version < 1.3 )    // <= 5.2 
+                       {
+                               hbfile_sanity_check();
+                               homebank_upgrade_to_v13();
+                       }
+                       if( ctx.data_version <= 50203 )
+                       {
+                               hbfile_sanity_check();
+                       }
  
                        // next ?
                        
@@@ -1016,7 -1066,7 +1071,7 @@@ static void hb_xml_append_txt(GString *
        if(value != NULL && *value != 0)
        {
                gchar *escaped = g_markup_escape_text(value, -1);
-               g_string_append_printf(gstring, "%s=\"%s\" ", attrname, escaped);
+               g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped);
                g_free(escaped);
        }
  }
@@@ -1089,14 -1139,14 +1144,14 @@@ static void hb_xml_append_txt_crlf(GStr
                length = strlen (value);
                escaped = g_string_sized_new (length);
                append_escaped_text (escaped, value, length);
-               g_string_append_printf(gstring, "%s=\"%s\" ", attrname, escaped->str);
+               g_string_append_printf(gstring, " %s=\"%s\"", attrname, escaped->str);
                g_string_free (escaped, TRUE);
        }
  }
  
  static void hb_xml_append_int0(GString *gstring, gchar *attrname, guint32 value)
  {
-       g_string_append_printf(gstring, "%s=\"%d\" ", attrname, value);
+       g_string_append_printf(gstring, " %s=\"%d\"", attrname, value);
  }
        
  static void hb_xml_append_int(GString *gstring, gchar *attrname, guint32 value)
@@@ -1113,7 -1163,7 +1168,7 @@@ char buf[G_ASCII_DTOSTR_BUF_SIZE]
  
        //we must use this, as fprintf use locale decimal settings and not '.'
        g_ascii_dtostr (buf, sizeof (buf), amount);
-       g_string_append_printf(gstring, "%s=\"%s\" ", attrname, buf);
+       g_string_append_printf(gstring, " %s=\"%s\"", attrname, buf);
  }
  
  
@@@ -1134,7 -1184,7 +1189,7 @@@ GError *error = NULL
  
        node = g_string_sized_new(255);
  
-       g_string_assign(node, "<properties ");
+       g_string_assign(node, "<properties");
        
        hb_xml_append_txt(node, "title", title);
        hb_xml_append_int(node, "curr", GLOBALS->kcur);
@@@ -1217,7 -1267,7 +1272,7 @@@ GError *error = NULL
  
                item->flags &= ~(AF_ADDED|AF_CHANGED);  //delete flag
  
-               g_string_assign(node, "<account ");
+               g_string_assign(node, "<account");
                
                hb_xml_append_int(node, "key", item->key);
                hb_xml_append_int(node, "flags", item->flags);
                hb_xml_append_int(node, "cheque1", item->cheque1);
                hb_xml_append_int(node, "cheque2", item->cheque2);
                hb_xml_append_txt_crlf(node, "notes", item->notes);
+               hb_xml_append_int(node, "tpl", item->karc);
  
                g_string_append(node, "/>\n");
  
@@@ -1271,7 -1323,7 +1328,7 @@@ GError *error = NULL
  
                if(item->key != 0)
                {
-                       g_string_assign(node, "<pay ");
+                       g_string_assign(node, "<pay");
  
                        hb_xml_append_int(node, "key", item->key);
                        hb_xml_append_txt(node, "name", item->name);
@@@ -1318,7 -1370,7 +1375,7 @@@ GError *error = NULL
  
                if(item->key != 0)
                {
-                       g_string_assign(node, "<cat ");
+                       g_string_assign(node, "<cat");
                
                        hb_xml_append_int(node, "key", item->key);
                        hb_xml_append_int(node, "parent", item->parent);
                        {
                                if(item->budget[i] != 0)
                                {
-                                       g_string_append_printf(node,"b%d=\"%s\" ", i, g_ascii_dtostr (buf, sizeof (buf), item->budget[i]));
+                                       g_string_append_printf(node," b%d=\"%s\"", i, g_ascii_dtostr (buf, sizeof (buf), item->budget[i]));
                                }
                        }
  
  /*
  ** XML tag save
  */
- static gint homebank_save_xml_tag(GIOChannel *io)
/*static gint homebank_save_xml_tag(GIOChannel *io)
  {
  GList *ltag, *list;
  gchar *tmpstr;
@@@ -1388,7 -1440,7 +1445,7 @@@ GError *error = NULL
        }
        g_list_free(ltag);
        return retval;
- }
+ }*/
  
  
  /*
@@@ -1408,7 -1460,7 +1465,7 @@@ GError *error = NULL
        {
        Assign *item = list->data;
  
-               g_string_assign(node, "<asg ");
+               g_string_assign(node, "<asg");
  
                hb_xml_append_int(node, "key"     , item->key);
                hb_xml_append_int(node, "flags"   , item->flags);
@@@ -1445,6 -1497,7 +1502,7 @@@ static gint homebank_save_xml_arc(GIOCh
  {
  GList *list;
  GString *node;
+ gchar *tagstr;
  gint retval = XML_OK;
  GError *error = NULL;
  
        {
        Archive *item = list->data;
  
-               g_string_assign(node, "<fav ");
+               tagstr = tags_tostring(item->tags);
+               g_string_assign(node, "<fav");
  
+               hb_xml_append_int(node, "key", item->key);
                hb_xml_append_amt(node, "amount", item->amount);
                hb_xml_append_int(node, "account", item->kacc);
                hb_xml_append_int(node, "dst_account", item->kxferacc);
                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->memo); 
+               hb_xml_append_txt(node, "wording", item->memo);
+               hb_xml_append_txt(node, "tags", tagstr);        
                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, "weekend", item->weekend);
                hb_xml_append_int(node, "gap", item->daygap);
  
-               if(da_splits_count(item->splits) > 0)
+               if(da_splits_length(item->splits) > 0)
                {
-                       gchar *cats, *amounts, *memos;
+               gchar *cats, *amounts, *memos;
                
                        da_splits_tostring(item->splits, &cats, &amounts, &memos);
-                       g_string_append_printf(node, "scat=\"%s\" ", cats);
-                       g_string_append_printf(node, "samt=\"%s\" ", amounts);
+                       g_string_append_printf(node, " scat=\"%s\"", cats);
+                       g_string_append_printf(node, " samt=\"%s\"", amounts);
  
                        //fix #1173910
                        gchar *escaped = g_markup_escape_text(memos, -1);
-                       g_string_append_printf(node, "smem=\"%s\" ", escaped);
+                       g_string_append_printf(node, " smem=\"%s\"", escaped);
                        g_free(escaped);
  
                        g_free(cats);
                }
  
                g_string_append(node, "/>\n");
+               
+               g_free(tagstr);
  
                error = NULL;
                g_io_channel_write_chars(io, node->str, -1, NULL, &error);
@@@ -1534,9 -1593,9 +1598,9 @@@ GError *error = NULL
                Transaction *item = list->data;
  
                        item->flags &= ~(OF_AUTO|OF_ADDED|OF_CHANGED);  //delete flag
-                       tagstr = transaction_tags_tostring(item);
+                       tagstr = tags_tostring(item->tags);
  
-                       g_string_assign(node, "<ope ");
+                       g_string_assign(node, "<ope");
                
                        hb_xml_append_int(node, "date", item->date);
                        hb_xml_append_amt(node, "amount", item->amount);
                        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_length(item->splits) > 0)
                        {
                        gchar *cats, *amounts, *memos;
                
                                da_splits_tostring(item->splits, &cats, &amounts, &memos);
-                               g_string_append_printf(node, "scat=\"%s\" ", cats);
-                               g_string_append_printf(node, "samt=\"%s\" ", amounts);
+                               g_string_append_printf(node, " scat=\"%s\"", cats);
+                               g_string_append_printf(node, " samt=\"%s\"", amounts);
  
                                //fix #1173910
                                gchar *escaped = g_markup_escape_text(memos, -1);
-                               g_string_append_printf(node, "smem=\"%s\" ", escaped);
+                               g_string_append_printf(node, " smem=\"%s\"", escaped);
                                g_free(escaped);
  
                                g_free(cats);
@@@ -1605,42 -1664,35 +1669,38 @@@ gchar *outstr
  gint retval = XML_OK;
  GError *error = NULL;
  
 +      GValue filename_val = G_VALUE_INIT;
 +      ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL);
 +
        io = g_io_channel_new_file(filename, "w", &error);
-       if(io == NULL)
+       if(error)
        {
-               g_message("file error on: %s", filename);
-               retval = XML_IO_ERROR;
-               
-               if(error)
-                       g_print("failed: %s\n", error->message);
-               
+               g_warning("unable to save file %s: %s", filename, error->message);
                g_error_free(error);
+               return(XML_IO_ERROR);
        }
-       else
-       {
-               g_io_channel_write_chars(io, "<?xml version=\"1.0\"?>\n", -1, NULL, NULL);
  
-               outstr = g_strdup_printf("<homebank v=\"%s\" d=\"%06d\">\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM);
-               g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
-               g_free(outstr);
+       g_io_channel_write_chars(io, "<?xml version=\"1.0\"?>\n", -1, NULL, NULL);
  
-               retval = homebank_save_xml_prop(io);
-               retval = homebank_save_xml_cur(io);
-               retval = homebank_save_xml_acc(io);
-               retval = homebank_save_xml_pay(io);
-               retval = homebank_save_xml_cat(io);
-               retval = homebank_save_xml_tag(io);
-               retval = homebank_save_xml_asg(io);
-               retval = homebank_save_xml_arc(io);
-               retval = homebank_save_xml_ope(io);
+       outstr = g_strdup_printf("<homebank v=\"%s\" d=\"%06d\">\n", g_ascii_dtostr (buf1, sizeof (buf1), FILE_VERSION), HB_VERSION_NUM);
+       g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
+       g_free(outstr);
  
-               g_io_channel_write_chars(io, "</homebank>\n", -1, NULL, NULL);
+       retval = homebank_save_xml_prop(io);
+       retval = homebank_save_xml_cur(io);
+       retval = homebank_save_xml_acc(io);
+       retval = homebank_save_xml_pay(io);
+       retval = homebank_save_xml_cat(io);
+       //retval = homebank_save_xml_tag(io);
+       retval = homebank_save_xml_asg(io);
+       retval = homebank_save_xml_arc(io);
+       retval = homebank_save_xml_ope(io);
+       g_io_channel_write_chars(io, "</homebank>\n", -1, NULL, NULL);
+       g_io_channel_unref (io);
  
-               g_io_channel_unref (io);
-       }
        return retval;
  }
  
diff --combined src/homebank.c
index 60e87c88650dbc4ccc7bc0329cec3e07db271bf4,f33a1cb97bd2353c89d5831bce6d38e98d6175dd..2eff668abf92d5347c69dd59c96c67316330e20c
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -19,9 -19,8 +19,9 @@@
  
  
  #include "homebank.h"
 +#include "ext.h"
  
- #include "dsp_mainwindow.h"
+ #include "dsp-mainwindow.h"
  #include "hb-preferences.h"
  #include "language.h"
  
@@@ -56,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>"
@@@ -86,7 -84,7 +86,7 @@@ static GOptionEntry option_entries[] 
  gint homebank_alienfile_recognize(gchar *filename)
  {
  GIOChannel *io;
- gint i, retval = FILETYPE_UNKNOW;
+ gint i, retval = FILETYPE_UNKNOWN;
  gchar *tmpstr;
  gint io_stat;
  GError *err = NULL;
@@@ -111,7 -109,7 +111,7 @@@ static gint csvtype[7] = 
  
                for(i=0;i<25;i++)
                {
-                       if( retval != FILETYPE_UNKNOW )
+                       if( retval != FILETYPE_UNKNOWN )
                                break;
  
                        io_stat = g_io_channel_read_line(io, &tmpstr, NULL, NULL, &err);
@@@ -248,11 -246,15 +248,15 @@@ gboolean retval = FALSE
  
        if( g_file_test(filepath, G_FILE_TEST_EXISTS) )
        {
+               DB( g_print(" - deleting: '%s'\n", filepath) );
                g_remove(filepath);
                retval = TRUE;
        }
-       DB( g_print(" - deleted: '%s' :: %d\n", filepath, retval) );
+       else
+       {
+               DB( g_print(" - cannot delete: '%s'\n", filepath) );
+       }
+       
        return retval;
  }
  
  void homebank_backup_current_file(void)
  {
  gchar *bakfilename;
+ GPtrArray *array;
+ gint i;
  
        DB( g_print("\n[homebank] backup_current_file\n") );
  
        //retval = g_rename(pathname, newname);
        homebank_file_copy (GLOBALS->xhb_filepath, bakfilename);
        g_free(bakfilename);
+       //do safe backup according to user preferences
+       DB( g_print(" user pref backup\n") );   
+       if( PREFS->bak_is_automatic == TRUE )
+       {
+               bakfilename = hb_filename_new_for_backup(GLOBALS->xhb_filepath);
+               if( g_file_test(bakfilename, G_FILE_TEST_EXISTS) == FALSE )
+               {
+                       homebank_file_copy (GLOBALS->xhb_filepath, bakfilename);
+               }
+               g_free(bakfilename);
+               //delete any offscale backup
+               DB( g_print(" clean old backup\n") );
+               array = hb_filename_backup_list(GLOBALS->xhb_filepath);
+               DB( g_print(" found %d match\n", array->len) );
+               gchar *dirname = g_path_get_dirname(GLOBALS->xhb_filepath);
+               
+               for(i=0;i<(gint)array->len;i++)
+               {
+               gchar *offscalefilename = g_ptr_array_index(array, i);
+       
+                       DB( g_print(" %d : '%s'\n", i, offscalefilename) );
+                       if( i >= PREFS->bak_max_num_copies )
+                       {
+                       gchar *bakdelfilepath = g_build_filename(dirname, offscalefilename, NULL);
+                               DB( g_print(" - should delete '%s'\n", bakdelfilepath) );
+                       
+                               homebank_file_delete_existing(bakdelfilepath);
+                               g_free(bakdelfilepath);
+                       }
+               }
+               g_ptr_array_free(array, TRUE);
+               g_free(dirname);
+       }
  }
  
  
@@@ -357,6 -402,7 +404,7 @@@ gchar *homebank_lastopenedfiles_load(vo
  GKeyFile *keyfile;
  gchar *group, *filename, *tmpfilename;
  gchar *lastfilename = NULL;
+ GError *error = NULL;
  
        DB( g_print("\n[homebank] lastopenedfiles load\n") );
  
        if(keyfile)
        {
                filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL );
-               if(g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL))
+               if(g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, &error))
                {
                        group = "HomeBank";
  
                                }
                        }
                }
+               if( error )
+               {
+                       g_print("failed: %s\n", error->message);
+                       g_error_free (error);
+               }
                g_free(filename);
                g_key_file_free (keyfile);
        }
@@@ -395,29 -448,41 +450,41 @@@ GKeyFile *keyfile
  gboolean retval = FALSE;
  gchar *group, *filename;
  gsize length;
+ GError *error = NULL;
  
        DB( g_print("\n[homebank] lastopenedfiles save\n") );
  
        if( GLOBALS->xhb_filepath != NULL )
        {
-               keyfile = g_key_file_new();
-               if(keyfile )
+               //don't save bakup files
+               if( hbfile_file_isbackup(GLOBALS->xhb_filepath) == FALSE )
                {
-                       DB( g_print(" - saving '%s'\n", GLOBALS->xhb_filepath) );
+                       keyfile = g_key_file_new();
+                       if(keyfile )
+                       {
+                               DB( g_print(" - saving '%s'\n", GLOBALS->xhb_filepath) );
  
-                       group = "HomeBank";
-                       g_key_file_set_string  (keyfile, group, "LastOpenedFile", GLOBALS->xhb_filepath);
+                               group = "HomeBank";
+                               g_key_file_set_string  (keyfile, group, "LastOpenedFile", GLOBALS->xhb_filepath);
  
-                       gchar *contents = g_key_file_to_data( keyfile, &length, NULL);
+                               gchar *contents = g_key_file_to_data( keyfile, &length, NULL);
  
-                       //DB( g_print(" keyfile:\n%s\nlen=%d\n", contents, length) );
+                               //DB( g_print(" keyfile:\n%s\nlen=%d\n", contents, length) );
  
-                       filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL );
-                       g_file_set_contents(filename, contents, length, NULL);
-                       g_free(filename);
+                               filename = g_build_filename(homebank_app_get_config_dir(), "lastopenedfiles", NULL );
  
-                       g_free(contents);
-                       g_key_file_free (keyfile);
+                               g_file_set_contents(filename, contents, length, &error);
+                               g_free(filename);
+                               if( error )
+                               {
+                                       g_print("failed: %s\n", error->message);
+                                       g_error_free (error);
+                               }
+                               
+                               g_free(contents);
+                               g_key_file_free (keyfile);
+                       }
                }
        }
  
@@@ -565,12 -630,6 +632,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
@@@ -587,7 -646,6 +654,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) );
  
  }
  
@@@ -760,7 -816,6 +827,7 @@@ static void homebank_cleanup(
        g_free (pixmaps_dir);
        g_free (locale_dir);
        g_free (help_dir);
 +      g_free (pkglib_dir);
  
  }
  
@@@ -891,7 -946,7 +958,7 @@@ homebank_init_i18n (void
  
  
  int
 -main (int argc, char *argv[])
 +main (int argc, char *argv[], char *env[])
  {
  GOptionContext *option_context;
  GOptionGroup *option_group;
@@@ -963,22 -1018,6 +1030,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)
                {
  
@@@ -1104,20 -1140,13 +1171,20 @@@ nobak
                        /* update the mainwin display */
                        ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL));
  
 +                      ext_hook("enter_main_loop", NULL);
 +
                        DB( g_print(" - gtk_main()\n" ) );
                        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 bc69153e0718f79991dea2885b7fe9919e38b566,dc6685f7f09e1b084ddba0ca8c1dd73a6cbe9a55..60cd2a450c22aa40e36784f331c2db47d8562eeb
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  #define N_(str) gettext_noop (str)
  
  /* = = = = = = = = = = = = = = = = */
- /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
+ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  
  #define HB_UNSTABLE                   FALSE
  #define HB_UNSTABLE_SHOW      FALSE
  
  
  #define HB_VERSION_MAJOR      5
- #define HB_VERSION_MINOR      1
- #define HB_VERSION_MICRO      7
+ #define HB_VERSION_MINOR      2
+ #define HB_VERSION_MICRO      4
  
- #define HB_VERSION                    "5.1.7"
+ #define HB_VERSION            "5.2.4"
  #define HB_VERSION_NUM        (HB_VERSION_MAJOR*10000) + (HB_VERSION_MINOR*100) + HB_VERSION_MICRO
  
- #define FILE_VERSION          1.2
- #define PREF_VERSION          517
+ #define FILE_VERSION          1.3
+ #define PREF_VERSION          524
  
  #if HB_UNSTABLE == FALSE
        #define PROGNAME                "HomeBank"
  #define SPACING_MEDIUM                12
  #define SPACING_LARGE         18
  
+ #define HB_DATE_MAX_GAP       7
  
+ // those 2 line are duplicated into dateentry
  #define HB_MINDATE  693596      //01/01/1900
  #define HB_MAXDATE  803533      //31/12/2200
  
  /* miscellaneous */
  #define PHI 1.61803399
  
- /* official GTK_RESPONSE are negative */
- #define GTK_RESPONSE_ADD               1
- #define GTK_RESPONSE_ADDKEEP   2
  
  #define HB_NUMBER_SAMPLE      1234567.89
  
  
  typedef enum
  {
-       FILETYPE_UNKNOW,
+       FILETYPE_UNKNOWN,
        FILETYPE_HOMEBANK,
        FILETYPE_OFX,
        FILETYPE_QIF,
  
  
  /* -------- named icons (Standard Icon Name) -------- */
- #define ICONNAME_NEW                          "document-new"
- #define ICONNAME_OPEN                         "document-open"
- #define ICONNAME_SAVE                         "document-save"
+ //obsolete, as since since gtk3.10 : no more icons for dialogs and menu
  #define ICONNAME_SAVE_AS                      "document-save-as"        //obsolete
- #define ICONNAME_REVERT                           "document-revert"     //obsolete
- #define ICONNAME_PRINT                                "document-print"                //unused
+ #define ICONNAME_REVERT                   "document-revert"     //obsolete
  #define ICONNAME_PROPERTIES                   "document-properties"   //obsolete
  #define ICONNAME_CLOSE                                "window-close"    //obsolete
  #define ICONNAME_QUIT                         "application-exit"        //obsolete
- #define ICONNAME_FIND                         "edit-find"
- #define ICONNAME_CLEAR                                "edit-clear"
- #define ICONNAME_WARNING                      "dialog-warning"
- #define ICONNAME_ERROR                                "dialog-error"
- #define ICONNAME_INFO                         "dialog-information"
  #define ICONNAME_HELP                         "help-browser"    //obsolete
  #define ICONNAME_ABOUT                                "help-about"      //obsolete
  #define ICONNAME_PREFERENCES          "preferences-system"      //obsolete
- #define ICONNAME_REFRESH                      "view-refresh"          
  
- #define ICONNAME_FOLDER                               "folder-symbolic"
- #define ICONNAME_EMBLEM_SYSTEM                "emblem-system-symbolic"
  
+ //#define ICONNAME_FIND                               "edit-find"                             //unused
+ //#define ICONNAME_CLEAR                      "edit-clear"                    //unused
+ //#define ICONNAME_HB_SCHED_SKIP              "media-skip-forward"
+ //#define ICONNAME_HB_SCHED_POST              "media-playback-start"
+ //in 5.2 no themeable icon to keep a consistent iconset
+ #define ICONNAME_WARNING                      "dialog-warning"
+ #define ICONNAME_ERROR                                "dialog-error"
+ #define ICONNAME_INFO                         "dialog-information"
  
+ #define ICONNAME_FOLDER                               "folder-symbolic"
+ #define ICONNAME_EMBLEM_OK                    "emblem-ok-symbolic"
+ #define ICONNAME_EMBLEM_SYSTEM                "emblem-system-symbolic"
+ #define ICONNAME_WINDOW_CLOSE         "window-close-symbolic"
  #define ICONNAME_LIST_ADD                     "list-add-symbolic"
  #define ICONNAME_LIST_REMOVE          "list-remove-symbolic"
+ #define ICONNAME_LIST_REMOVE_ALL      "list-remove-all-symbolic"
  #define ICONNAME_CHANGES_PREVENT      "changes-prevent-symbolic"
+ #define ICONNAME_SYSTEM_SEARCH                "system-search-symbolic"
  
  // custom or gnome not found
  #define ICONNAME_HB_BUTTON_MENU               "open-menu-symbolic"
+ #define ICONNAME_HB_BUTTON_COLLAPSE   "list-collapse-all-symbolic"
+ #define ICONNAME_HB_BUTTON_EXPAND     "list-expand-all-symbolic"
+ #define ICONNAME_HB_BUTTON_SPLIT      "edit-split-symbolic"
  #define ICONNAME_HB_TOGGLE_SIGN               "toggle-sign-symbolic"
  
  
  /* -------- named icons (Custom to homebank) -------- */
  #define ICONNAME_HB_CURRENCY          "hb-currency"
  #define ICONNAME_HB_ACCOUNT         "hb-account"
  #define ICONNAME_HB_ARCHIVE         "hb-archive"
  #define ICONNAME_HB_VIEW_STACK            "hb-view-stack"  //"view-chart-stack"
  #define ICONNAME_HB_VIEW_PIE      "hb-view-pie"    //"view-chart-pie"
  #define ICONNAME_HB_VIEW_DONUT            "hb-view-donut"  //"view-chart-donut"
- #define ICONNAME_HB_SHOW_LEGEND           "hb-legend"          //"view-legend"
- #define ICONNAME_HB_SHOW_RATE     "hb-rate"       // obsolete ?
- #define ICONNAME_HB_FILTER          "hb-filter"                //"edit-filter"
- #define ICONNAME_HB_FILE_IMPORT               "hb-file-import"        //document-import
- #define ICONNAME_HB_FILE_EXPORT               "hb-file-export"        //document-export
+ #define ICONNAME_HB_SHOW_LEGEND           "hb-legend"         //"view-legend"
+ #define ICONNAME_HB_SHOW_RATE     "hb-rate"           // obsolete ?
+ #define ICONNAME_HB_REFRESH               "hb-view-refresh"   //"view-refresh"        
+ #define ICONNAME_HB_FILTER                "hb-filter"         //"edit-filter"
+ #define ICONNAME_HB_FILE_NEW          "hb-document-new"               //document-new
+ #define ICONNAME_HB_FILE_OPEN         "hb-document-open"      //document-open
+ #define ICONNAME_HB_FILE_SAVE         "hb-document-save"      //document-save
+ //#define ICONNAME_PRINT                              "document-print"
+ #define ICONNAME_HB_FILE_IMPORT               "hb-file-import"                //document-import
+ #define ICONNAME_HB_FILE_EXPORT               "hb-file-export"                //document-export
  #define ICONNAME_HB_FILE_VALID                "hb-file-valid"
  #define ICONNAME_HB_FILE_INVALID      "hb-file-invalid"
  
- #define ICONNAME_HB_BUTTON_COLLAPSE   "btn-collapse-symbolic"
- #define ICONNAME_HB_BUTTON_EXPAND     "btn-expand-symbolic"
- #define ICONNAME_HB_BUTTON_SPLIT      "btn-split"
  #define ICONNAME_HB_OPE_AUTO        "hb-ope-auto"   //? 
  #define ICONNAME_HB_OPE_BUDGET      "hb-ope-budget" //? 
  #define ICONNAME_HB_OPE_ADD         "hb-ope-add"      //? "edit-add"
  #define ICONNAME_HB_OPE_EDIT        "hb-ope-edit"   //
  #define ICONNAME_HB_OPE_MULTIEDIT   "hb-ope-multiedit"   //
  #define ICONNAME_HB_OPE_DELETE      "hb-ope-delete" //? "edit-delete"
- #define ICONNAME_CONVERT                      "hb-ope-convert"
+ #define ICONNAME_CONVERT                      "hb-ope-convert"        // obsolete ?
  #define ICONNAME_HB_ASSIGN_RUN      "hb-assign-run"
  
- #define ICONNAME_HB_OPE_VALID       "hb-ope-valid"  // obsolete ?
- #define ICONNAME_HB_OPE_CLEARED     "hb-ope-cleared"
- #define ICONNAME_HB_OPE_RECONCILED  "hb-ope-reconciled"
+ #define ICONNAME_HB_OPE_NEW                "hb-ope-new"
+ // edit is defined above
  #define ICONNAME_HB_OPE_REMIND      "hb-ope-remind"
+ #define ICONNAME_HB_OPE_SIMILAR     "hb-ope-similar"
  
+ #define ICONNAME_HB_OPE_CLEARED     "hb-ope-cleared"
+ #define ICONNAME_HB_OPE_RECONCILED  "hb-ope-reconciled"
+ #define ICONNAME_HB_OPE_FUTURE      "hb-ope-future"
  
  
  /*
@@@ -277,7 -293,8 +293,8 @@@ struct HomeBan
        gboolean                hbfile_is_new;
        gboolean                hbfile_is_bak;
        gchar                   *xhb_filepath;
-       gboolean                xhb_hasbak;             //file has backup (*.xhb~) used for revert menu sensitivity
+       gboolean                xhb_hasrevert;          //file has backup (*.xhb~) used for revert menu sensitivity
+       guint64                 xhb_timemodified;
  
        // really global stuffs
        gboolean                first_run;
        gboolean                minor;
  
        GtkWidget               *mainwindow;    //should be global to access attached window data
+       GtkWidget               *alltxnwindow;  //window to mutex all txn show
        GtkIconTheme    *icontheme;
        //GdkPixbuf             *lst_pixbuf[NUM_LST_PIXBUF];
        //gint                  lst_pixbuf_maxwidth;
@@@ -310,7 -328,6 +328,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 bcee6b1848e09e19df8a61921583935c0496a3a9,a5c56eb6db19bbbedd5cac7f52cf9fe87dc52908..c9d435a72c622faefcb2dd4612bf09023002265f
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  #include "homebank.h"
  
  #include "ui-pref.h"
- #include "dsp_mainwindow.h"
+ #include "dsp-mainwindow.h"
  #include "gtk-chart-colors.h"
  
 +#include "ext.h"
 +
  #include "ui-currency.h"
  
  
@@@ -55,35 -53,43 +55,40 @@@ enum 
  
  enum
  {
 -      PREF_GENERAL,
 -      PREF_INTERFACE,
 -      PREF_LOCALE,    //old DISPLAY
 -      PREF_TXN,               //old COLUMNS
 -      PREF_IMPORT,
 -      PREF_REPORT,
 -      PREF_BACKUP,
 -      PREF_FOLDERS,
 -      PREF_EURO,
 -      PREF_MAX
 +      EXT_COLUMN_ENABLED = 0,
 +      EXT_COLUMN_LABEL,
 +      EXT_COLUMN_TOOLTIP,
 +      EXT_COLUMN_PLUGIN_NAME,
 +      EXT_NUM_COLUMNS
  };
  
  
  static gchar *pref_iconname[PREF_MAX] = {
  "prf-general",
  "prf-interface",
+ "prf-locale",
  "prf-columns",
- "prf-display",
 -//"prf-display", 
++//"prf-display",
  "prf-import",
  "prf-report",
+ "prf-backup",
+ "prf-folder",
  "prf-euro",                   // to be renamed
 +"prf-plugins",
  //"prf_charts.svg"
  };
  
  static gchar *pref_name[PREF_MAX]    = {
  N_("General"),
  N_("Interface"),
+ N_("Locale"),
  N_("Transactions"),
- N_("Display format"),
  N_("Import/Export"),
  N_("Report"),
 -N_("Euro minor")
+ N_("Backup"),
+ N_("Folders"),
 +N_("Euro minor"),
 +N_("Plugins")
  //
  };
  
@@@ -124,6 -130,7 +129,7 @@@ gchar *CYA_IMPORT_OFXNAME[] = 
  N_("Ignore"),
  N_("Memo"),
  N_("Payee"),
+ N_("Info"),
  NULL
  };
  
@@@ -186,17 -193,14 +192,17 @@@ static EuroParams euro_params[] 
  };
  
  
 +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns);
 +
 +
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  
  
  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" },
@@@ -404,7 -408,7 +410,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);
@@@ -453,7 -457,7 +459,7 @@@ const gchar *lang
                        g_warning(" locale name not found '%s'", locale);
                        lang = locale;
                }
 -              
 +
        }
  
        return lang;
@@@ -468,7 -472,7 +474,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);
@@@ -491,13 -495,13 +497,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);
@@@ -534,7 -538,7 +540,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;
  }
  
@@@ -628,17 -632,17 +634,17 @@@ gboolean r
  
        switch( type )
        {
-               case 1:
+               case PRF_PATH_WALLET:
                        path = &PREFS->path_hbfile;
                        entry = data->ST_path_hbfile;
                        title = _("Choose a default HomeBank files folder");
                        break;
-               case 2:
+               case PRF_PATH_IMPORT:
                        path = &PREFS->path_import;
                        entry = data->ST_path_import;
                        title = _("Choose a default import folder");
                        break;
-               case 3:
+               case PRF_PATH_EXPORT:
                        path = &PREFS->path_export;
                        entry = data->ST_path_export;
                        title = _("Choose a default export folder");
@@@ -711,7 -715,7 +717,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);
@@@ -751,11 -755,11 +757,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);
@@@ -804,8 -808,26 +810,26 @@@ gboolean sensitive
  
        sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_custom_colors));
  
+       gtk_widget_set_sensitive(data->LB_colors         , sensitive);
+       gtk_widget_set_sensitive(data->CY_colors         , sensitive);
+       gtk_widget_set_sensitive(data->LB_exp_color      , sensitive);
        gtk_widget_set_sensitive(data->GR_colors         , sensitive);
+ }
+ static void defpref_backuptoggle(GtkWidget *widget, gpointer user_data)
+ {
+ struct defpref_data *data;
+ gboolean sensitive;
+       DB( g_print("\n[ui-pref] backup toggle\n") );
  
+       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
+       sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_bak_is_automatic));
+       gtk_widget_set_sensitive(data->LB_bak_max_num_copies, sensitive);
+       gtk_widget_set_sensitive(data->NB_bak_max_num_copies, sensitive);
+       gtk_widget_set_sensitive(data->GR_bak_freq          , sensitive);
  }
  
  
@@@ -870,7 -892,7 +894,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);
 -      
 +
  }
  
  
@@@ -914,8 -936,8 +938,8 @@@ GdkRGBA rgba
  
        // files/backup
        gtk_entry_set_text(GTK_ENTRY(data->ST_path_hbfile), PREFS->path_hbfile);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_bak_is_automatic), PREFS->bak_is_automatic);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_bak_max_num_copies), PREFS->bak_max_num_copies);
  
        // interface
        if(PREFS->language != NULL)
        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);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_memoacp), PREFS->txn_memoacp);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->ST_memoacp_days), PREFS->txn_memoacp_days);
  
        // display format
        gtk_entry_set_text(GTK_ENTRY(data->ST_datefmt), PREFS->date_format);
  
        // import/export
        gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_dtex_datefmt), PREFS->dtex_datefmt);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_dtex_ucfirst), PREFS->dtex_ucfirst);
        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);
@@@ -1010,10 -1035,10 +1037,10 @@@ const gchar *lang
        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)));
+       ui_gtk_entry_replace_text(data->ST_path_hbfile, &PREFS->path_hbfile);
  
+       PREFS->bak_is_automatic  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_bak_is_automatic));
+       PREFS->bak_max_num_copies = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_bak_max_num_copies));
  
        g_free(PREFS->language);
        PREFS->language = NULL;
        {
                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->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);
  
 -      // 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));
+       PREFS->txn_memoacp = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_memoacp));
+       PREFS->txn_memoacp_days = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_memoacp_days));
  
        // display format
        g_free(PREFS->date_format);
  
        // import/export
        PREFS->dtex_datefmt = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_datefmt));
+       PREFS->dtex_ucfirst = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_ucfirst));
        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));
        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->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));
  }
  
  
  static GtkWidget *defpref_page_import (struct defpref_data *data)
  {
- GtkWidget *content_grid, *group_grid, *hbox, *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(_("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:"));
+       label = make_label_widget(_("OFX _Name:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_cycle(label, CYA_IMPORT_OFXNAME);
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        row++;
-       label = make_label_widget(_("_Memo field:"));
+       label = make_label_widget(_("OFX _Memo:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_cycle(label, CYA_IMPORT_OFXMEMO);
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
        label = make_label_group(_("QIF options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
 -      
 +
        row = 1;
-       label = make_label_widget(_("Memos:"));
-       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
-       widget = gtk_check_button_new_with_mnemonic (_("_Import"));
+       widget = gtk_check_button_new_with_mnemonic (_("_Import memos"));
        data->CM_dtex_qifmemo = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
-       widget = gtk_check_button_new_with_mnemonic (_("_Swap with payees"));
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
+       widget = gtk_check_button_new_with_mnemonic (_("_Swap memos with payees"));
        data->CM_dtex_qifswap = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1);
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
-       // group :: Files folder
+       // group :: other options
      group_grid = gtk_grid_new ();
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
-       label = make_label_group(_("Files folder"));
+       label = make_label_group(_("Other options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
-       label = make_label_widget(_("_Import:"));
-       //----------------------------------------- l, r, t, b
-       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
-       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_widget_set_hexpand (hbox, TRUE);
-       gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
-       widget = make_string(label);
-       data->ST_path_import = widget;
-       gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED);
-       gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
-       //widget = gtk_button_new_with_label("...");
-       widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON);
-       data->BT_path_import = widget;
-       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-       row++;
-       label = make_label_widget(_("_Export:"));
-       //----------------------------------------- l, r, t, b
-       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
-       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_widget_set_hexpand (hbox, TRUE);
-       gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
-       widget = make_string(label);
-       data->ST_path_export = widget;
-       gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED);
-       gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+       widget = gtk_check_button_new_with_mnemonic (_("Sentence _case memo/payee"));
+       data->CM_dtex_ucfirst = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 1, 1);
 -      
 +
-       //widget = gtk_button_new_with_label("...");
-       widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON);
-       data->BT_path_export = widget;
-       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  
        return content_grid;
  }
@@@ -1230,7 -1221,7 +1225,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++)
@@@ -1263,12 -1254,12 +1258,12 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
        label = make_label_group(_("Initial filter"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
 -      
 +
        row = 1;
-       label = make_label_widget(_("Date _range:"));
+       label = make_label_widget(_("_Range:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_daterange(label, FALSE);
        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;
@@@ -1359,7 -1350,7 +1354,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);
  
  static GtkWidget *defpref_page_display (struct defpref_data *data)
  {
- GtkWidget *content_grid, *group_grid, *label, *widget, *expander;
+ GtkWidget *content_grid, *group_grid, *label, *widget, *expander, *hbox;
  gint crow, row;
  
        content_grid = gtk_grid_new();
        gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
  
        crow = 0;
-       // group :: Date options
+       // group :: General
      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(_("Date"));
+       label = make_label_group(_("User interface"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
+       label = make_label(_("_Language:"), 0, 0.5);
+       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
+       widget = ui_language_combobox_new(label);
+       data->CY_language = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
+       row++;
+       row++;
+       label = make_label(_("_Date display:"), 0, 0.5);
+       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_label(NULL, 0, 0.5);
        data->LB_date = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        row++;
        expander = gtk_expander_new_with_mnemonic(_("_Customize"));
-       gtk_grid_attach (GTK_GRID (group_grid), expander, 1, row, 1, 1);
+       gtk_grid_attach (GTK_GRID (group_grid), expander, 2, row, 1, 1);
  
      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_container_add (GTK_CONTAINER (expander), group_grid);
  
-       row = 1;
+       row++;
        label = make_label_widget(_("_Format:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 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"
  "%m month as a decimal number [01,12]. \n"
  "%p locale's appropriate date representation. \n"
  "%y year without century as a decimal number [00,99]. \n"
- "%Y year with century as a decimal number. \n")
+ "%Y year with century as a decimal number.")
  );
  
        row++;
        gtk_label_set_markup (GTK_LABEL(widget), "<small><a href=\"http://man7.org/linux/man-pages/man3/strftime.3.html\">online reference</a></small>");
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
+       // group :: Fiscal year
+     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(_("Fiscal year"));
+       gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
+       row = 1;
+       //TRANSLATORS: (fiscal year) starts on
+       label = make_label_widget(_("Starts _on:"));
+       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 = make_numeric (label, 1, 28);
+       data->NB_fiscyearday = widget;
+       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+       widget = make_cycle (NULL, CYA_MONTHS);
+       data->CY_fiscyearmonth = widget;
+       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
        // group :: Measurement units
      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(_("Measurement units"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
@@@ -1580,12 -1609,12 +1613,12 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
        label = make_label_group(_("Transaction window"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
-       label = make_label_widget(_("Date _range:"));
+       label = make_label(_("_Range:"), 0, 0.5);
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_daterange(label, FALSE);
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        row++;
-       label = make_label_widget(_("_Show:"));
+       label = make_label(_("_Show future:"), 0, 0.5);
        //----------------------------------------- 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);
  
        //TRANSLATORS: there is a spinner on the left of this label, and so you have 0....x days in advance the current date
-       label = make_label(_("days in advance the current date"), 0, 0.5);
+       label = make_label(_("days ahead"), 0, 0.5);
        gtk_grid_attach (GTK_GRID (group_grid), label, 3, row, 1, 1);
  
        row++;
        widget = gtk_check_button_new_with_mnemonic (_("Hide reconciled transactions"));
        data->CM_hide_reconciled = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 2, 1);
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 3, 1);
  
        row++;
        widget = gtk_check_button_new_with_mnemonic (_("Always show remind transactions"));
        data->CM_show_remind = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 2, 1);
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 3, 1);
  
        // group :: Multiple add
      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(_("Multiple add"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        data->CM_herit_date = widget;
        gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
  
 -      
+       // group :: Memo autocomplete
+     group_grid = gtk_grid_new ();
+       gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
+       gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
+       gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
++
+       label = make_label_group(_("Memo autocomplete"));
+       gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
+       row = 1;
+       widget = gtk_check_button_new_with_mnemonic (_("Active"));
+       data->CM_memoacp = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       row++;
+       widget = make_numeric(NULL, 0, 1460);
+       data->ST_memoacp_days = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
+       label = make_label(_("rolling days"), 0, 0.5);
+       gtk_grid_attach (GTK_GRID (group_grid), label, 3, row, 1, 1);
        // group :: Column list
        /*
      group_grid = gtk_grid_new ();
        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);
  
@@@ -1672,29 -1722,34 +1726,34 @@@ 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);
  
        row = 1;
-       label = make_label_widget(_("_Language:"));
-       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 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:"));
+       label = make_label(_("_Toolbar:"), 0, 0.5);
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_cycle(label, CYA_TOOLBAR_STYLE);
        data->CY_toolbar = widget;
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
  
        row++;
        //widget = gtk_check_button_new_with_mnemonic (_("Enable rows in alternating colors"));
        //data->CM_ruleshint = widget;
-       label = make_label_widget(_("_Grid line:"));
+       label = make_label(_("_Grid line:"), 0, 0.5);
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_cycle(label, CYA_GRID_LINES);
        data->CY_gridlines = 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(_("Amount colors"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
        widget = gtk_check_button_new_with_mnemonic (_("Uses custom colors"));
        data->CM_custom_colors = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
-     group_grid = gtk_grid_new ();
-       data->GR_colors = 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);
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
  
        row++;
-       label = make_label_widget(_("_Preset:"));
+       label = make_label(_("_Preset:"), 0, 0.5);
+       data->LB_colors = label;
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_cycle(label, CYA_TANGO_COLORS);
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        row++;
-       label = make_label_widget(_("_Expense:"));
+       label = make_label(_("_Expense:"), 0, 0.5);
+       data->LB_exp_color = label;
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
+       data->GR_colors = hbox;
        gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
 -      
 +
        widget = gtk_color_button_new ();
        data->CP_exp_color = widget;
        gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
 -      
 +
        label = make_label_widget(_("_Income:"));
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  
  }
  
  
- static GtkWidget *defpref_page_general (struct defpref_data *data)
+ static GtkWidget *defpref_page_filebackup (struct defpref_data *data)
  {
  GtkWidget *content_grid, *group_grid, *hbox, *label, *widget;
  gint crow, row;
        gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
  
        crow = 0;
-       // group :: Program start
+       // group :: Backup
      group_grid = gtk_grid_new ();
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
-       label = make_label_group(_("Program start"));
+       label = make_label_group(_("Backup"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
-       widget = gtk_check_button_new_with_mnemonic (_("Show splash screen"));
-       data->CM_show_splash = widget;
+       widget = gtk_check_button_new_with_mnemonic (_("_Enable automatic backups"));
+       data->CM_bak_is_automatic = widget;
        gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
  
        row++;
-       widget = gtk_check_button_new_with_mnemonic (_("Load last opened file"));
-       data->CM_load_last = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       label = make_label_widget(_("_Number of backups to keep:"));
+       data->LB_bak_max_num_copies = label;
+       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
+       widget = make_numeric (label, 1, 99);
+       data->NB_bak_max_num_copies = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        row++;
-       widget = gtk_check_button_new_with_mnemonic (_("Post pending scheduled transactions"));
-       data->CM_append_scheduled = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
+       data->GR_bak_freq = hbox;
+       //gtk_widget_set_hexpand (hbox, TRUE);
+       gtk_grid_attach (GTK_GRID (group_grid), hbox, 1, row, 2, 1);
  
-       row++;
-       widget = gtk_check_button_new_with_mnemonic (_("Update currencies online"));
-       data->CM_do_update_currency = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+               widget = gtk_image_new_from_icon_name (ICONNAME_INFO, GTK_ICON_SIZE_BUTTON);
+               gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+               label = make_label_widget(_("Backup frequency is once a day"));
+               gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  
-       // group :: Fiscal year
+       return content_grid;
+ }
+ static GtkWidget *defpref_page_folders (struct defpref_data *data)
+ {
+ GtkWidget *content_grid, *group_grid, *hbox, *label, *widget;
+ gint crow, row;
+       content_grid = gtk_grid_new();
+       gtk_grid_set_row_spacing (GTK_GRID (content_grid), SPACING_LARGE);
+       gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
+       crow = 0;
+       // group :: Files folder
      group_grid = gtk_grid_new ();
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
-       label = make_label_group(_("Fiscal year"));
+       label = make_label_group(_("HomeBank files"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        row = 1;
-       //TRANSLATORS: (fiscal year) starts on
-       label = make_label_widget(_("Starts _on:"));
+       label = make_label_widget(_("_Wallets:"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
  
-       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
+       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+       gtk_widget_set_hexpand (hbox, TRUE);
        gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
-       widget = make_numeric (label, 1, 28);
-       data->NB_fiscyearday = widget;
-       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-       widget = make_cycle (NULL, CYA_MONTHS);
-       data->CY_fiscyearmonth = widget;
+       widget = make_string(label);
+       data->ST_path_hbfile = widget;
+       gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED);
+       gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+       //widget = gtk_button_new_with_label("...");
+       widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON);
+       data->BT_path_hbfile = widget;
        gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  
-       // group :: Main window reports
+       // group :: Files folder
      group_grid = gtk_grid_new ();
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
 +
-       label = make_label_group(_("Main window reports"));
+       label = make_label_group(_("Exchange files"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
 -      
 +
        row = 1;
-       label = make_label_widget(_("Date _range:"));
+       label = make_label_widget(_("_Import:"));
+       //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
-       widget = make_daterange(label, FALSE);
-       data->CY_daterange_wal = widget;
-       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
-       // group :: Files folder
-     group_grid = gtk_grid_new ();
-       gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
-       gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
-       gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
+       hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+       gtk_widget_set_hexpand (hbox, TRUE);
+       gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
  
-       label = make_label_group(_("Files folder"));
-       gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
+       widget = make_string(label);
+       data->ST_path_import = widget;
+       gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED);
+       gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
  
-       row = 1;
-       label = make_label_widget(_("_Default:"));
+       //widget = gtk_button_new_with_label("...");
+       widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON);
+       data->BT_path_import = widget;
+       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+       row++;
+       label = make_label_widget(_("_Export:"));
+       //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
  
        hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
        gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
  
        widget = make_string(label);
-       data->ST_path_hbfile = widget;
+       data->ST_path_export = widget;
        gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET(widget)), GTK_STYLE_CLASS_LINKED);
        gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
  
        //widget = gtk_button_new_with_label("...");
        widget = gtk_button_new_from_icon_name(ICONNAME_FOLDER, GTK_ICON_SIZE_BUTTON);
-       data->BT_path_hbfile = widget;
+       data->BT_path_export = widget;
        gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  
 -      
+       return content_grid;
+ }
+ static GtkWidget *defpref_page_general (struct defpref_data *data)
+ {
+ GtkWidget *content_grid, *group_grid, *label, *widget;
+ gint crow, row;
+       content_grid = gtk_grid_new();
+       gtk_grid_set_row_spacing (GTK_GRID (content_grid), SPACING_LARGE);
+       gtk_orientable_set_orientation(GTK_ORIENTABLE(content_grid), GTK_ORIENTATION_VERTICAL);
+       crow = 0;
+       // group :: Program start
+     group_grid = gtk_grid_new ();
+       gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
+       gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
+       gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
 -      
++
+       label = make_label_group(_("Program start"));
+       gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
+       row = 1;
+       widget = gtk_check_button_new_with_mnemonic (_("Show splash screen"));
+       data->CM_show_splash = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       row++;
+       widget = gtk_check_button_new_with_mnemonic (_("Load last opened file"));
+       data->CM_load_last = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       row++;
+       widget = gtk_check_button_new_with_mnemonic (_("Post pending scheduled transactions"));
+       data->CM_append_scheduled = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       row++;
+       widget = gtk_check_button_new_with_mnemonic (_("Update currencies online"));
+       data->CM_do_update_currency = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 1, row, 2, 1);
+       // group :: Main window reports
+     group_grid = gtk_grid_new ();
+       gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
+       gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
+       gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
++
+       label = make_label_group(_("Main window reports"));
+       gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
+       row = 1;
+       label = make_label(_("_Range:"), 0, 0.5);
+       gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
+       widget = make_daterange(label, FALSE);
+       data->CY_daterange_wal = widget;
+       gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
        return content_grid;
  }
  
  
 +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;
@@@ -2137,31 -2084,31 +2283,31 @@@ GtkTreeModel *model
  /*
  ** add an empty new account to our temp GList and treeview
  */
- static void defpref_clear(GtkWidget *widget, gpointer user_data)
+ static void defpref_reset(GtkWidget *widget, gpointer user_data)
  {
  struct defpref_data *data;
  gint result;
  
        data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
-       DB( g_print("\n(defpref_clear) (data=%p)\n", data) );
+       DB( g_print("\n(defpref_reset) (data=%p)\n", data) );
  
        result = ui_dialog_msg_confirm_alert(
                GTK_WINDOW(data->window),
-               _("Reset all preferences"),
-               _("Do you really want to reset all\npreferences to default values?"),
-           _("Reset")
+               _("Reset All Preferences"),
+               _("Do you really want to reset\nall preferences to default\nvalues?"),
+           _("_Reset")
                );
        if( result == GTK_RESPONSE_OK )
        {
                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;
@@@ -2170,6 -2117,8 +2316,8 @@@ GtkWidget *hbox, *vbox, *sw, *widget, *
        window = gtk_dialog_new_with_buttons (_("Preferences"),
                                GTK_WINDOW(GLOBALS->mainwindow),
                                0,
+                               _("_Reset"),
+                               55,
                                _("_Cancel"),
                                GTK_RESPONSE_REJECT,
                                _("_OK"),
                                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.LV_page = widget;
        gtk_container_add (GTK_CONTAINER (sw), widget);
  
-       // clear button
-       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);
        #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
  
      gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
  
  /*
- "general",
- "interface",
- "display",
- "help",
- "euro",
- "report"
+       PREF_GENERAL,
+       PREF_INTERFACE,
+       PREF_LOCALE,    //old DISPLAY
+       PREF_TXN,               //old COLUMNS
+       PREF_IMPORT,
+       PREF_REPORT,
+       PREF_BACKUP,
+       PREF_FOLDERS,
+       PREF_EURO,
+       PREF_MAX
  */
  
        //general
        page = defpref_page_interface(&data);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
  
-       //columns
-       page = defpref_page_transactions(&data);
+       //locale
+       page = defpref_page_display(&data);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
  
-       //display
-       page = defpref_page_display(&data);
+       //transaction
+       page = defpref_page_transactions(&data);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
  
        //import
        page = defpref_page_reports(&data);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
  
+       //backup
+       page = defpref_page_filebackup(&data);
+       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
+       //folders
+       page = defpref_page_folders(&data);
+       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), page, NULL);
        //euro
        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);
        //connect all our signals
        g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
  
-       g_signal_connect (G_OBJECT (data.BT_clear), "clicked", G_CALLBACK (defpref_clear), NULL);
+       g_signal_connect (data.CM_bak_is_automatic, "toggled", G_CALLBACK (defpref_backuptoggle), NULL);
 -      
 +
        //path selector
-       g_signal_connect (data.BT_path_hbfile, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(1));
-       g_signal_connect (data.BT_path_import, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(2));
-       g_signal_connect (data.BT_path_export, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(3));
+       g_signal_connect (data.BT_path_hbfile, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_WALLET));
+       g_signal_connect (data.BT_path_import, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_IMPORT));
+       g_signal_connect (data.BT_path_export, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(PRF_PATH_EXPORT));
  
        g_signal_connect (data.CM_custom_colors, "toggled", G_CALLBACK (defpref_colortoggle), NULL);
      g_signal_connect (data.CY_colors, "changed", G_CALLBACK (defpref_colorpreset), NULL);
  
  
 -      
 +
        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;
+                       case 55:
+                               defpref_reset (window, NULL);
+                               break;
                }
 -      
 +
  
        // cleanup and destroy
        //defhbfile_cleanup(&data, result);
@@@ -2484,7 -2440,7 +2645,7 @@@ GtkTreeIter  iter
  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
  gboolean fixed;
  
 -      // get toggled iter 
 +      // get toggled iter
        gtk_tree_model_get_iter (model, &iter, path);
        gtk_tree_model_get (model, &iter, COLUMN_VISIBLE, &fixed, -1);
  
@@@ -2508,7 -2464,7 +2669,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;
@@@ -2557,16 -2513,16 +2718,16 @@@ gint i
        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,
  }
  */
  
 +
 +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 1ec90ba22a200f429b973224e147b932f3ba6251,19d387636cc1a48fcb8327b666a9509395df8e87..1ceb45751cd09b7396ca45ea61cb360a7e89c098
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2018 Maxime DOYEN
+  *  Copyright (C) 1995-2019 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  
  struct defpref_data
  {
+       // common
        GtkWidget       *window;
        GtkWidget       *LV_page;
        GtkWidget       *GR_page;
        GtkWidget       *label;
        GtkWidget       *image;
        GtkWidget   *BT_clear;
  
+       // general
+       GtkWidget       *CM_show_splash;
+       GtkWidget       *CM_load_last;
+       GtkWidget       *CM_append_scheduled;
+       GtkWidget   *CM_do_update_currency;
+       GtkWidget       *ST_path_hbfile, *BT_path_hbfile;
+       GtkWidget   *CM_bak_is_automatic;
+       GtkWidget       *GR_bak_freq;
+       GtkWidget   *LB_bak_max_num_copies, *NB_bak_max_num_copies;
+       GtkWidget       *CY_daterange_wal;
+       GtkWidget   *NB_fiscyearday;
+       GtkWidget   *CY_fiscyearmonth;
        GtkWidget       *CY_language;
        GtkWidget       *CY_toolbar;
  
+       GtkWidget       *LB_colors, *CY_colors;
        GtkWidget   *GR_colors;
-       GtkWidget       *CY_colors;
        GtkWidget       *CM_custom_colors;
-       GtkWidget       *CP_exp_color;
+       GtkWidget       *LB_exp_color, *CP_exp_color;
        GtkWidget       *CP_inc_color;
        GtkWidget       *CP_warn_color;
        //GtkWidget     *CM_ruleshint;
        GtkWidget       *CY_gridlines;
  
-       GtkWidget       *LV_opecolumns;
+       //GtkWidget     *LV_opecolumns;
        GtkWidget       *BT_go_up;
        GtkWidget       *BT_go_down;
  
-       GtkWidget   *NB_fiscyearday;
-       GtkWidget   *CY_fiscyearmonth;
--      
++
        GtkWidget       *CM_runwizard;
  
-       GtkWidget       *ST_path_hbfile, *BT_path_hbfile;
        GtkWidget       *ST_path_import, *BT_path_import;
        GtkWidget       *ST_path_export, *BT_path_export;
  
-       GtkWidget       *CM_load_last;
-       GtkWidget       *CM_show_splash;
-       GtkWidget       *CM_append_scheduled;
-       GtkWidget   *CM_do_update_currency;
        GtkWidget       *CM_herit_date;
        GtkWidget       *CM_hide_reconciled;
        GtkWidget       *CM_show_remind;
+       GtkWidget       *CM_memoacp;
+       GtkWidget       *ST_memoacp_days;
  
        GtkWidget       *ST_datefmt;
        GtkWidget       *LB_date;
        GtkWidget       *CM_unitismile;
        GtkWidget       *CM_unitisgal;
  
-       GtkWidget       *CY_daterange_wal;
        GtkWidget       *CY_daterange_txn;
        GtkWidget   *ST_datefuture_nbdays;
        GtkWidget       *CY_daterange_rep;
--      
++
        /* currencies */
        GtkWidget       *LB_default;
--      GtkWidget       *BT_default; 
--      
++      GtkWidget       *BT_default;
++
        GtkWidget       *CM_euro_enable;
        GtkWidget       *GRP_currency;
        GtkWidget       *GRP_rate;
        GtkWidget       *GRP_format;
--       
++
        GtkWidget       *CY_euro_preset;
        GtkWidget       *ST_euro_country;
        GtkWidget       *NB_euro_value;
  
        GtkWidget       *ST_euro_symbol;
        GtkWidget       *CM_euro_isprefix;
--      GtkWidget       *ST_euro_decimalchar;   
--      GtkWidget       *ST_euro_groupingchar;  
++      GtkWidget       *ST_euro_decimalchar;
++      GtkWidget       *ST_euro_groupingchar;
        GtkWidget       *NB_euro_fracdigits;
        GtkWidget       *LB_numbereuro;
  
        GtkWidget       *CY_dtex_ofxmemo;
        GtkWidget       *CM_dtex_qifmemo;
        GtkWidget       *CM_dtex_qifswap;
+       GtkWidget       *CM_dtex_ucfirst;
  
        gint            country;
  
 +      GtkWidget       *PI_plugin_columns;
  };
  
-       PREF_TRANSACTIONS,
-       PREF_DISPLAY_FORMAT,
-       PREF_IMPORT_EXPORT,
 +enum
 +{
 +      PREF_GENERAL,
 +      PREF_INTERFACE,
-       PREF_EURO_MINOR,
++      PREF_LOCALE,    //old DISPLAY
++      PREF_TXN,               //old COLUMNS
++      PREF_IMPORT,
 +      PREF_REPORT,
++      PREF_BACKUP,
++      PREF_FOLDERS,
++      PREF_EURO,
 +      PREF_PLUGINS,
 +      PREF_MAX
 +};
  
 -typedef struct 
 +
- typedef struct 
++typedef struct
  {
        gchar   *locale;
        gchar   *name;
@@@ -159,10 -159,15 +175,15 @@@ typedef struc
  } EuroParams;
  
  
+ enum {
+       PRF_PATH_WALLET,
+       PRF_PATH_IMPORT,
+       PRF_PATH_EXPORT,
+ };
  
  void free_pref_icons(void);
  void load_pref_icons(void);
  
 -GtkWidget *defpref_dialog_new (void);
 +GtkWidget *defpref_dialog_new (gint initial_selection);
  
  #endif
index 91ced1bb5e66320fa97f5e7cc4c8daef952dd75e,48f5746cfbe21fcb06cce894aceba01c436277e9..fd5bcc945ccaeea65f2ea065b25fc5f52f229b93
@@@ -10,18 -10,11 +10,11 @@@ public_icons = 
        $(NULL)
  
  private_icons = \
-       hicolor_actions_16x16_btn-collapse.png \
-       hicolor_actions_16x16_btn-expand.png \
-       hicolor_status_16x16_btn-split.png \
-       hicolor_status_16x16_flt-exclude.png \
-       hicolor_status_16x16_flt-inactive.png \
-       hicolor_status_16x16_flt-include.png \
-       hicolor_actions_16x16_hb-ope-auto.png \
-       hicolor_actions_16x16_hb-ope-budget.png \
-       hicolor_actions_16x16_hb-ope-edit.png \
-       hicolor_actions_16x16_hb-ope-cleared.png \
-       hicolor_actions_16x16_hb-ope-remind.png \
-       hicolor_actions_16x16_hb-ope-reconciled.png \
+       hicolor_actions_16x16_hb-ope-future.png \
+       hicolor_actions_24x24_hb-document-new.png \
+       hicolor_actions_24x24_hb-document-open.png \
+       hicolor_actions_24x24_hb-document-save.png \
+       hicolor_actions_24x24_hb-document-save-as.png \
        hicolor_actions_24x24_hb-account.png \
        hicolor_actions_24x24_hb-archive.png \
        hicolor_actions_24x24_hb-assign.png \
        hicolor_actions_24x24_hb-view-list.png \
        hicolor_actions_24x24_hb-view-pie.png \
        hicolor_actions_24x24_hb-view-stack.png \
+       hicolor_actions_24x24_hb-view-refresh.png \
+       hicolor_status_16x16_flt-exclude.png \
+       hicolor_status_16x16_flt-inactive.png \
+       hicolor_status_16x16_flt-include.png \
+       hicolor_status_16x16_hb-ope-new.png \
+       hicolor_status_16x16_hb-ope-similar.png \
+       hicolor_status_16x16_hb-ope-auto.png \
+       hicolor_status_16x16_hb-ope-budget.png \
+       hicolor_status_16x16_hb-ope-edit.png \
+       hicolor_status_16x16_hb-ope-cleared.png \
+       hicolor_status_16x16_hb-ope-remind.png \
+       hicolor_status_16x16_hb-ope-reconciled.png \
        hicolor_status_16x16_pm-none.png \
        hicolor_status_16x16_pm-ccard.png \
        hicolor_status_16x16_pm-dcard.png \
        hicolor_status_16x16_pm-deposit.png \
        hicolor_status_16x16_pm-fifee.png \
        hicolor_status_16x16_pm-directdebit.png \
+       hicolor_status_48x48_prf-backup.png \
        hicolor_status_48x48_prf-columns.png \
-       hicolor_status_48x48_prf-display.png \
        hicolor_status_48x48_prf-euro.png \
+       hicolor_status_48x48_prf-folder.png \
        hicolor_status_48x48_prf-general.png \
        hicolor_status_48x48_prf-import.png \
        hicolor_status_48x48_prf-interface.png \
+       hicolor_status_48x48_prf-locale.png \
        hicolor_status_48x48_prf-report.png \
 +      hicolor_status_48x48_prf-plugins.png \
+       hicolor_actions_scalable_edit-split-symbolic.svg \
        hicolor_actions_scalable_toggle-sign-symbolic.svg \
-       hicolor_actions_scalable_btn-collapse-symbolic.svg \
-       hicolor_actions_scalable_btn-expand-symbolic.svg \
+       hicolor_actions_scalable_list-collapse-all-symbolic.svg \
+       hicolor_actions_scalable_list-expand-all-symbolic.svg \
        $(NULL)
  
  
This page took 0.385567 seconds and 5 git commands to generate.