]> Dogcows Code - chaz/homebank/commitdiff
Merge branch 'master' into ext-perl
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sat, 28 Jan 2017 22:39:24 +0000 (15:39 -0700)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Sat, 28 Jan 2017 22:39:24 +0000 (15:39 -0700)
17 files changed:
1  2 
configure.ac
src/dsp_mainwindow.c
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 83f65098fc6c15ec96e0ddfb9dc83a35d1c31d02,d938d855804b4410901396bdff8b1ee3cbc4b150..798e623fd87ef94656bfa36afa343cb580b1ca7b
@@@ -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.2])
+ AC_INIT([homebank], [5.1.3])
  #AC_INIT([homebank], [x.x-rc])
  
  AM_CONFIG_HEADER(config.h)
  
  AM_INIT_AUTOMAKE([1.9 foreign])
  
 +LT_PREREQ([2.2])
 +LT_INIT([dlopen])
 +AC_CONFIG_MACRO_DIR([m4])
 +
  # If the source code has changed at all, increment REVISION
  # If any interfaces have been added, removed, or changed, increment CURRENT, and set REVISION to 0.
  # If any interfaces have been added since the last public release, then increment AGE.
@@@ -26,7 -22,7 +26,7 @@@ AC_PROG_INSTAL
  AC_PROG_INTLTOOL
  
  # Checks for libraries.
 -PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.12 glib-2.0 >= 2.39)
 +PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.12 glib-2.0 >= 2.39 gmodule-2.0 >= 2.39)
  AC_SUBST(DEPS_CFLAGS)
  AC_SUBST(DEPS_LIBS)
  AC_CHECK_LIB(m, pow)
@@@ -35,7 -31,7 +35,7 @@@ PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.
  AC_SUBST(LIBSOUP_CFLAGS)
  AC_SUBST(LIBSOUP_LIBS)
  
- # general usage flags
+ # release flags
  CFLAGS="${CFLAGS} -Wall -Wmissing-prototypes"
  
  # disable deprecated warnings
@@@ -70,7 -66,7 +70,7 @@@ the
      then
          AC_CHECK_LIB(ofx, ofx_set_status_cb, OFX_0_7="-DOFX_ENABLE")
          DEPS_LIBS="-lofx ${DEPS_LIBS}"
 -        CFLAGS="${CFLAGS} $OFX_0_7"
 +        CPPFLAGS="${CPPFLAGS} $OFX_0_7"
      else
          noofx=true
          AC_MSG_RESULT([Libofx header missing. Check your libofx installation])
@@@ -82,41 -78,6 +82,41 @@@ els
  fi
  AM_CONDITIONAL(NOOFX, test x$noofx = xtrue)
  
 +AC_ARG_WITH(perl,
 +      [  --with-perl             build with perl plug-in support [default=without]],
 +      [build_perl=$withval],
 +      [build_perl=no]
 +)
 +if test x$build_perl != xno
 +then
 +      test x$build_perl != xyes -a -x "$build_perl" && PERL=$build_perl
 +      AC_PATH_PROG(PERL, perl, perl)
 +      AC_MSG_CHECKING(if perl can be embedded)
 +      if $PERL -MExtUtils::Embed -e "use v5.8" >/dev/null 2>&1
 +      then
 +              AC_MSG_RESULT(yes)
 +              CPPFLAGS="${CPPFLAGS} -DPERL_ENABLE"
 +              PERL_CPPFLAGS="`$PERL -MExtUtils::Embed -e ccopts`"
 +              PERL_OBJS="ext-perl.o perlxsi.o"
 +              PERL_PRIVLIBEXP="`$PERL -MConfig -e 'print $Config{privlibexp}'`"
 +              PERL_SITELIBEXP="`$PERL -MConfig -e 'print $Config{sitelibexp}'`"
 +              DEPS_LIBS="`$PERL -MExtUtils::Embed -e ldopts` ${DEPS_LIBS}"
 +              if test -e "$PERL_SITELIBEXP/ExtUtils/xsubpp"
 +              then
 +                      XSUBPP="$PERL $PERL_SITELIBEXP/ExtUtils/xsubpp"
 +              else
 +                      XSUBPP="$PERL $PERL_PRIVLIBEXP/ExtUtils/xsubpp"
 +              fi
 +      else
 +              AC_MSG_ERROR([no working perl found, or perl not version >= 5.8])
 +      fi
 +fi
 +AC_SUBST(PERL_CPPFLAGS)
 +AC_SUBST(PERL_OBJS)
 +AC_SUBST(PERL_PRIVLIBEXP)
 +AC_SUBST(PERL_SITELIBEXP)
 +AC_SUBST(XSUBPP)
 +
  # Checks for header files.
  AC_HEADER_STDC
  AC_CHECK_HEADERS([libintl.h locale.h stdlib.h string.h])
@@@ -153,7 -114,6 +153,7 @@@ themes/hicolor/Makefil
  po/Makefile.in
  doc/Makefile
  doc/images/Makefile
 +plugins/Makefile
  ])
  
  AC_OUTPUT
@@@ -166,7 -126,6 +166,7 @@@ echo $PACKAGE $VERSIO
  echo 
  echo Compiler................ : $CC
  echo Build with OFX support.. : $build_ofx
 +echo Build with perl support. : $build_perl
  if test "x$noofx" = "xtrue" ; then
  echo ........................ : **error** libofx header is missing, ofx feature will be disabled. Check your libofx installation
  fi
diff --combined src/dsp_mainwindow.c
index 707f68a0f6a8dce48af4fc14681fa12533e15116,ea62b80c3994e9c0e6cdbc8b1b80c4cffa62c63f..e819137b509e1297fa3809f6fdf2637facf2aebf
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -22,8 -22,6 +22,8 @@@
  
  #include "dsp_mainwindow.h"
  
 +#include "ext.h"
 +
  #include "list_account.h"
  #include "list_upcoming.h"
  #include "list_topspending.h"
@@@ -113,8 -111,6 +113,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);
@@@ -141,13 -137,13 +141,15 @@@ void ui_mainwindow_update(GtkWidget *wi
  void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
  
+ static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data);
  static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data);
  
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
  
 +static void ui_mainwindow_showprefs(gint page);
 +
  extern gchar *CYA_ACC_TYPE[];
  
  gchar *CYA_CATSUBCAT[] = { 
@@@ -169,7 -165,6 +171,7 @@@ static GtkActionEntry entries[] = 
    { "TxnMenu"    , NULL, N_("_Transactions"), NULL, NULL, NULL },
    { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL  },
    { "ToolsMenu"  , NULL, N_("_Tools"), NULL, NULL, NULL },
 +  { "PluginMenu" , NULL, N_("_Plugins"), NULL, NULL, NULL },
    { "HelpMenu"   , NULL, N_("_Help"), NULL, NULL, NULL },
  
  //  { "Import"       , NULL, N_("Import") },
    { "FileStats"   , NULL              , N_("File statistics...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_file_statistics) },
    { "Anonymize"   , NULL              , N_("Anonymize...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_anonymize) },
        
 +  /* Plugins */
 +  { "PluginPreferences", "prf-plugins", N_("_Plugins..."), "<control>U", N_("Configure plugin preferences"), G_CALLBACK(ui_mainwindow_action_pluginprefs) },
 +
    /* HelpMenu */
    { "Contents"    , ICONNAME_HELP     , N_("_Contents")                    , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
    { "Online"      , "lpi-help"        , N_("Get Help Online...")           , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
@@@ -316,11 -308,6 +318,11 @@@ static const gchar *ui_info 
  "        <separator/>"
  "      <menuitem action='Anonymize'/>"
  "    </menu>"
 +"    <menu action='PluginMenu'>"
 +"      <separator/>"
 +"      <menuitem action='PluginPreferences'/>"
 +"      <separator/>"
 +"    </menu>"
  "    <menu action='HelpMenu'>"
  "      <menuitem action='Contents'/>"
  "        <separator/>"
  "    <toolitem action='RBalance'/>"
  "    <toolitem action='RBudget'/>"
  "    <toolitem action='RVehiculeCost'/>"
 +"      <separator/>"
  "  </toolbar>"
  
  "</ui>";
@@@ -433,8 -419,7 +435,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-2016 - Maxime DOYEN";
+       static const gchar *copyright = "Copyright \xc2\xa9 1995-2017 - Maxime DOYEN";
  
  
  
@@@ -567,12 -552,6 +569,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();
@@@ -682,15 -661,10 +684,15 @@@ static void ui_mainwindow_action_defass
  
  
  static void ui_mainwindow_action_preferences(void)
 +{
 +      ui_mainwindow_showprefs(PREF_GENERAL);
 +}
 +
 +static void ui_mainwindow_showprefs(gint page)
  {
  struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
  
 -      defpref_dialog_new();
 +      defpref_dialog_new(page);
        if(!PREFS->euro_active)
        {
        GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor");
@@@ -738,7 -712,8 +740,8 @@@ struct hbfile_data *data = g_object_get
  
        // top spending
        gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor);
-       hb_label_set_amount(GTK_LABEL(data->TX_topamount), data->toptotal, GLOBALS->kcur, GLOBALS->minor);
+       
+       ui_panel_topspending_update(data->window, data);
  
  }
  
@@@ -1060,6 -1035,8 +1063,8 @@@ gboolean file_clear = GPOINTER_TO_INT(u
        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;
+       
        hbfile_cleanup(file_clear);
        hbfile_setup(file_clear);
  
@@@ -1083,8 -1060,9 +1088,9 @@@ gint account, count
  
        /* init the transaction */
        date = homebank_app_date_get_julian();
-       //todo: maybe think about set a default account here
-       account = 1;
+       //#1656531
+       account = 0;
        if(data->acc != NULL)
                account = data->acc->key;
  
@@@ -1153,12 -1131,44 +1159,44 @@@ struct tmpto
        gdouble         value;
  };
  
+ #define MAX_TOPSPENDING 5
  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)
+ {
+ struct hbfile_data *data;
+ GtkTreeModel *model;
+ gchar *title;
+ gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE];
+       DB( g_print("\n[ui-mainwindow] topspending_update\n") );
+       data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
+       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);
+       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(title);
+       //future usage
+       gchar *fu = _("Top %d spending"); title = fu;
+ }
  static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data)
  {
  struct hbfile_data *data;
@@@ -1171,7 -1181,6 +1209,6 @@@ GArray *garray
  gdouble total, other;
  Account *acc;
  
- #define MAX_TOPSPENDING 5
        
        DB( g_print("\n[ui-mainwindow] populate_topspending\n") );
  
                gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model);
                g_object_unref(model);
                
-               data->toptotal = total;
-               hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor);
-               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, NULL, NULL);
-               //gtk_chart_show_legend(GTK_CHART(data->RE_pie), FALSE);
-         /* update info range text */
+               
+               // 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);
@@@ -1883,6 -1888,78 +1916,78 @@@ gint r = XML_UNSET
  }
  
  
