]> Dogcows Code - chaz/homebank/commitdiff
Merge branch 'master' into ext-perl
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Wed, 28 Dec 2016 22:59:58 +0000 (15:59 -0700)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Wed, 28 Dec 2016 22:59:58 +0000 (15:59 -0700)
22 files changed:
1  2 
Makefile.am
configure.ac
plugins/hello.pl
src/Makefile.am
src/dsp_mainwindow.c
src/ext-perl.xs
src/hb-account.c
src/hb-archive.c
src/hb-assign.c
src/hb-category.c
src/hb-payee.c
src/hb-preferences.c
src/hb-preferences.h
src/hb-tag.c
src/hb-transaction.c
src/hb-xml.c
src/homebank.c
src/homebank.h
src/ui-pref.c
src/ui-pref.h
themes/hicolor/Makefile.am
themes/hicolor/hicolor_status_48x48_prf-plugins.png

diff --cc Makefile.am
index ac9cc1c743eb55e2148d5656cdc424a565821b8e,0a662030ff8fc8ca804ced95a7eaae5a6dfba5a7..de75d0f3cfbe7415f044a9ac8338a23cec6568b2
@@@ -1,9 -1,7 +1,9 @@@
  # HomeBank Makefile.am
  
 +ACLOCAL_AMFLAGS       = -I m4
 +
  #SUBDIRS = src
- SUBDIRS = src data images mime po doc plugins
 -SUBDIRS = src data images mime pixmaps themes po doc
++SUBDIRS = src data images mime pixmaps themes po doc plugins
  
  
  # don't forget to do a 'make check' 
diff --cc configure.ac
index dfaa66d48e303bd8ca6dcc9021bce1ed7a4a4a37,b4680b5425d2f2212fe210033710c0b70a322232..83f65098fc6c15ec96e0ddfb9dc83a35d1c31d02
@@@ -25,7 -22,7 +26,7 @@@ AC_PROG_INSTAL
  AC_PROG_INTLTOOL
  
  # Checks for libraries.
- PKG_CHECK_MODULES(DEPS, gtk+-2.0 >= 2.24 glib-2.0 >= 2.28 gmodule-2.0 >= 2.28)
 -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)
@@@ -139,11 -108,12 +147,13 @@@ data/Makefil
  data/datas/Makefile
  images/Makefile
  mime/Makefile
- po/Makefile.in 
+ pixmaps/Makefile
+ themes/Makefile
+ themes/hicolor/Makefile
+ po/Makefile.in
  doc/Makefile
  doc/images/Makefile
 +plugins/Makefile
  ])
  
  AC_OUTPUT
index c6abdf9e79cb6f6dad767455a065b0d2db84437a,0000000000000000000000000000000000000000..9171bb208eb119808ed03ba7973d23b4c2be7ec8
mode 100644,000000..100644
--- /dev/null
@@@ -1,281 -1,0 +1,234 @@@
-     $self->create_menuitem;
 +
 +# NAME:     Hello World
 +# VERSION:  0.01
 +# ABSTRACT: This is the "hello world" of HomeBank plugins.
 +# AUTHOR:   Charles McGarvey <chazmcgarvey@brokenzipper.com>
 +# WEBSITE:  http://acme.tld/
 +# (These comments are read, before the plugin is executed, to provide some
 +# information to HomeBank and the user about what this plugin is.)
 +
 +eval { HomeBank->version } or die "Cannot run outside of HomeBank";
 +
 +use warnings;
 +use strict;
 +
 +use Scalar::Util qw/weaken/;
 +
 +#use Moose;
 +
 +#has "cool_beans",
 +    #is      => 'rw',
 +    #isa     => 'Str',
 +    #lazy    => 1,
 +    #default => "Booya!!!";
 +
 +
 +our $counter = 0;
 +our $temp;
 +
 +my $ACC;
 +
 +sub new {
 +    my $class = shift;
 +    my $self  = $class->SUPER::new(@_);
 +
 +    $self->on(account_inserted => sub {
 +            my $acc = shift;
 +            print "account inserted: ", Dumper($acc);
 +            print "account name is ", $acc->name, " and balance is ", $acc->bank_balance, "\n";
 +            #$acc->name("FOOOOBAR!");
 +            if ($acc->name eq 'Vacation') {
 +                $acc->remove;
 +                $ACC = $acc;
 +            }
 +            print Dumper($acc->is_inserted);
 +            if ($acc->is_inserted) {
 +                print "IT IS INSERTED\n";
 +            } else {
 +                print "not inserted\n";
 +            }
 +            print Dumper($acc->transactions);
 +        });
 +
 +    #print $self->cool_beans, "\n";
 +    #$self->cool_beans(123);
 +    #print $self->cool_beans, "\n";
 +
-         require Gtk2;
 +    $self;
 +}
 +
 +sub on_create_main_window {
 +    my $self = shift;
 +    my $window = shift;
 +
 +    if (!$window) {
-     $self->create_menuitem;
++        require Gtk3;
 +        $window = HomeBank->main_window;
 +    }
 +
 +    Dump($window);
 +    print Dumper($window);
 +    $window->set_title("foo bar baz");
 +    print $window->get_title, "\n";
 +
 +    HomeBank->hook("my_hook", $window);
-     require Gtk2;
 +}
 +
 +my $test_win;
 +
 +sub on_test {
 +    my $self = shift;
-     my $window = Gtk2::Window->new('toplevel');
++    require Gtk3;
 +
-     #$window->signal_connect(delete_event => sub { Gtk2->main_quit });
++    my $window = Gtk3::Window->new('toplevel');
 +    use Devel::Peek;
 +    Dump($window);
 +    print Dumper($window);
 +    $window->set_title("Hello World");
-     my $button = Gtk2::Button->new('Click Me!');
++    #$window->signal_connect(delete_event => sub { Gtk3->main_quit });
 +    $window->signal_connect(delete_event => sub { undef $test_win });
 +
-             print "Hello Gtk2-Perl: $counter (perl plugin: $self)\n";
++    my $button = Gtk3::Button->new('Click Me!');
 +    Dump($button);
 +    print Dumper($button);
 +    $button->signal_connect(clicked => sub {
-     #require Gtk2;
++            print "Hello Gtk3-Perl: $counter (perl plugin: $self)\n";
 +            $counter++;
 +            #if ($temp->is_inserted) {
 +                #print "$temp is inserted\n";
 +            #} else {
 +                #print "$temp is NOT inserted\n";
 +            #}
 +            #if ($counter == 5) {
 +                #$temp = undef;
 +            #}
 +    my $acc = HomeBank::Account->get(rand(10));
 +    print "Changin account named ", $acc->name, " to ", $acc->name($acc), "\n";
 +    HomeBank->main_window->queue_draw;
 +
 +        });
 +    $window->add($button);
 +
 +    $window->show_all;
 +    $test_win = $window;
 +
 +    weaken $self;
 +}
 +
 +sub on_enter_main_loop {
 +    my $self = shift;
 +
 +    use Data::Dumper;
 +    print Dumper(\@_);
 +    my $t = HomeBank::Transaction->new;
 +    print "Transaction::::::::  $t: ", $t->amount, "\n";
 +
 +    $temp = HomeBank::Account->get(7);
 +    print "retained account: ", $temp->name, "\n";
 +
- sub on_main_window_disposal {
-     my $self = shift;
-     print "main window disposed so forgetting about merge id et al.\n";
-     delete $self->{merge_id};
-     delete $self->{action_group};
- }
++    #require Gtk3;
 +    #
 +    my $txn = HomeBank::Transaction->new;
 +    $txn->amount(12.3456);
 +    print Dumper($txn), $txn->amount, "\n";
 +    #$txn->open;
 +
 +    my @ret = HomeBank->hook("my_hook", @_, $temp, [qw/foo bar baz/, $txn], { asf => 42, quux => \1, meh => HomeBank->main_window });
 +    #my @ret = HomeBank->hook("my_hook", @_, HomeBank->main_window, {
 +    #foo => 'bar', baz => 42
 +    #});
 +    print Dumper(\@ret);
 +
 +    print "adding back account...\n";
 +    $ACC->name("vacation with a different name");
 +    $ACC->insert;
 +    HomeBank::Account->compute_balances;
 +    print "account name is ", $ACC->name, " and balance is ", $ACC->balance, "\n";
 +    print Dumper($ACC->transactions);
 +
 +    my $cloned = $ACC->clone;
 +    $cloned->name("vacation copy");
 +    $cloned->insert;
 +    #my $asdf = $cloned->open;
 +    #$asdf->set_title("this is a new friggin account");
 +
 +    #my $z = HomeBank::Account->get_by_name('Checking');
 +    for my $xc (HomeBank::File->transactions) {
 +        use DateTime;
 +        my $num = $xc->date;
 +        my $date = DateTime->new($xc->date)->datetime;
 +        print "transaction of amount: ", $xc->amount, "\t", $xc->wording, ", ", $xc->info, ", $num, $date\n";
 +    }
 +
 +    HomeBank::File->owner('Billy Murphy');
 +    #HomeBank::File->anonymize;
 +    print HomeBank::File->owner, "\n";
 +
 +    HomeBank::File->baz($ACC);
 +}
 +
 +sub on_deep_hook_recursion {
 +    my $self = shift;
 +    my $level = shift;
 +    print STDERR "recursion is too deep ($level)\n";
 +    exit -2;
 +}
 +
 +sub on_my_hook {
 +    my $self = shift;
 +    print "This is MY HOOK!!!!!!\n";
 +    print Dumper(\@_);
 +
 +    print Dumper($_[2]);
 +    Dump($_[2]);
 +    if ($_[2]) {
 +        print "meh\n";
 +    }
 +    if ($_[2]->isa('HomeBank::Boolean')) {
 +        print "it is a home;;boolean\n";
 +    }
 +    if ($_[2]->isa('Types::Serialiser::Boolean')) {
 +        print "it is a types serialiser thingy\n";
 +    }
 +    if ($_[2]->isa('HomeBank::BooleanBase')) {
 +        print "it is a base bool\n";
 +    }
 +
 +    my $win = $_[6];
 +    if ($win && ref($win) eq 'HASH') {
 +        my $w = $win->{meh};
 +        if ($w) {
 +            $w->set_title("this is MY HOOK setting a window title");
 +        }
 +    }
 +    #print Dumper($acc);
 +    #print "transferred account: ", $acc->name, "\n";
 +
 +    #my $fff = HomeBank::File->foo({foo => 'asdf', bar => 123456789});
 +    my $fff = HomeBank::File->meh([qw/hello this is a test 82/, \1, {foo => 'bar'}, 48]);
 +    print Dumper($fff);
 +
 +    print "my hook done\n";
 +}
 +
 +sub on_unhandled {
 +    my ($self, $hook) = @_;
 +    warn "Unhandled hook '$hook'\n";
 +    #HomeBank->warn($hook, 'Hook not handled.');
 +}
 +
