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

diff --cc Makefile.am
index de75d0f3cfbe7415f044a9ac8338a23cec6568b2,e5c6cfec6cbd8e6459ce23702a7de23039a48241..45d1f49f22cf51ba7d7828c84a9bfada8a7f6952
@@@ -1,11 -1,16 +1,18 @@@
  # HomeBank Makefile.am
  
 +ACLOCAL_AMFLAGS       = -I m4
 +
  #SUBDIRS = src
 -SUBDIRS = src data images mime pixmaps themes po doc
 +SUBDIRS = src data images mime pixmaps themes po doc plugins
  
  
+ datasdir   = $(datadir)/homebank/datas/
+ datas_DATA = \
+ ChangeLog 
+ EXTRA_DIST   = $(datas_DATA)
  # don't forget to do a 'make check' 
  # to ensure all files are in po/POTFILES.in
  
@@@ -21,8 -26,11 +28,17 @@@ DISTCLEANFILES = ... intltool-extract 
                   intltool-update \
                   po/.intltool-merge-cache
  
 -
+ # we clean every folder under /usr/share/homebank as well on uninstall
+ uninstall-hook:
+       -rm -rf $(datadir)/homebank/datas
+       -rm -rf $(datadir)/homebank/help
+       -rm -rf $(datadir)/homebank/icons
+       -rm -rf $(datadir)/homebank/images
+ #-rmdir $(datadir)/homebank
++
 +run: all
 +      PERL5LIB=src src/homebank
 +
 +debug: all
 +      PERL5LIB=src gdb src/homebank
++
diff --cc configure.ac
index 798e623fd87ef94656bfa36afa343cb580b1ca7b,99db971a60d1c468451c7b0cda8d02d3102ceee6..f1c2dfd33250904f88f5887a5ba7a3ed6d859b72
@@@ -26,7 -22,7 +26,7 @@@ AC_PROG_INSTAL
  AC_PROG_INTLTOOL
  
  # Checks for libraries.
- PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.12 glib-2.0 >= 2.39 gmodule-2.0 >= 2.39)
 -PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.16 glib-2.0 >= 2.39)
++PKG_CHECK_MODULES(DEPS, gtk+-3.0 >= 3.16 glib-2.0 >= 2.39 gmodule-2.0 >= 2.39)
  AC_SUBST(DEPS_CFLAGS)
  AC_SUBST(DEPS_LIBS)
  AC_CHECK_LIB(m, pow)
index 9171bb208eb119808ed03ba7973d23b4c2be7ec8,0000000000000000000000000000000000000000..25520b5f43d5ef64440cc3e94fb838d3ae758aef
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
-         print "transaction of amount: ", $xc->amount, "\t", $xc->wording, ", ", $xc->info, ", $num, $date\n";
 +
 +# NAME:     Hello World
 +# VERSION:  0.01
 +# ABSTRACT: This is the "hello world" of HomeBank plugins.
 +# AUTHOR:   Charles McGarvey <chazmcgarvey@brokenzipper.com>
 +# WEBSITE:  http://acme.tld/
 +# (These comments are read, before the plugin is executed, to provide some
 +# information to HomeBank and the user about what this plugin is.)
 +
 +eval { HomeBank->version } or die "Cannot run outside of HomeBank";
 +
 +use warnings;
 +use strict;
 +
 +use Scalar::Util qw/weaken/;
 +
 +#use Moose;
 +
 +#has "cool_beans",
 +    #is      => 'rw',
 +    #isa     => 'Str',
 +    #lazy    => 1,
 +    #default => "Booya!!!";
 +
 +
 +our $counter = 0;
 +our $temp;
 +
 +my $ACC;
 +
 +sub new {
 +    my $class = shift;
 +    my $self  = $class->SUPER::new(@_);
 +
 +    $self->on(account_inserted => sub {
 +            my $acc = shift;
 +            print "account inserted: ", Dumper($acc);
 +            print "account name is ", $acc->name, " and balance is ", $acc->bank_balance, "\n";
 +            #$acc->name("FOOOOBAR!");
 +            if ($acc->name eq 'Vacation') {
 +                $acc->remove;
 +                $ACC = $acc;
 +            }
 +            print Dumper($acc->is_inserted);
 +            if ($acc->is_inserted) {
 +                print "IT IS INSERTED\n";
 +            } else {
 +                print "not inserted\n";
 +            }
 +            print Dumper($acc->transactions);
 +        });
 +
 +    #print $self->cool_beans, "\n";
 +    #$self->cool_beans(123);
 +    #print $self->cool_beans, "\n";
 +
 +    $self;
 +}
 +
 +sub on_create_main_window {
 +    my $self = shift;
 +    my $window = shift;
 +
 +    if (!$window) {
 +        require Gtk3;
 +        $window = HomeBank->main_window;
 +    }
 +
 +    Dump($window);
 +    print Dumper($window);
 +    $window->set_title("foo bar baz");
 +    print $window->get_title, "\n";
 +
 +    HomeBank->hook("my_hook", $window);
 +}
 +
 +my $test_win;
 +
 +sub on_test {
 +    my $self = shift;
 +    require Gtk3;
 +
 +    my $window = Gtk3::Window->new('toplevel');
 +    use Devel::Peek;
 +    Dump($window);
 +    print Dumper($window);
 +    $window->set_title("Hello World");
 +    #$window->signal_connect(delete_event => sub { Gtk3->main_quit });
 +    $window->signal_connect(delete_event => sub { undef $test_win });
 +
 +    my $button = Gtk3::Button->new('Click Me!');
 +    Dump($button);
 +    print Dumper($button);
 +    $button->signal_connect(clicked => sub {
 +            print "Hello Gtk3-Perl: $counter (perl plugin: $self)\n";
 +            $counter++;
 +            #if ($temp->is_inserted) {
 +                #print "$temp is inserted\n";
 +            #} else {
 +                #print "$temp is NOT inserted\n";
 +            #}
 +            #if ($counter == 5) {
 +                #$temp = undef;
 +            #}
 +    my $acc = HomeBank::Account->get(rand(10));
 +    print "Changin account named ", $acc->name, " to ", $acc->name($acc), "\n";
 +    HomeBank->main_window->queue_draw;
 +
 +        });
 +    $window->add($button);
 +
 +    $window->show_all;
 +    $test_win = $window;
 +
 +    weaken $self;
 +}
 +
 +sub on_enter_main_loop {
 +    my $self = shift;
 +
 +    use Data::Dumper;
 +    print Dumper(\@_);
 +    my $t = HomeBank::Transaction->new;
 +    print "Transaction::::::::  $t: ", $t->amount, "\n";
 +
 +    $temp = HomeBank::Account->get(7);
 +    print "retained account: ", $temp->name, "\n";
 +
 +    #require Gtk3;
 +    #
 +    my $txn = HomeBank::Transaction->new;
 +    $txn->amount(12.3456);
 +    print Dumper($txn), $txn->amount, "\n";
 +    #$txn->open;
 +
 +    my @ret = HomeBank->hook("my_hook", @_, $temp, [qw/foo bar baz/, $txn], { asf => 42, quux => \1, meh => HomeBank->main_window });
 +    #my @ret = HomeBank->hook("my_hook", @_, HomeBank->main_window, {
 +    #foo => 'bar', baz => 42
 +    #});
 +    print Dumper(\@ret);
 +
 +    print "adding back account...\n";
 +    $ACC->name("vacation with a different name");
 +    $ACC->insert;
 +    HomeBank::Account->compute_balances;
 +    print "account name is ", $ACC->name, " and balance is ", $ACC->balance, "\n";
 +    print Dumper($ACC->transactions);
 +
 +    my $cloned = $ACC->clone;
 +    $cloned->name("vacation copy");
 +    $cloned->insert;
 +    #my $asdf = $cloned->open;
 +    #$asdf->set_title("this is a new friggin account");
 +
 +    #my $z = HomeBank::Account->get_by_name('Checking');
 +    for my $xc (HomeBank::File->transactions) {
 +        use DateTime;
 +        my $num = $xc->date;
 +        my $date = DateTime->new($xc->date)->datetime;
++        print "transaction of amount: ", $xc->amount, "\t", $xc->memo, ", ", $xc->info, ", $num, $date\n";
 +    }
 +
 +    HomeBank::File->owner('Billy Murphy');
 +    #HomeBank::File->anonymize;
 +    print HomeBank::File->owner, "\n";
 +
 +    HomeBank::File->baz($ACC);
 +}
 +
 +sub on_deep_hook_recursion {
 +    my $self = shift;
 +    my $level = shift;
 +    print STDERR "recursion is too deep ($level)\n";
 +    exit -2;
 +}
 +
 +sub on_my_hook {
 +    my $self = shift;
 +    print "This is MY HOOK!!!!!!\n";
 +    print Dumper(\@_);
 +
 +    print Dumper($_[2]);
 +    Dump($_[2]);
 +    if ($_[2]) {
 +        print "meh\n";
 +    }
 +    if ($_[2]->isa('HomeBank::Boolean')) {
 +        print "it is a home;;boolean\n";
 +    }
 +    if ($_[2]->isa('Types::Serialiser::Boolean')) {
 +        print "it is a types serialiser thingy\n";
 +    }
 +    if ($_[2]->isa('HomeBank::BooleanBase')) {
 +        print "it is a base bool\n";
 +    }
 +
 +    my $win = $_[6];
 +    if ($win && ref($win) eq 'HASH') {
 +        my $w = $win->{meh};
 +        if ($w) {
 +            $w->set_title("this is MY HOOK setting a window title");
 +        }
 +    }
 +    #print Dumper($acc);
 +    #print "transferred account: ", $acc->name, "\n";
 +
 +    #my $fff = HomeBank::File->foo({foo => 'asdf', bar => 123456789});
 +    my $fff = HomeBank::File->meh([qw/hello this is a test 82/, \1, {foo => 'bar'}, 48]);
 +    print Dumper($fff);
 +
 +    print "my hook done\n";
 +}
 +
 +sub on_unhandled {
 +    my ($self, $hook) = @_;
 +    warn "Unhandled hook '$hook'\n";
 +    #HomeBank->warn($hook, 'Hook not handled.');
 +}
 +
 +sub DESTROY {
 +    my $self = shift;
 +    print "DESTROYING HELLO WORLD!!!!!!\n";
 +    if ($test_win) {
 +        print "there is a test_win...\n";
 +    }
 +    $test_win->destroy if $test_win;
 +}
 +
 +sub EXECUTE {
 +    print "the perl plugin is being configured.....\n";
 +    HomeBank->info("Hello Prefs", "YEEEEEARGGH!!!!!");
 +}
 +
 +#__PACKAGE__->meta->make_immutable;