+ 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;
+       nballoc = da_acc_length ();
+       hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
+       elt = g_list_first(lacc);
+       while (elt != NULL)
+       {
+       Account *acc = elt->data;
+       GPtrArray *group;
+       
+               if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) )
+               {
+                       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;
@@@ -1890,59 -1967,49 +1995,49 @@@ GtkTreeModel *model
  GtkTreeIter  iter1, child_iter;
  GList *lacc, *elt;
  Account *acc;
- guint i, j, nbtype;
+ 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 */
-       GPtrArray *typeacc[ACC_TYPE_MAXVALUE] = {0};
        lacc = elt = g_hash_table_get_values(GLOBALS->h_acc);
-       while (elt != NULL)
-       {
-               acc = elt->data;
-               //#1339572
-               if( !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) )
-               {
-                       DB( g_print(" - insert %d:%s\n", acc->key, acc->name) );
-                       if(typeacc[acc->type] == NULL)
-                               typeacc[acc->type] = g_ptr_array_sized_new(da_acc_length ());
-                       g_ptr_array_add(typeacc[acc->type], (gpointer)acc);
-               }
-               elt = g_list_next(elt);
-       }
+       
+       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\n") );
+       gtbank = gttoday = gtfuture = 0;
  
+       DB( g_print(" populate listview\n") );
  
-       /* then populate the listview */
        model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc));
        gtk_tree_store_clear (GTK_TREE_STORE(model));
  
        nbtype = 0;
-       for(i=0;i<ACC_TYPE_MAXVALUE;i++)
+       g_hash_table_iter_init (&grp_iter, h_group);
+       while (g_hash_table_iter_next (&grp_iter, &key, &value))
        {
-       GPtrArray *gpa = typeacc[i];
+       GPtrArray *gpa = value;
        gdouble tbank, ttoday, tfuture;
  
                if(gpa != NULL)
                {
                        nbtype++;
                        //1: Header: Bank, Cash, ...
-                       DB( g_print(" - append type '%s'\n", CYA_ACC_TYPE[i]) );
+                       //DB( g_print(" - append type '%s'\n", CYA_ACC_TYPE[i]) );
+                       DB( g_print("\n - append type '%d'\n", key) );
  
                        gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL);
                        gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
                                          LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER,
-                                         LST_DSPACC_NAME, _(CYA_ACC_TYPE[i]),
+                                         LST_DSPACC_NAME, key,
                                          -1);
  
                        tbank = ttoday = tfuture = 0;
                        }
  
                        /* set balance to header to display when collasped */
+                       DB( g_print(" - enrich totals to header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) );
                        gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
                                        LST_DSPACC_BANK, tbank,
                                        LST_DSPACC_TODAY, ttoday,
  
        DB( g_print(" - free ressources\n") );
  
-       /* free all temp stuff */
-       for(i=0;i<ACC_TYPE_MAXVALUE;i++)
+       g_hash_table_iter_init (&grp_iter, h_group);
+       while (g_hash_table_iter_next (&grp_iter, &key, &value))
        {
-       GPtrArray *gpa = typeacc[i];
-               if(gpa != NULL)
-                       g_ptr_array_free (gpa, TRUE);
+               g_ptr_array_free (value, TRUE);
        }
+       g_hash_table_destroy (h_group);  
  
  }
  
@@@ -2054,7 -2118,7 +2146,7 @@@ gint flags
        gchar *basename;
        gchar *changed;
  
-               DB( g_print(" +  1: wintitle %x\n", (gint)data->wintitle) );
+               DB( g_print(" +  1: wintitle %x\n", data->wintitle) );
  
                basename = g_path_get_basename(GLOBALS->xhb_filepath);
  
  
                DB( g_print(" +  2: disabled, opelist count\n") );
  
-               selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc));
+               //#1656531
+               data->acc = NULL;
  
+               selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc));
                active = gtk_tree_selection_get_selected(selection, &model, &iter);
                if(active)
                {
  
                                gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPACC_DATAS, &acc, -1);
                                data->acc = acc;
                        }
                        else
                                active = FALSE;
                }
-               else
-               {
-                       //ensure data->acc will not be null
-                       data->acc = da_acc_get(1);
-               }
  
  
                // no change: disable save