-     $self->destroy_menuitem;
- }
- sub destroy_menuitem {
-     my $self = shift;
-     return unless $self->{merge_id};
-     my $ui_manager = HomeBank->main_ui_manager;
-     $ui_manager->remove_action_group($self->{action_group});
-     $ui_manager->remove_ui($self->{merge_id});
- }
- sub create_menuitem {
-     my $self = shift;
-     return if $self->{merge_id};
-     require Gtk2;
-     my $ui_manager = HomeBank->main_ui_manager;
-     print Dumper($ui_manager);
-     return unless $ui_manager;
-     $self->{merge_id} = $ui_manager->new_merge_id;
-     $self->{action_group} = Gtk2::ActionGroup->new('HelloActionGroup');
-     my $action = Gtk2::Action->new(name => 'HelloPlugin', label => 'Booyah!', stock_id => 'prf-plugins', tooltip => 'blaaaargh');
-     $action->signal_connect(activate => sub { print "hello!!!!!!!!\n" });
-     $self->{action_group}->add_action($action);
-     $ui_manager->insert_action_group($self->{action_group}, -1);
-     $ui_manager->add_ui($self->{merge_id}, 'ui/MenuBar/PluginMenu', 'HelloPlugin', 'HelloPlugin', 'auto', '');
-     #$self->{merge_id} = $ui_manager->new_merge_id;
-     $ui_manager->add_ui($self->{merge_id}, 'ui/ToolBar', 'HelloPluginTool', 'HelloPlugin', 'auto', '');
 +sub DESTROY {
 +    my $self = shift;
 +    print "DESTROYING HELLO WORLD!!!!!!\n";
 +    if ($test_win) {
 +        print "there is a test_win...\n";
 +    }
 +    $test_win->destroy if $test_win;
 +}
 +
 +sub EXECUTE {
 +    print "the perl plugin is being configured.....\n";
 +    HomeBank->info("Hello Prefs", "YEEEEEARGGH!!!!!");
 +}
 +
 +#__PACKAGE__->meta->make_immutable;
diff --cc src/Makefile.am
index 71c57f193b249e9e6bf3cf952f3539645e6ddad2,200e63c679872d99c5ad228b1c8c484db45b4cf4..484ce27b8a65ad79127df95daac4335f1d554c32
@@@ -107,35 -119,13 +120,36 @@@ homebank_SOURCES =  
        ui-transaction.c \
        ui-transaction.h \
        ui-widgets.c \
 -      ui-widgets.h
 +      ui-widgets.h \
-       gtk-chart-colors.c \
-       gtk-chart-colors.h \
 +      refcount.h \
 +      ext.c \
 +      ext.h \
 +      ext-value.c \
 +      ext-value.h \
 +      ext-native.c \
 +      ext-perl.xs
 +
 +EXTRA_homebank_DEPENDENCIES = $(PERL_OBJS)
  
- homebank_LDADD = $(PERL_OBJS) $(DEPS_LIBS)
+ homebank_LDADD = $(DEPS_LIBS) \
 -      $(LIBSOUP_LIBS)
++      $(LIBSOUP_LIBS) \
++      $(PERL_OBJS)
  
  AM_CPPFLAGS = \
        $(DEPS_CFLAGS) \
+       $(LIBSOUP_CFLAGS) \
        $(common_defines)
  
 +$(PERL_OBJS): CPPFLAGS += $(PERL_CPPFLAGS)
 +
 +ext-perl.c: ext-perl.xs typemap
 +      $(XSUBPP) -typemap $(PERL_PRIVLIBEXP)/ExtUtils/typemap -typemap typemap $< >$@
 +
 +perlxsi.c: Makefile
 +      $(PERL) -MExtUtils::Embed -e xsinit -- -std HomeBank
 +
 +CLEANFILES = ext-perl.c perlxsi.c
 +
 +pluginsupportdir = $(pkglibdir)
 +pluginsupport_DATA = HomeBank.pm
 +
index 98c5ea1406b6a56da082d978602163f410e75f48,c96fdc6ba305a3a4a1fe5f3b14e3ba30bb9ba836..707f68a0f6a8dce48af4fc14681fa12533e15116
@@@ -106,12 -106,11 +108,13 @@@ static void ui_mainwindow_action_budget
  static void ui_mainwindow_action_balance(void);
  static void ui_mainwindow_action_vehiclecost(void);
  
- static void ui_mainwindow_action_pluginprefs(void);
- static void ui_mainwindow_action_import(void);
+ static void ui_mainwindow_action_import(GtkAction *action);
  static void ui_mainwindow_action_export(void);
  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,79 -140,90 +144,96 @@@ void ui_mainwindow_recent_add (struct h
  static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data);
  void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data);
  