diff --cc src/Makefile.am
index 484ce27b8a65ad79127df95daac4335f1d554c32,9c7e1936cc8bd4f298b0309c35ef48339f75ffb8..20da8f18246114c77313051187aa34980ea3da4f
@@@ -119,21 -118,13 +119,23 @@@ homebank_SOURCES =  
        ui-split.h \
        ui-transaction.c \
        ui-transaction.h \
+       ui-txn-multi.c \
+       ui-txn-multi.h \
        ui-widgets.c \
 -      ui-widgets.h
 +      ui-widgets.h \
 +      refcount.h \
 +      ext.c \
 +      ext.h \
 +      ext-value.c \
 +      ext-value.h \
 +      ext-native.c \
 +      ext-perl.xs
 +
 +EXTRA_homebank_DEPENDENCIES = $(PERL_OBJS)
  
  homebank_LDADD = $(DEPS_LIBS) \
 -      $(LIBSOUP_LIBS)
 +      $(LIBSOUP_LIBS) \
 +      $(PERL_OBJS)
  
  AM_CPPFLAGS = \
        $(DEPS_CFLAGS) \
index e819137b509e1297fa3809f6fdf2637facf2aebf,2cb2ecd2d5e6c47b7ab8eeb3ecef0ddee12a3d19..c733f4cb730be8c3f443f05f2c3bf5fc3a850152
@@@ -148,8 -152,8 +156,10 @@@ void ui_mainwindow_scheduled_postall(Gt
  
  void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
  
 +static void ui_mainwindow_showprefs(gint page);
 +
+ static void ui_panel_accounts_setup(struct hbfile_data *data);
  extern gchar *CYA_ACC_TYPE[];
  
  gchar *CYA_CATSUBCAT[] = { 
@@@ -318,17 -321,14 +331,19 @@@ static const gchar *ui_info 
  "        <separator/>"
  "      <menuitem action='Anonymize'/>"
  "    </menu>"
 +"    <menu action='PluginMenu'>"
 +"      <separator/>"
 +"      <menuitem action='PluginPreferences'/>"
 +"      <separator/>"
 +"    </menu>"
  "    <menu action='HelpMenu'>"
  "      <menuitem action='Contents'/>"
- "        <separator/>"
  "      <menuitem action='Online'/>"
- "      <menuitem action='Translate'/>"
+ "        <separator/>"
+ "      <menuitem action='Updates'/>"
+ "      <menuitem action='ReleaseNotes'/>"
  "      <menuitem action='Problem'/>"
+ "      <menuitem action='Translate'/>"
  "        <separator/>"
  "      <menuitem action='About'/>"
  "    </menu>"
@@@ -2371,10 -2457,7 +2485,10 @@@ struct hbfile_data *data = user_data
  struct WinGeometry *wg;
  gboolean retval = FALSE;
  
-       DB( g_print("\n[ui-mainwindow] dispose\n") );
 +      GValue widget_value = G_VALUE_INIT;
 +      ext_hook("main_window_disposal", EXT_OBJECT(&widget_value, widget), NULL);
 +
+       DB( g_print("\n[ui-mainwindow] delete-event\n") );
  
        //store position and size
        wg = &PREFS->wal_wg;
diff --cc src/ext-perl.xs
index 5aa56b01df5480491909eb647b4d6ae6b48696b5,0000000000000000000000000000000000000000..9c7bd8bc11aac03f1098fbeb4049def0a77a90cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1043 -1,0 +1,1043 @@@
- wording(Transaction* SELF, ...)
 +
 +#include <EXTERN.h>
 +#include <perl.h>
 +#include <XSUB.h>
 +
 +#include <string.h>
 +
 +#undef _
 +#include "homebank.h"
 +#include "ext.h"
 +#include "refcount.h"
 +
 +extern struct HomeBank *GLOBALS;
 +#include "dsp_mainwindow.h"
 +#include "dsp_account.h"
 +#include "ui-transaction.h"
 +
 +
 +static gint ext_perl_init(int* argc, char** argv[], char** env[]);
 +static void ext_perl_term(void);
 +static gboolean ext_perl_check_file(const gchar* plugin_filepath);
 +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath);
 +static gint ext_perl_load_plugin(const gchar* plugin_filepath);
 +static void ext_perl_unload_plugin(const gchar* plugin_filepath);
 +static void ext_perl_execute_action(const gchar* plugin_filepath);
 +static void ext_perl_call_hook(const gchar* hook_id, GList* args);
 +
 +static SV* val_to_sv(GValue* val);
 +static GValue* sv_to_val(SV* sv);
 +
 +static gboolean gperl_value_from_sv(GValue* value, SV* sv);
 +static SV*      gperl_sv_from_value(const GValue* value, gboolean copy_boxed);
 +
 +
 +static inline GValue* EXT_SV(GValue* v, SV* sv, GType type)
 +{
 +      g_value_init(v, type);
 +      gperl_value_from_sv(v, sv);
 +      return v;
 +}
 +
 +
 +#define EXT_P2C_OBJECT(PKG, ARG, VAR, TYP)  \
 +if (sv_derived_from(ARG, PKG)) {            \
 +    IV iv = SvIV((SV*)SvRV(ARG));           \
 +    VAR = INT2PTR(TYP, iv);                 \
 +} else {                                    \
 +    croak(#VAR" is not of type "PKG);       \
 +}
 +
 +#define EXT_C2P_OBJECT(PKG, ARG, VAR)       \
 +sv_setref_pv(ARG, PKG, (void*)VAR)
 +
 +
 +static inline GPtrArray* SvGptrarray(const SV* sv)
 +{
 +      if (SvROK(sv)) {
 +              sv = MUTABLE_SV(SvRV(sv));
 +      }
 +      if (SvTYPE(sv) == SVt_PVAV) {
 +              AV* av = (AV*)sv;
 +              int i;
 +              int top = av_len(av);
 +              GPtrArray* array = g_ptr_array_new();
 +              for (i = 0; i <= top; ++i) {
 +                      SV** item = av_fetch(av, i, 0);
 +                      if (!item) continue;
 +                      g_ptr_array_add(array, sv_to_val(*item));
 +              }
 +              return array;
 +              // TODO- leaking
 +      } else {
 +              croak("var is not an array");
 +      }
 +}
 +
 +static inline SV* newSVgptrarray(const GPtrArray* a)
 +{
 +      if (a) {
 +              AV* av = newAV();
 +              int i;
 +              for (i = 0; i < a->len; ++i) {
 +                      GValue* item = g_ptr_array_index(a, i);
 +                      av_push(av, val_to_sv(item));
 +              }
 +              return newRV((SV*)av);
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static inline GHashTable* SvGhashtable(const SV* sv)
 +{
 +      if (SvROK(sv)) {
 +              sv = MUTABLE_SV(SvRV(sv));
 +      }
 +      if (SvTYPE(sv) == SVt_PVHV) {
 +              HV* hv = (HV*)sv;
 +              hv_iterinit(hv);
 +              gchar* key;
 +              I32 len;
 +              SV* item;
 +              GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
 +              while ((item = hv_iternextsv(hv, &key, &len))) {
 +                      g_hash_table_insert(hash, key, sv_to_val(item));
 +              }
 +              return hash;
 +              // TODO- leaking
 +      } else {
 +              croak("var is not a hash");
 +      }
 +}
 +
 +static inline SV* newSVghashtable(GHashTable* h)
 +{
 +      if (h) {
 +              HV* hv = newHV();
 +              GHashTableIter it;
 +              g_hash_table_iter_init(&it, h);
 +              gchar* key = NULL;
 +              GValue* item = NULL;
 +              while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
 +                      hv_store(hv, key, -g_utf8_strlen(key, -1), val_to_sv(item), 0);
 +              }
 +              return newRV((SV*)hv);
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static inline gboolean SvGboolean(SV* sv)
 +{
 +      if (!sv) {
 +              return FALSE;
 +      }
 +      if (SvROK(sv)) {
 +              return !!SvIV(SvRV(sv));
 +      } else {
 +              return SvTRUE(sv);
 +      }
 +}
 +
 +static inline SV* newSVgboolean(gboolean b)
 +{
 +      return sv_setref_iv(newSV(0), "HomeBank::Boolean", !!b);
 +}
 +
 +
 +static inline gchar* SvGchar_ptr(SV* sv)
 +{
 +      return SvPVutf8_nolen(sv);
 +}
 +
 +static inline SV* newSVgchar_ptr(const gchar* str)
 +{
 +      if (!str) return &PL_sv_undef;
 +
 +      SV* sv = newSVpv(str, 0);
 +      SvUTF8_on(sv);
 +      return sv;
 +}
 +
 +
 +static inline GObject* SvGobject(const SV* sv)
 +{
 +      GObject* (*func)(const SV*) = ext_symbol_lookup("gperl_get_object");
 +      if (func) {
 +              return func(sv);
 +      }
 +      return NULL;
 +}
 +
 +static inline SV* newSVgobject(const GObject* o)
 +{
 +    SV* (*func)(const GObject*, gboolean) = ext_symbol_lookup("gperl_new_object");
 +    if (func) {
 +        return func(o, FALSE);
 +    }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static PerlInterpreter* context = NULL;
 +
 +
 +static gint ext_perl_init(int* argc, char** argv[], char** env[])
 +{
 +      int ret = 0;
 +
 +      PERL_SYS_INIT3(argc, argv, env);
 +      context = perl_alloc();
 +      perl_construct(context);
 +
 +      PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
 +      PL_origalen = 1;
 +      PL_perl_destruct_level = 1;
 +
 +      gchar* bootstrap = g_strdup_printf("-e"
 +              "use lib '%s';"
 +              "use HomeBank;"
 +              "HomeBank->bootstrap;",
 +              homebank_app_get_pkglib_dir());
 +      char *args[] = { "", bootstrap };
 +
 +      EXTERN_C void xs_init(pTHX);
 +      if (perl_parse(context, xs_init, 2, args, NULL) || perl_run(context)) {
 +              ext_perl_term();
 +              ret = -1;
 +      }
 +
 +      g_free(bootstrap);
 +      return ret;
 +}
 +
 +static void ext_perl_term(void)
 +{
 +      if (context) {
 +              perl_destruct(context);
 +              perl_free(context);
 +              context = NULL;
 +      }
 +      PERL_SYS_TERM();
 +}
 +
 +static gboolean ext_perl_check_file(const gchar* plugin_filepath)
 +{
 +      if (g_str_has_suffix(plugin_filepath, ".pl")) {
 +              return TRUE;
 +      }
 +      return FALSE;
 +}
 +
 +static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath)
 +{
 +      GHashTable* table = NULL;
 +
 +      if (!context) return NULL;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +
 +      int ret = call_pv("HomeBank::read_metadata", G_SCALAR | G_EVAL);
 +
 +      SPAGAIN;
 +
 +      if (ret == 1) {
 +              table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 +              SV* sv = POPs;
 +              if (SvROK(sv)) {
 +                      sv = MUTABLE_SV(SvRV(sv));
 +              }
 +              if (SvTYPE(sv) == SVt_PVHV) {
 +                      HV* hv = (HV*)sv;
 +                      hv_iterinit(hv);
 +                      gchar* key;
 +                      I32 len;
 +                      SV* item;
 +                      while ((item = hv_iternextsv(hv, &key, &len))) {
 +                              if (SvPOK(item)) {
 +                                      gchar* val = SvPVutf8_nolen(item);
 +                                      g_hash_table_insert(table, g_strdup(key), g_strdup(val));
 +                              }
 +                      }
 +              }
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      return table;
 +}
 +
 +static gint ext_perl_load_plugin(const gchar* plugin_filepath)
 +{
 +      if (!context) return -1;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::load_plugin", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      gint ret = 0;
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +              ret = -1;
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +
 +      return ret;
 +}
 +
 +static void ext_perl_unload_plugin(const gchar* plugin_filepath)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::unload_plugin", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +static void ext_perl_execute_action(const gchar* plugin_filepath)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(plugin_filepath));
 +      PUTBACK;
 +      call_pv("HomeBank::execute_action", G_DISCARD | G_EVAL);
 +      SPAGAIN;
 +
 +      if (SvTRUE(ERRSV)) {
 +              g_printerr("%s", SvPV_nolen(ERRSV));
 +      }
 +
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +static void ext_perl_call_hook(const gchar* hook_id, GList* args)
 +{
 +      if (!context) return;
 +      PERL_SET_CONTEXT(context);
 +
 +      dSP;
 +      ENTER;
 +      SAVETMPS;
 +      PUSHMARK(SP);
 +      mXPUSHs(newSVgchar_ptr(hook_id));
 +
 +      GList *list = g_list_first(args);
 +      while (list) {
 +              GValue* val = list->data;
 +              XPUSHs(sv_2mortal(val_to_sv(val)));
 +              list = g_list_next(list);
 +      }
 +
 +      PUTBACK;
 +      call_pv("HomeBank::call_hook", G_ARRAY);
 +      SPAGAIN;
 +      POPi;
 +      PUTBACK;
 +      FREETMPS;
 +      LEAVE;
 +}
 +
 +
 +static SV* val_to_sv(GValue* val)
 +{
 +      if (!val || !G_IS_VALUE(val) || G_VALUE_TYPE(val) == G_TYPE_NONE) {
 +              return &PL_sv_undef;
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_BOOLEAN) {
 +              return newSVgboolean(g_value_get_boolean(val));
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_PTR_ARRAY) {
 +              return newSVgptrarray((GPtrArray*)g_value_get_boxed(val));
 +      }
 +      if (G_VALUE_TYPE(val) == G_TYPE_HASH_TABLE) {
 +              return newSVghashtable((GHashTable*)g_value_get_boxed(val));
 +      }
 +#define obj(CTYPE, _2, PART, GTYPE, _5)                         \
 +      if (G_VALUE_TYPE(val) == GTYPE) {                           \
 +              SV* sv = newSV(0);                                      \
 +              CTYPE* ptr = (CTYPE*)g_value_get_##PART(val);           \
 +              EXT_C2P_OBJECT("HomeBank::"#CTYPE, sv, rc_ref(ptr));    \
 +              return sv;                                              \
 +      }
 +#include "ext-value.h"
 +#undef obj
 +      return gperl_sv_from_value(val, FALSE);
 +}
 +
 +static GValue* sv_to_val(SV* sv)
 +{
 +      GValue* val = g_new0(GValue, 1);
 +
 +      if (SvUOK(sv)) return EXT_SV(val, sv, G_TYPE_UINT);
 +      if (SvIOK(sv)) return EXT_SV(val, sv, G_TYPE_INT);
 +      if (SvNOK(sv)) return EXT_SV(val, sv, G_TYPE_DOUBLE);
 +      if (SvPOK(sv)) return EXT_SV(val, sv, G_TYPE_STRING);
 +      if (sv_isobject(sv)) {
 +              if (sv_derived_from(sv, "HomeBank::Boolean")) {
 +                      return EXT_BOOLEAN(val, SvGboolean(sv));
 +              }
 +#define obj(CTYPE, NAME, _3, _4, _5)                                \
 +              if (sv_derived_from(sv, "HomeBank::"#CTYPE)) {              \
 +                      CTYPE* ptr;                                             \
 +                      EXT_P2C_OBJECT("HomeBank::"#CTYPE, sv, ptr, CTYPE*);    \
 +                      return EXT_##NAME(val, ptr);                            \
 +              }
 +#include "ext-value.h"
 +#undef obj
 +              return EXT_SV(val, sv, G_TYPE_OBJECT);
 +      }
 +      if (SvROK(sv)) {
 +              sv = SvRV(sv);
 +              switch (SvTYPE(sv)) {
 +                      case SVt_IV:
 +                              return EXT_BOOLEAN(val, SvGboolean(sv));
 +                      case SVt_PVAV:
 +                              return EXT_ARRAY(val, SvGptrarray(sv));
 +                      case SVt_PVHV:
 +                              return EXT_HASH_TABLE(val, SvGhashtable(sv));
 +                      default:
 +                              break;
 +              }
 +      }
 +      switch (SvTYPE(sv)) {
 +              case SVt_PVAV:
 +                      return EXT_ARRAY(val, SvGptrarray(sv));
 +              case SVt_PVHV:
 +                      return EXT_HASH_TABLE(val, SvGhashtable(sv));
 +              default:
 +                      break;
 +      }
 +
 +      g_free(val);
 +      return NULL;
 +}
 +
 +
 +static gboolean gperl_value_from_sv(GValue* value, SV* sv)
 +{
 +      gboolean (*func)(GValue*, SV*) = ext_symbol_lookup("gperl_value_from_sv");
 +      if (func) return func(value, sv);
 +
 +      GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
 +      if (!SvOK(sv)) return TRUE;
 +      switch (type) {
 +              case G_TYPE_CHAR:
 +              {
 +                      gchar *tmp = SvGchar_ptr(sv);
 +                      g_value_set_schar(value, (gint8)(tmp ? tmp[0] : 0));
 +                      break;
 +              }
 +              case G_TYPE_UCHAR:
 +              {
 +                      char *tmp = SvPV_nolen(sv);
 +                      g_value_set_uchar(value, (guchar)(tmp ? tmp[0] : 0));
 +                      break;
 +              }
 +              case G_TYPE_BOOLEAN:
 +                      g_value_set_boolean(value, SvTRUE(sv));
 +                      break;
 +              case G_TYPE_INT:
 +                      g_value_set_int(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_UINT:
 +                      g_value_set_uint(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_LONG:
 +                      g_value_set_long(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_ULONG:
 +                      g_value_set_ulong(value, SvIV(sv));
 +                      break;
 +              case G_TYPE_FLOAT:
 +                      g_value_set_float(value, (gfloat)SvNV(sv));
 +                      break;
 +              case G_TYPE_DOUBLE:
 +                      g_value_set_double(value, SvNV(sv));
 +                      break;
 +              case G_TYPE_STRING:
 +                      g_value_set_string(value, SvGchar_ptr(sv));
 +                      break;
 +      }
 +      return TRUE;
 +}
 +
 +static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed)
 +{
 +      SV* (*func)(const GValue*, gboolean) = ext_symbol_lookup("gperl_sv_from_value");
 +      if (func) return func(value, copy_boxed);
 +
 +      GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
 +      switch (type) {
 +              case G_TYPE_CHAR:
 +                      return newSViv(g_value_get_schar(value));
 +              case G_TYPE_UCHAR:
 +                      return newSVuv(g_value_get_uchar(value));
 +              case G_TYPE_BOOLEAN:
 +                      return newSViv(g_value_get_boolean(value));
 +              case G_TYPE_INT:
 +                      return newSViv(g_value_get_int(value));
 +              case G_TYPE_UINT:
 +                      return newSVuv(g_value_get_uint(value));
 +              case G_TYPE_LONG:
 +                      return newSViv(g_value_get_long(value));
 +              case G_TYPE_ULONG:
 +                      return newSVuv(g_value_get_ulong(value));
 +              case G_TYPE_FLOAT:
 +                      return newSVnv(g_value_get_float(value));
 +              case G_TYPE_DOUBLE:
 +                      return newSVnv(g_value_get_double(value));
 +              case G_TYPE_STRING:
 +                      return newSVgchar_ptr(g_value_get_string(value));
 +      }
 +      return &PL_sv_undef;
 +}
 +
 +
 +static void _register(void) __attribute__((constructor));
 +static void _register()
 +{
 +      ext_register("perl",
 +                      ext_perl_init,
 +                      ext_perl_term,
 +                      ext_perl_check_file,
 +                      ext_perl_read_plugin_metadata,
 +                      ext_perl_load_plugin,
 +                      ext_perl_unload_plugin,
 +                      ext_perl_execute_action,
 +                      ext_perl_call_hook);
 +}
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank
 +
 +PROTOTYPES: ENABLE
 +
 +const gchar*
 +version(void)
 +      CODE:
 +              RETVAL = VERSION;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +config_dir(void)
 +      CODE:
 +              RETVAL = homebank_app_get_config_dir();
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +has(const gchar* CLASS, ...)
 +      PREINIT:
 +              int i;
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = TRUE;
 +              for (i = 1; i < items; ++i) {
 +                      gchar* feature = SvGchar_ptr(ST(i));
 +                      if (!feature || !ext_has(feature)) {
 +                              RETVAL = FALSE;
 +                              break;
 +                      }
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +main_window(void)
 +      CODE:
 +              RETVAL = G_OBJECT(GLOBALS->mainwindow);
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +main_ui_manager(void)
 +      PREINIT:
 +              struct hbfile_data *data;
 +      CODE:
 +              RETVAL = NULL;
 +              if (GLOBALS->mainwindow) {
 +                      data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GLOBALS->mainwindow, GTK_TYPE_WINDOW)), "inst_data");
 +                      if (data) {
 +                              RETVAL = G_OBJECT(data->manager);
 +                      }
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +info(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "info");
 +
 +void
 +warn(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "warn");
 +
 +void
 +error(const gchar* CLASS, const gchar* title, const gchar* text)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              ext_run_modal(title, text, "error");
 +
 +void
 +hook(const gchar* CLASS, const gchar* hook_name, ...)
 +      PREINIT:
 +              int i;
 +              GList* list = NULL;
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              for (i = 2; i < items; ++i) {
 +                      SV* sv = ST(i);
 +                      GValue *val = sv_to_val(sv);
 +                      list = g_list_append(list, val);
 +              }
 +      CLEANUP:
 +              ext_vhook(hook_name, list);
 +              g_list_free(list);
 +              // TODO free all the things
 +
 +GObject*
 +open_prefs(const gchar* CLASS)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = G_OBJECT(defpref_dialog_new(PREF_GENERAL));
 +      OUTPUT:
 +              RETVAL
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::File
 +
 +const gchar*
 +owner(const gchar* CLASS, ...)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              if (1 < items) {
 +                      hbfile_change_owner(g_strdup(SvGchar_ptr(ST(1))));
 +              }
 +              RETVAL = GLOBALS->owner;
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +transactions(const gchar* CLASS)
 +      PPCODE:
 +              PERL_UNUSED_ARG(CLASS);
 +
 +              GList* acc_list = g_hash_table_get_values(GLOBALS->h_acc);
 +              GList* acc_link = g_list_first(acc_list);
 +              for (; acc_link; acc_link = g_list_next(acc_link)) {
 +                      Account *acc = acc_link->data;
 +
 +                      GList* txn_link = g_queue_peek_head_link(acc->txn_queue);
 +                      for (; txn_link; txn_link = g_list_next(txn_link)) {
 +                              Transaction* txn = txn_link->data;
 +
 +                              GValue val = G_VALUE_INIT;
 +                              SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
 +                              mXPUSHs(sv);
 +                      }
 +              }
 +
 +              g_list_free(acc_list);
 +
 +void
 +anonymize(void)
 +      CODE:
 +              hbfile_anonymize();
 +
 +void
 +baz(const gchar* CLASS, Account* account)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("hello: %s\n", account->name);
 +
 +GPtrArray*
 +meh(const gchar* CLASS, GPtrArray* asdf)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
 +              if (asdf) {
 +                      ;
 +              } else {
 +                      g_print("the array is nil\n");
 +              }
 +              RETVAL = asdf;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_ptr_array_unref(asdf);
 +
 +GHashTable*
 +foo(const gchar* CLASS, GHashTable* asdf)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
 +              if (asdf) {
 +                      GHashTableIter it;
 +                      g_hash_table_iter_init(&it, asdf);
 +                      gchar* key = NULL;
 +                      GValue* item = NULL;
 +                      while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
 +                              g_print("hash with key: %s\n", key);
 +                      }
 +              } else {
 +                      g_print("the hash is nil\n");
 +              }
 +              RETVAL = asdf;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_hash_table_unref(asdf);
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::Account
 +
 +void
 +compute_balances(const gchar* CLASS)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              account_compute_balances();
 +
 +Account*
 +new(void)
 +      CODE:
 +              RETVAL = da_acc_malloc();
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +DESTROY(Account* SELF)
 +      CODE:
 +              da_acc_free(SELF);
 +
 +Account*
 +get(const gchar* CLASS, guint key)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = rc_ref(da_acc_get(key));
 +      OUTPUT:
 +              RETVAL
 +
 +Account*
 +get_by_name(const gchar* CLASS, const gchar* name)
 +      CODE:
 +              PERL_UNUSED_ARG(CLASS);
 +              RETVAL = rc_ref(da_acc_get_by_name((gchar*)name));
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +name(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      account_rename(SELF, SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->name;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +number(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      g_free(SELF->number);
 +                      SELF->number = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->number;
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +bankname(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      g_free(SELF->bankname);
 +                      SELF->bankname = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->bankname;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +initial(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->initial = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->initial;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +minimum(Account* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->minimum = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->minimum;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +cheque1(Account* SELF, ...)
 +      ALIAS:
 +              check1 = 1
 +      CODE:
 +              PERL_UNUSED_VAR(ix);
 +              if (1 < items) {
 +                      SELF->cheque1 = SvUV(ST(1));
 +              }
 +              RETVAL = SELF->cheque1;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +cheque2(Account* SELF, ...)
 +      ALIAS:
 +              check2 = 1
 +      CODE:
 +              PERL_UNUSED_VAR(ix);
 +              if (1 < items) {
 +                      SELF->cheque2 = SvUV(ST(1));
 +              }
 +              RETVAL = SELF->cheque2;
 +      OUTPUT:
 +              RETVAL
 +
 +gdouble
 +balance(Account* SELF)
 +      ALIAS:
 +              bank_balance    = 1
 +              future_balance  = 2
 +      CODE:
 +              switch (ix) {
 +                      case 1:
 +                              RETVAL = SELF->bal_bank;
 +                              break;
 +                      case 2:
 +                              RETVAL = SELF->bal_future;
 +                              break;
 +                      default:
 +                              RETVAL = SELF->bal_today;
 +                              break;
 +              }
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +is_inserted(Account* SELF)
 +      CODE:
 +              RETVAL = da_acc_get(SELF->key) == SELF;
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +is_used(Account* SELF)
 +      CODE:
 +              RETVAL = account_is_used(SELF->key);
 +      OUTPUT:
 +              RETVAL
 +
 +gboolean
 +insert(Account* SELF)
 +      CODE:
 +              if (SELF->key == 0 || account_is_used(SELF->key))
 +                      RETVAL = da_acc_append(rc_ref(SELF));
 +              else
 +                      RETVAL = da_acc_insert(rc_ref(SELF));
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +remove(Account* SELF)
 +      CODE:
 +              da_acc_remove(SELF->key);
 +
 +void
 +transactions(Account* SELF)
 +      PPCODE:
 +              GList* list = g_queue_peek_head_link(SELF->txn_queue);
 +              for (; list; list = g_list_next(list)) {
 +                      Transaction* txn = list->data;
 +                      GValue val = G_VALUE_INIT;
 +                      SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
 +                      mXPUSHs(sv);
 +              }
 +
 +GObject*
 +open(Account* SELF)
 +      CODE:
 +              RETVAL = G_OBJECT(register_panel_window_new(SELF->key, SELF));
 +      OUTPUT:
 +              RETVAL
 +
 +
 +MODULE = HomeBank  PACKAGE = HomeBank::Transaction
 +
 +Transaction*
 +new(void)
 +      CODE:
 +              RETVAL = da_transaction_malloc();
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +DESTROY(Transaction* SELF)
 +      CODE:
 +              da_transaction_free(SELF);
 +
 +gdouble
 +amount(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->amount = SvNV(ST(1));
 +              }
 +              RETVAL = SELF->amount;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kacc;
 +      OUTPUT:
 +              RETVAL
 +
 +guint
 +paired_account_num(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      SELF->kxferacc = SvIV(ST(1));
 +              }
 +              RETVAL = SELF->kxferacc;
 +      OUTPUT:
 +              RETVAL
 +
 +void
 +date(Transaction* SELF, ...)
 +      PPCODE:
 +              if (1 < items) {
 +                      SELF->date = SvIV(ST(1));
 +              }
 +              if (GIMME_V == G_ARRAY) {
 +                      GDate* d = g_date_new_julian(SELF->date);
 +                      mXPUSHp("day", 3);
 +                      mXPUSHi(g_date_get_day(d));
 +                      mXPUSHp("month", 5);
 +                      mXPUSHi(g_date_get_month(d));
 +                      mXPUSHp("year", 4);
 +                      mXPUSHi(g_date_get_year(d));
 +                      g_date_free(d);
 +                      XSRETURN(6);
 +              } else {
 +                      XSRETURN_IV(SELF->date);
 +              }
 +
 +const gchar*
-                       if (SELF->wording) g_free(SELF->wording);
-                       SELF->wording = g_strdup(SvGchar_ptr(ST(1)));
++memo(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
-               RETVAL = SELF->wording ? SELF->wording : "";
++                      if (SELF->memo) g_free(SELF->memo);
++                      SELF->memo = g_strdup(SvGchar_ptr(ST(1)));
 +              }
-                       SELF->wording, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
++              RETVAL = SELF->memo ? SELF->memo : "";
 +      OUTPUT:
 +              RETVAL
 +
 +const gchar*
 +info(Transaction* SELF, ...)
 +      CODE:
 +              if (1 < items) {
 +                      if (SELF->info) g_free(SELF->info);
 +                      SELF->info = g_strdup(SvGchar_ptr(ST(1)));
 +              }
 +              RETVAL = SELF->info ? SELF->info : "";
 +      OUTPUT:
 +              RETVAL
 +
 +GObject*
 +open(Transaction* SELF)
 +      CODE:
 +              RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE));
 +              deftransaction_set_transaction(GTK_WIDGET(RETVAL), SELF);
 +      OUTPUT:
 +              RETVAL
 +
 +Transaction*
 +pair_with(Transaction* SELF, Transaction* other, ...)
 +      PREINIT:
 +              int i;
 +              GList* list = NULL;
 +      CODE:
 +              if (2 < items) {
 +                      list = g_list_append(list, other);
 +                      for (i = 2; i < items; ++i) {
 +                              Transaction* ptr = NULL;
 +                              SV* sv = ST(i);
 +                              EXT_P2C_OBJECT("HomeBank::Transaction", sv, ptr, Transaction*);
 +                              list = g_list_append(list, ptr);
 +                      }
 +                      other = ui_dialog_transaction_xfer_select_child(SELF, list);
 +              }
 +              if (other) {
 +                      transaction_xfer_change_to_child(SELF, other);
 +                      SELF->paymode = PAYMODE_INTXFER;
 +              }
 +              RETVAL = other;
 +      OUTPUT:
 +              RETVAL
 +      CLEANUP:
 +              g_list_free(list);
 +
 +void
 +dump(Transaction* SELF)
 +      CODE:
 +              g_print("txn: %p (%s) at %u (%d/%d) flags:%d, paymode:%d, kpay:%d, kcat:%d", SELF,
++                      SELF->memo, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
 +
Simple merge
index e0789de31bb5f7c45e08f32b1640a002bab1147f,0e88c48549f243252fb63d64c87738d249ff8291..628e978a9ce7c0ec4125909f3cc16d7a54e04ad4
  extern struct HomeBank *GLOBALS;
  
  
- /* = = = = = = = = = = = = = = = = = = = = */
- /* Archive */
  Archive *da_archive_malloc(void)
  {
 -      return g_malloc0(sizeof(Archive));
 +      return rc_alloc(sizeof(Archive));
  }
  
  Archive *da_archive_clone(Archive *src_item)
  {
 -Archive *new_item = g_memdup(src_item, sizeof(Archive));
 +Archive *new_item = rc_dup(src_item, sizeof(Archive));
  
        if(new_item)
        {
        return new_item;
  }
  
  void da_archive_free(Archive *item)
  {
 -      if(item != NULL)
 +      if(rc_unref(item))
        {
-               if(item->wording != NULL)
-                       g_free(item->wording);
+               if(item->memo != NULL)
+                       g_free(item->memo);
  
                da_splits_free(item->splits);
                //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared            
diff --cc src/hb-assign.c
Simple merge
Simple merge
diff --cc src/hb-payee.c
Simple merge
Simple merge
Simple merge
diff --cc src/hb-tag.c
Simple merge
index 5f77203fed1a988218a6945bb1dd5ca272b78562,29812d9ce5e1050640b55f05998c512d66a95c0a..eb825093e8b674239d7c4a3c4a326cde61e1d7bd
@@@ -850,41 -946,9 +952,12 @@@ Account *acc
                {
                        transaction_xfer_search_or_add_child(NULL, newope, FALSE);
                }
 +
 +              GValue txn_value = G_VALUE_INIT;
 +              ext_hook("transaction_inserted", EXT_TRANSACTION(&txn_value, newope), NULL);
        }
- }
- void transaction_add_treeview(Transaction *ope, GtkWidget *treeview, guint32 accnum)
- {
- GtkTreeModel *model;
- GtkTreeIter  iter;
- //GtkTreePath *path;
- //GtkTreeSelection *sel;
-       DB( g_print("\n[transaction] add_treeview\n") );
-       if(ope->kacc == accnum)
-       {
-               model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
-               gtk_list_store_append (GTK_LIST_STORE(model), &iter);
-               gtk_list_store_set (GTK_LIST_STORE(model), &iter,
-                               LST_DSPOPE_DATAS, ope,
-                               -1);
-               //activate that new line
-               //path = gtk_tree_model_get_path(model, &iter);
-               //gtk_tree_view_expand_to_path(GTK_TREE_VIEW(treeview), path);
-               //sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
-               //gtk_tree_selection_select_iter(sel, &iter);
-               //gtk_tree_path_free(path);
-       }
+       
+       return newope;
  }
  
  
diff --cc src/hb-xml.c
Simple merge
diff --cc src/homebank.c
index 9a9e9157a89fafca1252bebe915f3f3da711d634,3b65ca1e57043713de1d2195a37be971e29c03ae..60e87c88650dbc4ccc7bc0329cec3e07db271bf4
@@@ -17,8 -17,8 +17,9 @@@
   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  #include "homebank.h"
 +#include "ext.h"
  
  #include "dsp_mainwindow.h"
  #include "hb-preferences.h"
@@@ -1079,18 -1073,13 +1104,20 @@@ nobak
                        /* update the mainwin display */
                        ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL));
  
-               DB( g_print(" - gtk_main()\n" ) );
 +                      ext_hook("enter_main_loop", NULL);
 +
+                       DB( g_print(" - gtk_main()\n" ) );
                        gtk_main ();
+       
 +                      ext_hook("exit_main_loop", NULL);
++
+                       DB( g_print(" - call destroy mainwin\n" ) );
+                       gtk_widget_destroy(mainwin);
                }
  
 +              DB( g_print(" - unloading plugins\n") );
 +              ext_term();
 +
        }
  
  
diff --cc src/homebank.h
Simple merge
diff --cc src/ui-pref.c
index 1597d688aa3f055501c127f3f61df3568245d41f,7da069f50719083bab1878da9480ff5dbb65dceb..bcee6b1848e09e19df8a61921583935c0496a3a9
@@@ -206,29 -185,14 +186,17 @@@ static EuroParams euro_params[] 
  };
  
  
- GtkWidget *pref_list_create(void);
- GtkWidget *list_txn_colprefcreate(void);
- static void list_txn_colpref_get(GtkTreeView *treeview, gboolean *columns);
 +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns);
 +
 +
  /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
- typedef struct 
- {
-       gchar   *locale;
-       gchar   *name;
-       
- } LangName;
  
  static LangName languagenames[] =
  {
--// af ar ast be bg ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl he hr hu id is it 
++// af ar ast be bg ca cs cy da de el en_AU en_CA en_GB es et eu fa fi fr ga gl he hr hu id is it
  //ja ka ko lt lv ms nb nds nl oc pl pt_BR pt pt_PT ro ru si sk sl sr sv tr uk vi zh_CN zh_TW
--      
++
        { "aa", "Afar" },
        { "ab", "Abkhazian" },
        { "ae", "Avestan" },
@@@ -433,7 -400,7 +404,7 @@@ gchar *name1, *name2
        //keep system laguage on top
        if(code1 == NULL) name1 = NULL;
        if(code2 == NULL) name2 = NULL;
--      
++
      retval = hb_string_utf8_compare(name1, name2);
  
      g_free(name2);
@@@ -482,7 -449,7 +453,7 @@@ const gchar *lang
                        g_warning(" locale name not found '%s'", locale);
                        lang = locale;
                }
--              
++
        }
  
        return lang;
@@@ -497,7 -464,7 +468,7 @@@ GtkTreeIter  iter
  
        model = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox));
        gtk_list_store_append (GTK_LIST_STORE(model), &iter);
--      gtk_list_store_set (GTK_LIST_STORE(model), &iter, 
++      gtk_list_store_set (GTK_LIST_STORE(model), &iter,
                            0, NULL,
                            1, _("System Language"),
                            -1);
@@@ -520,13 -487,13 +491,13 @@@ const gchar *dirname
                {
                const gchar *lang;
                gchar *label;
--                      
++
                        gtk_list_store_append (GTK_LIST_STORE(model), &iter);
  
                        lang = ui_language_combobox_get_name(dirname);
                        label = g_strdup_printf ("%s [%s]", lang, dirname);
  
--                      gtk_list_store_set (GTK_LIST_STORE(model), &iter, 
++                      gtk_list_store_set (GTK_LIST_STORE(model), &iter,
                                                    0, dirname,
                                                    1, label,
                                                    -1);
@@@ -563,7 -530,7 +534,7 @@@ GtkCellRenderer *renderer
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combobox), renderer, "text", 1, NULL);
  
        gtk_combo_box_set_id_column( GTK_COMBO_BOX(combobox), 0);
--              
++
        g_object_unref(store);
  
        if(label)
        ui_language_combobox_populate(combobox);
  
        gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0);
--      
++
        return combobox;
  }
  
@@@ -740,7 -707,7 +711,7 @@@ gchar buf[128]
        cur.frac_digits   = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits));
  
        da_cur_initformat (&cur);
--      
++
        DB( g_print("fmt: %s\n", cur.format) );
  
        g_ascii_formatd(formatd_buf, sizeof (formatd_buf), cur.format, HB_NUMBER_SAMPLE);
@@@ -780,11 -747,11 +751,11 @@@ struct defpref_data *data
  EuroParams *euro;
  gchar *buf;
  gint active;
--      
++
        DB( g_print("\n[ui-pref] eurosetcurrency\n") );
  
        data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
--      
++
        active = ui_euro_combobox_id_to_active(country);
        euro = &euro_params[active];
        buf = g_strdup_printf("%s - %s", euro->iso, euro->name);
@@@ -899,7 -866,7 +870,7 @@@ struct defpref_data *data
        data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
  
        gtk_widget_queue_draw (data->DA_colors);
--      
++
  }
  
  
@@@ -1047,7 -1018,7 +1022,7 @@@ const gchar *lang
        {
                PREFS->language = g_strdup(lang);
        }
--      
++
        PREFS->toolbar_style = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_toolbar));
        //PREFS->image_size = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_image_size));
  
        gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(data->CP_warn_color), &rgba);
        g_free(PREFS->color_warn);
        PREFS->color_warn = gdk_rgba_to_hex(&rgba);
        //PREFS->rules_hint = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_ruleshint));
        PREFS->grid_lines = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_gridlines));