@@@ -2283,9 -2343,6 +2371,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] dispose\n") );
  
        //store position and size
        }
        else
        {
-               DB( g_print(" free wintitle %x\n", (gint)data->wintitle) );
+               DB( g_print(" free wintitle %x\n", data->wintitle) );
  
                gtk_widget_destroy(data->LV_top);
  
@@@ -2453,9 -2510,9 +2541,9 @@@ static void ui_mainwindow_drag_data_rec
                        GtkSelectionData *selection_data,
                        guint info, guint time, GtkWindow *window)
  {
      gchar **uris, **str;
      gchar *newseldata;
      gint filetype, slen;
+ gchar **uris, **str;
+ gchar *newseldata;
+ gint filetype, slen;
  
        if (info != TARGET_URI_LIST)
                return;
  
        uris = g_uri_list_extract_uris (newseldata);
  
+       DB( g_print(" - dragged %d %d files\n", slen, g_strv_length(uris) ) );
        str = uris;
        //for (str = uris; *str; str++)
        if( *str )
                        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,
                                        _("File error"),
@@@ -2548,7 -2610,7 +2641,7 @@@ GtkRecentFilter *filter
  static void ui_mainwindow_create_menu_bar_and_toolbar(struct hbfile_data *data, GtkWidget *mainvbox)
  {
  GtkUIManager *manager;
- GtkActionGroup *action_group;
+ GtkActionGroup *actions;
  GtkAction *action;
  GError *error = NULL;
  
        gtk_window_add_accel_group (GTK_WINDOW (data->window),
                                gtk_ui_manager_get_accel_group(manager));
  
-       action_group = gtk_action_group_new ("MainWindow");
-       gtk_action_group_set_translation_domain(action_group, GETTEXT_PACKAGE);
+       actions = gtk_action_group_new ("MainWindow");
+       gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
  
-       gtk_action_group_add_actions (action_group,
+       gtk_action_group_add_actions (actions,
                        entries,
                        n_entries,
                        NULL);
  
-       gtk_action_group_add_toggle_actions (action_group,
+       gtk_action_group_add_toggle_actions (actions,
                        toggle_entries,
                        n_toggle_entries,
                        NULL);
  
-       gtk_ui_manager_insert_action_group (data->manager, action_group, 0);
-       g_object_unref (action_group);
-       data->actions = action_group;
+       gtk_ui_manager_insert_action_group (data->manager, actions, 0);
+       g_object_unref (actions);
+       data->actions = actions;
  
        /* set short labels to use in the toolbar */
-       action = gtk_action_group_get_action(action_group, "Open");
+       action = gtk_action_group_get_action(actions, "Open");
        g_object_set(action, "short_label", _("Open"), NULL);
  
        //action = gtk_action_group_get_action(action_group, "Save");
        //g_object_set(action, "is_important", TRUE, NULL);
  
-       action = gtk_action_group_get_action(action_group, "Account");
+       action = gtk_action_group_get_action(actions, "Account");
        g_object_set(action, "short_label", _("Account"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "Payee");
+       action = gtk_action_group_get_action(actions, "Payee");
        g_object_set(action, "short_label", _("Payee"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "Category");
+       action = gtk_action_group_get_action(actions, "Category");
        g_object_set(action, "short_label", _("Category"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "Archive");
+       action = gtk_action_group_get_action(actions, "Archive");
        //TRANSLATORS: an archive is stored transaction buffers (kind of bookmark to prefill manual insertion)
        g_object_set(action, "short_label", _("Archive"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "Budget");
+       action = gtk_action_group_get_action(actions, "Budget");
        g_object_set(action, "short_label", _("Budget"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "ShowOpe");
+       action = gtk_action_group_get_action(actions, "ShowOpe");
        g_object_set(action, "short_label", _("Show"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "AddOpe");
+       action = gtk_action_group_get_action(actions, "AddOpe");
        g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "RStatistics");
+       action = gtk_action_group_get_action(actions, "RStatistics");
        g_object_set(action, "short_label", _("Statistics"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "RBudget");
+       action = gtk_action_group_get_action(actions, "RBudget");
        g_object_set(action, "short_label", _("Budget"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "RBalance");
+       action = gtk_action_group_get_action(actions, "RBalance");
        g_object_set(action, "short_label", _("Balance"), NULL);
  
-       action = gtk_action_group_get_action(action_group, "RVehiculeCost");
+       action = gtk_action_group_get_action(actions, "RVehiculeCost");
        g_object_set(action, "short_label", _("Vehicle cost"), NULL);
  
        /* now load the UI definition */
  
  }
  
- static GtkWidget *ui_mainwindow_create_youraccounts(struct hbfile_data *data)
+ /* Callback function for the undo action */
+ /*static void
+ activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
  {
- GtkWidget *mainvbox, *label, *widget, *sw;
+   g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action)));
+ }*/
  
-       mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ static void
+ activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
+ {
+ struct hbfile_data *data = user_data;
+   GVariant *old_state, *new_state;
  
-       label = make_label_group(_("Your accounts"));
-       gtk_widget_set_margin_top(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_bottom(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_start(GTK_WIDGET(label), SPACING_SMALL);
-       gtk_widget_set_margin_end(GTK_WIDGET(label), SPACING_SMALL);
-     gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0);
+   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 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_widget_set_margin_top(GTK_WIDGET(sw), 0);
-       gtk_widget_set_margin_bottom(GTK_WIDGET(sw), SPACING_SMALL);
-       gtk_widget_set_margin_start(GTK_WIDGET(sw), 2*SPACING_SMALL);
-       gtk_widget_set_margin_end(GTK_WIDGET(sw), SPACING_SMALL);
-       gtk_box_pack_start (GTK_BOX (mainvbox), sw, TRUE, TRUE, 0);
+       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);
  
-       return mainvbox;
+       //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)
+       widget = gtk_menu_button_new();
+       gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP);
+       gtk_widget_set_halign (widget, GTK_ALIGN_END);
+       image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU);
+       g_object_set (widget, "image", image,  NULL);
+       toolitem = gtk_tool_item_new();
+       gtk_container_add (GTK_CONTAINER(toolitem), widget);
+       gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
+ GMenu *menu, *section;
+       menu = g_menu_new ();
+       //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 ();
+       g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), data);
+       //init radio
+       GAction *action = g_action_map_lookup_action (G_ACTION_MAP (group), "groupby");
+       const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank";
+       g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_string (value));
+       gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group));
+       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 *mainvbox, *hbox, *vbox;
+ GtkWidget *panel, *hbox, *tbar;
  GtkWidget *label, *widget;
+ GtkToolItem *toolitem;
  
-       mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       data->GR_top = mainvbox;
+       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"));
-       gtk_widget_set_margin_top(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_bottom(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_start(GTK_WIDGET(label), SPACING_SMALL);
-       gtk_widget_set_margin_end(GTK_WIDGET(label), SPACING_SMALL);
-     gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0);
+       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);
  
-       vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
-       //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 (mainvbox), vbox, TRUE, TRUE, 0);
-       
        /* total + date range */
        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
-       gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-       
-       label = make_label(_("Top spending"), 0.0, 0.5);
-       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+       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(NULL, 0.0, 0.5);
-       data->TX_topamount = label;
-       gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
        data->CY_range = make_daterange(label, FALSE);
        gtk_box_pack_end (GTK_BOX (hbox), data->CY_range, FALSE, FALSE, 0);
  
        data->RA_type = widget;
        gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  
-       /* pie + listview */
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
-       gtk_box_pack_start (GTK_BOX (vbox), 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_box_pack_start (GTK_BOX (hbox), widget, 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 (hbox), sw, FALSE, FALSE, 0);
-       */
-       
-       widget = (GtkWidget *)create_list_topspending();
-       data->LV_top = widget;
-       gtk_chart_show_legend(GTK_CHART(data->RE_pie), TRUE, TRUE);
- //            gtk_container_add (GTK_CONTAINER (sw), widget);
-       return mainvbox;
+       return panel;
  }
  
  
  static GtkWidget *ui_mainwindow_scheduled_create(struct hbfile_data *data)
  {
- GtkWidget *mainvbox, *hbox, *vbox, *bbox, *sw, *tbar;
+ GtkWidget *panel, *hbox, *vbox, *bbox, *sw, *tbar;
  GtkWidget *label, *widget;
  GtkToolItem *toolitem;
        
-       mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-       data->GR_upc = mainvbox;
-       hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
-     gtk_box_pack_start (GTK_BOX (mainvbox), hbox, FALSE, FALSE, 0);
+       panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+       gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
+       data->GR_upc = panel;
  
-       label = make_label_group(_("Scheduled transactions"));
-       gtk_widget_set_margin_top(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_bottom(GTK_WIDGET(label), SPACING_SMALL/2);
-       gtk_widget_set_margin_start(GTK_WIDGET(label), SPACING_SMALL);
-       gtk_widget_set_margin_end(GTK_WIDGET(label), SPACING_SMALL);
-     gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-       label = make_label(_("maximum post date"), 0.0, 0.7);
-       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;
-       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);
-       
        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 (mainvbox), vbox, TRUE, TRUE, 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_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);
+               widget = gtk_button_new_with_label(_("Skip"));
+               data->BT_sched_skip = 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);
+               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);
  
/*    image = gtk_image_new_from_icon_name (ICONNAME_HB_SCHED_SKIP, GTK_ICON_SIZE_MENU);
-       toolitem = gtk_tool_button_new(image, NULL);
-       data->BT_sched_skip = toolitem;
      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);
-       gtk_widget_set_tooltip_text(GTK_WIDGET(toolitem), _("Skip"));
  
-       image = gtk_image_new_from_icon_name (ICONNAME_HB_SCHED_POST, GTK_ICON_SIZE_MENU);
-       toolitem = gtk_tool_button_new(image, NULL);
-       data->BT_sched_post = toolitem;
+       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);
-       gtk_widget_set_tooltip_text(GTK_WIDGET(toolitem), _("Post"));
- */
  
-       
-       return mainvbox;
+               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;
  }
  
  /*
  ** the window creation
  */
@@@ -2881,7 -3059,7 +3090,7 @@@ GtkAction *action
  
        //store our window private data
        g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data);
-       DB( g_print(" - new window=%x, inst_data=%0x\n", (gint)window, (gint)data) );
+       DB( g_print(" - new window=%x, inst_data=%0x\n", window, data) );
  
        // this is our mainwindow, so store it to GLOBALS data
        data->window = window;
  
        ui_mainwindow_create_menu_bar_and_toolbar (data, mainvbox);
  
- #if HB_UNSTABLE == TRUE
+ #if HB_UNSTABLE_SHOW == TRUE
  GtkWidget *bar, *label;
  
        bar = gtk_info_bar_new ();
        filter_default_all_set(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");
  
  
        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 (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);
diff --combined src/hb-account.c
index 9064868c71257d88d5ef18a4e0d5f8cce2b6dd29,fa9b751efbcbfd3dbcf9765e19120c7a523a9ca8..a7c0051c11e474a45de0b22a3b16243f1b640edc
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -20,9 -20,6 +20,9 @@@
  #include "homebank.h"
  #include "hb-account.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  /****************************************************************************/
  /* Debug macros                                                                                */
  /****************************************************************************/
@@@ -42,7 -39,7 +42,7 @@@ voi
  da_acc_free(Account *item)
  {
        DB( g_print("da_acc_free\n") );
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                DB( g_print(" => %d, %s\n", item->key, item->name) );
  
@@@ -54,7 -51,7 +54,7 @@@
                
                g_queue_free (item->txn_queue);
                
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -65,7 -62,7 +65,7 @@@ da_acc_malloc(void
  Account *item;
  
        DB( g_print("da_acc_malloc\n") );
 -      item = g_malloc0(sizeof(Account));
 +      item = rc_alloc(sizeof(Account));
        item->txn_queue = g_queue_new ();
        return item;
  }
@@@ -160,9 -157,6 +160,9 @@@ guint32 *new_key
        *new_key = item->key;
        g_hash_table_insert(GLOBALS->h_acc, new_key, item);
  
 +      GValue item_val = G_VALUE_INIT;
 +      ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
 +
        return TRUE;
  }
  
@@@ -198,10 -192,6 +198,10 @@@ guint32 *new_key
                        DB( g_print(" -> insert id: %d\n", *new_key) );
  
                        g_hash_table_insert(GLOBALS->h_acc, new_key, item);
 +
 +                      GValue item_val = G_VALUE_INIT;
 +                      ext_hook("account_inserted", EXT_ACCOUNT(&item_val, item), NULL);
 +
                        return TRUE;
                }
        }
@@@ -599,7 -589,12 +599,12 @@@ GList *lnk_txn
                lnk_txn = g_queue_peek_head_link(acc->txn_queue);
                while (lnk_txn != NULL)
                {
-                       account_balances_add_internal(acc, lnk_txn->data);
+               Transaction *txn = lnk_txn->data;
+               
+                       if(!(txn->status == TXN_STATUS_REMIND))
+                       {
+                               account_balances_add_internal(acc, txn);
+                       }
                        lnk_txn = g_list_next(lnk_txn);
                }
                