static void ui_mainwindow_showprefs(gint page);
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[] = { 
+       N_("Category"), 
+       N_("Subcategory"), 
+       NULL
+ };
  static GtkActionEntry entries[] = {
  
-   /* name, stock id, label */
+   /* name, icon-name, label */
  
-   { "FileMenu"     , NULL, N_("_File"), NULL, NULL, NULL },
-   { "EditMenu"     , NULL, N_("_Edit"), NULL, NULL, NULL },
-   { "ViewMenu"     , NULL, N_("_View"), NULL, NULL, NULL },
-   { "ManageMenu"   , NULL, N_("_Manage"), NULL, NULL, NULL },
-   { "TransactionMenu", NULL, N_("_Transactions"), NULL, NULL, NULL },
-   { "ReportMenu"   , NULL, N_("_Reports"), NULL, NULL, NULL  },
-   { "PluginMenu"   , NULL, N_("_Plugins"), NULL, NULL, NULL },
-   { "HelpMenu"     , NULL, N_("_Help"), NULL, NULL, NULL },
+   { "FileMenu"   , NULL, N_("_File"), NULL, NULL, NULL },
+   { "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL },
+   { "EditMenu"   , NULL, N_("_Edit"), NULL, NULL, NULL },
+   { "ViewMenu"   , NULL, N_("_View"), NULL, NULL, NULL },
+   { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL },
+   { "TxnMenu"    , NULL, N_("_Transactions"), NULL, NULL, NULL },
+   { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL  },
+   { "ToolsMenu"  , NULL, N_("_Tools"), NULL, NULL, NULL },
++  { "PluginMenu" , NULL, N_("_Plugins"), NULL, NULL, NULL },
+   { "HelpMenu"   , NULL, N_("_Help"), NULL, NULL, NULL },
  
  //  { "Import"       , NULL, N_("Import") },
  //  { "Export"       , NULL, N_("Export to") },
-       /* name, stock id, label, accelerator, tooltip */
+       /* name, icon-name, label, accelerator, tooltip */
  
    /* FileMenu */
-   { "New"        , GTK_STOCK_NEW            , N_("_New")          , NULL, N_("Create a new file"),    G_CALLBACK (ui_mainwindow_action_new) },
-   { "Open"       , GTK_STOCK_OPEN           , N_("_Open...")      , NULL, N_("Open a file"),    G_CALLBACK (ui_mainwindow_action_open) },
-   { "Save"       , GTK_STOCK_SAVE           , N_("_Save")         , NULL, N_("Save the current file"),    G_CALLBACK (ui_mainwindow_action_save) },
-   { "SaveAs"     , GTK_STOCK_SAVE_AS        , N_("Save As...")    , "<shift><control>S", N_("Save the current file with a different name"),    G_CALLBACK (ui_mainwindow_action_saveas) },
-   { "Revert"     , GTK_STOCK_REVERT_TO_SAVED, N_("Revert")        , NULL, N_("Revert to a saved version of this file"),    G_CALLBACK (ui_mainwindow_action_revert) },
+   { "New"        , ICONNAME_NEW            , N_("_New")          , "<control>N", N_("Create a new file"),    G_CALLBACK (ui_mainwindow_action_new) },
+   { "Open"       , ICONNAME_OPEN           , N_("_Open...")      , "<control>O", N_("Open a file"),    G_CALLBACK (ui_mainwindow_action_open) },
+   { "Save"       , ICONNAME_SAVE           , N_("_Save")         , "<control>S", N_("Save the current file"),    G_CALLBACK (ui_mainwindow_action_save) },
+   { "SaveAs"     , ICONNAME_SAVE_AS        , N_("Save _As...")    , "<shift><control>S", N_("Save the current file with a different name"),    G_CALLBACK (ui_mainwindow_action_saveas) },
+   { "Revert"     , ICONNAME_REVERT         , N_("Revert")        , NULL, N_("Revert to a saved version of this file"),    G_CALLBACK (ui_mainwindow_action_revert) },
  
-   { "Properties" , GTK_STOCK_PROPERTIES     , N_("_Properties..."), NULL, N_("Configure the file"),    G_CALLBACK (ui_mainwindow_action_properties) },
-   { "Close"      , GTK_STOCK_CLOSE          , N_("_Close")        , NULL, N_("Close the current file"),    G_CALLBACK (ui_mainwindow_action_close) },
-   { "Quit"       , GTK_STOCK_QUIT           , N_("_Quit")         , NULL, N_("Quit homebank"),    G_CALLBACK (ui_mainwindow_action_quit) },
+   { "Properties" , ICONNAME_PROPERTIES     , N_("Properties..."), NULL, N_("Configure the file"),    G_CALLBACK (ui_mainwindow_action_properties) },
+   { "Close"      , ICONNAME_CLOSE          , N_("_Close")        , "<control>W", N_("Close the current file"),    G_CALLBACK (ui_mainwindow_action_close) },
+   { "Quit"       , ICONNAME_QUIT           , N_("_Quit")         , "<control>Q", N_("Quit HomeBank"),    G_CALLBACK (ui_mainwindow_action_quit) },
  
    /* Exchange */
-   { "FileImport" , "hb-file-import"         , N_("Import QIF/OFX/CSV...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
-   { "ExportQIF"  , "hb-file-export"         , N_("Export QIF...")     , NULL, N_("Open the export to QIF assistant"),    G_CALLBACK (ui_mainwindow_action_export) },
-   { "Anonymize"  , NULL                     , N_("Anonymize...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_anonymize) },
+   { "ImportQIF" , ICONNAME_HB_FILE_IMPORT  , N_("QIF file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+   { "ImportOFX" , ICONNAME_HB_FILE_IMPORT  , N_("OFX/QFX file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+   { "ImportCSV" , ICONNAME_HB_FILE_IMPORT  , N_("CSV file...")     , NULL, N_("Open the import assistant"),    G_CALLBACK (ui_mainwindow_action_import) },
+       
+   { "ExportQIF" , ICONNAME_HB_FILE_EXPORT  , N_("Export QIF file...")     , NULL, N_("Export all account in a QIF file"),    G_CALLBACK (ui_mainwindow_action_export) },
  
    /* EditMenu */
-   { "Preferences", GTK_STOCK_PREFERENCES, N_("Preferences..."), NULL,    N_("Configure homebank"),    G_CALLBACK (ui_mainwindow_action_preferences) },
+   { "Preferences", ICONNAME_PREFERENCES    , N_("Preferences..."), NULL,    N_("Configure HomeBank"),    G_CALLBACK (ui_mainwindow_action_preferences) },
  
    /* ManageMenu */
//  { "Currency"   , "hb-currency"  , N_("Currencies...") , NULL,    N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) },
-   { "Account"    , "hb-account"   , N_("Acc_ounts...")  , NULL,    N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) },
-   { "Payee"      , "hb-payee"     , N_("_Payees...")    , NULL,    N_("Configure the payees"),    G_CALLBACK (ui_mainwindow_action_defpayee) },
-   { "Category"   , "hb-category"  , N_("Categories...") , NULL,    N_("Configure the categories"),    G_CALLBACK (ui_mainwindow_action_defcategory) },
-   { "Archive"    , "hb-archive"   , N_("Scheduled/Template...")  , NULL,    N_("Configure the scheduled/template transactions"),    G_CALLBACK (ui_mainwindow_action_defarchive) },
-   { "Budget"     , "hb-budget"    , N_("Budget...")     , NULL,    N_("Configure the budget"),    G_CALLBACK (ui_mainwindow_action_defbudget) },
-   { "Assign"     , "hb-assign"    , N_("Assignments..."), NULL,    N_("Configure the automatic assignments"),    G_CALLBACK (ui_mainwindow_action_defassign) },
-   /* TransactionMenu */
-   { "ShowOpe"    , HB_STOCK_OPE_SHOW, N_("Show...")             , NULL, N_("Shows selected account transactions"),    G_CALLBACK (ui_mainwindow_action_showtransactions) },
-   { "AddOpe"     , HB_STOCK_OPE_ADD , N_("Add...")              , NULL, N_("Add transaction"),    G_CALLBACK (ui_mainwindow_action_addtransactions) },
-   { "Scheduler"  , NULL             , N_("Set scheduler...")    , NULL, N_("Configure the transaction scheduler"),    G_CALLBACK (ui_mainwindow_action_properties) },
-   { "AddScheduled"  , NULL             , N_("Process scheduled..."), NULL, N_("Insert pending scheduled transactions"),    G_CALLBACK (ui_mainwindow_action_checkscheduled) },
  { "Currency"   , ICONNAME_HB_CURRENCY    , N_("Currencies...") , NULL,    N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) },
+   { "Account"    , ICONNAME_HB_ACCOUNT     , N_("Acc_ounts...")  , NULL,    N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) },
+   { "Payee"      , ICONNAME_HB_PAYEE       , N_("_Payees...")    , NULL,    N_("Configure the payees"),    G_CALLBACK (ui_mainwindow_action_defpayee) },
+   { "Category"   , ICONNAME_HB_CATEGORY    , N_("Categories...") , NULL,    N_("Configure the categories"),    G_CALLBACK (ui_mainwindow_action_defcategory) },
+   { "Archive"    , ICONNAME_HB_ARCHIVE     , N_("Scheduled/Template...")  , NULL,    N_("Configure the scheduled/template transactions"),    G_CALLBACK (ui_mainwindow_action_defarchive) },
+   { "Budget"     , ICONNAME_HB_BUDGET      , N_("Budget...")     , NULL,    N_("Configure the budget"),    G_CALLBACK (ui_mainwindow_action_defbudget) },
+   { "Assign"     , ICONNAME_HB_ASSIGN      , N_("Assignments..."), NULL,    N_("Configure the automatic assignments"),    G_CALLBACK (ui_mainwindow_action_defassign) },
+   /* TxnMenu */
+   { "ShowOpe"     , ICONNAME_HB_OPE_SHOW   , N_("Show...")             , NULL, N_("Shows selected account transactions"),    G_CALLBACK (ui_mainwindow_action_showtransactions) },
+   { "AddOpe"      , ICONNAME_HB_OPE_ADD    , N_("Add...")              , NULL, N_("Add transactions"),    G_CALLBACK (ui_mainwindow_action_addtransactions) },
+   { "Scheduler"   , NULL                   , N_("Set scheduler...")    , NULL, N_("Configure the transaction scheduler"),    G_CALLBACK (ui_mainwindow_action_properties) },
+   { "AddScheduled", NULL                   , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"),    G_CALLBACK (ui_mainwindow_action_checkscheduled) },
  
    /* ReportMenu */
-   { "RStatistics" , HB_STOCK_REP_STATS , N_("_Statistics...") , NULL,    N_("Open the Statistics report"),    G_CALLBACK (ui_mainwindow_action_statistic) },
-   { "RTrendTime"   , HB_STOCK_REP_TIME , N_("_Trend Time...") , NULL,    N_("Open the Trend Time report"),    G_CALLBACK (ui_mainwindow_action_trendtime) },
-   { "RBudget"    , HB_STOCK_REP_BUDGET, N_("B_udget...")     , NULL,    N_("Open the Budget report"),    G_CALLBACK (ui_mainwindow_action_budget) },
-   { "RBalance"  , HB_STOCK_REP_BALANCE, N_("Balance...")  , NULL,    N_("Open the Balance report"),    G_CALLBACK (ui_mainwindow_action_balance) },
-   { "RVehiculeCost"    , HB_STOCK_REP_CAR   , N_("_Vehicle cost...")   , NULL,    N_("Open the Vehicle cost report"),    G_CALLBACK (ui_mainwindow_action_vehiclecost) },
+   { "RStatistics" , ICONNAME_HB_REP_STATS  , N_("_Statistics...") , NULL,    N_("Open the Statistics report"),    G_CALLBACK (ui_mainwindow_action_statistic) },
+   { "RTrendTime"  , ICONNAME_HB_REP_TIME   , N_("_Trend Time...") , NULL,    N_("Open the Trend Time report"),    G_CALLBACK (ui_mainwindow_action_trendtime) },
+   { "RBudget"     , ICONNAME_HB_REP_BUDGET , N_("B_udget...")     , NULL,    N_("Open the Budget report"),    G_CALLBACK (ui_mainwindow_action_budget) },
+   { "RBalance"    , ICONNAME_HB_REP_BALANCE, N_("Balance...")  , NULL,    N_("Open the Balance report"),    G_CALLBACK (ui_mainwindow_action_balance) },
+   { "RVehiculeCost", ICONNAME_HB_REP_CAR   , N_("_Vehicle cost...")   , NULL,    N_("Open the Vehicle cost report"),    G_CALLBACK (ui_mainwindow_action_vehiclecost) },
+   /* Tools */
+   { "Welcome"     , NULL              , N_("Show welcome dialog...")  , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) },
+   { "FileStats"   , NULL              , N_("File statistics...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_file_statistics) },
+   { "Anonymize"   , NULL              , N_("Anonymize...")  , NULL, NULL,    G_CALLBACK (ui_mainwindow_action_anonymize) },
+       
++  /* Plugins */
 +  { "PluginPreferences", "prf-plugins", N_("_Plugins..."), "<control>U", N_("Configure plugin preferences"), G_CALLBACK(ui_mainwindow_action_pluginprefs) },
 +
    /* HelpMenu */
-   { "Contents"   , GTK_STOCK_HELP    , N_("_Contents")                    , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
-   { "Welcome"    , NULL              , N_("Show welcome dialog...")       , NULL, NULL                              , G_CALLBACK (ui_mainwindow_action_help_welcome) },
-   { "Online"     , "lpi-help"        , N_("Get Help Online...")           , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
-   { "Translate"  , "lpi-translate"   , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) },
-   { "Problem"    , "lpi-bug"         , N_("Report a Problem...")          , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) },
+   { "Contents"    , ICONNAME_HELP     , N_("_Contents")                    , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
+   { "Online"      , "lpi-help"        , N_("Get Help Online...")           , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
+   { "Translate"   , "lpi-translate"   , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) },
+   { "Problem"     , "lpi-bug"         , N_("Report a Problem...")          , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) },
  
-   { "About"      , GTK_STOCK_ABOUT      , N_("_About")     , NULL, N_("About HomeBank")      ,G_CALLBACK (ui_mainwindow_action_about) },
+   { "About"       , ICONNAME_ABOUT      , N_("_About")     , NULL, N_("About HomeBank")      ,G_CALLBACK (ui_mainwindow_action_about) },
  
  };
  static guint n_entries = G_N_ELEMENTS (entries);
@@@ -286,11 -300,12 +310,17 @@@ static const gchar *ui_info 
  "      <menuitem action='RBudget'/>"
  "      <menuitem action='RVehiculeCost'/>"
  "    </menu>"
+ "    <menu action='ToolsMenu'>"
+ "      <menuitem action='Welcome'/>"
+ "      <menuitem action='FileStats'/>"
+ "        <separator/>"
+ "      <menuitem action='Anonymize'/>"
+ "    </menu>"
 +"    <menu action='PluginMenu'>"
 +"      <separator/>"
 +"      <menuitem action='PluginPreferences'/>"
 +"      <separator/>"
 +"    </menu>"
  "    <menu action='HelpMenu'>"
  "      <menuitem action='Contents'/>"
  "        <separator/>"
@@@ -547,9 -544,12 +561,18 @@@ gboolean result
        //gtk_main_quit();
  }
  
+ static void ui_mainwindow_action_file_statistics(void)
+ {
+       ui_dialog_file_statistics();
+ }
  
  
++static void ui_mainwindow_action_pluginprefs(void)
++{
++      ui_mainwindow_showprefs(PREF_PLUGINS);
++}
++
 +
  static void ui_mainwindow_action_properties(void)
  {
        create_defhbfile_dialog();
diff --cc src/ext-perl.xs
index 80020473e87e9c00516c8fbc0131e29a4097f02d,0000000000000000000000000000000000000000..5aa56b01df5480491909eb647b4d6ae6b48696b5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1042 -1,0 +1,1043 @@@
-               GList* list = g_list_first(GLOBALS->ope_list);
-               for (; list; list = g_list_next(list)) {
-                       GValue val = G_VALUE_INIT;
-                       SV* sv = val_to_sv(EXT_TRANSACTION(&val, list->data));
-                       mXPUSHs(sv);
 +
 +#include <EXTERN.h>
 +#include <perl.h>
 +#include <XSUB.h>
 +
 +#include <string.h>
 +
 +#undef _
 +#include "homebank.h"
 +#include "ext.h"
 +#include "refcount.h"
 +
 +extern struct HomeBank *GLOBALS;
 +#include "dsp_mainwindow.h"
 +#include "dsp_account.h"
 +#include "ui-transaction.h"
 +
 +
 +static gint ext_perl_init(int* argc, char** argv[], char** env[]);
 +static void ext_perl_term(void);
 +static gboolean ext_perl_check_file(const gchar* plugin_filepath);
 +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath);
 +static gint ext_perl_load_plugin(const gchar* plugin_filepath);
 +static void ext_perl_unload_plugin(const gchar* plugin_filepath);
 +static void ext_perl_execute_action(const gchar* plugin_filepath);
 +static void ext_perl_call_hook(const gchar* hook_id, GList* args);
 +
 +static SV* val_to_sv(GValue* val);
 +static GValue* sv_to_val(SV* sv);
 +
 +static gboolean gperl_value_from_sv(GValue* value, SV* sv);
 +static SV*      gperl_sv_from_value(const GValue* value, gboolean copy_boxed);
 +
 +
 +static inline GValue* EXT_SV(GValue* v, SV* sv, GType type)
 +{
 +      g_value_init(v, type);
 +      gperl_value_from_sv(v, sv);
 +      return v;
 +}
 +
 +
 +#define EXT_P2C_OBJECT(PKG, ARG, VAR, TYP)  \
 +if (sv_derived_from(ARG, PKG)) {            \
 +    IV iv = SvIV((SV*)SvRV(ARG));           \
 +    VAR = INT2PTR(TYP, iv);                 \
 +} else {                                    \
 +    croak(#VAR" is not of type "PKG);       \
 +}
 +
 +#define EXT_C2P_OBJECT(PKG, ARG, VAR)       \
 +sv_setref_pv(ARG, PKG, (void*)VAR)
 +
 +
 +static inline GPtrArray* SvGptrarray(const SV* sv)
 +{
 +      if (SvROK(sv)) {
 +              sv = MUTABLE_SV(SvRV(sv));
 +      }
 +      if (SvTYPE(sv) == SVt_PVAV) {
 +              AV* av = (AV*)sv;
 +              int i;
 +              int top = av_len(av);
 +              GPtrArray* array = g_ptr_array_new();
 +              for (i = 0; i <= top; ++i) {
 +                      SV** item = av_fetch(av, i, 0);
 +                      if (!item) continue;
 +                      g_ptr_array_add(array, sv_to_val(*item));
 +              }
 +              return array;
 +              // TODO- leaking
 +      } else {
 +              croak("var is not an array");
 +      }
 +}
 +
 +static inline SV* newSVgptrarray(const GPtrArray* a)
 +{
 +      if (a) {
 +              AV* av = newAV();
 +              int i;
 +              for (i = 0; i < a->len; ++i) {
 +                      GValue* item = g_ptr_array_index(a, i);
 +                      av_push(av, val_to_sv(item));
 +              }
 +              return newRV((SV*)av);
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static inline GHashTable* SvGhashtable(const SV* sv)
 +{
 +      if (SvROK(sv)) {
 +              sv = MUTABLE_SV(SvRV(sv));
 +      }
 +      if (SvTYPE(sv) == SVt_PVHV) {
 +              HV* hv = (HV*)sv;
 +              hv_iterinit(hv);
 +              gchar* key;
 +              I32 len;
 +              SV* item;
 +              GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
 +              while ((item = hv_iternextsv(hv, &key, &len))) {
 +                      g_hash_table_insert(hash, key, sv_to_val(item));
 +              }
 +              return hash;
 +              // TODO- leaking
 +      } else {
 +              croak("var is not a hash");
 +      }
 +}
 +
 +static inline SV* newSVghashtable(GHashTable* h)
 +{
 +      if (h) {
 +              HV* hv = newHV();
 +              GHashTableIter it;
 +              g_hash_table_iter_init(&it, h);
 +              gchar* key = NULL;
 +              GValue* item = NULL;
 +              while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
 +                      hv_store(hv, key, -g_utf8_strlen(key, -1), val_to_sv(item), 0);
 +              }
 +              return newRV((SV*)hv);
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static inline gboolean SvGboolean(SV* sv)
 +{
 +      if (!sv) {
 +              return FALSE;
 +      }
 +      if (SvROK(sv)) {
 +              return !!SvIV(SvRV(sv));
 +      } else {
 +              return SvTRUE(sv);
 +      }
 +}
 +
 +static inline SV* newSVgboolean(gboolean b)
 +{
 +      return sv_setref_iv(newSV(0), "HomeBank::Boolean", !!b);
 +}
 +
 +
 +static inline gchar* SvGchar_ptr(SV* sv)
 +{
 +      return SvPVutf8_nolen(sv);
 +}
 +
 +static inline SV* newSVgchar_ptr(const gchar* str)
 +{
 +      if (!str) return &PL_sv_undef;
 +
 +      SV* sv = newSVpv(str, 0);
 +      SvUTF8_on(sv);
 +      return sv;
 +}
 +
 +
 +static inline GObject* SvGobject(const SV* sv)
 +{
 +      GObject* (*func)(const SV*) = ext_symbol_lookup("gperl_get_object");
 +      if (func) {
 +              return func(sv);
 +      }
 +      return NULL;
 +}
 +
 +static inline SV* newSVgobject(const GObject* o)
 +{
 +    SV* (*func)(const GObject*, gboolean) = ext_symbol_lookup("gperl_new_object");
 +    if (func) {
 +        return func(o, FALSE);
 +    }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static PerlInterpreter* context = NULL;
 +
 +
 +static gint ext_perl_init(int* argc, char** argv[], char** env[])
 +{
 +      int ret = 0;
 +
 +      PERL_SYS_INIT3(argc, argv, env);
 +      context = perl_alloc();
 +      perl_construct(context);
 +
 +      PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 +      PL_origalen = 1;
 +      PL_perl_destruct_level = 1;
 +
 +      gchar* bootstrap = g_strdup_printf("-e"
 +              "use lib '%s';"
 +              "use HomeBank;"
 +              "HomeBank->bootstrap;",
 +              homebank_app_get_pkglib_dir());
 +      char *args[] = { "", bootstrap };
 +
 +      EXTERN_C void xs_init(pTHX);
 +      if (perl_parse(context, xs_init, 2, args, NULL) || perl_run(context)) {
 +              ext_perl_term();
 +              ret = -1;
 +      }
 +
 +      g_free(bootstrap);
 +      return ret;
 +}
 +
 +static void ext_perl_term(void)
 +{
 +      if (context) {
 +              perl_destruct(context);
 +              perl_free(context);
 +              context = NULL;
 +      }
 +      PERL_SYS_TERM();
 +}
 +
 +static gboolean ext_perl_check_file(const gchar* plugin_filepath)
 +{
 +      if (g_str_has_suffix(plugin_filepath, ".pl")) {
 +              return TRUE;
 +      }
 +      return FALSE;
 +}
 +
 +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath)
 +{
 +      GHashTable* table = NULL;
 +
 +      if (!context) return NULL;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +
 +      int ret = call_pv("HomeBank::read_metadata", G_SCALAR | G_EVAL);
 +
 +      SPAGAIN;
 +
 +      if (ret == 1) {
 +              table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 +              SV* sv = POPs;
 +              if (SvROK(sv)) {
 +                      sv = MUTABLE_SV(SvRV(sv));
 +              }
 +              if (SvTYPE(sv) == SVt_PVHV) {
 +                      HV* hv = (HV*)sv;
 +                      hv_iterinit(hv);
 +                      gchar* key;
 +                      I32 len;
 +                      SV* item;
 +                      while ((item = hv_iternextsv(hv, &key, &len))) {
 +                              if (SvPOK(item)) {
 +                                      gchar* val = SvPVutf8_nolen(item);
 +                                      g_hash_table_insert(table, g_strdup(key), g_strdup(val));
 +                              }
 +                      }
 +              }
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      return table;
 +}
 +
 +static gint ext_perl_load_plugin(const gchar* plugin_filepath)
 +{
 +      if (!context) return -1;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::load_plugin", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      gint ret = 0;
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +              ret = -1;
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      return ret;
 +}
 +
 +static void ext_perl_unload_plugin(const gchar* plugin_filepath)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::unload_plugin", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +static void ext_perl_execute_action(const gchar* plugin_filepath)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::execute_action", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +static void ext_perl_call_hook(const gchar* hook_id, GList* args)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(hook_id));
 +
 +      GList *list = g_list_first(args);
 +      while (list) {
 +              GValue* val = list->data;
 +              XPUSHs(sv_2mortal(val_to_sv(val)));
 +              list = g_list_next(list);
 +      }
 +
 +      PUTBACK;
 +      call_pv("HomeBank::call_hook", G_ARRAY);
 +      SPAGAIN;
 +      POPi;
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +
 +static SV* val_to_sv(GValue* val)
 +{
 +      if (!val || !G_IS_VALUE(val) || G_VALUE_TYPE(val) == G_TYPE_NONE) {
 +              return &PL_sv_undef;
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_BOOLEAN) {
 +              return newSVgboolean(g_value_get_boolean(val));
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_PTR_ARRAY) {
 +              return newSVgptrarray((GPtrArray*)g_value_get_boxed(val));
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_HASH_TABLE) {
 +              return newSVghashtable((GHashTable*)g_value_get_boxed(val));
 +      }
 +#define obj(CTYPE, _2, PART, GTYPE, _5)                         \
 +      if (G_VALUE_TYPE(val) == GTYPE) {                           \
 +              SV* sv = newSV(0);                                      \
 +              CTYPE* ptr = (CTYPE*)g_value_get_##PART(val);           \
 +              EXT_C2P_OBJECT("HomeBank::"#CTYPE, sv, rc_ref(ptr));    \
 +              return sv;                                              \
 +      }
 +#include "ext-value.h"
 +#undef obj
 +      return gperl_sv_from_value(val, FALSE);
 +}
 +
 +static GValue* sv_to_val(SV* sv)
 +{
 +      GValue* val = g_new0(GValue, 1);
 +
 +      if (SvUOK(sv)) return EXT_SV(val, sv, G_TYPE_UINT);
 +      if (SvIOK(sv)) return EXT_SV(val, sv, G_TYPE_INT);
 +      if (SvNOK(sv)) return EXT_SV(val, sv, G_TYPE_DOUBLE);
 +      if (SvPOK(sv)) return EXT_SV(val, sv, G_TYPE_STRING);
 +      if (sv_isobject(sv)) {
 +              if (sv_derived_from(sv, "HomeBank::Boolean")) {
 +                      return EXT_BOOLEAN(val, SvGboolean(sv));
 +              }
 +#define obj(CTYPE, NAME, _3, _4, _5)                                \
 +              if (sv_derived_from(sv, "HomeBank::"#CTYPE)) {              \
 +                      CTYPE* ptr;                                             \
 +                      EXT_P2C_OBJECT("HomeBank::"#CTYPE, sv, ptr, CTYPE*);    \
 +                      return EXT_##NAME(val, ptr);                            \
 +              }
 +#include "ext-value.h"
 +#undef obj
 +              return EXT_SV(val, sv, G_TYPE_OBJECT);
 +      }
 +      if (SvROK(sv)) {
 +              sv = SvRV(sv);
 +              switch (SvTYPE(sv)) {
 +                      case SVt_IV:
 +                              return EXT_BOOLEAN(val, SvGboolean(sv));
 +                      case SVt_PVAV:
 +                              return EXT_ARRAY(val, SvGptrarray(sv));
 +                      case SVt_PVHV:
 +                              return EXT_HASH_TABLE(val, SvGhashtable(sv));
 +                      default:
 +                              break;
 +              }
 +      }
 +      switch (SvTYPE(sv)) {
 +              case SVt_PVAV:
 +                      return EXT_ARRAY(val, SvGptrarray(sv));
 +              case SVt_PVHV:
 +                      return EXT_HASH_TABLE(val, SvGhashtable(sv));
 +              default:
 +                      break;
 +      }
 +
 +      g_free(val);
 +      return NULL;
 +}
 +
 +
 +static gboolean gperl_value_from_sv(GValue* value, SV* sv)
 +{
 +      gboolean (*func)(GValue*, SV*) = ext_symbol_lookup("gperl_value_from_sv");
 +      if (func) return func(value, sv);
 +
 +      GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
 +      if (!SvOK(sv)) return TRUE;
 +      switch (type) {
 +              case G_TYPE_CHAR:
 +              {
 +                      gchar *tmp = SvGchar_ptr(sv);
 +                      g_value_set_schar(value, (gint8)(tmp ? tmp[0] : 0));
 +                      break;
 +              }
 +              case G_TYPE_UCHAR:
 +              {
 +                      char *tmp = SvPV_nolen(sv);
 +                      g_value_set_uchar(value, (guchar)(tmp ? tmp[0] : 0));
 +                      break;
 +              }
 +              case G_TYPE_BOOLEAN:
 +                      g_value_set_boolean(value, SvTRUE(sv));
 +                      break;
 +              case G_TYPE_INT:
 +                      g_value_set_int(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_UINT:
 +                      g_value_set_uint(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_LONG:
 +                      g_value_set_long(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_ULONG:
 +                      g_value_set_ulong(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_FLOAT:
 +                      g_value_set_float(value, (gfloat)SvNV(sv));
 +                      break;
 +              case G_TYPE_DOUBLE:
 +                      g_value_set_double(value, SvNV(sv));
 +                      break;
 +              case G_TYPE_STRING:
 +                      g_value_set_string(value, SvGchar_ptr(sv));
 +                      break;
 +      }
 +      return TRUE;
 +}
 +
 +static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed)
 +{
 +      SV* (*func)(const GValue*, gboolean) = ext_symbol_lookup("gperl_sv_from_value");
 +      if (func) return func(value, copy_boxed);
 +
 +      GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
 +      switch (type) {
 +              case G_TYPE_CHAR:
 +                      return newSViv(g_value_get_schar(value));
 +              case G_TYPE_UCHAR:
 +                      return newSVuv(g_value_get_uchar(value));
 +              case G_TYPE_BOOLEAN:
 +                      return newSViv(g_value_get_boolean(value));
 +              case G_TYPE_INT:
 +                      return newSViv(g_value_get_int(value));
 +              case G_TYPE_UINT:
 +                      return newSVuv(g_value_get_uint(value));
 +              case G_TYPE_LONG:
 +                      return newSViv(g_value_get_long(value));
 +              case G_TYPE_ULONG:
 +                      return newSVuv(g_value_get_ulong(value));
 +              case G_TYPE_FLOAT:
 +                      return newSVnv(g_value_get_float(value));
 +              case G_TYPE_DOUBLE:
 +                      return newSVnv(g_value_get_double(value));
 +              case G_TYPE_STRING:
 +                      return newSVgchar_ptr(g_value_get_string(value));
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static void _register(void) __attribute__((constructor));
 +static void _register()
 +{
 +      ext_register("perl",
 +                      ext_perl_init,
 +                      ext_perl_term,
 +                      ext_perl_check_file,
 +                      ext_perl_read_plugin_metadata,
 +                      ext_perl_load_plugin,
 +                      ext_perl_unload_plugin,
 +                      ext_perl_execute_action,
 +                      ext_perl_call_hook);
 +}
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank
 +
 +PROTOTYPES: ENABLE
 +
 +const gchar*
 +version(void)
 +      CODE:
 +              RETVAL = VERSION;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +config_dir(void)
 +      CODE:
 +              RETVAL = homebank_app_get_config_dir();
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +has(const gchar* CLASS, ...)
 +      PREINIT:
 +              int i;
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = TRUE;
 +              for (i = 1; i < items; ++i) {
 +                      gchar* feature = SvGchar_ptr(ST(i));
 +                      if (!feature || !ext_has(feature)) {
 +                              RETVAL = FALSE;
 +                              break;
 +                      }
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +main_window(void)
 +      CODE:
 +              RETVAL = G_OBJECT(GLOBALS->mainwindow);
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +main_ui_manager(void)
 +      PREINIT:
 +              struct hbfile_data *data;
 +      CODE:
 +              RETVAL = NULL;
 +              if (GLOBALS->mainwindow) {
 +                      data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GLOBALS->mainwindow, GTK_TYPE_WINDOW)), "inst_data");
 +                      if (data) {
 +                              RETVAL = G_OBJECT(data->manager);
 +                      }
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +info(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "info");
 +
 +void
 +warn(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "warn");
 +
 +void
 +error(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "error");
 +
 +void
 +hook(const gchar* CLASS, const gchar* hook_name, ...)
 +      PREINIT:
 +              int i;
 +              GList* list = NULL;
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              for (i = 2; i < items; ++i) {
 +                      SV* sv = ST(i);
 +                      GValue *val = sv_to_val(sv);
 +                      list = g_list_append(list, val);
 +              }
 +      CLEANUP:
 +              ext_vhook(hook_name, list);
 +              g_list_free(list);
 +              // TODO free all the things
 +
 +GObject*
 +open_prefs(const gchar* CLASS)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = G_OBJECT(defpref_dialog_new(PREF_GENERAL));
 +      OUTPUT:
 +              RETVAL
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::File
 +
 +const gchar*
 +owner(const gchar* CLASS, ...)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              if (1 < items) {
 +                      hbfile_change_owner(g_strdup(SvGchar_ptr(ST(1))));
 +              }
 +              RETVAL = GLOBALS->owner;
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +transactions(const gchar* CLASS)
 +      PPCODE:
 +              PERL_UNUSED_ARG(CLASS);
- Account*
- clone(Account* SELF)
-       CODE:
-               RETVAL = da_acc_clone(SELF);
-               RETVAL->key = 0;
-       OUTPUT:
-               RETVAL
++
++              GList* acc_list = g_hash_table_get_values(GLOBALS->h_acc);
++              GList* acc_link = g_list_first(acc_list);
++              for (; acc_link; acc_link = g_list_next(acc_link)) {
++                      Account *acc = acc_link->data;
++
++                      GList* txn_link = g_queue_peek_head_link(acc->txn_queue);
++                      for (; txn_link; txn_link = g_list_next(txn_link)) {
++                              Transaction* txn = txn_link->data;
++
++                              GValue val = G_VALUE_INIT;
++                              SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
++                              mXPUSHs(sv);
++                      }
 +              }
 +
++              g_list_free(acc_list);
++
 +void
 +anonymize(void)
 +      CODE:
 +              hbfile_anonymize();
 +
 +void
 +baz(const gchar* CLASS, Account* account)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("hello: %s\n", account->name);
 +
 +GPtrArray*
 +meh(const gchar* CLASS, GPtrArray* asdf)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
 +              if (asdf) {
 +                      ;
 +              } else {
 +                      g_print("the array is nil\n");
 +              }
 +              RETVAL = asdf;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_ptr_array_unref(asdf);
 +
 +GHashTable*
 +foo(const gchar* CLASS, GHashTable* asdf)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
 +              if (asdf) {
 +                      GHashTableIter it;
 +                      g_hash_table_iter_init(&it, asdf);
 +                      gchar* key = NULL;
 +                      GValue* item = NULL;
 +                      while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
 +                              g_print("hash with key: %s\n", key);
 +                      }
 +              } else {
 +                      g_print("the hash is nil\n");
 +              }
 +              RETVAL = asdf;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_hash_table_unref(asdf);
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::Account
 +
 +void
 +compute_balances(const gchar* CLASS)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              account_compute_balances();
 +
 +Account*
 +new(void)
 +      CODE:
 +              RETVAL = da_acc_malloc();
 +      OUTPUT:
 +              RETVAL
 +
-               GList* list = g_list_first(GLOBALS->ope_list);
 +void
 +DESTROY(Account* SELF)
 +      CODE:
 +              da_acc_free(SELF);
 +
 +Account*
 +get(const gchar* CLASS, guint key)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = rc_ref(da_acc_get(key));
 +      OUTPUT:
 +              RETVAL
 +
 +Account*
 +get_by_name(const gchar* CLASS, const gchar* name)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = rc_ref(da_acc_get_by_name((gchar*)name));
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +name(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      account_rename(SELF, SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->name;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +number(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      g_free(SELF->number);
 +                      SELF->number = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->number;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +bankname(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      g_free(SELF->bankname);
 +                      SELF->bankname = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->bankname;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +initial(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->initial = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->initial;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +minimum(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->minimum = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->minimum;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +cheque1(Account* SELF, ...)
 +      ALIAS:
 +              check1 = 1
 +      CODE:
 +              PERL_UNUSED_VAR(ix);
 +              if (1 < items) {
 +                      SELF->cheque1 = SvUV(ST(1));
 +              }
 +              RETVAL = SELF->cheque1;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +cheque2(Account* SELF, ...)
 +      ALIAS:
 +              check2 = 1
 +      CODE:
 +              PERL_UNUSED_VAR(ix);
 +              if (1 < items) {
 +                      SELF->cheque2 = SvUV(ST(1));
 +              }
 +              RETVAL = SELF->cheque2;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +balance(Account* SELF)
 +      ALIAS:
 +              bank_balance    = 1
 +              future_balance  = 2
 +      CODE:
 +              switch (ix) {
 +                      case 1:
 +                              RETVAL = SELF->bal_bank;
 +                              break;
 +                      case 2:
 +                              RETVAL = SELF->bal_future;
 +                              break;
 +                      default:
 +                              RETVAL = SELF->bal_today;
 +                              break;
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +is_inserted(Account* SELF)
 +      CODE:
 +              RETVAL = da_acc_get(SELF->key) == SELF;
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +is_used(Account* SELF)
 +      CODE:
 +              RETVAL = account_is_used(SELF->key);
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +insert(Account* SELF)
 +      CODE:
 +              if (SELF->key == 0 || account_is_used(SELF->key))
 +                      RETVAL = da_acc_append(rc_ref(SELF));
 +              else
 +                      RETVAL = da_acc_insert(rc_ref(SELF));
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +remove(Account* SELF)
 +      CODE:
 +              da_acc_remove(SELF->key);
 +
 +void
 +transactions(Account* SELF)
 +      PPCODE:
-                       if (txn->kacc == SELF->key) {
-                               GValue val = G_VALUE_INIT;
-                               SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
-                               mXPUSHs(sv);
-                       }
++              GList* list = g_queue_peek_head_link(SELF->txn_queue);
 +              for (; list; list = g_list_next(list)) {
 +                      Transaction* txn = list->data;
-               RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY));
++                      GValue val = G_VALUE_INIT;
++                      SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
++                      mXPUSHs(sv);
 +              }
 +
 +GObject*
 +open(Account* SELF)
 +      CODE:
 +              RETVAL = G_OBJECT(register_panel_window_new(SELF->key, SELF));
 +      OUTPUT:
 +              RETVAL
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::Transaction
 +
 +Transaction*
 +new(void)
 +      CODE:
 +              RETVAL = da_transaction_malloc();
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +DESTROY(Transaction* SELF)
 +      CODE:
 +              da_transaction_free(SELF);
 +
 +gdouble
 +amount(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->amount = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->amount;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kacc;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +paired_account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kxferacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kxferacc;
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +date(Transaction* SELF, ...)
 +      PPCODE:
 +              if (1 < items) {
 +                      SELF->date = SvIV(ST(1));
 +              }
 +              if (GIMME_V == G_ARRAY) {
 +                      GDate* d = g_date_new_julian(SELF->date);
 +                      mXPUSHp("day", 3);
 +                      mXPUSHi(g_date_get_day(d));
 +                      mXPUSHp("month", 5);
 +                      mXPUSHi(g_date_get_month(d));
 +                      mXPUSHp("year", 4);
 +                      mXPUSHi(g_date_get_year(d));
 +                      g_date_free(d);
 +                      XSRETURN(6);
 +              } else {
 +                      XSRETURN_IV(SELF->date);
 +              }
 +
 +const gchar*
 +wording(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      if (SELF->wording) g_free(SELF->wording);
 +                      SELF->wording = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->wording ? SELF->wording : "";
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +info(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      if (SELF->info) g_free(SELF->info);
 +                      SELF->info = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->info ? SELF->info : "";
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +open(Transaction* SELF)
 +      CODE:
-                       other = ui_dialog_transaction_xfer_select_child(list);
++              RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE));
 +              deftransaction_set_transaction(GTK_WIDGET(RETVAL), SELF);
 +      OUTPUT:
 +              RETVAL
 +
 +Transaction*
 +pair_with(Transaction* SELF, Transaction* other, ...)
 +      PREINIT:
 +              int i;
 +              GList* list = NULL;
 +      CODE:
 +              if (2 < items) {
 +                      list = g_list_append(list, other);
 +                      for (i = 2; i < items; ++i) {
 +                              Transaction* ptr = NULL;
 +                              SV* sv = ST(i);
 +                              EXT_P2C_OBJECT("HomeBank::Transaction", sv, ptr, Transaction*);
 +                              list = g_list_append(list, ptr);
 +                      }
++                      other = ui_dialog_transaction_xfer_select_child(SELF, list);
 +              }
 +              if (other) {
 +                      transaction_xfer_change_to_child(SELF, other);
 +                      SELF->paymode = PAYMODE_INTXFER;
 +              }
 +              RETVAL = other;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_list_free(list);
 +
 +void
 +dump(Transaction* SELF)
 +      CODE:
 +              g_print("txn: %p (%s) at %u (%d/%d) flags:%d, paymode:%d, kpay:%d, kcat:%d", SELF,
 +                      SELF->wording, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
 +
index c3366e770167a414e02984c55bd8c19409f56847,56b5339c1da2dfdff03969fec48ed5d48dbd6e41..9064868c71257d88d5ef18a4e0d5f8cce2b6dd29
@@@ -70,7 -47,11 +50,11 @@@ da_acc_free(Account *item
                g_free(item->name);
                g_free(item->number);
                g_free(item->bankname);
 -              g_free(item);
+               g_free(item->notes);
+               
+               g_queue_free (item->txn_queue);
+               
 +              rc_free(item);
        }
  }
  
  Account *
  da_acc_malloc(void)
  {
+ Account *item;
        DB( g_print("da_acc_malloc\n") );
-       return rc_alloc(sizeof(Account));
 -      item = g_malloc0(sizeof(Account));
++      item = rc_alloc(sizeof(Account));
+       item->txn_queue = g_queue_new ();
+       return item;
  }
  
  
index e3faf5d40101af4c8958df252789db54a2a3eb56,c552f85d60ec02b867a7b9e2fb01de3fa94e0b28..d815703fc5067af1b3d96dad8aad4d1509e70635
  
  #include "homebank.h"
  #include "hb-archive.h"
+ #include "hb-split.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  /****************************************************************************/
  /* Debug macros                                                             */
  /****************************************************************************/
@@@ -65,7 -66,10 +69,10 @@@ void da_archive_free(Archive *item
                if(item->wording != NULL)
                        g_free(item->wording);
  
 -              g_free(item);
+               da_splits_free(item->splits);
+               //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared            
+               
 +              rc_free(item);
        }
  }
  
diff --cc src/hb-assign.c
index 8303436ea80d7a7e0ef0276e2a8a0d51ecb50eb0,93fd2da83854df61fbbc928bc082cf6ef194de93..951cf92563bb1c519cf6ef9fcb7fa70daa26dd0c
@@@ -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->name) );
+               DB( g_print(" => %d, %s\n", item->key, item->text) );
  
-               g_free(item->name);
+               g_free(item->text);
 -              g_free(item);
 +              rc_free(item);
        }
  }
  
Simple merge
diff --cc src/hb-payee.c
Simple merge
index e7695bc5f83877af411c5ce15dc1bf7d42a67199,5bf8234c19728dc2399425531d57afbcfa317751..d257ca7c3dcc7035f0713b8d0ed155ad90c9f552
@@@ -400,24 -427,6 +430,23 @@@ gint i
        PREFS->vehicle_unit_ismile = FALSE;
        PREFS->vehicle_unit_isgal  = FALSE;
  
-       _homebank_pref_createformat();
 +      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();
  
  }
Simple merge
diff --cc src/hb-tag.c
Simple merge
index 1d6699871a85d174156d7e893b3d8ee2fe1be5de,2758da6d04404bc1d78e0788fab1c939059bcfb4..17fbad5dda73d181bab1c45845f4b9d200dcb3b1
  
  #include "hb-transaction.h"
  #include "hb-tag.h"
+ #include "hb-split.h"
  
 +#include "ext.h"
 +#include "refcount.h"
 +
  /****************************************************************************/
- /* Debug macros                                                                                */
+ /* Debug macros                                                                                                       */
  /****************************************************************************/
  #define MYDEBUG 0
  
@@@ -265,8 -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));
- guint count;
  
        DB( g_print("da_transaction_clone\n") );
  
@@@ -475,29 -417,58 +420,61 @@@ gint nbsplit
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
  /* new transfer functions */
  
Transaction *transaction_strong_get_child_transfer(Transaction *src)
static void transaction_xfer_create_child(Transaction *ope)
  {
GList *list;
      DB( g_print("\n[transaction] transaction_strong_get_child_transfer\n") );
Transaction *child;
+ Account *acc;
gchar swap;
  
-       DB( g_print(" - search: %d %s %f %d=>%d\n", src->date, src->wording, src->amount, src->kacc, src->kxferacc) );
+       DB( g_print("\n[transaction] transaction_xfer_create_child\n") );
  
-       list = g_list_first(GLOBALS->ope_list);
-       while (list != NULL)
+       if( ope->kxferacc > 0 )
        {
-               Transaction *item = list->data;
-               //#1252230
-               //if( item->paymode == PAYMODE_INTXFER && item->kacc == src->kxferacc && item->kxfer == src->kxfer )
-               if( item->paymode == PAYMODE_INTXFER && item->kxfer == src->kxfer && item != src )
+               child = da_transaction_clone(ope);
+               ope->flags |= OF_CHANGED;
+               child->flags |= OF_ADDED;
+               child->amount = -child->amount;
+               child->flags ^= (OF_INCOME);    // invert flag
+               //#1268026
+               child->status = TXN_STATUS_NONE;
+               //child->flags &= ~(OF_VALID);  // delete reconcile state
+               swap = child->kacc;
+               child->kacc = child->kxferacc;
+               child->kxferacc = swap;
+               /* update acc flags */
+               acc = da_acc_get( child->kacc );
+               if(acc != NULL)
                {
-                       DB( g_print(" - found : %d %s %f %d=>%d\n", item->date, item->wording, item->amount, item->kacc, item->kxferacc) );
-                       return item;
+                       acc->flags |= AF_ADDED;
+                       //strong link
+                       guint maxkey = da_transaction_get_max_kxfer();
+                       DB( g_print(" + maxkey is %d\n", maxkey) );
+                       ope->kxfer = maxkey+1;
+                       child->kxfer = maxkey+1;
+                       DB( g_print(" + strong link to %d\n", ope->kxfer) );
+                       DB( g_print(" + add transfer, %p\n", child) );
+                       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);
++
                }
-               list = g_list_next(list);
        }
-       DB( g_print(" - not found...\n") );
-       return NULL;
  }
  
  
@@@ -831,11 -837,8 +843,11 @@@ Account *acc
  
                if(newope->paymode == PAYMODE_INTXFER)
                {
-                       transaction_xfer_search_or_add_child(newope, treeview);
+                       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);
        }
  }
  
diff --cc src/hb-xml.c
index 9db1e3014744c1f69aaddddcae19eebeee4c6665,2338e581857133d5402597ec6a0a280fc62ced50..68768faf5449f7d30bf2ddfb6ec9f2270796ec0a
  #include "hb-transaction.h"
  #include "hb-xml.h"
  
 +#include "ext.h"
 +
+ #include "ui-dialogs.h"
  /****************************************************************************/
  /* Debug macros                                                             */
  /****************************************************************************/
@@@ -689,105 -821,131 +823,134 @@@ gchar *v_buffer
  }
  
  
- // v0.6 to v0.7 : assign a default currency
  /*
- static void homebank_upgrade_to_v08(void)
+ ** XML load homebank file: hbfile
+ */
+ gint homebank_load_xml(gchar *filename)
  {
+ gint retval;
+ gchar *buffer;
+ gsize length;
+ GError *error = NULL;
+ ParseContext ctx;
+ GMarkupParseContext *context;
+ gboolean rc;
+       DB( g_print("\n[hb-xml] homebank_load_xml\n") );
++      GValue filename_val = G_VALUE_INIT;
++      ext_hook("load_file", EXT_STRING(&filename_val, filename), NULL);
++
+       retval = XML_OK;
+       if (!g_file_get_contents (filename, &buffer, &length, &error))
+       {
+               //g_message ("%s", error->message);
+               retval = XML_IO_ERROR;
+               g_error_free (error);
+       }
+       else
+       {
+               if( hb_xml_get_version(&ctx, buffer) == FALSE )
+               {
+                       return XML_FILE_ERROR;
+               }
  
-       // set a base currency to the hbfile if not
-       g_print("GLOBALS->kcur %d\n", GLOBALS->kcur);
+               if( ctx.file_version > FILE_VERSION )
+               {
+                       DB( g_print("- failed: version %f is not supported (max is %f)\n", ctx.file_version, FILE_VERSION) );
+                       return XML_VERSION_ERROR;
+               }
+               else
+               {
+                       DB( g_print("- file ok : v=%.1f data_v=%06d\n", ctx.file_version, ctx.data_version) );
  
-       if(GLOBALS->kcur == 0)
-       {
-       //struct iso4217format *choice = ui_cur_select_dialog_new(GLOBALS->mainwindow);
-       struct iso4217format *curfmt =  iso4217format_get(PREFS->curr_default);
+                       /* 1st: validate the file is well in utf-8 */
+                       DB( g_print("- ensure UTF-8\n") );
+                       buffer = homebank_utf8_ensure(buffer);
  
-               if(curfmt == NULL)
-                       curfmt = iso4217format_get_en_us();
-               
-               
-               Currency *item = currency_add_from_user(curfmt);
+                       /* then process the buffer */
+                       #if MYDEBUG == 1
+                               GTimer *t = g_timer_new();
+                               g_print("- start parse\n");
+                       #endif
  
-                       GLOBALS->kcur = item->key;
+                       context = g_markup_parse_context_new (&hb_parser, 0, &ctx, NULL);
  
-                       g_print("GLOBALS->kcur %d\n", GLOBALS->kcur);
+                       error = NULL;
+                       rc = g_markup_parse_context_parse (context, buffer, length, &error);
  
-                       // set every accounts to base currecny
-                       GList *list = g_hash_table_get_values(GLOBALS->h_acc);
-                       while (list != NULL)
-                       {
-                       Account *acc;
-                               acc = list->data;
+                       if( error )
+                               g_print("failed: %s\n", error->message);
  
-                               acc->kcur = item->key;
+                       if( rc == FALSE )
+                       {
+                               error = NULL;
+                               g_markup_parse_context_end_parse(context, &error);
  
-                               list = g_list_next(list);
+                               if( error )
+                                       g_print("failed: %s\n", error->message);
                        }
-                       g_list_free(list);
-               
-       }
- }
- */
- // lower v0.6 : we must assume categories/payee exists
- // and strong link to xfer
- // #632496
- static void homebank_upgrade_lower_v06(void)
- {
- Category *cat;
- Payee *pay;
- GList *lrul, *list;
  
-       DB( g_print("\n[hb-xml] homebank_upgrade_lower_v06\n") );
-       list = g_list_first(GLOBALS->ope_list);
-       while (list != NULL)
-       {
-       Transaction *entry = list->data;
+                       g_markup_parse_context_free (context);
+                       g_free (buffer);
  
-               da_transaction_consistency(entry);
+                       DB( g_print("- end parse : %f sec\n", g_timer_elapsed(t, NULL)) );
+                       DB( g_timer_destroy (t) );
  
-               //also strong link internal xfer
-               if(entry->paymode == PAYMODE_INTXFER)
-               {
-               Transaction *child = transaction_old_get_child_transfer(entry);
-                       if(child != NULL)
+                       /* file upgrade / bugfix */
+                       if( ctx.file_version <= 0.1 )
+                               homebank_upgrade_to_v02();
+                       if( ctx.file_version <= 0.2 )
+                               homebank_upgrade_to_v03();
+                       if( ctx.file_version <= 0.3 )
+                               homebank_upgrade_to_v04();
+                       if( ctx.file_version <= 0.4 )
+                               homebank_upgrade_to_v05();
+                       if( ctx.file_version <= 0.5 )
                        {
-                               transaction_xfer_change_to_child(entry, child);
+                               homebank_upgrade_to_v06();
+                               homebank_upgrade_lower_v06();
+                       }
+                       if( ctx.file_version <= 0.6 )
+                       {
+                               homebank_upgrade_to_v07();
+                               hbfile_sanity_check();
+                       }
+                       if( ctx.file_version <= 0.7 )   // <= 4.5
+                       {       
+                               homebank_upgrade_to_v08();
+                       }
+                       if( ctx.file_version <= 0.8 )   // <= 4.6
+                       {
+                               hbfile_sanity_check();
+                       }
+                       if( ctx.file_version <= 0.9 )   // <= 4.6.3
+                       {
+                               hbfile_sanity_check();
+                               homebank_upgrade_to_v10();
+                       }
+                       if( ctx.file_version <= 1.0 )   // <= 5.0.0 
+                       {
+                               hbfile_sanity_check();
+                               homebank_upgrade_to_v11();
+                       }
+                       //starting 5.0.4 data upgrade is done without changing file_version
+                       if( ctx.data_version < 050005 ) // <= 5.0.5 
+                       {
+                               hbfile_sanity_check();
+                       }
+                       if( ctx.file_version <= 1.1 )   // <= 5.1.0 
+                       {
+                               hbfile_sanity_check();
+                               homebank_upgrade_to_v12();
                        }
-               }
-               list = g_list_next(list);
-       }
-       lrul = list = g_hash_table_get_values(GLOBALS->h_rul);
-       while (list != NULL)
-       {
-       Assign *entry = list->data;
-               cat = da_cat_get(entry->kcat);
-               if(cat == NULL)
-               {
-                       DB( g_print(" !! fixing cat for rul: %d is unknow\n", entry->kcat) );
-                       entry->kcat = 0;
-               }
  
-               pay = da_pay_get(entry->kpay);
-               if(pay == NULL)
-               {
-                       DB( g_print(" !! fixing pay for rul: %d is unknow\n", entry->kpay) );
-                       entry->kpay = 0;
+                       // next ?
+                       
                }
-               list = g_list_next(list);
        }
-       g_list_free(lrul);
  
+       return retval;
  }
  
  
@@@ -1190,11 -1545,9 +1550,12 @@@ GIOChannel *io
  char buf1[G_ASCII_DTOSTR_BUF_SIZE];
  gchar *outstr;
  gint retval = XML_OK;
+ GError *error = NULL;
  
-       io = g_io_channel_new_file(filename, "w", 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)
        {
                g_message("file error on: %s", filename);
diff --cc src/homebank.c
index 106b8ecb90e5e7d97dcb0a521aad1aa48c6f8229,421d0eff7a45fe62367dad4fc9493503a1e43af9..c8a6895798d91f36b977e92ff1762ac864238533
@@@ -660,13 -575,12 +583,13 @@@ 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);
- #ifdef PORTABLE_APP
-       DB( g_print("- app is portable under windows\n") );
-       config_dir   = g_build_filename(prefix, "config", NULL);
- #else
-       config_dir   = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
- #endif
 +      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);
+       #else
+               config_dir   = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
+       #endif
        g_free (prefix);
  #else
        locale_dir   = g_build_filename (DATA_DIR, "locale", 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);
-       config_dir   = g_build_filename (g_get_user_config_dir(), HB_DATA_PATH, 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
        if(! g_file_test(help_dir, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
        }
  #endif
  
-       DB( g_print("- config_dir : %s\n", config_dir) );
-       DB( g_print("- images_dir : %s\n", images_dir) );
-       DB( g_print("- pixmaps_dir: %s\n", pixmaps_dir) );
-       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) );
+       DB( g_print(" - config_dir : %s\n", config_dir) );
+       DB( g_print(" - images_dir : %s\n", images_dir) );
+       DB( g_print(" - pixmaps_dir: %s\n", pixmaps_dir) );
+       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) );
  
  }
  
@@@ -1042,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") );
++              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();
                        /* update the mainwin display */
                        ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL));
  
-               DB( g_print(" -> gtk_main()\n" ) );
 +                      ext_hook("enter_main_loop", NULL);
 +
+               DB( g_print(" - gtk_main()\n" ) );
                        gtk_main ();
 +
 +                      ext_hook("exit_main_loop", NULL);
                }
  
-               DB( g_print(" -> unloading plugins\n") );
++              DB( g_print(" - unloading plugins\n") );
 +              ext_term();
 +
        }
  
  
diff --cc src/homebank.h
Simple merge
diff --cc src/ui-pref.c
index 4cc1eebf66c78871d9fa8711977476b9312b8d27,5a63a4957422dbbe27c9dd6e85bd46d16bf152f7..fa7f906142dcf5722c66e625d3cc3e499ba4b2bc
  #include "dsp_mainwindow.h"
  #include "gtk-chart-colors.h"
  
 +#include "ext.h"
 +
+ #include "ui-currency.h"
  /****************************************************************************/
  /* Debug macros                                                             */
  /****************************************************************************/
@@@ -60,17 -60,18 +62,15 @@@ 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
  };
  
- GdkPixbuf *pref_pixbuf[PREF_MAX];
  
- static gchar *pref_pixname[PREF_MAX] = {
+ static gchar *pref_iconname[PREF_MAX] = {
  "prf-general",
  "prf-interface",
  "prf-columns",
@@@ -1248,44 -1102,8 +1104,9 @@@ 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));
  }
  
- /*
- GtkWidget *defpref_page_charts (struct defpref_data *data)
- {
- GtkWidget *container;
- GtkWidget *table, *label, *widget;
- gint row;
-       container = gtk_hbox_new(FALSE, 0);
-       table = gtk_table_new (2, 2, FALSE);
-       gtk_container_set_border_width (GTK_CONTAINER (table), HB_BOX_SPACING);
-       gtk_table_set_row_spacings (GTK_TABLE (table), HB_TABROW_SPACING);
-       gtk_table_set_col_spacings (GTK_TABLE (table), HB_TABCOL_SPACING);
-       gtk_box_pack_start (GTK_BOX (container), table, FALSE, FALSE, 0);
-       row = 0;
-       widget = gtk_check_button_new_with_mnemonic (_("Show legend"));
-       data->CM_chartlegend = widget;
-       gtk_table_attach (GTK_TABLE (table), widget, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-       row++;
-       label = make_label(_("Bar width:"), 1.0, 0.5);
-       //----------------------------------------- l, r, t, b
-       gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-       widget = make_numeric(label, 8.0, 32.0);
-       //data->NB_numnbdec = widget;
-       gtk_table_attach (GTK_TABLE (table), widget, 1, 2, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-       return(container);
- }
- */
  
  static GtkWidget *defpref_page_import (struct defpref_data *data)
  {
@@@ -2061,206 -1878,9 +1881,205 @@@ gint crow, row
        data->BT_path_hbfile = widget;
        gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
  
-       return(container);
+       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;
diff --cc src/ui-pref.h
index 47c0b011f588182a312695beb09738f3a0e3411b,afd529ee817a9d64953e3f56e0c97635dbdc1340..1eb95f19d3c775a2730e81edc714ccc2e1589b4e
@@@ -113,22 -112,13 +112,27 @@@ struct defpref_dat
        GtkWidget       *CM_chartlegend;
  
        GtkWidget       *CY_dtex_datefmt;
+       GtkWidget       *CY_dtex_ofxname;
        GtkWidget       *CY_dtex_ofxmemo;
+       GtkWidget       *CM_dtex_qifmemo;
+       GtkWidget       *CM_dtex_qifswap;
+       gint            country;
  
-       PREF_COLUMNS,
-       PREF_DISPLAY,
-       PREF_IMPORT,
 +      GtkWidget       *PI_plugin_columns;
 +};
 +
 +enum
 +{
 +      PREF_GENERAL,
 +      PREF_INTERFACE,
-       PREF_EURO,
++      PREF_TRANSACTIONS,
++      PREF_DISPLAY_FORMAT,
++      PREF_IMPORT_EXPORT,
 +      PREF_REPORT,
++      PREF_EURO_MINOR,
 +      PREF_PLUGINS,
 +      PREF_MAX
  };
  
  
index 0000000000000000000000000000000000000000,a70b789423b301b7454aba664066f1fc853a855b..f5ac1b75129045428bb726d2d9852f83be3d8b84
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,144 +1,145 @@@
+ ## Process this file with automake to produce Makefile.in
+ NULL =
+ public_icons_themes = \
+       hicolor \
+       $(NULL)
+ public_icons = \
+       $(NULL)
+ private_icons = \
+       hicolor_actions_16x16_btn-collapse.png \
+       hicolor_actions_16x16_btn-expand.png \
+       hicolor_status_16x16_btn-split.png \
+       hicolor_status_16x16_flt-exclude.png \
+       hicolor_status_16x16_flt-inactive.png \
+       hicolor_status_16x16_flt-include.png \
+       hicolor_actions_16x16_hb-ope-auto.png \
+       hicolor_actions_16x16_hb-ope-budget.png \
+       hicolor_actions_16x16_hb-ope-edit.png \
+       hicolor_actions_16x16_hb-ope-cleared.png \
+       hicolor_actions_16x16_hb-ope-remind.png \
+       hicolor_actions_16x16_hb-ope-reconciled.png \
+       hicolor_actions_24x24_hb-account.png \
+       hicolor_actions_24x24_hb-archive.png \
+       hicolor_actions_24x24_hb-assign.png \
+       hicolor_actions_24x24_hb-assign-run.png \
+       hicolor_actions_24x24_hb-budget.png \
+       hicolor_actions_24x24_hb-category.png \
+       hicolor_actions_24x24_hb-currency.png \
+       hicolor_actions_24x24_hb-file-export.png \
+       hicolor_actions_24x24_hb-file-import.png \
+       hicolor_actions_24x24_hb-file-valid.png \
+       hicolor_actions_24x24_hb-file-invalid.png \
+       hicolor_actions_24x24_hb-filter.png \
+       hicolor_actions_24x24_hb-legend.png \
+       hicolor_actions_24x24_hb-ope-add.png \
+       hicolor_actions_24x24_hb-ope-cleared.png \
+       hicolor_actions_24x24_hb-ope-delete.png \
+       hicolor_actions_24x24_hb-ope-edit.png \
+       hicolor_actions_24x24_hb-ope-herit.png \
+       hicolor_actions_24x24_hb-ope-multiedit.png \
+       hicolor_actions_24x24_hb-ope-reconciled.png \
+       hicolor_actions_24x24_hb-ope-convert.png \
+       hicolor_actions_24x24_hb-ope-show.png \
+       hicolor_actions_24x24_hb-payee.png \
+       hicolor_actions_24x24_hb-rate.png \
+       hicolor_actions_24x24_hb-rep-balance.png \
+       hicolor_actions_24x24_hb-rep-budget.png \
+       hicolor_actions_24x24_hb-rep-stats.png \
+       hicolor_actions_24x24_hb-rep-time.png \
+       hicolor_actions_24x24_hb-rep-vehicle.png \
+       hicolor_actions_24x24_hb-view-bar.png \
+       hicolor_actions_24x24_hb-view-column.png \
+       hicolor_actions_24x24_hb-view-donut.png \
+       hicolor_actions_24x24_hb-view-line.png \
+       hicolor_actions_24x24_hb-view-list.png \
+       hicolor_actions_24x24_hb-view-pie.png \
+       hicolor_actions_24x24_hb-view-stack.png \
+       hicolor_status_16x16_pm-none.png \
+       hicolor_status_16x16_pm-ccard.png \
+       hicolor_status_16x16_pm-dcard.png \
+       hicolor_status_16x16_pm-check.png \
+       hicolor_status_16x16_pm-cash.png \
+       hicolor_status_16x16_pm-transfer.png \
+       hicolor_status_16x16_pm-intransfer.png \
+       hicolor_status_16x16_pm-none.png \
+       hicolor_status_16x16_pm-standingorder.png \
+       hicolor_status_16x16_pm-epayment.png \
+       hicolor_status_16x16_pm-deposit.png \
+       hicolor_status_16x16_pm-fifee.png \
+       hicolor_status_16x16_pm-directdebit.png \
+       hicolor_status_48x48_prf-columns.png \
+       hicolor_status_48x48_prf-display.png \
+       hicolor_status_48x48_prf-euro.png \
+       hicolor_status_48x48_prf-general.png \
+       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 \
+       $(NULL)
+ EXTRA_DIST = \
+       $(public_icons)         \
+       $(private_icons)        \
+       $(noinst_DATA)          \
+       $(NULL)
+ ###############################################################################
+ gtk_update_icon_cache = gtk-update-icon-cache -f -t
+ update-icon-cache:
+       @-if test -z "$(DESTDIR)"; then \
+               echo "Updating Gtk icon cache."; \
+               for theme in $(public_icons_themes); do \
+                       $(gtk_update_icon_cache) $(datadir)/icons/$$theme; \
+               done; \
+       else \
+               echo "*** Icon cache not updated.  After (un)install, run this:"; \
+               for theme in $(public_icons_themes); do \
+                       echo "***   $(gtk_update_icon_cache) $(datadir)/icons/$$theme"; \
+               done; \
+       fi
+ install-icons:
+       for icon in $(public_icons); do \
+               THEME=`echo $$icon | cut -d_ -f1`; \
+               CONTEXT=`echo $$icon | cut -d_ -f2`; \
+               SIZE=`echo $$icon | cut -d_ -f3`; \
+               ICONFILE=`echo $$icon | cut -d_ -f4`; \
+               mkdir -p $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT; \
+               $(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+       done; \
+       for icon in $(private_icons); do \
+               THEME=`echo $$icon | cut -d_ -f1`; \
+               CONTEXT=`echo $$icon | cut -d_ -f2`; \
+               SIZE=`echo $$icon | cut -d_ -f3`; \
+               ICONFILE=`echo $$icon | cut -d_ -f4`; \
+               mkdir -p $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT; \
+               $(INSTALL_DATA) $(srcdir)/$$icon $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+       done
+ uninstall-icons:
+       -for icon in $(public_icons); do \
+               THEME=`echo $$icon | cut -d_ -f1`; \
+               CONTEXT=`echo $$icon | cut -d_ -f2`; \
+               SIZE=`echo $$icon | cut -d_ -f3`; \
+               ICONFILE=`echo $$icon | cut -d_ -f4`; \
+               rm -f $(DESTDIR)$(datadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+       done; \
+       for icon in $(private_icons); do \
+               THEME=`echo $$icon | cut -d_ -f1`; \
+               CONTEXT=`echo $$icon | cut -d_ -f2`; \
+               SIZE=`echo $$icon | cut -d_ -f3`; \
+               ICONFILE=`echo $$icon | cut -d_ -f4`; \
+               rm -f $(DESTDIR)$(pkgdatadir)/icons/$$THEME/$$SIZE/$$CONTEXT/$$ICONFILE; \
+       done
+ install-data-local: install-icons update-icon-cache
+ uninstall-local: uninstall-icons update-icon-cache
index 395001990fcc10752449c18a85eb3e55e3085618,0000000000000000000000000000000000000000..395001990fcc10752449c18a85eb3e55e3085618
mode 100644,000000..100644
Binary files differ
This page took 0.121905 seconds and 5 git commands to generate.