+       //list_txn_colpref_get(GTK_TREE_VIEW(data->LV_opecolumns), PREFS->lst_ope_columns);
  
-       PREFS->fisc_year_day = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_fiscyearday));
-       PREFS->fisc_year_month = 1 + gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_fiscyearmonth));
-       list_txn_colpref_get(GTK_TREE_VIEW(data->LV_opecolumns), PREFS->lst_ope_columns);
-       g_free(PREFS->path_hbfile);
-       PREFS->path_hbfile = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_path_hbfile)));
-       ui_gtk_entry_replace_text(data->ST_path_import, &PREFS->path_import);
-       ui_gtk_entry_replace_text(data->ST_path_export, &PREFS->path_export);
-       PREFS->loadlast  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_load_last));
-       PREFS->appendscheduled  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_append_scheduled));
-       PREFS->do_update_currency  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_do_update_currency));
-               
-       PREFS->showsplash  = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_show_splash));
-       PREFS->heritdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_herit_date));
 -      // transaction 
++      // transaction
+       PREFS->date_range_txn = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_daterange_txn));
+       PREFS->date_future_nbdays  = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->ST_datefuture_nbdays));
        PREFS->hidereconciled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_hide_reconciled));
        PREFS->showremind = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_show_remind));
+       PREFS->heritdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_herit_date));
  