diff --combined src/hb-archive.c
index d815703fc5067af1b3d96dad8aad4d1509e70635,43cfbeac68dc2908a8908a31185bd89c0fe35733..e0789de31bb5f7c45e08f32b1640a002bab1147f
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 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                                                             */
  /****************************************************************************/
@@@ -44,12 -41,12 +44,12 @@@ extern struct HomeBank *GLOBALS
  
  Archive *da_archive_malloc(void)
  {
 -      return g_malloc0(sizeof(Archive));
 +      return rc_alloc(sizeof(Archive));
  }
  
  Archive *da_archive_clone(Archive *src_item)
  {
 -Archive *new_item = g_memdup(src_item, sizeof(Archive));
 +Archive *new_item = rc_dup(src_item, sizeof(Archive));
  
        if(new_item)
        {
@@@ -64,7 -61,7 +64,7 @@@
  
  void da_archive_free(Archive *item)
  {
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                if(item->wording != NULL)
                        g_free(item->wording);
@@@ -72,7 -69,7 +72,7 @@@
                da_splits_free(item->splits);
                //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared            
                
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
diff --combined src/hb-assign.c
index 951cf92563bb1c519cf6ef9fcb7fa70daa26dd0c,83e5f897eb601e391600865f797978d06840068c..495ead2da698a2dccd39dbb52dbef7088ead46b6
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 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 781598a472b20788a32f77a82ce6f94c00640075,807e93d92d01e3db514282527aca69b2b34922af..f3d43bd549c28af3953c9e114a6f8558324ee43b
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -20,9 -20,6 +20,9 @@@
  #include "homebank.h"
  #include "hb-category.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  
  /****************************************************************************/
  /* Debug macros                                                                                */
@@@ -43,7 -40,7 +43,7 @@@ extern struct HomeBank *GLOBALS
  Category *
  da_cat_clone(Category *src_item)
  {
 -Category *new_item = g_memdup(src_item, sizeof(Category));
 +Category *new_item = rc_dup(src_item, sizeof(Category));
  
        DB( g_print("da_cat_clone\n") );
        if(new_item)
@@@ -59,12 -56,12 +59,12 @@@ voi
  da_cat_free(Category *item)
  {
        DB( g_print("da_cat_free\n") );
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                DB( g_print(" => %d, %s\n", item->key, item->name) );
  
                g_free(item->name);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -73,7 -70,7 +73,7 @@@ Category 
  da_cat_malloc(void)
  {
        DB( g_print("da_cat_malloc\n") );
 -      return g_malloc0(sizeof(Category));
 +      return rc_alloc(sizeof(Category));
  }
  
  
@@@ -969,11 -966,9 +969,9 @@@ const gchar *encoding
                                if( tmpstr != NULL )
                                {
                                        DB( g_print(" + strip %s\n", tmpstr) );
                                        hb_string_strip_crlf(tmpstr);
  
                                        DB( g_print(" + split\n") );
                                        str_array = g_strsplit (tmpstr, ";", 3);
                                        // type; sign; name
  
diff --combined src/hb-payee.c
index 419bdeae643eb9307af790eccf53cb39de089fe3,8852a90c8b4307958520c20b5d9a61c089df25d0..e416fcf9324671ad5e7b38fe80d8b0c76a9652c6
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -20,9 -20,6 +20,9 @@@
  #include "homebank.h"
  #include "hb-payee.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  
  /****************************************************************************/
  /* Debug macros                                                                                */
@@@ -44,12 -41,12 +44,12 @@@ voi
  da_pay_free(Payee *item)
  {
        DB( g_print("da_pay_free\n") );
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                DB( g_print(" => %d, %s\n", item->key, item->name) );
  
                g_free(item->name);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -58,7 -55,7 +58,7 @@@ Payee 
  da_pay_malloc(void)
  {
        DB( g_print("da_pay_malloc\n") );
 -      return g_malloc0(sizeof(Payee));
 +      return rc_alloc(sizeof(Payee));
  }
  
  
@@@ -483,31 -480,31 +483,31 @@@ gchar *stripname
   *
   * append a new payee into the GHashTable
   *
-  * Return value: a new Payee or NULL
+  * Return value: true/false + new payee
   *
   */
- Payee *
- payee_append_if_new(gchar *name)
+ gboolean
+ payee_append_if_new(gchar *name, Payee **newpayee)
  {
- gchar *stripname;
+ gboolean retval = FALSE;
+ gchar *stripname = g_strdup(name);
  Payee *item;
  
-       stripname = g_strdup(name);
        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);
+               retval = TRUE;
        }
-       else
-               item = NULL;
+       if( newpayee != NULL )
+               *newpayee = item;
  
        g_free(stripname);
  
-       return item;
+       return retval;
  }
  
  static gint
@@@ -536,16 -533,21 +536,21 @@@ GList *list = g_hash_table_get_values(G
  
  
  
- void
- payee_load_csv(gchar *filename)
+ gboolean
+ payee_load_csv(gchar *filename, gchar **error)
  {
+ gboolean retval;
  GIOChannel *io;
  gchar *tmpstr;
  gint io_stat;
+ gchar **str_array;
  const gchar *encoding;
+ gint nbcol;
  
        encoding = homebank_file_getencoding(filename);
  
+       retval = TRUE;
+       *error = NULL;
        io = g_io_channel_new_file(filename, "r", NULL);
        if(io != NULL)
        {
                        {
                                if( tmpstr != NULL)
                                {
+                                       DB( g_print("\n + strip\n") );
                                        hb_string_strip_crlf(tmpstr);
  
-                                       DB( g_print(" read %s\n", tmpstr) );
+                                       DB( g_print(" + split '%s'\n", tmpstr) );
+                                       str_array = g_strsplit (tmpstr, ";", 2);
+                                       // payee;category   : later paymode?
  
-                                       if( payee_append_if_new( tmpstr ) )
+                                       nbcol = g_strv_length (str_array);
+                                       if( nbcol > 2 )
                                        {
-                                               GLOBALS->changes_count++;
+                                               *error = _("invalid CSV format");
+                                               retval = FALSE;
+                                               DB( g_print(" + error %s\n", *error) );
                                        }
+                                       else
+                                       {
+                                       gboolean added;
+                                       Payee *pay = 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 )
+                                                       {                               
+                                                               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);
+                                                       
+                                                       DB( g_print(" cat: %p %p\n", cat, pay) );
+                                                       if( cat != NULL )
+                                                       {
+                                                               if( pay != NULL)
+                                                               {
+                                                                       DB( g_print(" set default cat to %d\n", cat->key) );
+                                                                       pay->kcat = cat->key;
+                                                               }
+                                                               GLOBALS->changes_count++;
+                                                       }
+                                               }
+                                       }
+                                       g_strfreev (str_array);
                                }
                                g_free(tmpstr);
                        }
                g_io_channel_unref (io);
        }
  
+       return retval;
  }
  
  
@@@ -599,15 -643,33 +646,33 @@@ gchar *outstr
                while (list != NULL)
                {
                Payee *item = list->data;
+               gchar *fullcatname;
  
                        if(item->key != 0)
                        {
-                               outstr = g_strdup_printf("%s\n", item->name);
-                               g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
+                               fullcatname = NULL;
+                               if( item->kcat > 0 )
+                               {
+                               Category *cat = da_cat_get(item->kcat);
+                                       
+                                       if( cat != NULL )
+                                       {
+                                               fullcatname = da_cat_get_fullname (cat);
+                                       }
+                               }
+                               if( fullcatname != NULL )
+                                       outstr = g_strdup_printf("%s;%s\n", item->name, fullcatname);
+                               else
+                                       outstr = g_strdup_printf("%s;\n", item->name);
  
-                               DB( g_print("%s", outstr) );
+                               DB( g_print(" + export %s\n", outstr) );
+                               
+                               g_io_channel_write_chars(io, outstr, -1, NULL, NULL);
  
                                g_free(outstr);
+                               g_free(fullcatname);
                        }
                        list = g_list_next(list);
                }
diff --combined src/hb-preferences.c
index 076a5460df5166d4fb8b8226c27817ba59094702,058ba4c55b2cc1e8868da8cdcc557d1f694d46ff..8df09995cd89a75f877ff8749ec317a266156f61
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -294,9 -294,6 +294,9 @@@ void homebank_pref_free(void
        g_free(PREFS->minor_cur.decimal_char);
        g_free(PREFS->minor_cur.grouping_char);
  
 +      g_strfreev(PREFS->ext_path);
 +      g_list_free_full(PREFS->ext_whitelist, g_free);
 +
        memset(PREFS, 0, sizeof(struct Preferences));
  }
  
@@@ -357,6 -354,10 +357,10 @@@ gint i
        PREFS->wal_vpaned = 600/2;
        PREFS->wal_hpaned = 1024/2;
  
+       PREFS->pnl_acc_col_acc_width = -1;
+       PREFS->pnl_acc_show_by = 0;
+       PREFS->pnl_upc_col_pay_width = -1;
+       PREFS->pnl_upc_col_mem_width = -1;
  
  
        i = 0;
        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();
  
  }
@@@ -823,6 -807,17 +827,17 @@@ GError *error = NULL
                                homebank_pref_get_boolean(keyfile, group, "WalSpending", &PREFS->wal_spending);
                                homebank_pref_get_boolean(keyfile, group, "WalUpcoming", &PREFS->wal_upcoming);
  
+                       //since 5.1.3
+                       group = "Panels";
+                               DB( g_print(" -> ** Panels\n") );
+                               homebank_pref_get_short(keyfile, group, "AccColAccW", &PREFS->pnl_acc_col_acc_width);
+                               homebank_pref_get_short(keyfile, group, "AccShowBy" , &PREFS->pnl_acc_show_by);
+                               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);
  
                        group = "Format";
  
                        //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;
@@@ -1078,6 -1052,16 +1093,16 @@@ gsize length
                g_key_file_set_boolean (keyfile, group, "WalSpending", PREFS->wal_spending);
                g_key_file_set_boolean (keyfile, group, "WalUpcoming", PREFS->wal_upcoming);
  
+               //since 5.1.3
+               DB( g_print(" -> ** Panels\n") );
+               group = "Panels";
+               g_key_file_set_integer(keyfile, group, "AccColAccW", PREFS->pnl_acc_col_acc_width);
+               g_key_file_set_integer(keyfile, group, "AccShowBy" , PREFS->pnl_acc_show_by);
+               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);
  
                DB( g_print(" -> ** format\n") );
  
                //group = "Chart";
                //g_key_file_set_boolean (keyfile, group, "Legend", PREFS->chart_legend);
  
 +              group = "Plugins";
 +              {
 +                      g_key_file_set_string_list(keyfile, group, "Path", (const gchar* const*)PREFS->ext_path, g_strv_length(PREFS->ext_path));
 +
 +                      gsize len = g_list_length(PREFS->ext_whitelist);
 +                      gchar** strv = g_new0(gchar*, len + 1);
 +                      guint i;
 +
 +                      for (i = 0; i < len; ++i) {
 +                              strv[i] = g_list_nth_data(PREFS->ext_whitelist, i);
 +                      }
 +                      g_key_file_set_string_list(keyfile, group, "Whitelist", (const gchar* const*)strv, len);
 +                      g_free(strv);
 +              }
 +
                //g_key_file_set_string  (keyfile, group, "", PREFS->);
                //g_key_file_set_boolean (keyfile, group, "", PREFS->);
                //g_key_file_set_integer (keyfile, group, "", PREFS->);
diff --combined src/hb-preferences.h
index 4b1cc72fcd2123ead2075c365917e4e7ce505aa5,129e8f3cf923094cf599464f94d29405b37be4c8..69bb44e4d27b7a3c16d7404d30a7819da6855c85
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -120,6 -120,7 +120,7 @@@ struct Preference
        /* windows/dialogs size an position */
        struct WinGeometry      wal_wg;
        struct WinGeometry      acc_wg;
+       
        struct WinGeometry      sta_wg;
        struct WinGeometry      tme_wg;
        struct WinGeometry      ove_wg;
  
        struct WinGeometry      txn_wg;
  
+       // main window stuffs 
        gboolean        wal_toolbar;
        gboolean        wal_spending;
        gboolean        wal_upcoming;
        gint            wal_vpaned;
        gint            wal_hpaned;
  
+       //home panel
+       gshort          pnl_acc_col_acc_width;
+       gshort          pnl_acc_show_by;
+       gshort          pnl_upc_col_pay_width;
+       gshort          pnl_upc_col_mem_width;
+       
        //vehiclecost units (mile/gal or km/liters)
        
        gchar      *vehicle_unit_dist;
        gchar      *vehicle_unit_100;
        gchar      *vehicle_unit_distbyvol;
  
 +      // plugins
 +      gchar** ext_path;
 +      GList* ext_whitelist;
 +
  };
  
  
