From: Charles McGarvey Date: Wed, 28 Dec 2016 22:59:58 +0000 (-0700) Subject: Merge branch 'master' into ext-perl X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fhomebank;a=commitdiff_plain;h=613fd4014fa5814bf2adce50574d520df8927ce1 Merge branch 'master' into ext-perl --- 613fd4014fa5814bf2adce50574d520df8927ce1 diff --cc Makefile.am index ac9cc1c,0a66203..de75d0f --- a/Makefile.am +++ b/Makefile.am @@@ -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 dfaa66d,b4680b5..83f6509 --- a/configure.ac +++ b/configure.ac @@@ -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 diff --cc plugins/hello.pl index c6abdf9,0000000..9171bb2 mode 100644,000000..100644 --- a/plugins/hello.pl +++ b/plugins/hello.pl @@@ -1,281 -1,0 +1,234 @@@ + +# NAME: Hello World +# VERSION: 0.01 +# ABSTRACT: This is the "hello world" of HomeBank plugins. +# AUTHOR: Charles McGarvey +# 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->create_menuitem; - + $self; +} + +sub on_create_main_window { + my $self = shift; + my $window = shift; + + if (!$window) { - require Gtk2; ++ 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); - - $self->create_menuitem; +} + +my $test_win; + +sub on_test { + my $self = shift; - require Gtk2; ++ require Gtk3; + - my $window = Gtk2::Window->new('toplevel'); ++ 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 { Gtk2->main_quit }); ++ #$window->signal_connect(delete_event => sub { Gtk3->main_quit }); + $window->signal_connect(delete_event => sub { undef $test_win }); + - my $button = Gtk2::Button->new('Click Me!'); ++ my $button = Gtk3::Button->new('Click Me!'); + Dump($button); + print Dumper($button); + $button->signal_connect(clicked => sub { - print "Hello Gtk2-Perl: $counter (perl plugin: $self)\n"; ++ 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 Gtk2; ++ #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.'); +} + - 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}; - } - +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; - - $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 EXECUTE { + print "the perl plugin is being configured.....\n"; + HomeBank->info("Hello Prefs", "YEEEEEARGGH!!!!!"); +} + +#__PACKAGE__->meta->make_immutable; diff --cc src/Makefile.am index 71c57f1,200e63c..484ce27 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -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 + diff --cc src/dsp_mainwindow.c index 98c5ea1,c96fdc6..707f68a --- a/src/dsp_mainwindow.c +++ b/src/dsp_mainwindow.c @@@ -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...") , "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") , "N", N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) }, + { "Open" , ICONNAME_OPEN , N_("_Open...") , "O", N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) }, + { "Save" , ICONNAME_SAVE , N_("_Save") , "S", N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) }, + { "SaveAs" , ICONNAME_SAVE_AS , N_("Save _As...") , "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") , "W", N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) }, + { "Quit" , ICONNAME_QUIT , N_("_Quit") , "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..."), "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 " " " " " " + " " + " " + " " + " " + " " + " " +" " +" " +" " +" " +" " " " " " " " @@@ -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 8002047,0000000..5aa56b0 mode 100644,000000..100644 --- a/src/ext-perl.xs +++ b/src/ext-perl.xs @@@ -1,1042 -1,0 +1,1043 @@@ + +#include +#include +#include + +#include + +#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* 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); ++ ++ 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 + - Account* - clone(Account* SELF) - CODE: - RETVAL = da_acc_clone(SELF); - RETVAL->key = 0; - 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_list_first(GLOBALS->ope_list); ++ GList* list = g_queue_peek_head_link(SELF->txn_queue); + for (; list; list = g_list_next(list)) { + Transaction* txn = list->data; - if (txn->kacc == SELF->key) { - GValue val = G_VALUE_INIT; - SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn)); - mXPUSHs(sv); - } ++ 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: - RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY)); ++ 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(list); ++ 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); + diff --cc src/hb-account.c index c3366e7,56b5339..9064868 --- a/src/hb-account.c +++ b/src/hb-account.c @@@ -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->notes); + + g_queue_free (item->txn_queue); + - g_free(item); + rc_free(item); } } @@@ -78,8 -59,12 +62,12 @@@ 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; } diff --cc src/hb-archive.c index e3faf5d,c552f85..d815703 --- a/src/hb-archive.c +++ b/src/hb-archive.c @@@ -19,10 -19,8 +19,11 @@@ #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); + da_splits_free(item->splits); + //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared + - g_free(item); + rc_free(item); } } diff --cc src/hb-assign.c index 8303436,93fd2da..951cf92 --- a/src/hb-assign.c +++ b/src/hb-assign.c @@@ -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); } } diff --cc src/hb-preferences.c index e7695bc,5bf8234..d257ca7 --- a/src/hb-preferences.c +++ b/src/hb-preferences.c @@@ -400,24 -427,6 +430,23 @@@ gint i PREFS->vehicle_unit_ismile = FALSE; PREFS->vehicle_unit_isgal = FALSE; + gchar** plugin_path = g_new0(gchar**, 4); + i = 0; + const gchar* env = g_getenv("HOMEBANK_PLUGINS"); + if (env) { + if (g_path_is_absolute(env)) { + plugin_path[i++] = g_strdup(env); + } else { + gchar* cur = g_get_current_dir(); + plugin_path[i++] = g_build_filename(cur, env, NULL); + g_free(cur); + } + } + plugin_path[i++] = g_build_filename(homebank_app_get_config_dir(), "plugins", NULL); + plugin_path[i++] = g_build_filename(homebank_app_get_pkglib_dir(), "plugins", NULL); + PREFS->ext_path = plugin_path; + PREFS->ext_whitelist = NULL; + - _homebank_pref_createformat(); _homebank_pref_init_measurement_units(); } diff --cc src/hb-transaction.c index 1d66998,2758da6..17fbad5 --- a/src/hb-transaction.c +++ b/src/hb-transaction.c @@@ -21,12 -21,10 +21,13 @@@ #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 9db1e30,2338e58..68768fa --- a/src/hb-xml.c +++ b/src/hb-xml.c @@@ -23,8 -23,8 +23,10 @@@ #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; + GValue filename_val = G_VALUE_INIT; + ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL); + - io = g_io_channel_new_file(filename, "w", 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 106b8ec,421d0ef..c8a6895 --- a/src/homebank.c +++ b/src/homebank.c @@@ -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); + 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 + #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); @@@ -674,8 -588,7 +597,8 @@@ 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))) @@@ -685,13 -598,12 +608,13 @@@ } #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(); @@@ -1166,17 -1048,11 +1079,18 @@@ /* update the mainwin display */ ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL)); + ext_hook("enter_main_loop", NULL); + - DB( g_print(" -> gtk_main()\n" ) ); + 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/ui-pref.c index 4cc1eeb,5a63a49..fa7f906 --- a/src/ui-pref.c +++ b/src/ui-pref.c @@@ -24,8 -24,9 +24,11 @@@ #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("%s", name); + gchar* tooltip = g_strdup_printf("%s", 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%s: %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%s: %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 47c0b01,afd529e..1eb95f1 --- a/src/ui-pref.h +++ b/src/ui-pref.h @@@ -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; + GtkWidget *PI_plugin_columns; +}; + +enum +{ + PREF_GENERAL, + PREF_INTERFACE, - PREF_COLUMNS, - PREF_DISPLAY, - PREF_IMPORT, ++ PREF_TRANSACTIONS, ++ PREF_DISPLAY_FORMAT, ++ PREF_IMPORT_EXPORT, + PREF_REPORT, - PREF_EURO, ++ PREF_EURO_MINOR, + PREF_PLUGINS, + PREF_MAX }; diff --cc themes/hicolor/Makefile.am index 0000000,a70b789..f5ac1b7 mode 000000,100644..100644 --- a/themes/hicolor/Makefile.am +++ b/themes/hicolor/Makefile.am @@@ -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 diff --cc themes/hicolor/hicolor_status_48x48_prf-plugins.png index 3950019,0000000..3950019 mode 100644,000000..100644 Binary files differ