-       //g_free(PREFS->path_navigator);
-       //PREFS->path_navigator = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_path_navigator)));
+       // display format
        g_free(PREFS->date_format);
        PREFS->date_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(data->ST_datefmt)));
        PREFS->vehicle_unit_ismile = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_unitismile));
        PREFS->vehicle_unit_isgal = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_unitisgal));
  
        ui_gtk_entry_replace_text(data->ST_euro_decimalchar, &PREFS->minor_cur.decimal_char);
        ui_gtk_entry_replace_text(data->ST_euro_groupingchar, &PREFS->minor_cur.grouping_char);
        PREFS->minor_cur.frac_digits = gtk_spin_button_get_value(GTK_SPIN_BUTTON(data->NB_euro_fracdigits));
-       PREFS->stat_byamount   = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_byamount));
-       PREFS->stat_showrate   = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showrate));
-       PREFS->stat_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_stat_showdetail));
-       PREFS->budg_showdetail = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_budg_showdetail));
-       PREFS->report_color_scheme = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_color_scheme));
-       /* import */
-       PREFS->dtex_datefmt = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_datefmt));
-       PREFS->dtex_ofxname = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxname));
-       PREFS->dtex_ofxmemo = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_dtex_ofxmemo));
-       PREFS->dtex_qifmemo = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifmemo));
-       PREFS->dtex_qifswap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_dtex_qifswap));
        //PREFS->chart_legend = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_chartlegend));
 +
 +      list_ext_colpref_get(GTK_TREE_VIEW(data->PI_plugin_columns), &(PREFS->ext_whitelist));
  }
  
  