diff --combined src/hb-tag.c
index 42412c944b9a248f4bd9b08949959f8f9e9acbf3,dc7e25e4e7363af177a16572a6dc1cad48518da9..8a93babbdfb071ee2854596fec190057f0f7f014
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -20,9 -20,6 +20,9 @@@
  #include "homebank.h"
  #include "hb-tag.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  #define MYDEBUG 0
  
  #if MYDEBUG
@@@ -40,12 -37,12 +40,12 @@@ extern struct HomeBank *GLOBALS
  void da_tag_free(Tag *item)
  {
        DB( g_print("da_tag_free\n") );
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                DB( g_print(" => %d, %s\n", item->key, item->name) );
  
                g_free(item->name);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -53,7 -50,7 +53,7 @@@
  Tag *da_tag_malloc(void)
  {
        DB( g_print("da_tag_malloc\n") );
 -      return g_malloc0(sizeof(Tag));
 +      return rc_alloc(sizeof(Tag));
  }
  
  
diff --combined src/hb-transaction.c
index 17fbad5dda73d181bab1c45845f4b9d200dcb3b1,8ab4306a937e3fc013d92e0c6f6306416091fa7e..5f77203fed1a988218a6945bb1dd5ca272b78562
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -23,9 -23,6 +23,9 @@@
  #include "hb-tag.h"
  #include "hb-split.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  /****************************************************************************/
  /* Debug macros                                                                                                       */
  /****************************************************************************/
@@@ -82,10 -79,10 +82,10 @@@ da_transaction_clean(Transaction *item
  void
  da_transaction_free(Transaction *item)
  {
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
                da_transaction_clean(item);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
@@@ -93,7 -90,7 +93,7 @@@
  Transaction *
  da_transaction_malloc(void)
  {
 -      return g_malloc0(sizeof(Transaction));
 +      return rc_alloc(sizeof(Transaction));
  }
  
  
@@@ -143,7 -140,7 +143,7 @@@ Transaction *da_transaction_init_from_t
  
  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") );
  
@@@ -426,7 -423,7 +426,7 @@@ Transaction *child
  Account *acc;
  gchar swap;
  
-       DB( g_print("\n[transaction] transaction_xfer_create_child\n") );
+       DB( g_print("\n[transaction] xfer_create_child\n") );
  
        if( ope->kxferacc > 0 )
        {
                        DB( g_print(" + strong link to %d\n", ope->kxfer) );
  
  
-                       DB( g_print(" + add transfer, %p\n", child) );
+                       DB( g_print(" + add transfer, %p to acc %d\n", child, acc->key) );
  
                        da_transaction_insert_sorted(child);
  
                        account_balances_add (child);
  
 +                      GValue txn_value = G_VALUE_INIT;
 +                      ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, child), NULL);
 +
                }
        }
  
@@@ -483,6 -477,8 +483,8 @@@ static gboolean transaction_xfer_child_
  {
  gboolean retval = FALSE;
  
+       //DB( g_print("\n[transaction] xfer_child_might\n") );
        if(stxn == dtxn)
                return FALSE;
  
@@@ -516,7 -512,7 +518,7 @@@ static GList *transaction_xfer_child_mi
  GList *lst_acc, *lnk_acc;
  GList *list, *matchlist = NULL;
  
-       DB( g_print("\n[transaction]xfer_get_potential_child\n") );
+       //DB( g_print("\n[transaction] xfer_child_might_list_get\n") );
  
        lst_acc = g_hash_table_get_values(GLOBALS->h_acc);
        lnk_acc = g_list_first(lst_acc);
@@@ -557,12 -553,12 +559,12 @@@ void transaction_xfer_search_or_add_chi
  GList *matchlist;
  gint count;
  
-       DB( g_print("\n[transaction] transaction_xfer_search_or_add_child\n") );
+       DB( g_print("\n[transaction] xfer_search_or_add_child\n") );
  
        matchlist = transaction_xfer_child_might_list_get(ope);
        count = g_list_length(matchlist);
  
-       DB( g_print(" - found result is %d, switching\n", count) );
+       DB( g_print(" - found %d might match, switching\n", count) );
  
        switch(count)
        {
  
                default:        //the user must choose himself
                {
-       Transaction *child;
+               Transaction *child;
  
                        child = ui_dialog_transaction_xfer_select_child(ope, matchlist);
-               if(child == NULL)
-                       transaction_xfer_create_child(ope);
-               else
-                       transaction_xfer_change_to_child(ope, child);
+                       if(child == NULL)
+                               transaction_xfer_create_child(ope);
+                       else
+                               transaction_xfer_change_to_child(ope, child);
                }
        }
  
@@@ -602,7 -598,7 +604,7 @@@ Transaction *transaction_xfer_child_str
  Account *dstacc;
  GList *list;
  
-       DB( g_print("\n[transaction] transaction_xfer_child_strong_get\n") );
+       DB( g_print("\n[transaction] xfer_child_strong_get\n") );
  
        dstacc = da_acc_get(src->kxferacc);
        if( !dstacc || src->kxfer <= 0 )
@@@ -640,7 -636,7 +642,7 @@@ void transaction_xfer_change_to_child(T
  {
  Account *dstacc;
  
-       DB( g_print("\n[transaction] transaction_xfer_change_to_child\n") );
+       DB( g_print("\n[transaction] xfer_change_to_child\n") );
  
        if(ope->kcur != child->kcur)
                return;
  void transaction_xfer_sync_child(Transaction *s_txn, Transaction *child)
  {
  
-       DB( g_print("\n[transaction] transaction_xfer_sync_child\n") );
+       DB( g_print("\n[transaction] xfer_sync_child\n") );
  
        account_balances_sub (child);
  
@@@ -707,7 -703,7 +709,7 @@@ void transaction_xfer_remove_child(Tran
  {
  Transaction *dst;
  
-       DB( g_print("\n[transaction] transaction_xfer_remove_child\n") );
+       DB( g_print("\n[transaction] xfer_remove_child\n") );
  
        dst = transaction_xfer_child_strong_get( src );
  
@@@ -733,7 -729,7 +735,7 @@@ Transaction *transaction_old_get_child_
  Account *acc;
  GList *list;
  
-       DB( g_print("\n[transaction] transaction_get_child_transfer\n") );
+       DB( g_print("\n[transaction] get_child_transfer\n") );
  
        //DB( g_print(" search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->account, src->kxferacc) );
        acc = da_acc_get(src->kxferacc);
@@@ -776,12 -772,14 +778,14 @@@ void transaction_add(Transaction *ope, 
  Transaction *newope;
  Account *acc;
  
-       DB( g_print("\n[transaction] transaction add\n") );
+       DB( g_print("\n[transaction] transaction_add\n") );
  
        //controls accounts valid (archive scheduled maybe bad)
        acc = da_acc_get(ope->kacc);
        if(acc == NULL) return;
  
+       DB( g_print(" acc is '%s' %d\n", acc->name, acc->key) );
        ope->kcur = acc->kcur;
        
        if(ope->paymode == PAYMODE_INTXFER)
                ope->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
        }
  
        //allocate a new entry and copy from our edited structure
        newope = da_transaction_clone(ope);
  
        {
                acc->flags |= AF_ADDED;
  
-               DB( g_print(" + add normal %p\n", newope) );
+               DB( g_print(" + add normal %p to acc %d\n", newope, acc->key) );
                //da_transaction_append(newope);
                da_transaction_insert_sorted(newope);
  
                {
                        transaction_xfer_search_or_add_child(NULL, newope, FALSE);
                }
 +
 +              GValue txn_value = G_VALUE_INIT;
 +              ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, newope), NULL);
        }
  }
  
@@@ -859,7 -855,7 +864,7 @@@ GtkTreeIter  iter
  //GtkTreePath *path;
  //GtkTreeSelection *sel;
  
-       DB( g_print("\n[transaction] transaction add treeview\n") );
+       DB( g_print("\n[transaction] add_treeview\n") );
  
        if(ope->kacc == accnum)
        {
@@@ -887,6 -883,8 +892,8 @@@ gboolean transaction_acc_move(Transacti
  {
  Account *oacc, *nacc;
  
+       DB( g_print("\n[transaction] acc_move\n") );
        oacc = da_acc_get(okacc);
        nacc = da_acc_get(nkacc);
        if( oacc && nacc )
@@@ -953,7 -951,7 +960,7 @@@ 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 );
@@@ -967,7 -965,9 +974,9 @@@ static Assign *transaction_auto_assign_
  {
  Assign *rule = 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") );
  
        list = g_list_first(l_rul);
@@@ -1006,6 -1006,8 +1015,8 @@@ static Assign *transaction_auto_assign_
  {
  Assign *rule = 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") );
  
@@@ -1040,7 -1042,7 +1051,7 @@@ GList *l_ope
  GList *l_rul;
  gint changes = 0;
  
-       DB( g_print("\n[transaction] transaction_auto_assign\n") );
+       DB( g_print("\n[transaction] auto_assign\n") );
  
        l_rul = g_hash_table_get_values(GLOBALS->h_rul);
  
@@@ -1135,7 -1137,7 +1146,7 @@@ transaction_tags_count(Transaction *ope
  guint count = 0;
  guint32 *ptr = ope->tags;
  
-       DB( g_print("(transaction_tags_count)\n") );
+       //DB( g_print("\n[transaction] tags_count\n") );
        
        if( ope->tags == NULL )
                return 0;
@@@ -1167,7 -1169,7 +1178,7 @@@ gchar **str_array
  guint count, i;
  Tag *tag;
  
-       DB( g_print("(transaction_tags_parse)\n") );
+       DB( g_print("\n[transaction] tags_parse\n") );
  
        DB( g_print(" - tagstring='%s'\n", tagstring) );
  
@@@ -1221,7 -1223,7 +1232,7 @@@ gchar **str_array
  gchar *tagstring;
  Tag *tag;
  
-       DB( g_print("transaction_tags_tostring\n") );
+       DB( g_print("\n[transaction] tags_tostring\n") );
  
        DB( g_print(" -> tags at=%p\n", ope->tags) );
  
diff --combined src/hb-xml.c
index 68768faf5449f7d30bf2ddfb6ec9f2270796ec0a,2d2e8130e5aa7fd3ce096295aa1e9e6a8af5d31d..6476fd8e0c3f327a009d1b4cef851ebfbf2ab712
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 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"
  
  /****************************************************************************/
@@@ -838,9 -836,6 +838,9 @@@ gboolean rc
  
        DB( g_print("\n[hb-xml] homebank_load_xml\n") );
  
 +      GValue filename_val = G_VALUE_INIT;
 +      ext_hook("load_file", EXT_STRING(&filename_val, filename), NULL);
 +
        retval = XML_OK;
        if (!g_file_get_contents (filename, &buffer, &length, &error))
        {
@@@ -1552,9 -1547,6 +1552,9 @@@ gchar *outstr
  gint retval = XML_OK;
  GError *error = NULL;
  
 +      GValue filename_val = G_VALUE_INIT;
 +      ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL);
 +
        io = g_io_channel_new_file(filename, "w", &error);
        if(io == NULL)
        {
diff --combined src/homebank.c
index c8a6895798d91f36b977e92ff1762ac864238533,ba577cec937036593d3b99e6895c2303d31163be..9a9e9157a89fafca1252bebe915f3f3da711d634
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -18,7 -18,6 +18,7 @@@
   */
  
  #include "homebank.h"
 +#include "ext.h"
  
  #include "dsp_mainwindow.h"
  #include "hb-preferences.h"
@@@ -55,7 -54,6 +55,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>"
@@@ -561,12 -559,6 +561,12 @@@ homebank_app_get_datas_dir (void
        return datas_dir;
  }
  
 +const gchar *
 +homebank_app_get_pkglib_dir (void)
 +{
 +      return pkglib_dir;
 +}
 +
  
  /* build package paths at runtime */
  static void
@@@ -583,7 -575,6 +583,7 @@@ build_package_paths (void
        pixmaps_dir  = g_build_filename (prefix, "share", PACKAGE, "icons", NULL);
        help_dir     = g_build_filename (prefix, "share", PACKAGE, "help", NULL);
        datas_dir    = g_build_filename (prefix, "share", PACKAGE, "datas", NULL);
 +      pkglib_dir   = g_build_filename (prefix, "lib", PACKAGE, NULL);
        #ifdef PORTABLE_APP
                DB( g_print(" - app is portable under windows\n") );
                config_dir   = g_build_filename(prefix, "config", NULL);
        pixmaps_dir  = g_build_filename (DATA_DIR, PACKAGE, "icons", NULL);
        help_dir     = g_build_filename (DATA_DIR, PACKAGE, "help", NULL);
        datas_dir    = g_build_filename (DATA_DIR, PACKAGE, "datas", NULL);
 +      pkglib_dir   = g_build_filename (PKGLIB_DIR, NULL);
        config_dir   = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
  
        //#870023 Ubuntu packages the help files in "/usr/share/doc/homebank-data/help/" for some strange reason
        DB( g_print(" - locale_dir : %s\n", locale_dir) );
        DB( g_print(" - help_dir   : %s\n", help_dir) );
        DB( g_print(" - datas_dir  : %s\n", datas_dir) );
 +      DB( g_print(" - pkglib_dir : %s\n", pkglib_dir) );
  
  }
  
@@@ -756,7 -745,6 +756,7 @@@ static void homebank_cleanup(
        g_free (pixmaps_dir);
        g_free (locale_dir);
        g_free (help_dir);
 +      g_free (pkglib_dir);
  
  }
  
@@@ -887,7 -875,7 +887,7 @@@ homebank_init_i18n (void
  
  
  int
 -main (int argc, char *argv[])
 +main (int argc, char *argv[], char *env[])
  {
  GOptionContext *option_context;
  GOptionGroup *option_group;
@@@ -959,22 -947,6 +959,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)
                {
  
                        /* 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(" - unloading plugins\n") );
 +              ext_term();
 +
        }
  
  
diff --combined src/homebank.h
index a89fc438f6de2b82843edab9979636779d5d32b9,ce348fb67650e0c7abe1f9a90bea9f0ee1bd7ddb..e54023743e9bb4c3f1869e910ab6b19bf51c4629
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  
  #define HB_UNSTABLE           FALSE
+ #define HB_UNSTABLE_SHOW      FALSE
  
  #define HB_VERSION_MAJOR      5
  #define HB_VERSION_MINOR      1
- #define HB_VERSION_MICRO      2
+ #define HB_VERSION_MICRO      3
  
- #define HB_VERSION                    "5.1.2"
+ #define HB_VERSION                    "5.1.3"
  #define HB_VERSION_NUM        (HB_VERSION_MAJOR*10000) + (HB_VERSION_MINOR*100) + HB_VERSION_MICRO
  
  #define FILE_VERSION          1.2
- #define PREF_VERSION          512
+ #define PREF_VERSION          513
  
  #if HB_UNSTABLE == FALSE
        #define PROGNAME                "HomeBank"
@@@ -175,6 -177,8 +177,8 @@@ typedef enu
  #define ICONNAME_REFRESH                      "view-refresh"          
  
  #define ICONNAME_FOLDER                               "folder-symbolic"
+ #define ICONNAME_EMBLEM_SYSTEM                "emblem-system-symbolic"
  
  #define ICONNAME_LIST_ADD                     "list-add-symbolic"
  #define ICONNAME_LIST_REMOVE          "list-remove-symbolic"
  #define ICONNAME_HB_FILE_VALID                "hb-file-valid"
  #define ICONNAME_HB_FILE_INVALID      "hb-file-invalid"
  
- #define ICONNAME_HB_BUTTON_COLLAPSE   "btn-collapse"
- #define ICONNAME_HB_BUTTON_EXPAND     "btn-expand"
+ #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"   //? 
@@@ -305,7 -309,6 +309,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 fa7f906142dcf5722c66e625d3cc3e499ba4b2bc,d167a5811f284270cad34345facdba903d53dc72..1597d688aa3f055501c127f3f61df3568245d41f
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -24,8 -24,6 +24,8 @@@
  #include "dsp_mainwindow.h"
  #include "gtk-chart-colors.h"
  
 +#include "ext.h"
 +
  #include "ui-currency.h"
  
  
@@@ -62,11 -60,14 +62,11 @@@ enu
  
  enum
  {
 -      PREF_GENERAL,
 -      PREF_INTERFACE,
 -      PREF_COLUMNS,
 -      PREF_DISPLAY,
 -      PREF_IMPORT,
 -      PREF_REPORT,
 -      PREF_EURO,
 -      PREF_MAX
 +      EXT_COLUMN_ENABLED = 0,
 +      EXT_COLUMN_LABEL,
 +      EXT_COLUMN_TOOLTIP,
 +      EXT_COLUMN_PLUGIN_NAME,
 +      EXT_NUM_COLUMNS
  };
  
  
@@@ -78,7 -79,6 +78,7 @@@ static gchar *pref_iconname[PREF_MAX] 
  "prf-import",
  "prf-report",
  "prf-euro",                   // to be renamed
 +"prf-plugins",
  //"prf_charts.svg"
  };
  
@@@ -89,8 -89,7 +89,8 @@@ N_("Transactions")
  N_("Display format"),
  N_("Import/Export"),
  N_("Report"),
 -N_("Euro minor")
 +N_("Euro minor"),
 +N_("Plugins")
  //
  };
  
@@@ -148,6 -147,7 +148,7 @@@ extern gchar *CYA_MONTHS[]
  
  typedef struct
  {
+       gshort          id;
        gchar           *iso;
        gchar           *name;
        gdouble         value;
@@@ -170,45 -170,38 +171,38 @@@ source
  */
  static EuroParams euro_params[] =
  {
- //                           , rate     , symb  , prfx , dec, grp, frac
+ //                                , rate     , symb  , prfx , dec, grp, frac
  // ---------------------------------------------------------------------
-       { ""   , "--------"      , 1.0          , ""    , FALSE, ",", ".", 2  },
-       { "ATS", "Austria"       , 13.7603      , "S"   , TRUE , ",", ".", 2  },        // -S 1.234.567,89
-       { "BEF", "Belgium"       , 40.3399      , "BF"  , TRUE , ",", ".", 2  },        // BF 1.234.567,89 -
-       { "FIM", "Finland"       , 5.94573      , "mk"  , FALSE, ",", " ", 2  },        // -1 234 567,89 mk
-       { "FRF", "France"        , 6.55957      , "F"   , FALSE, ",", " ", 2  },        // -1 234 567,89 F
-       { "DEM", "Germany"       , 1.95583      , "DM"  , FALSE, ",", ".", 2  },        // -1.234.567,89 DM
-       { "GRD", "Greece"        , 340.750      , "d"   , TRUE , ".", ",", 2  },        // ??
-       { "IEP", "Ireland"       , 0.787564 , "£"   , TRUE , ".", ",", 2  },   // -£1,234,567.89
-       { "ITL", "Italy"         , 1936.27      , "L"   , TRUE , "" , ".", 0  },        // L -1.234.567
-       { "LUF", "Luxembourg"    , 40.3399      , "LU"  , TRUE , ",", ".", 2  },        // LU 1.234.567,89 -
-       { "NLG", "Netherlands"   , 2.20371      , "F"   , TRUE , ",", ".", 2  },        // F 1.234.567,89-
-       { "PTE", "Portugal"      , 200.482      , "Esc.", FALSE, "$", ".", 2  },        // -1.234.567$89 Esc.
-       { "ESP", "Spain"         , 166.386      , "Pts" , TRUE , "" , ".", 0  },        // -Pts 1.234.567
- /* 2007 */
-       { "SIT", "Slovenia"      , 239.640      , "tol" , TRUE , ",", ".", 2  },        //
- /* 2008 */
-       { "CYP", "Cyprus"        , 0.585274 , "£"   , TRUE , ",", "" , 2  },   //
-       { "MTL", "Malta"         , 0.429300 , "Lm"  , TRUE , ",", "" , 2  },    //
- /* 2009 */
-       { "SKK", "Slovaquia"     , 30.12600 , "Sk"  , FALSE, ",", " ", 2  },    //
- /* 2011 */
-       { "EEK", "Estonia"       , 15.6466  , "kr"  , FALSE, ",", " ", 2  },    //
- /* 2014 */
-       { "LVL", "Latvia"        , 0.702804 , "lat.", FALSE, ",", "" , 2  },    // jan. 2014
- /* 2016 */
-       { "LTL", "Lithuania"     , 3.45280      , "Lt." , TRUE , ",", "" , 2  },        // jan. 2015
- /* future */
-       { "BGN", "Bulgaria"      , 1.95583      , "лв." , TRUE , ",", " ", 2  },      // non-fixé - 2014 target for euro
-       { "HUF", "Hungary"       , 261.51       , "Ft"  , TRUE , ",", " ", 2  },        // non-fixé - No current target for euro
-       { "RON", "Romania"       , 3.5155       , "Leu" , FALSE, ",", ".", 2  },        // non-fixé - 2015 target for euro earliest
-       { "CZK", "Czech republic", 28.36        , "Kč"  , FALSE, ",", " ", 2  },       // non-fixé - 2015 earliest
-       { "HRK", "Croatia"       , 1.0000   , "kn"  , FALSE, "" , ".", 0  },    // non-fixé - 2015 target for euro earliest
-       { "PLN", "Poland"        , 0.25     , "zł"  , FALSE, ",", "" , 2  },   // non-fixé - No current target for euro
+       {  0, ""   , "--------"       , 1.0             , ""    , FALSE, ",", ".", 2  },
+       {  1, "ATS", "Austria"        , 13.7603 , "S"   , TRUE , ",", ".", 2  },        // -S 1.234.567,89
+       {  2, "BEF", "Belgium"        , 40.3399 , "BF"  , TRUE , ",", ".", 2  },        // BF 1.234.567,89 -
+       { 20, "BGN", "Bulgaria"       , 1.95583 , "лв." , TRUE , ",", " ", 2  },      // non-fixé - 2014 target for euro
+       { 24, "HRK", "Croatia"        , 1.0000   , "kn"  , FALSE, "" , ".", 0  },       // non-fixé - 2015 target for euro earliest
+       { 14, "CYP", "Cyprus"         , 0.585274 , "£"   , TRUE , ",", "" , 2  },      //
+       { 23, "CZK", "Czech Republic" , 28.36      , "Kč"  , FALSE, ",", " ", 2  },    // non-fixé - 2015 earliest
+       // Denmark
+       { 17, "EEK", "Estonia"        , 15.6466  , "kr"  , FALSE, ",", " ", 2  },       //
+       {  3, "FIM", "Finland"        , 5.94573 , "mk"  , FALSE, ",", " ", 2  },        // -1 234 567,89 mk
+       {  4, "FRF", "France"         , 6.55957 , "F"   , FALSE, ",", " ", 2  },        // -1 234 567,89 F
+       {  5, "DEM", "Germany"        , 1.95583 , "DM"  , FALSE, ",", ".", 2  },        // -1.234.567,89 DM
+       {  6, "GRD", "Greece"         , 340.750 , "d"   , TRUE , ".", ",", 2  },        // ??
+       { 21, "HUF", "Hungary"        , 261.51  , "Ft"  , TRUE , ",", " ", 2  },        // non-fixé - No current target for euro
+       {  7, "IEP", "Ireland"        , 0.787564  , "£"   , TRUE , ".", ",", 2  },     // -£1,234,567.89
+       {  8, "ITL", "Italy"          , 1936.27 , "L"   , TRUE , "" , ".", 0  },        // L -1.234.567
+       { 18, "LVL", "Latvia"         , 0.702804 , "lat.", FALSE, ",", "" , 2  },       // jan. 2014
+       { 19, "LTL", "Lithuania"      , 3.45280 , "Lt"  , FALSE, ",", "" , 2  },        // jan. 2015
+       {  9, "LUF", "Luxembourg"     , 40.3399 , "LU"  , TRUE , ",", ".", 2  },        // LU 1.234.567,89 -
+       { 15, "MTL", "Malta"          , 0.429300 , "Lm"  , TRUE , ",", "" , 2  },       //
+       { 10, "NLG", "Netherlands"    , 2.20371 , "F"   , TRUE , ",", ".", 2  },        // F 1.234.567,89-
+       { 25, "PLN", "Poland"         , 0.25     , "zł"  , FALSE, ",", "" , 2  },      // non-fixé - No current target for euro
+       { 11, "PTE", "Portugal"       , 200.482 , "Esc.", FALSE, "$", ".", 2  },        // -1.234.567$89 Esc.
+       { 22, "RON", "Romania"        , 3.5155  , "Leu" , FALSE, ",", ".", 2  },        // non-fixé - 2015 target for euro earliest
+       { 16, "SKK", "Slovak Republic", 30.12600 , "Sk"  , FALSE, ",", " ", 2  },       //
+       { 13, "SIT", "Slovenia"       , 239.640 , "tol" , TRUE , ",", ".", 2  },        //
+       { 12, "ESP", "Spain"          , 166.386 , "Pts" , TRUE , "" , ".", 0  },        // -Pts 1.234.567
+       //Sweden
+       //United Kingdom
  //    { "   ", ""    , 1.00000        , ""   , ""  , FALSE, ",", "", 2  },
-       
  };
  
  
@@@ -217,7 -210,6 +211,7 @@@ GtkWidget *list_txn_colprefcreate(void)
  
  static void list_txn_colpref_get(GtkTreeView *treeview, gboolean *columns);
  
 +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns);
  
  
  
@@@ -244,7 -236,7 +238,7 @@@ static LangName languagenames[] 
        { "an", "Aragonese" },
        { "ar", "Arabic" },
        { "as", "Assamese" },
-               { "ast", "Asturian, Bable, Leonese, Asturleonese" },
+       { "ast", "Asturian, Bable, Leonese, Asturleonese" },
        { "av", "Avaric" },
        { "ay", "Aymara" },
        { "az", "Azerbaijani" },
        { "na", "Nauru" },
        { "nb", "Norwegian Bokmål" },
        { "nd", "North Ndebele" },
-               { "nds", "Low German, Low Saxon" },
+       { "nds", "Low German, Low Saxon" },
        { "ne", "Nepali" },
        { "ng", "Ndonga" },
        { "nl", "Dutch" },
@@@ -587,11 -579,47 +581,47 @@@ GtkCellRenderer *renderer
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  
+ static gint ui_euro_combobox_id_to_active(gint id)
+ {
+ guint i, retval;
  
- /*
- **
- */
- static GtkWidget *make_euro_presets(GtkWidget *label)
+       DB( g_print("\n[ui-pref] ui_euro_combobox_id_to_active\n") );
+       retval = 0;
+       for (i = 0; i < G_N_ELEMENTS (euro_params); i++)
+       {
+               if( euro_params[i].id == id )
+               {
+                       retval = i;
+                       DB( g_print("- id (country)=%d => %d - %s\n", id, i, euro_params[i].name) );
+                       break;
+               }
+       }
+       return retval;
+ }
+ static gint ui_euro_combobox_active_to_id(gint active)
+ {
+ gint id;
+       DB( g_print("\n[ui-pref] ui_euro_combobox_active_to_id\n") );
+       DB( g_print("- to %d\n", active) );
+       id = 0;
+       if( active < (gint)G_N_ELEMENTS (euro_params) )
+       {
+               id = euro_params[active].id;
+               DB( g_print("- id (country)=%d '%s'\n", id, euro_params[active].name) );
+       }
+       return id;
+ }
+ static GtkWidget *ui_euro_combobox_new(GtkWidget *label)
  {
  GtkWidget *combobox;
  guint i;
@@@ -744,51 -772,50 +774,50 @@@ gboolean sensitive
  /*
  ** set euro value widget from a country
  */
- static void defpref_eurosetcurrency(GtkWidget *widget, gpointer user_data)
+ static void defpref_eurosetcurrency(GtkWidget *widget, gint country)
  {
  struct defpref_data *data;
- EuroParams *euro = user_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);
        gtk_label_set_markup(GTK_LABEL(data->ST_euro_country), buf);
        g_free(buf);
  }
  
  
  /*
  ** set euro value widget from a country
  */
  static void defpref_europreset(GtkWidget *widget, gpointer user_data)
  {
  struct defpref_data *data;
- gint country;
+ gint active;
  
        DB( g_print("\n[ui-pref] euro preset\n") );
  
        data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
  
-       country = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_euro_preset));
-       data->country = country;
+       active = gtk_combo_box_get_active (GTK_COMBO_BOX(data->CY_euro_preset));
+       data->country = ui_euro_combobox_active_to_id (active);;
  
-       defpref_eurosetcurrency(widget, &euro_params[country]);
+       defpref_eurosetcurrency(widget, data->country);
  
-       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_value), euro_params[country].value);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_value), euro_params[active].value);
  
-       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits), euro_params[country].frac_digits);
+       gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits), euro_params[active].frac_digits);
  
-       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_symbol)   , euro_params[country].symbol);
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_isprefix), euro_params[country].sym_prefix);
-       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_decimalchar) , euro_params[country].decimal_char);
-       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_groupingchar), euro_params[country].grouping_char);
+       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_symbol)   , euro_params[active].symbol);
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_isprefix), euro_params[active].sym_prefix);
+       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_decimalchar) , euro_params[active].decimal_char);
+       gtk_entry_set_text(GTK_ENTRY(data->ST_euro_groupingchar), euro_params[active].grouping_char);
  
  }
  