@@@ -1153,10 -1097,10 +1103,10 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Date options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Date order:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("OFX/QFX options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("_Name field:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("QIF options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Memos:"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Files folder"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("_Import:"));
        //----------------------------------------- l, r, t, b
@@@ -1280,7 -1224,7 +1230,7 @@@ gint i, x, y
        index = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_color_scheme));
  
        colorscheme_init(&scheme, index);
--      
++
        gtk_widget_get_size_request (widget, &w, &h);
        x = y = 0;
        for(i=0;i<scheme.nb_cols;i++)
@@@ -1313,10 -1257,10 +1263,10 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Initial filter"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Date _range:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Charts options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        label = make_label_widget(_("Color scheme:"));
        //----------------------------------------- l, r, t, b
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Statistics options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        widget = gtk_check_button_new_with_mnemonic (_("Show by _amount"));
        data->CM_stat_byamount = widget;
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Budget options"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
--      
++
        row = 1;
        widget = gtk_check_button_new_with_mnemonic (_("Show _details"));
        data->CM_budg_showdetail = widget;
@@@ -1409,7 -1353,7 +1359,7 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("General"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Currency"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 4, 1);
  
        //gtk_grid_attach (GTK_GRID (group_grid), data->CY_option[FILTER_DATE], 1, 2, row, row+1);
        gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1);
  