@@@ -911,6 -938,8 +940,8 @@@ GdkRGBA rgba
        gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_toolbar), PREFS->toolbar_style);
        //gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_image_size), PREFS->image_size);
  
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_custom_colors), PREFS->custom_colors);
  
        gdk_rgba_parse(&rgba, PREFS->color_exp);
        /* euro */
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->CM_euro_enable), PREFS->euro_active);
        //gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_euro_preset), PREFS->euro_country);
        data->country = PREFS->euro_country;
-       defpref_eurosetcurrency(data->window, &euro_params[PREFS->euro_country]);
+       defpref_eurosetcurrency(data->window, data->country);
  
        gtk_spin_button_set_value(GTK_SPIN_BUTTON(data->NB_euro_value), PREFS->euro_value);
  
@@@ -1104,7 -1132,6 +1134,7 @@@ const gchar *lang
  
        //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));
  }
  
  
@@@ -1408,7 -1435,7 +1438,7 @@@ gint crow, row
        label = make_label_widget(_("_Preset:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 2, row, 1, 1);
-       widget = make_euro_presets(label);
+       widget = ui_euro_combobox_new (label);
        data->CY_euro_preset = widget;
        gtk_widget_set_margin_left (label, 2*SPACING_LARGE);
        //gtk_grid_attach (GTK_GRID (group_grid), data->CY_option[FILTER_DATE], 1, 2, row, row+1);
@@@ -1884,202 -1911,6 +1914,202 @@@ gint crow, row
        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;
@@@ -2179,7 -2010,7 +2209,7 @@@ gint result
  
  
  // the window creation
 -GtkWidget *defpref_dialog_new (void)
 +GtkWidget *defpref_dialog_new (gint initial_selection)
  {
  struct defpref_data data;
  GtkWidget *window, *content, *mainvbox;
@@@ -2321,10 -2152,6 +2351,10 @@@ GtkWidget *hbox, *vbox, *sw, *widget, *
        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);
  
  
        //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;
@@@ -2630,32 -2455,3 +2660,32 @@@ gint i
        return(view);
  }
  
 +
 +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns)
 +{
 +      GtkTreeModel *model;
 +      GtkTreeIter     iter;
 +
 +      g_list_free_full(*columns, g_free);
 +      *columns = NULL;
 +
 +      model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
 +
 +      gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
 +      while (valid) {
 +              gboolean        enabled = FALSE;
 +              const gchar*    name;
 +
 +              gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
 +                      EXT_COLUMN_ENABLED,     &enabled,
 +                      EXT_COLUMN_PLUGIN_NAME, &name,
 +                      -1);
 +
 +              if (enabled) {
 +                      *columns = g_list_append(*columns, g_strdup(name));
 +              }
 +
 +              valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
 +      }
 +}
 +
diff --combined src/ui-pref.h
index 1eb95f19d3c775a2730e81edc714ccc2e1589b4e,b8de0d02846c47e03ef18cf60763288f38e2b6d7..51799d3baf804647bfcc58a7f6b41a7b2cc8eaac
@@@ -1,5 -1,5 +1,5 @@@
  /*  HomeBank -- Free, easy, personal accounting for everyone.
-  *  Copyright (C) 1995-2016 Maxime DOYEN
+  *  Copyright (C) 1995-2017 Maxime DOYEN
   *
   *  This file is part of HomeBank.
   *
@@@ -119,26 -119,12 +119,26 @@@ struct defpref_dat
  
        gint            country;
  
 +      GtkWidget       *PI_plugin_columns;
 +};
 +
 +enum
 +{
 +      PREF_GENERAL,
 +      PREF_INTERFACE,
 +      PREF_TRANSACTIONS,
 +      PREF_DISPLAY_FORMAT,
 +      PREF_IMPORT_EXPORT,
 +      PREF_REPORT,
 +      PREF_EURO_MINOR,
 +      PREF_PLUGINS,
 +      PREF_MAX
  };
  
  
  void free_pref_icons(void);
  void load_pref_icons(void);
  
 -GtkWidget *defpref_dialog_new (void);
 +GtkWidget *defpref_dialog_new (gint initial_selection);
  
  #endif
index f5ac1b75129045428bb726d2d9852f83be3d8b84,39cd3ec090f72fde43c20a20e795bde237c2c1b7..91ced1bb5e66320fa97f5e7cc4c8daef952dd75e
@@@ -78,8 -78,9 +78,10 @@@ private_icons = 
        hicolor_status_48x48_prf-import.png \
        hicolor_status_48x48_prf-interface.png \
        hicolor_status_48x48_prf-report.png \
 +      hicolor_status_48x48_prf-plugins.png \
        hicolor_actions_scalable_toggle-sign-symbolic.svg \
+       hicolor_actions_scalable_btn-collapse-symbolic.svg \
+       hicolor_actions_scalable_btn-expand-symbolic.svg \
        $(NULL)
  
  
This page took 0.114009 seconds and 4 git commands to generate.