--      
++
        // group :: Exchange rate
      group_grid = gtk_grid_new ();
        data->GRP_rate = group_grid;
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Format"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_container_add (GTK_CONTAINER (expander), group_grid);
--      
++
        row = 0;
        label = make_label_widget(_("_Symbol:"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
@@@ -1539,7 -1483,7 +1489,7 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Date"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        widget = gtk_image_new_from_icon_name (ICONNAME_INFO, GTK_ICON_SIZE_BUTTON);
        gtk_grid_attach (GTK_GRID (group_grid), widget, 3, row, 1, 1);
  
--      
++
        gtk_widget_set_tooltip_text(widget,
        _("%a locale's abbreviated weekday name.\n"
  "%A locale's full weekday name. \n"
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Measurement units"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
@@@ -1630,7 -1574,7 +1580,7 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Transaction window"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        //----------------------------------------- l, r, t, b
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        widget = make_numeric(NULL, 0, 366);
--      
++
        data->ST_datefuture_nbdays = widget;
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Multiple add"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Column list"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
@@@ -1720,7 -1666,7 +1672,7 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("General"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        widget = ui_language_combobox_new(label);
        data->CY_language = widget;
        gtk_grid_attach (GTK_GRID (group_grid), widget, 2, row, 1, 1);
--      
++
        row++;
        label = make_label_widget(_("_Toolbar:"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Amount colors"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_attach (GTK_GRID (group_grid), label, 1, row, 1, 1);
        hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
        gtk_grid_attach (GTK_GRID (group_grid), hbox, 2, row, 1, 1);
--      
++
        widget = gtk_color_button_new ();
        data->CP_exp_color = widget;
        gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
--      
++
        label = make_label_widget(_("_Income:"));
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  
@@@ -1821,7 -1767,7 +1773,7 @@@ gint crow, row
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Program start"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Main window reports"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
        gtk_grid_set_row_spacing (GTK_GRID (group_grid), SPACING_SMALL);
        gtk_grid_set_column_spacing (GTK_GRID (group_grid), SPACING_MEDIUM);
        gtk_grid_attach (GTK_GRID (content_grid), group_grid, 0, crow++, 1, 1);
--      
++
        label = make_label_group(_("Files folder"));
        gtk_grid_attach (GTK_GRID (group_grid), label, 0, 0, 3, 1);
  
@@@ -2204,7 -1954,7 +2156,7 @@@ gint result
                homebank_pref_setdefault();
                defpref_set(data);
        }
--      
++
  }
  
  
@@@ -2225,7 -1975,7 +2177,7 @@@ GtkWidget *hbox, *vbox, *sw, *widget, *
                                NULL);
  
        data.window = window;
--      
++
        //store our window private data
        g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)&data);
  
        //left part
        vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, SPACING_SMALL);
        gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
--      
++
        //list
        sw = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
        data.BT_clear = gtk_button_new_with_mnemonic(_("_Reset"));
        gtk_box_pack_start (GTK_BOX (vbox), data.BT_clear, FALSE, TRUE, 0);
  
--      
++
        //right part : notebook
        vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM);
        gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
        #else
        GtkCssProvider *provider;
                provider = gtk_css_provider_new ();
--              gtk_css_provider_load_from_data (provider, 
++              gtk_css_provider_load_from_data (provider,
                "#hbebox { color: @theme_selected_fg_color; background-color: @theme_selected_bg_color; }"
                , -1, NULL);
                gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER(provider), G_MAXUINT);
--      
++
        //      gtk_style_context_set_state(context, GTK_STATE_FLAG_SELECTED);
        #endif
  
        g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
  
        g_signal_connect (G_OBJECT (data.BT_clear), "clicked", G_CALLBACK (defpref_clear), NULL);
--      
++
        //path selector
        g_signal_connect (data.BT_path_hbfile, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(1));
        g_signal_connect (data.BT_path_import, "pressed", G_CALLBACK (defpref_pathselect), GINT_TO_POINTER(2));
      g_signal_connect (data.CY_colors, "changed", G_CALLBACK (defpref_colorpreset), NULL);
  
  
--      
++
        g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data.LV_page)), "changed", G_CALLBACK (defpref_selection), notebook);
  
        g_signal_connect (data.CM_euro_enable, "toggled", G_CALLBACK (defpref_eurotoggle), NULL);
                                ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_BALANCE+UF_VISUAL));
  
                                DB( g_print("old='%s' new='%s'\n", old_lang, PREFS->language) );
--                              
++
                                if(g_ascii_strncasecmp(old_lang == NULL ? "" : old_lang, PREFS->language == NULL ? "" : PREFS->language, -1) != 0)
                                {
                                        ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_INFO,
                                                _("Info"),
                                                _("You will have to restart HomeBank\nfor the language change to take effect.")
                                        );
--                      
++
                                }
  
                                g_free(old_lang);
                                break;
                }
--      
++
  
        // cleanup and destroy
        //defhbfile_cleanup(&data, result);
@@@ -2532,7 -2276,7 +2484,7 @@@ GtkTreeIter  iter
  GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
  gboolean fixed;
  
-       /* get toggled iter */
 -      // get toggled iter 
++      // get toggled iter
        gtk_tree_model_get_iter (model, &iter, path);
        gtk_tree_model_get (model, &iter, COLUMN_VISIBLE, &fixed, -1);
  
@@@ -2556,8 -2300,7 +2508,7 @@@ gboolean visible
  gint i, id;
  
        DB( g_print("[lst_txn-colpref] store column order \n") );
 -      
 +
-       
        model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
        valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
        i = 0;
@@@ -2609,16 -2349,16 +2557,16 @@@ gint i
        gboolean visible;
  
                DB( g_print("eval %d, %s\n", i, list_txn_column_label[i]) );
--              
++
                if(i <= LST_DSPOPE_DATE) // status, date always displayed
                        continue;
  
                //[i-1] here because lst_ope_columns[] do not store LST_DSPOPE_DATAS
--              id = ABS(PREFS->lst_ope_columns[i-1]);  
++              id = ABS(PREFS->lst_ope_columns[i-1]);
                if(id == 0) id = i;      //if we pass here, new column or weird into pref file
                visible = (PREFS->lst_ope_columns[i-1] > 0) ? TRUE : FALSE;
  
--              
++
                DB( g_print(" - pos=%2d, id=%2d - %d '%s'\n", i, id, visible, list_txn_column_label[id]) );
  
                gtk_list_store_append (store, &iter);
                        COLUMN_NAME, _(list_txn_column_label[id]),
                        COLUMN_ID  , id,
                        -1);
--              
++
        }
  
        //treeview
        g_signal_connect (renderer, "toggled",
                            G_CALLBACK (list_txn_colpref_toggled_cell_data_function), store);
  
--      
++
        renderer = gtk_cell_renderer_text_new ();
        column = gtk_tree_view_column_new_with_attributes (_("Column"),
                                                             renderer,
  
        return(view);
  }
+ */
  
 +
 +static void list_ext_colpref_get(GtkTreeView *treeview, GList **columns)
 +{
 +      GtkTreeModel *model;
 +      GtkTreeIter     iter;
 +
 +      g_list_free_full(*columns, g_free);
 +      *columns = NULL;
 +
 +      model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
 +
 +      gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
 +      while (valid) {
 +              gboolean        enabled = FALSE;
 +              const gchar*    name;
 +
 +              gtk_tree_model_get(GTK_TREE_MODEL(model), &iter,
 +                      EXT_COLUMN_ENABLED,     &enabled,
 +                      EXT_COLUMN_PLUGIN_NAME, &name,
 +                      -1);
 +
 +              if (enabled) {
 +                      *columns = g_list_append(*columns, g_strdup(name));
 +              }
 +
 +              valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter);
 +      }
 +}
 +
diff --cc src/ui-pref.h
Simple merge
This page took 0.084365 seconds and 4 git commands to generate.