# 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'
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)
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
--- /dev/null
- $self->create_menuitem;
-
+
+# NAME: Hello World
+# VERSION: 0.01
+# ABSTRACT: This is the "hello world" of HomeBank plugins.
+# AUTHOR: Charles McGarvey <chazmcgarvey@brokenzipper.com>
+# WEBSITE: http://acme.tld/
+# (These comments are read, before the plugin is executed, to provide some
+# information to HomeBank and the user about what this plugin is.)
+
+eval { HomeBank->version } or die "Cannot run outside of HomeBank";
+
+use warnings;
+use strict;
+
+use Scalar::Util qw/weaken/;
+
+#use Moose;
+
+#has "cool_beans",
+ #is => 'rw',
+ #isa => 'Str',
+ #lazy => 1,
+ #default => "Booya!!!";
+
+
+our $counter = 0;
+our $temp;
+
+my $ACC;
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new(@_);
+
+ $self->on(account_inserted => sub {
+ my $acc = shift;
+ print "account inserted: ", Dumper($acc);
+ print "account name is ", $acc->name, " and balance is ", $acc->bank_balance, "\n";
+ #$acc->name("FOOOOBAR!");
+ if ($acc->name eq 'Vacation') {
+ $acc->remove;
+ $ACC = $acc;
+ }
+ print Dumper($acc->is_inserted);
+ if ($acc->is_inserted) {
+ print "IT IS INSERTED\n";
+ } else {
+ print "not inserted\n";
+ }
+ print Dumper($acc->transactions);
+ });
+
+ #print $self->cool_beans, "\n";
+ #$self->cool_beans(123);
+ #print $self->cool_beans, "\n";
+
- require Gtk2;
+ $self;
+}
+
+sub on_create_main_window {
+ my $self = shift;
+ my $window = shift;
+
+ if (!$window) {
-
- $self->create_menuitem;
++ require Gtk3;
+ $window = HomeBank->main_window;
+ }
+
+ Dump($window);
+ print Dumper($window);
+ $window->set_title("foo bar baz");
+ print $window->get_title, "\n";
+
+ HomeBank->hook("my_hook", $window);
- require Gtk2;
+}
+
+my $test_win;
+
+sub on_test {
+ my $self = shift;
- my $window = Gtk2::Window->new('toplevel');
++ require Gtk3;
+
- #$window->signal_connect(delete_event => sub { Gtk2->main_quit });
++ my $window = Gtk3::Window->new('toplevel');
+ use Devel::Peek;
+ Dump($window);
+ print Dumper($window);
+ $window->set_title("Hello World");
- my $button = Gtk2::Button->new('Click Me!');
++ #$window->signal_connect(delete_event => sub { Gtk3->main_quit });
+ $window->signal_connect(delete_event => sub { undef $test_win });
+
- print "Hello Gtk2-Perl: $counter (perl plugin: $self)\n";
++ my $button = Gtk3::Button->new('Click Me!');
+ Dump($button);
+ print Dumper($button);
+ $button->signal_connect(clicked => sub {
- #require Gtk2;
++ print "Hello Gtk3-Perl: $counter (perl plugin: $self)\n";
+ $counter++;
+ #if ($temp->is_inserted) {
+ #print "$temp is inserted\n";
+ #} else {
+ #print "$temp is NOT inserted\n";
+ #}
+ #if ($counter == 5) {
+ #$temp = undef;
+ #}
+ my $acc = HomeBank::Account->get(rand(10));
+ print "Changin account named ", $acc->name, " to ", $acc->name($acc), "\n";
+ HomeBank->main_window->queue_draw;
+
+ });
+ $window->add($button);
+
+ $window->show_all;
+ $test_win = $window;
+
+ weaken $self;
+}
+
+sub on_enter_main_loop {
+ my $self = shift;
+
+ use Data::Dumper;
+ print Dumper(\@_);
+ my $t = HomeBank::Transaction->new;
+ print "Transaction:::::::: $t: ", $t->amount, "\n";
+
+ $temp = HomeBank::Account->get(7);
+ print "retained account: ", $temp->name, "\n";
+
- sub on_main_window_disposal {
- my $self = shift;
- print "main window disposed so forgetting about merge id et al.\n";
- delete $self->{merge_id};
- delete $self->{action_group};
- }
-
++ #require Gtk3;
+ #
+ my $txn = HomeBank::Transaction->new;
+ $txn->amount(12.3456);
+ print Dumper($txn), $txn->amount, "\n";
+ #$txn->open;
+
+ my @ret = HomeBank->hook("my_hook", @_, $temp, [qw/foo bar baz/, $txn], { asf => 42, quux => \1, meh => HomeBank->main_window });
+ #my @ret = HomeBank->hook("my_hook", @_, HomeBank->main_window, {
+ #foo => 'bar', baz => 42
+ #});
+ print Dumper(\@ret);
+
+ print "adding back account...\n";
+ $ACC->name("vacation with a different name");
+ $ACC->insert;
+ HomeBank::Account->compute_balances;
+ print "account name is ", $ACC->name, " and balance is ", $ACC->balance, "\n";
+ print Dumper($ACC->transactions);
+
+ my $cloned = $ACC->clone;
+ $cloned->name("vacation copy");
+ $cloned->insert;
+ #my $asdf = $cloned->open;
+ #$asdf->set_title("this is a new friggin account");
+
+ #my $z = HomeBank::Account->get_by_name('Checking');
+ for my $xc (HomeBank::File->transactions) {
+ use DateTime;
+ my $num = $xc->date;
+ my $date = DateTime->new($xc->date)->datetime;
+ print "transaction of amount: ", $xc->amount, "\t", $xc->wording, ", ", $xc->info, ", $num, $date\n";
+ }
+
+ HomeBank::File->owner('Billy Murphy');
+ #HomeBank::File->anonymize;
+ print HomeBank::File->owner, "\n";
+
+ HomeBank::File->baz($ACC);
+}
+
+sub on_deep_hook_recursion {
+ my $self = shift;
+ my $level = shift;
+ print STDERR "recursion is too deep ($level)\n";
+ exit -2;
+}
+
+sub on_my_hook {
+ my $self = shift;
+ print "This is MY HOOK!!!!!!\n";
+ print Dumper(\@_);
+
+ print Dumper($_[2]);
+ Dump($_[2]);
+ if ($_[2]) {
+ print "meh\n";
+ }
+ if ($_[2]->isa('HomeBank::Boolean')) {
+ print "it is a home;;boolean\n";
+ }
+ if ($_[2]->isa('Types::Serialiser::Boolean')) {
+ print "it is a types serialiser thingy\n";
+ }
+ if ($_[2]->isa('HomeBank::BooleanBase')) {
+ print "it is a base bool\n";
+ }
+
+ my $win = $_[6];
+ if ($win && ref($win) eq 'HASH') {
+ my $w = $win->{meh};
+ if ($w) {
+ $w->set_title("this is MY HOOK setting a window title");
+ }
+ }
+ #print Dumper($acc);
+ #print "transferred account: ", $acc->name, "\n";
+
+ #my $fff = HomeBank::File->foo({foo => 'asdf', bar => 123456789});
+ my $fff = HomeBank::File->meh([qw/hello this is a test 82/, \1, {foo => 'bar'}, 48]);
+ print Dumper($fff);
+
+ print "my hook done\n";
+}
+
+sub on_unhandled {
+ my ($self, $hook) = @_;
+ warn "Unhandled hook '$hook'\n";
+ #HomeBank->warn($hook, 'Hook not handled.');
+}
+
-
- $self->destroy_menuitem;
- }
-
- sub destroy_menuitem {
- my $self = shift;
-
- return unless $self->{merge_id};
-
- my $ui_manager = HomeBank->main_ui_manager;
- $ui_manager->remove_action_group($self->{action_group});
- $ui_manager->remove_ui($self->{merge_id});
- }
-
- sub create_menuitem {
- my $self = shift;
-
- return if $self->{merge_id};
-
- require Gtk2;
-
- my $ui_manager = HomeBank->main_ui_manager;
- print Dumper($ui_manager);
- return unless $ui_manager;
-
- $self->{merge_id} = $ui_manager->new_merge_id;
- $self->{action_group} = Gtk2::ActionGroup->new('HelloActionGroup');
-
- my $action = Gtk2::Action->new(name => 'HelloPlugin', label => 'Booyah!', stock_id => 'prf-plugins', tooltip => 'blaaaargh');
- $action->signal_connect(activate => sub { print "hello!!!!!!!!\n" });
- $self->{action_group}->add_action($action);
-
- $ui_manager->insert_action_group($self->{action_group}, -1);
- $ui_manager->add_ui($self->{merge_id}, 'ui/MenuBar/PluginMenu', 'HelloPlugin', 'HelloPlugin', 'auto', '');
- #$self->{merge_id} = $ui_manager->new_merge_id;
- $ui_manager->add_ui($self->{merge_id}, 'ui/ToolBar', 'HelloPluginTool', 'HelloPlugin', 'auto', '');
+sub DESTROY {
+ my $self = shift;
+ print "DESTROYING HELLO WORLD!!!!!!\n";
+ if ($test_win) {
+ print "there is a test_win...\n";
+ }
+ $test_win->destroy if $test_win;
+}
+
+sub EXECUTE {
+ print "the perl plugin is being configured.....\n";
+ HomeBank->info("Hello Prefs", "YEEEEEARGGH!!!!!");
+}
+
+#__PACKAGE__->meta->make_immutable;
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
+
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);
static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data);
void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data);
- static void ui_mainwindow_showprefs(gint page);
+ void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
++static void ui_mainwindow_showprefs(gint page);
+
extern gchar *CYA_ACC_TYPE[];
+ gchar *CYA_CATSUBCAT[] = {
+ N_("Category"),
+ N_("Subcategory"),
+ NULL
+ };
+
+
static GtkActionEntry entries[] = {
- /* name, stock id, label */
+ /* name, icon-name, label */
- { "FileMenu" , NULL, N_("_File"), NULL, NULL, NULL },
- { "EditMenu" , NULL, N_("_Edit"), NULL, NULL, NULL },
- { "ViewMenu" , NULL, N_("_View"), NULL, NULL, NULL },
- { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL },
- { "TransactionMenu", NULL, N_("_Transactions"), NULL, NULL, NULL },
- { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL },
- { "PluginMenu" , NULL, N_("_Plugins"), NULL, NULL, NULL },
- { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL },
+ { "FileMenu" , NULL, N_("_File"), NULL, NULL, NULL },
+ { "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL },
+ { "EditMenu" , NULL, N_("_Edit"), NULL, NULL, NULL },
+ { "ViewMenu" , NULL, N_("_View"), NULL, NULL, NULL },
+ { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL },
+ { "TxnMenu" , NULL, N_("_Transactions"), NULL, NULL, NULL },
+ { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL },
+ { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL },
++ { "PluginMenu" , NULL, N_("_Plugins"), NULL, NULL, NULL },
+ { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL },
// { "Import" , NULL, N_("Import") },
// { "Export" , NULL, N_("Export to") },
- /* name, stock id, label, accelerator, tooltip */
+ /* name, icon-name, label, accelerator, tooltip */
/* FileMenu */
- { "New" , GTK_STOCK_NEW , N_("_New") , NULL, N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) },
- { "Open" , GTK_STOCK_OPEN , N_("_Open...") , NULL, N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) },
- { "Save" , GTK_STOCK_SAVE , N_("_Save") , NULL, N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) },
- { "SaveAs" , GTK_STOCK_SAVE_AS , N_("Save As...") , "<shift><control>S", N_("Save the current file with a different name"), G_CALLBACK (ui_mainwindow_action_saveas) },
- { "Revert" , GTK_STOCK_REVERT_TO_SAVED, N_("Revert") , NULL, N_("Revert to a saved version of this file"), G_CALLBACK (ui_mainwindow_action_revert) },
+ { "New" , ICONNAME_NEW , N_("_New") , "<control>N", N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) },
+ { "Open" , ICONNAME_OPEN , N_("_Open...") , "<control>O", N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) },
+ { "Save" , ICONNAME_SAVE , N_("_Save") , "<control>S", N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) },
+ { "SaveAs" , ICONNAME_SAVE_AS , N_("Save _As...") , "<shift><control>S", N_("Save the current file with a different name"), G_CALLBACK (ui_mainwindow_action_saveas) },
+ { "Revert" , ICONNAME_REVERT , N_("Revert") , NULL, N_("Revert to a saved version of this file"), G_CALLBACK (ui_mainwindow_action_revert) },
- { "Properties" , GTK_STOCK_PROPERTIES , N_("_Properties..."), NULL, N_("Configure the file"), G_CALLBACK (ui_mainwindow_action_properties) },
- { "Close" , GTK_STOCK_CLOSE , N_("_Close") , NULL, N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) },
- { "Quit" , GTK_STOCK_QUIT , N_("_Quit") , NULL, N_("Quit homebank"), G_CALLBACK (ui_mainwindow_action_quit) },
+ { "Properties" , ICONNAME_PROPERTIES , N_("Properties..."), NULL, N_("Configure the file"), G_CALLBACK (ui_mainwindow_action_properties) },
+ { "Close" , ICONNAME_CLOSE , N_("_Close") , "<control>W", N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) },
+ { "Quit" , ICONNAME_QUIT , N_("_Quit") , "<control>Q", N_("Quit HomeBank"), G_CALLBACK (ui_mainwindow_action_quit) },
/* Exchange */
- { "FileImport" , "hb-file-import" , N_("Import QIF/OFX/CSV...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
- { "ExportQIF" , "hb-file-export" , N_("Export QIF...") , NULL, N_("Open the export to QIF assistant"), G_CALLBACK (ui_mainwindow_action_export) },
- { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) },
+ { "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
+ { "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
+ { "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
+
+ { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export QIF file...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) },
/* EditMenu */
- { "Preferences", GTK_STOCK_PREFERENCES, N_("Preferences..."), NULL, N_("Configure homebank"), G_CALLBACK (ui_mainwindow_action_preferences) },
+ { "Preferences", ICONNAME_PREFERENCES , N_("Preferences..."), NULL, N_("Configure HomeBank"), G_CALLBACK (ui_mainwindow_action_preferences) },
/* ManageMenu */
- // { "Currency" , "hb-currency" , N_("Currencies...") , NULL, N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) },
- { "Account" , "hb-account" , N_("Acc_ounts...") , NULL, N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) },
- { "Payee" , "hb-payee" , N_("_Payees...") , NULL, N_("Configure the payees"), G_CALLBACK (ui_mainwindow_action_defpayee) },
- { "Category" , "hb-category" , N_("Categories...") , NULL, N_("Configure the categories"), G_CALLBACK (ui_mainwindow_action_defcategory) },
- { "Archive" , "hb-archive" , N_("Scheduled/Template...") , NULL, N_("Configure the scheduled/template transactions"), G_CALLBACK (ui_mainwindow_action_defarchive) },
- { "Budget" , "hb-budget" , N_("Budget...") , NULL, N_("Configure the budget"), G_CALLBACK (ui_mainwindow_action_defbudget) },
- { "Assign" , "hb-assign" , N_("Assignments..."), NULL, N_("Configure the automatic assignments"), G_CALLBACK (ui_mainwindow_action_defassign) },
-
- /* TransactionMenu */
- { "ShowOpe" , HB_STOCK_OPE_SHOW, N_("Show...") , NULL, N_("Shows selected account transactions"), G_CALLBACK (ui_mainwindow_action_showtransactions) },
- { "AddOpe" , HB_STOCK_OPE_ADD , N_("Add...") , NULL, N_("Add transaction"), G_CALLBACK (ui_mainwindow_action_addtransactions) },
- { "Scheduler" , NULL , N_("Set scheduler...") , NULL, N_("Configure the transaction scheduler"), G_CALLBACK (ui_mainwindow_action_properties) },
- { "AddScheduled" , NULL , N_("Process scheduled..."), NULL, N_("Insert pending scheduled transactions"), G_CALLBACK (ui_mainwindow_action_checkscheduled) },
+ { "Currency" , ICONNAME_HB_CURRENCY , N_("Currencies...") , NULL, N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) },
+ { "Account" , ICONNAME_HB_ACCOUNT , N_("Acc_ounts...") , NULL, N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) },
+ { "Payee" , ICONNAME_HB_PAYEE , N_("_Payees...") , NULL, N_("Configure the payees"), G_CALLBACK (ui_mainwindow_action_defpayee) },
+ { "Category" , ICONNAME_HB_CATEGORY , N_("Categories...") , NULL, N_("Configure the categories"), G_CALLBACK (ui_mainwindow_action_defcategory) },
+ { "Archive" , ICONNAME_HB_ARCHIVE , N_("Scheduled/Template...") , NULL, N_("Configure the scheduled/template transactions"), G_CALLBACK (ui_mainwindow_action_defarchive) },
+ { "Budget" , ICONNAME_HB_BUDGET , N_("Budget...") , NULL, N_("Configure the budget"), G_CALLBACK (ui_mainwindow_action_defbudget) },
+ { "Assign" , ICONNAME_HB_ASSIGN , N_("Assignments..."), NULL, N_("Configure the automatic assignments"), G_CALLBACK (ui_mainwindow_action_defassign) },
+
+ /* TxnMenu */
+ { "ShowOpe" , ICONNAME_HB_OPE_SHOW , N_("Show...") , NULL, N_("Shows selected account transactions"), G_CALLBACK (ui_mainwindow_action_showtransactions) },
+ { "AddOpe" , ICONNAME_HB_OPE_ADD , N_("Add...") , NULL, N_("Add transactions"), G_CALLBACK (ui_mainwindow_action_addtransactions) },
+ { "Scheduler" , NULL , N_("Set scheduler...") , NULL, N_("Configure the transaction scheduler"), G_CALLBACK (ui_mainwindow_action_properties) },
+ { "AddScheduled", NULL , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"), G_CALLBACK (ui_mainwindow_action_checkscheduled) },
/* ReportMenu */
- { "RStatistics" , HB_STOCK_REP_STATS , N_("_Statistics...") , NULL, N_("Open the Statistics report"), G_CALLBACK (ui_mainwindow_action_statistic) },
- { "RTrendTime" , HB_STOCK_REP_TIME , N_("_Trend Time...") , NULL, N_("Open the Trend Time report"), G_CALLBACK (ui_mainwindow_action_trendtime) },
- { "RBudget" , HB_STOCK_REP_BUDGET, N_("B_udget...") , NULL, N_("Open the Budget report"), G_CALLBACK (ui_mainwindow_action_budget) },
- { "RBalance" , HB_STOCK_REP_BALANCE, N_("Balance...") , NULL, N_("Open the Balance report"), G_CALLBACK (ui_mainwindow_action_balance) },
- { "RVehiculeCost" , HB_STOCK_REP_CAR , N_("_Vehicle cost...") , NULL, N_("Open the Vehicle cost report"), G_CALLBACK (ui_mainwindow_action_vehiclecost) },
-
+ { "RStatistics" , ICONNAME_HB_REP_STATS , N_("_Statistics...") , NULL, N_("Open the Statistics report"), G_CALLBACK (ui_mainwindow_action_statistic) },
+ { "RTrendTime" , ICONNAME_HB_REP_TIME , N_("_Trend Time...") , NULL, N_("Open the Trend Time report"), G_CALLBACK (ui_mainwindow_action_trendtime) },
+ { "RBudget" , ICONNAME_HB_REP_BUDGET , N_("B_udget...") , NULL, N_("Open the Budget report"), G_CALLBACK (ui_mainwindow_action_budget) },
+ { "RBalance" , ICONNAME_HB_REP_BALANCE, N_("Balance...") , NULL, N_("Open the Balance report"), G_CALLBACK (ui_mainwindow_action_balance) },
+ { "RVehiculeCost", ICONNAME_HB_REP_CAR , N_("_Vehicle cost...") , NULL, N_("Open the Vehicle cost report"), G_CALLBACK (ui_mainwindow_action_vehiclecost) },
+
+ /* Tools */
+ { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) },
+ { "FileStats" , NULL , N_("File statistics...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_file_statistics) },
+ { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) },
+
++ /* Plugins */
+ { "PluginPreferences", "prf-plugins", N_("_Plugins..."), "<control>U", N_("Configure plugin preferences"), G_CALLBACK(ui_mainwindow_action_pluginprefs) },
+
/* HelpMenu */
- { "Contents" , GTK_STOCK_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
- { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL , G_CALLBACK (ui_mainwindow_action_help_welcome) },
- { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
- { "Translate" , "lpi-translate" , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) },
- { "Problem" , "lpi-bug" , N_("Report a Problem...") , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) },
+ { "Contents" , ICONNAME_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
+ { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
+ { "Translate" , "lpi-translate" , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) },
+ { "Problem" , "lpi-bug" , N_("Report a Problem...") , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) },
- { "About" , GTK_STOCK_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) },
+ { "About" , ICONNAME_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) },
};
static guint n_entries = G_N_ELEMENTS (entries);
" <menuitem action='RBudget'/>"
" <menuitem action='RVehiculeCost'/>"
" </menu>"
+ " <menu action='ToolsMenu'>"
+ " <menuitem action='Welcome'/>"
+ " <menuitem action='FileStats'/>"
+ " <separator/>"
+ " <menuitem action='Anonymize'/>"
+ " </menu>"
+" <menu action='PluginMenu'>"
+" <separator/>"
+" <menuitem action='PluginPreferences'/>"
+" <separator/>"
+" </menu>"
" <menu action='HelpMenu'>"
" <menuitem action='Contents'/>"
" <separator/>"
//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();
--- /dev/null
- GList* list = g_list_first(GLOBALS->ope_list);
- for (; list; list = g_list_next(list)) {
- GValue val = G_VALUE_INIT;
- SV* sv = val_to_sv(EXT_TRANSACTION(&val, list->data));
- mXPUSHs(sv);
+
+#include <EXTERN.h>
+#include <perl.h>
+#include <XSUB.h>
+
+#include <string.h>
+
+#undef _
+#include "homebank.h"
+#include "ext.h"
+#include "refcount.h"
+
+extern struct HomeBank *GLOBALS;
+#include "dsp_mainwindow.h"
+#include "dsp_account.h"
+#include "ui-transaction.h"
+
+
+static gint ext_perl_init(int* argc, char** argv[], char** env[]);
+static void ext_perl_term(void);
+static gboolean ext_perl_check_file(const gchar* plugin_filepath);
+static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath);
+static gint ext_perl_load_plugin(const gchar* plugin_filepath);
+static void ext_perl_unload_plugin(const gchar* plugin_filepath);
+static void ext_perl_execute_action(const gchar* plugin_filepath);
+static void ext_perl_call_hook(const gchar* hook_id, GList* args);
+
+static SV* val_to_sv(GValue* val);
+static GValue* sv_to_val(SV* sv);
+
+static gboolean gperl_value_from_sv(GValue* value, SV* sv);
+static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed);
+
+
+static inline GValue* EXT_SV(GValue* v, SV* sv, GType type)
+{
+ g_value_init(v, type);
+ gperl_value_from_sv(v, sv);
+ return v;
+}
+
+
+#define EXT_P2C_OBJECT(PKG, ARG, VAR, TYP) \
+if (sv_derived_from(ARG, PKG)) { \
+ IV iv = SvIV((SV*)SvRV(ARG)); \
+ VAR = INT2PTR(TYP, iv); \
+} else { \
+ croak(#VAR" is not of type "PKG); \
+}
+
+#define EXT_C2P_OBJECT(PKG, ARG, VAR) \
+sv_setref_pv(ARG, PKG, (void*)VAR)
+
+
+static inline GPtrArray* SvGptrarray(const SV* sv)
+{
+ if (SvROK(sv)) {
+ sv = MUTABLE_SV(SvRV(sv));
+ }
+ if (SvTYPE(sv) == SVt_PVAV) {
+ AV* av = (AV*)sv;
+ int i;
+ int top = av_len(av);
+ GPtrArray* array = g_ptr_array_new();
+ for (i = 0; i <= top; ++i) {
+ SV** item = av_fetch(av, i, 0);
+ if (!item) continue;
+ g_ptr_array_add(array, sv_to_val(*item));
+ }
+ return array;
+ // TODO- leaking
+ } else {
+ croak("var is not an array");
+ }
+}
+
+static inline SV* newSVgptrarray(const GPtrArray* a)
+{
+ if (a) {
+ AV* av = newAV();
+ int i;
+ for (i = 0; i < a->len; ++i) {
+ GValue* item = g_ptr_array_index(a, i);
+ av_push(av, val_to_sv(item));
+ }
+ return newRV((SV*)av);
+ }
+ return &PL_sv_undef;
+}
+
+
+static inline GHashTable* SvGhashtable(const SV* sv)
+{
+ if (SvROK(sv)) {
+ sv = MUTABLE_SV(SvRV(sv));
+ }
+ if (SvTYPE(sv) == SVt_PVHV) {
+ HV* hv = (HV*)sv;
+ hv_iterinit(hv);
+ gchar* key;
+ I32 len;
+ SV* item;
+ GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);
+ while ((item = hv_iternextsv(hv, &key, &len))) {
+ g_hash_table_insert(hash, key, sv_to_val(item));
+ }
+ return hash;
+ // TODO- leaking
+ } else {
+ croak("var is not a hash");
+ }
+}
+
+static inline SV* newSVghashtable(GHashTable* h)
+{
+ if (h) {
+ HV* hv = newHV();
+ GHashTableIter it;
+ g_hash_table_iter_init(&it, h);
+ gchar* key = NULL;
+ GValue* item = NULL;
+ while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
+ hv_store(hv, key, -g_utf8_strlen(key, -1), val_to_sv(item), 0);
+ }
+ return newRV((SV*)hv);
+ }
+ return &PL_sv_undef;
+}
+
+
+static inline gboolean SvGboolean(SV* sv)
+{
+ if (!sv) {
+ return FALSE;
+ }
+ if (SvROK(sv)) {
+ return !!SvIV(SvRV(sv));
+ } else {
+ return SvTRUE(sv);
+ }
+}
+
+static inline SV* newSVgboolean(gboolean b)
+{
+ return sv_setref_iv(newSV(0), "HomeBank::Boolean", !!b);
+}
+
+
+static inline gchar* SvGchar_ptr(SV* sv)
+{
+ return SvPVutf8_nolen(sv);
+}
+
+static inline SV* newSVgchar_ptr(const gchar* str)
+{
+ if (!str) return &PL_sv_undef;
+
+ SV* sv = newSVpv(str, 0);
+ SvUTF8_on(sv);
+ return sv;
+}
+
+
+static inline GObject* SvGobject(const SV* sv)
+{
+ GObject* (*func)(const SV*) = ext_symbol_lookup("gperl_get_object");
+ if (func) {
+ return func(sv);
+ }
+ return NULL;
+}
+
+static inline SV* newSVgobject(const GObject* o)
+{
+ SV* (*func)(const GObject*, gboolean) = ext_symbol_lookup("gperl_new_object");
+ if (func) {
+ return func(o, FALSE);
+ }
+ return &PL_sv_undef;
+}
+
+
+static PerlInterpreter* context = NULL;
+
+
+static gint ext_perl_init(int* argc, char** argv[], char** env[])
+{
+ int ret = 0;
+
+ PERL_SYS_INIT3(argc, argv, env);
+ context = perl_alloc();
+ perl_construct(context);
+
+ PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+ PL_origalen = 1;
+ PL_perl_destruct_level = 1;
+
+ gchar* bootstrap = g_strdup_printf("-e"
+ "use lib '%s';"
+ "use HomeBank;"
+ "HomeBank->bootstrap;",
+ homebank_app_get_pkglib_dir());
+ char *args[] = { "", bootstrap };
+
+ EXTERN_C void xs_init(pTHX);
+ if (perl_parse(context, xs_init, 2, args, NULL) || perl_run(context)) {
+ ext_perl_term();
+ ret = -1;
+ }
+
+ g_free(bootstrap);
+ return ret;
+}
+
+static void ext_perl_term(void)
+{
+ if (context) {
+ perl_destruct(context);
+ perl_free(context);
+ context = NULL;
+ }
+ PERL_SYS_TERM();
+}
+
+static gboolean ext_perl_check_file(const gchar* plugin_filepath)
+{
+ if (g_str_has_suffix(plugin_filepath, ".pl")) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static GHashTable* ext_perl_read_plugin_metadata(const gchar* plugin_filepath)
+{
+ GHashTable* table = NULL;
+
+ if (!context) return NULL;
+ PERL_SET_CONTEXT(context);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ mXPUSHs(newSVgchar_ptr(plugin_filepath));
+ PUTBACK;
+
+ int ret = call_pv("HomeBank::read_metadata", G_SCALAR | G_EVAL);
+
+ SPAGAIN;
+
+ if (ret == 1) {
+ table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ SV* sv = POPs;
+ if (SvROK(sv)) {
+ sv = MUTABLE_SV(SvRV(sv));
+ }
+ if (SvTYPE(sv) == SVt_PVHV) {
+ HV* hv = (HV*)sv;
+ hv_iterinit(hv);
+ gchar* key;
+ I32 len;
+ SV* item;
+ while ((item = hv_iternextsv(hv, &key, &len))) {
+ if (SvPOK(item)) {
+ gchar* val = SvPVutf8_nolen(item);
+ g_hash_table_insert(table, g_strdup(key), g_strdup(val));
+ }
+ }
+ }
+ }
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ return table;
+}
+
+static gint ext_perl_load_plugin(const gchar* plugin_filepath)
+{
+ if (!context) return -1;
+ PERL_SET_CONTEXT(context);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ mXPUSHs(newSVgchar_ptr(plugin_filepath));
+ PUTBACK;
+ call_pv("HomeBank::load_plugin", G_DISCARD | G_EVAL);
+ SPAGAIN;
+
+ gint ret = 0;
+ if (SvTRUE(ERRSV)) {
+ g_printerr("%s", SvPV_nolen(ERRSV));
+ ret = -1;
+ }
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ return ret;
+}
+
+static void ext_perl_unload_plugin(const gchar* plugin_filepath)
+{
+ if (!context) return;
+ PERL_SET_CONTEXT(context);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ mXPUSHs(newSVgchar_ptr(plugin_filepath));
+ PUTBACK;
+ call_pv("HomeBank::unload_plugin", G_DISCARD | G_EVAL);
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ g_printerr("%s", SvPV_nolen(ERRSV));
+ }
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+}
+
+static void ext_perl_execute_action(const gchar* plugin_filepath)
+{
+ if (!context) return;
+ PERL_SET_CONTEXT(context);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ mXPUSHs(newSVgchar_ptr(plugin_filepath));
+ PUTBACK;
+ call_pv("HomeBank::execute_action", G_DISCARD | G_EVAL);
+ SPAGAIN;
+
+ if (SvTRUE(ERRSV)) {
+ g_printerr("%s", SvPV_nolen(ERRSV));
+ }
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+}
+
+static void ext_perl_call_hook(const gchar* hook_id, GList* args)
+{
+ if (!context) return;
+ PERL_SET_CONTEXT(context);
+
+ dSP;
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ mXPUSHs(newSVgchar_ptr(hook_id));
+
+ GList *list = g_list_first(args);
+ while (list) {
+ GValue* val = list->data;
+ XPUSHs(sv_2mortal(val_to_sv(val)));
+ list = g_list_next(list);
+ }
+
+ PUTBACK;
+ call_pv("HomeBank::call_hook", G_ARRAY);
+ SPAGAIN;
+ POPi;
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+}
+
+
+static SV* val_to_sv(GValue* val)
+{
+ if (!val || !G_IS_VALUE(val) || G_VALUE_TYPE(val) == G_TYPE_NONE) {
+ return &PL_sv_undef;
+ }
+ if (G_VALUE_TYPE(val) == G_TYPE_BOOLEAN) {
+ return newSVgboolean(g_value_get_boolean(val));
+ }
+ if (G_VALUE_TYPE(val) == G_TYPE_PTR_ARRAY) {
+ return newSVgptrarray((GPtrArray*)g_value_get_boxed(val));
+ }
+ if (G_VALUE_TYPE(val) == G_TYPE_HASH_TABLE) {
+ return newSVghashtable((GHashTable*)g_value_get_boxed(val));
+ }
+#define obj(CTYPE, _2, PART, GTYPE, _5) \
+ if (G_VALUE_TYPE(val) == GTYPE) { \
+ SV* sv = newSV(0); \
+ CTYPE* ptr = (CTYPE*)g_value_get_##PART(val); \
+ EXT_C2P_OBJECT("HomeBank::"#CTYPE, sv, rc_ref(ptr)); \
+ return sv; \
+ }
+#include "ext-value.h"
+#undef obj
+ return gperl_sv_from_value(val, FALSE);
+}
+
+static GValue* sv_to_val(SV* sv)
+{
+ GValue* val = g_new0(GValue, 1);
+
+ if (SvUOK(sv)) return EXT_SV(val, sv, G_TYPE_UINT);
+ if (SvIOK(sv)) return EXT_SV(val, sv, G_TYPE_INT);
+ if (SvNOK(sv)) return EXT_SV(val, sv, G_TYPE_DOUBLE);
+ if (SvPOK(sv)) return EXT_SV(val, sv, G_TYPE_STRING);
+ if (sv_isobject(sv)) {
+ if (sv_derived_from(sv, "HomeBank::Boolean")) {
+ return EXT_BOOLEAN(val, SvGboolean(sv));
+ }
+#define obj(CTYPE, NAME, _3, _4, _5) \
+ if (sv_derived_from(sv, "HomeBank::"#CTYPE)) { \
+ CTYPE* ptr; \
+ EXT_P2C_OBJECT("HomeBank::"#CTYPE, sv, ptr, CTYPE*); \
+ return EXT_##NAME(val, ptr); \
+ }
+#include "ext-value.h"
+#undef obj
+ return EXT_SV(val, sv, G_TYPE_OBJECT);
+ }
+ if (SvROK(sv)) {
+ sv = SvRV(sv);
+ switch (SvTYPE(sv)) {
+ case SVt_IV:
+ return EXT_BOOLEAN(val, SvGboolean(sv));
+ case SVt_PVAV:
+ return EXT_ARRAY(val, SvGptrarray(sv));
+ case SVt_PVHV:
+ return EXT_HASH_TABLE(val, SvGhashtable(sv));
+ default:
+ break;
+ }
+ }
+ switch (SvTYPE(sv)) {
+ case SVt_PVAV:
+ return EXT_ARRAY(val, SvGptrarray(sv));
+ case SVt_PVHV:
+ return EXT_HASH_TABLE(val, SvGhashtable(sv));
+ default:
+ break;
+ }
+
+ g_free(val);
+ return NULL;
+}
+
+
+static gboolean gperl_value_from_sv(GValue* value, SV* sv)
+{
+ gboolean (*func)(GValue*, SV*) = ext_symbol_lookup("gperl_value_from_sv");
+ if (func) return func(value, sv);
+
+ GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+ if (!SvOK(sv)) return TRUE;
+ switch (type) {
+ case G_TYPE_CHAR:
+ {
+ gchar *tmp = SvGchar_ptr(sv);
+ g_value_set_schar(value, (gint8)(tmp ? tmp[0] : 0));
+ break;
+ }
+ case G_TYPE_UCHAR:
+ {
+ char *tmp = SvPV_nolen(sv);
+ g_value_set_uchar(value, (guchar)(tmp ? tmp[0] : 0));
+ break;
+ }
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean(value, SvTRUE(sv));
+ break;
+ case G_TYPE_INT:
+ g_value_set_int(value, SvIV(sv));
+ break;
+ case G_TYPE_UINT:
+ g_value_set_uint(value, SvIV(sv));
+ break;
+ case G_TYPE_LONG:
+ g_value_set_long(value, SvIV(sv));
+ break;
+ case G_TYPE_ULONG:
+ g_value_set_ulong(value, SvIV(sv));
+ break;
+ case G_TYPE_FLOAT:
+ g_value_set_float(value, (gfloat)SvNV(sv));
+ break;
+ case G_TYPE_DOUBLE:
+ g_value_set_double(value, SvNV(sv));
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string(value, SvGchar_ptr(sv));
+ break;
+ }
+ return TRUE;
+}
+
+static SV* gperl_sv_from_value(const GValue* value, gboolean copy_boxed)
+{
+ SV* (*func)(const GValue*, gboolean) = ext_symbol_lookup("gperl_sv_from_value");
+ if (func) return func(value, copy_boxed);
+
+ GType type = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
+ switch (type) {
+ case G_TYPE_CHAR:
+ return newSViv(g_value_get_schar(value));
+ case G_TYPE_UCHAR:
+ return newSVuv(g_value_get_uchar(value));
+ case G_TYPE_BOOLEAN:
+ return newSViv(g_value_get_boolean(value));
+ case G_TYPE_INT:
+ return newSViv(g_value_get_int(value));
+ case G_TYPE_UINT:
+ return newSVuv(g_value_get_uint(value));
+ case G_TYPE_LONG:
+ return newSViv(g_value_get_long(value));
+ case G_TYPE_ULONG:
+ return newSVuv(g_value_get_ulong(value));
+ case G_TYPE_FLOAT:
+ return newSVnv(g_value_get_float(value));
+ case G_TYPE_DOUBLE:
+ return newSVnv(g_value_get_double(value));
+ case G_TYPE_STRING:
+ return newSVgchar_ptr(g_value_get_string(value));
+ }
+ return &PL_sv_undef;
+}
+
+
+static void _register(void) __attribute__((constructor));
+static void _register()
+{
+ ext_register("perl",
+ ext_perl_init,
+ ext_perl_term,
+ ext_perl_check_file,
+ ext_perl_read_plugin_metadata,
+ ext_perl_load_plugin,
+ ext_perl_unload_plugin,
+ ext_perl_execute_action,
+ ext_perl_call_hook);
+}
+
+
+MODULE = HomeBank PACKAGE = HomeBank
+
+PROTOTYPES: ENABLE
+
+const gchar*
+version(void)
+ CODE:
+ RETVAL = VERSION;
+ OUTPUT:
+ RETVAL
+
+const gchar*
+config_dir(void)
+ CODE:
+ RETVAL = homebank_app_get_config_dir();
+ OUTPUT:
+ RETVAL
+
+gboolean
+has(const gchar* CLASS, ...)
+ PREINIT:
+ int i;
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ RETVAL = TRUE;
+ for (i = 1; i < items; ++i) {
+ gchar* feature = SvGchar_ptr(ST(i));
+ if (!feature || !ext_has(feature)) {
+ RETVAL = FALSE;
+ break;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+GObject*
+main_window(void)
+ CODE:
+ RETVAL = G_OBJECT(GLOBALS->mainwindow);
+ OUTPUT:
+ RETVAL
+
+GObject*
+main_ui_manager(void)
+ PREINIT:
+ struct hbfile_data *data;
+ CODE:
+ RETVAL = NULL;
+ if (GLOBALS->mainwindow) {
+ data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(GLOBALS->mainwindow, GTK_TYPE_WINDOW)), "inst_data");
+ if (data) {
+ RETVAL = G_OBJECT(data->manager);
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+void
+info(const gchar* CLASS, const gchar* title, const gchar* text)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ ext_run_modal(title, text, "info");
+
+void
+warn(const gchar* CLASS, const gchar* title, const gchar* text)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ ext_run_modal(title, text, "warn");
+
+void
+error(const gchar* CLASS, const gchar* title, const gchar* text)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ ext_run_modal(title, text, "error");
+
+void
+hook(const gchar* CLASS, const gchar* hook_name, ...)
+ PREINIT:
+ int i;
+ GList* list = NULL;
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ for (i = 2; i < items; ++i) {
+ SV* sv = ST(i);
+ GValue *val = sv_to_val(sv);
+ list = g_list_append(list, val);
+ }
+ CLEANUP:
+ ext_vhook(hook_name, list);
+ g_list_free(list);
+ // TODO free all the things
+
+GObject*
+open_prefs(const gchar* CLASS)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ RETVAL = G_OBJECT(defpref_dialog_new(PREF_GENERAL));
+ OUTPUT:
+ RETVAL
+
+
+MODULE = HomeBank PACKAGE = HomeBank::File
+
+const gchar*
+owner(const gchar* CLASS, ...)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ if (1 < items) {
+ hbfile_change_owner(g_strdup(SvGchar_ptr(ST(1))));
+ }
+ RETVAL = GLOBALS->owner;
+ OUTPUT:
+ RETVAL
+
+void
+transactions(const gchar* CLASS)
+ PPCODE:
+ PERL_UNUSED_ARG(CLASS);
- Account*
- clone(Account* SELF)
- CODE:
- RETVAL = da_acc_clone(SELF);
- RETVAL->key = 0;
- OUTPUT:
- RETVAL
-
++
++ GList* acc_list = g_hash_table_get_values(GLOBALS->h_acc);
++ GList* acc_link = g_list_first(acc_list);
++ for (; acc_link; acc_link = g_list_next(acc_link)) {
++ Account *acc = acc_link->data;
++
++ GList* txn_link = g_queue_peek_head_link(acc->txn_queue);
++ for (; txn_link; txn_link = g_list_next(txn_link)) {
++ Transaction* txn = txn_link->data;
++
++ GValue val = G_VALUE_INIT;
++ SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
++ mXPUSHs(sv);
++ }
+ }
+
++ g_list_free(acc_list);
++
+void
+anonymize(void)
+ CODE:
+ hbfile_anonymize();
+
+void
+baz(const gchar* CLASS, Account* account)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ g_print("hello: %s\n", account->name);
+
+GPtrArray*
+meh(const gchar* CLASS, GPtrArray* asdf)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
+ if (asdf) {
+ ;
+ } else {
+ g_print("the array is nil\n");
+ }
+ RETVAL = asdf;
+ OUTPUT:
+ RETVAL
+ CLEANUP:
+ g_ptr_array_unref(asdf);
+
+GHashTable*
+foo(const gchar* CLASS, GHashTable* asdf)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ g_print("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW\n");
+ if (asdf) {
+ GHashTableIter it;
+ g_hash_table_iter_init(&it, asdf);
+ gchar* key = NULL;
+ GValue* item = NULL;
+ while (g_hash_table_iter_next(&it, (gpointer*)&key, (gpointer*)&item)) {
+ g_print("hash with key: %s\n", key);
+ }
+ } else {
+ g_print("the hash is nil\n");
+ }
+ RETVAL = asdf;
+ OUTPUT:
+ RETVAL
+ CLEANUP:
+ g_hash_table_unref(asdf);
+
+
+MODULE = HomeBank PACKAGE = HomeBank::Account
+
+void
+compute_balances(const gchar* CLASS)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ account_compute_balances();
+
+Account*
+new(void)
+ CODE:
+ RETVAL = da_acc_malloc();
+ OUTPUT:
+ RETVAL
+
- GList* list = g_list_first(GLOBALS->ope_list);
+void
+DESTROY(Account* SELF)
+ CODE:
+ da_acc_free(SELF);
+
+Account*
+get(const gchar* CLASS, guint key)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ RETVAL = rc_ref(da_acc_get(key));
+ OUTPUT:
+ RETVAL
+
+Account*
+get_by_name(const gchar* CLASS, const gchar* name)
+ CODE:
+ PERL_UNUSED_ARG(CLASS);
+ RETVAL = rc_ref(da_acc_get_by_name((gchar*)name));
+ OUTPUT:
+ RETVAL
+
+const gchar*
+name(Account* SELF, ...)
+ CODE:
+ if (1 < items) {
+ account_rename(SELF, SvGchar_ptr(ST(1)));
+ }
+ RETVAL = SELF->name;
+ OUTPUT:
+ RETVAL
+
+const gchar*
+number(Account* SELF, ...)
+ CODE:
+ if (1 < items) {
+ g_free(SELF->number);
+ SELF->number = g_strdup(SvGchar_ptr(ST(1)));
+ }
+ RETVAL = SELF->number;
+ OUTPUT:
+ RETVAL
+
+const gchar*
+bankname(Account* SELF, ...)
+ CODE:
+ if (1 < items) {
+ g_free(SELF->bankname);
+ SELF->bankname = g_strdup(SvGchar_ptr(ST(1)));
+ }
+ RETVAL = SELF->bankname;
+ OUTPUT:
+ RETVAL
+
+gdouble
+initial(Account* SELF, ...)
+ CODE:
+ if (1 < items) {
+ SELF->initial = SvNV(ST(1));
+ }
+ RETVAL = SELF->initial;
+ OUTPUT:
+ RETVAL
+
+gdouble
+minimum(Account* SELF, ...)
+ CODE:
+ if (1 < items) {
+ SELF->minimum = SvNV(ST(1));
+ }
+ RETVAL = SELF->minimum;
+ OUTPUT:
+ RETVAL
+
+guint
+cheque1(Account* SELF, ...)
+ ALIAS:
+ check1 = 1
+ CODE:
+ PERL_UNUSED_VAR(ix);
+ if (1 < items) {
+ SELF->cheque1 = SvUV(ST(1));
+ }
+ RETVAL = SELF->cheque1;
+ OUTPUT:
+ RETVAL
+
+guint
+cheque2(Account* SELF, ...)
+ ALIAS:
+ check2 = 1
+ CODE:
+ PERL_UNUSED_VAR(ix);
+ if (1 < items) {
+ SELF->cheque2 = SvUV(ST(1));
+ }
+ RETVAL = SELF->cheque2;
+ OUTPUT:
+ RETVAL
+
+gdouble
+balance(Account* SELF)
+ ALIAS:
+ bank_balance = 1
+ future_balance = 2
+ CODE:
+ switch (ix) {
+ case 1:
+ RETVAL = SELF->bal_bank;
+ break;
+ case 2:
+ RETVAL = SELF->bal_future;
+ break;
+ default:
+ RETVAL = SELF->bal_today;
+ break;
+ }
+ OUTPUT:
+ RETVAL
+
+gboolean
+is_inserted(Account* SELF)
+ CODE:
+ RETVAL = da_acc_get(SELF->key) == SELF;
+ OUTPUT:
+ RETVAL
+
+gboolean
+is_used(Account* SELF)
+ CODE:
+ RETVAL = account_is_used(SELF->key);
+ OUTPUT:
+ RETVAL
+
+gboolean
+insert(Account* SELF)
+ CODE:
+ if (SELF->key == 0 || account_is_used(SELF->key))
+ RETVAL = da_acc_append(rc_ref(SELF));
+ else
+ RETVAL = da_acc_insert(rc_ref(SELF));
+ OUTPUT:
+ RETVAL
+
+void
+remove(Account* SELF)
+ CODE:
+ da_acc_remove(SELF->key);
+
+void
+transactions(Account* SELF)
+ PPCODE:
- if (txn->kacc == SELF->key) {
- GValue val = G_VALUE_INIT;
- SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
- mXPUSHs(sv);
- }
++ GList* list = g_queue_peek_head_link(SELF->txn_queue);
+ for (; list; list = g_list_next(list)) {
+ Transaction* txn = list->data;
- RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY));
++ GValue val = G_VALUE_INIT;
++ SV* sv = val_to_sv(EXT_TRANSACTION(&val, txn));
++ mXPUSHs(sv);
+ }
+
+GObject*
+open(Account* SELF)
+ CODE:
+ RETVAL = G_OBJECT(register_panel_window_new(SELF->key, SELF));
+ OUTPUT:
+ RETVAL
+
+
+MODULE = HomeBank PACKAGE = HomeBank::Transaction
+
+Transaction*
+new(void)
+ CODE:
+ RETVAL = da_transaction_malloc();
+ OUTPUT:
+ RETVAL
+
+void
+DESTROY(Transaction* SELF)
+ CODE:
+ da_transaction_free(SELF);
+
+gdouble
+amount(Transaction* SELF, ...)
+ CODE:
+ if (1 < items) {
+ SELF->amount = SvNV(ST(1));
+ }
+ RETVAL = SELF->amount;
+ OUTPUT:
+ RETVAL
+
+guint
+account_num(Transaction* SELF, ...)
+ CODE:
+ if (1 < items) {
+ SELF->kacc = SvIV(ST(1));
+ }
+ RETVAL = SELF->kacc;
+ OUTPUT:
+ RETVAL
+
+guint
+paired_account_num(Transaction* SELF, ...)
+ CODE:
+ if (1 < items) {
+ SELF->kxferacc = SvIV(ST(1));
+ }
+ RETVAL = SELF->kxferacc;
+ OUTPUT:
+ RETVAL
+
+void
+date(Transaction* SELF, ...)
+ PPCODE:
+ if (1 < items) {
+ SELF->date = SvIV(ST(1));
+ }
+ if (GIMME_V == G_ARRAY) {
+ GDate* d = g_date_new_julian(SELF->date);
+ mXPUSHp("day", 3);
+ mXPUSHi(g_date_get_day(d));
+ mXPUSHp("month", 5);
+ mXPUSHi(g_date_get_month(d));
+ mXPUSHp("year", 4);
+ mXPUSHi(g_date_get_year(d));
+ g_date_free(d);
+ XSRETURN(6);
+ } else {
+ XSRETURN_IV(SELF->date);
+ }
+
+const gchar*
+wording(Transaction* SELF, ...)
+ CODE:
+ if (1 < items) {
+ if (SELF->wording) g_free(SELF->wording);
+ SELF->wording = g_strdup(SvGchar_ptr(ST(1)));
+ }
+ RETVAL = SELF->wording ? SELF->wording : "";
+ OUTPUT:
+ RETVAL
+
+const gchar*
+info(Transaction* SELF, ...)
+ CODE:
+ if (1 < items) {
+ if (SELF->info) g_free(SELF->info);
+ SELF->info = g_strdup(SvGchar_ptr(ST(1)));
+ }
+ RETVAL = SELF->info ? SELF->info : "";
+ OUTPUT:
+ RETVAL
+
+GObject*
+open(Transaction* SELF)
+ CODE:
- other = ui_dialog_transaction_xfer_select_child(list);
++ RETVAL = G_OBJECT(create_deftransaction_window(NULL, TRANSACTION_EDIT_MODIFY, FALSE));
+ deftransaction_set_transaction(GTK_WIDGET(RETVAL), SELF);
+ OUTPUT:
+ RETVAL
+
+Transaction*
+pair_with(Transaction* SELF, Transaction* other, ...)
+ PREINIT:
+ int i;
+ GList* list = NULL;
+ CODE:
+ if (2 < items) {
+ list = g_list_append(list, other);
+ for (i = 2; i < items; ++i) {
+ Transaction* ptr = NULL;
+ SV* sv = ST(i);
+ EXT_P2C_OBJECT("HomeBank::Transaction", sv, ptr, Transaction*);
+ list = g_list_append(list, ptr);
+ }
++ other = ui_dialog_transaction_xfer_select_child(SELF, list);
+ }
+ if (other) {
+ transaction_xfer_change_to_child(SELF, other);
+ SELF->paymode = PAYMODE_INTXFER;
+ }
+ RETVAL = other;
+ OUTPUT:
+ RETVAL
+ CLEANUP:
+ g_list_free(list);
+
+void
+dump(Transaction* SELF)
+ CODE:
+ g_print("txn: %p (%s) at %u (%d/%d) flags:%d, paymode:%d, kpay:%d, kcat:%d", SELF,
+ SELF->wording, SELF->date, SELF->kacc, SELF->kxferacc, SELF->flags, SELF->paymode, SELF->kpay, SELF->kcat);
+
g_free(item->name);
g_free(item->number);
g_free(item->bankname);
- g_free(item);
+ g_free(item->notes);
+
+ g_queue_free (item->txn_queue);
+
+ rc_free(item);
}
}
Account *
da_acc_malloc(void)
{
+ Account *item;
+
DB( g_print("da_acc_malloc\n") );
- return rc_alloc(sizeof(Account));
- item = g_malloc0(sizeof(Account));
++ item = rc_alloc(sizeof(Account));
+ item->txn_queue = g_queue_new ();
+ return item;
}
#include "homebank.h"
#include "hb-archive.h"
+ #include "hb-split.h"
+#include "ext.h"
+#include "refcount.h"
+
/****************************************************************************/
/* Debug macros */
/****************************************************************************/
if(item->wording != NULL)
g_free(item->wording);
- g_free(item);
+ da_splits_free(item->splits);
+ //item->flags &= ~(OF_SPLIT); //Flag that Splits are cleared
+
+ rc_free(item);
}
}
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);
}
}
PREFS->vehicle_unit_ismile = FALSE;
PREFS->vehicle_unit_isgal = FALSE;
- _homebank_pref_createformat();
+ gchar** plugin_path = g_new0(gchar**, 4);
+ i = 0;
+ const gchar* env = g_getenv("HOMEBANK_PLUGINS");
+ if (env) {
+ if (g_path_is_absolute(env)) {
+ plugin_path[i++] = g_strdup(env);
+ } else {
+ gchar* cur = g_get_current_dir();
+ plugin_path[i++] = g_build_filename(cur, env, NULL);
+ g_free(cur);
+ }
+ }
+ plugin_path[i++] = g_build_filename(homebank_app_get_config_dir(), "plugins", NULL);
+ plugin_path[i++] = g_build_filename(homebank_app_get_pkglib_dir(), "plugins", NULL);
+ PREFS->ext_path = plugin_path;
+ PREFS->ext_whitelist = NULL;
+
_homebank_pref_init_measurement_units();
}
#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
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") );
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* 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;
+
}
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);
}
}
#include "hb-transaction.h"
#include "hb-xml.h"
+#include "ext.h"
+
+ #include "ui-dialogs.h"
+
/****************************************************************************/
/* Debug macros */
/****************************************************************************/
}
- // 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;
}
char buf1[G_ASCII_DTOSTR_BUF_SIZE];
gchar *outstr;
gint retval = XML_OK;
+ GError *error = NULL;
- io = g_io_channel_new_file(filename, "w", NULL);
+ GValue filename_val = G_VALUE_INIT;
+ ext_hook("save_file", EXT_STRING(&filename_val, filename), NULL);
+
+ io = g_io_channel_new_file(filename, "w", &error);
if(io == NULL)
{
g_message("file error on: %s", filename);
pixmaps_dir = g_build_filename (prefix, "share", PACKAGE, "icons", NULL);
help_dir = g_build_filename (prefix, "share", PACKAGE, "help", NULL);
datas_dir = g_build_filename (prefix, "share", PACKAGE, "datas", NULL);
- #ifdef PORTABLE_APP
- DB( g_print("- app is portable under windows\n") );
- config_dir = g_build_filename(prefix, "config", NULL);
- #else
- config_dir = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
- #endif
+ pkglib_dir = g_build_filename (prefix, "lib", PACKAGE, NULL);
+ #ifdef PORTABLE_APP
+ DB( g_print(" - app is portable under windows\n") );
+ config_dir = g_build_filename(prefix, "config", NULL);
+ #else
+ config_dir = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
+ #endif
g_free (prefix);
#else
locale_dir = g_build_filename (DATA_DIR, "locale", NULL);
pixmaps_dir = g_build_filename (DATA_DIR, PACKAGE, "icons", NULL);
help_dir = g_build_filename (DATA_DIR, PACKAGE, "help", NULL);
datas_dir = g_build_filename (DATA_DIR, PACKAGE, "datas", NULL);
- config_dir = g_build_filename (g_get_user_config_dir(), HB_DATA_PATH, NULL);
+ pkglib_dir = g_build_filename (PKGLIB_DIR, NULL);
+ config_dir = g_build_filename(g_get_user_config_dir(), HB_DATA_PATH, NULL);
//#870023 Ubuntu packages the help files in "/usr/share/doc/homebank-data/help/" for some strange reason
if(! g_file_test(help_dir, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
}
#endif
- DB( g_print("- config_dir : %s\n", config_dir) );
- DB( g_print("- images_dir : %s\n", images_dir) );
- DB( g_print("- pixmaps_dir: %s\n", pixmaps_dir) );
- DB( g_print("- locale_dir : %s\n", locale_dir) );
- DB( g_print("- help_dir : %s\n", help_dir) );
- DB( g_print("- datas_dir : %s\n", datas_dir) );
- DB( g_print("- pkglib_dir : %s\n", pkglib_dir) );
+ DB( g_print(" - config_dir : %s\n", config_dir) );
+ DB( g_print(" - images_dir : %s\n", images_dir) );
+ DB( g_print(" - pixmaps_dir: %s\n", pixmaps_dir) );
+ DB( g_print(" - locale_dir : %s\n", locale_dir) );
+ DB( g_print(" - help_dir : %s\n", help_dir) );
+ DB( g_print(" - datas_dir : %s\n", datas_dir) );
++ DB( g_print(" - pkglib_dir : %s\n", pkglib_dir) );
}
/* change the locale if a language is specified */
language_init (PREFS->language);
- DB( g_print(" -> loading plugins\n") );
++ DB( g_print(" - loading plugins\n") );
+ ext_init(&argc, &argv, &env);
+
+ GList* it;
+ for (it = PREFS->ext_whitelist; it; it = g_list_next(it)) {
+ ext_load_plugin(it->data);
+ }
+
+ gchar** plugins = ext_list_plugins();
+ gchar** plugins_it;
+ for (plugins_it = plugins; *plugins_it; ++plugins_it) {
+ gboolean loaded = ext_is_plugin_loaded(*plugins_it);
+ g_print("found plugin: %s, loaded: %d\n", *plugins_it, loaded);
+ }
+ g_strfreev(plugins);
+
if( PREFS->showsplash == TRUE )
{
splash = homebank_construct_splash();
/* update the mainwin display */
ui_mainwindow_update(mainwin, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_VISUAL));
- DB( g_print(" -> gtk_main()\n" ) );
+ ext_hook("enter_main_loop", NULL);
+
+ DB( g_print(" - gtk_main()\n" ) );
+
gtk_main ();
+
+ ext_hook("exit_main_loop", NULL);
}
- DB( g_print(" -> unloading plugins\n") );
++ DB( g_print(" - unloading plugins\n") );
+ ext_term();
+
}
#include "dsp_mainwindow.h"
#include "gtk-chart-colors.h"
+#include "ext.h"
+
+ #include "ui-currency.h"
+
+
/****************************************************************************/
/* Debug macros */
/****************************************************************************/
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",
//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)
{
data->BT_path_hbfile = widget;
gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
-
- return(container);
+ return content_grid;
}
+
+void plugin_execute_action(GtkTreeView* treeview, GtkTreePath* path, GtkTreeViewColumn* col, gpointer userdata);
+
+static void
+toggle_plugin(GtkCellRendererToggle *cell, gchar* path_str, gpointer data)
+{
+ GtkTreeModel *model = (GtkTreeModel*)data;
+ GtkTreeIter iter;
+ GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
+
+ const gchar* plugin;
+
+ gtk_tree_model_get_iter(model, &iter, path);
+ gtk_tree_model_get(model, &iter, EXT_COLUMN_PLUGIN_NAME, &plugin, -1);
+
+ gboolean enabled = ext_is_plugin_loaded(plugin);
+ if (enabled) {
+ ext_unload_plugin(plugin);
+ enabled = FALSE;
+ } else {
+ enabled = (ext_load_plugin(plugin) == 0);
+ if (!enabled) {
+ ext_run_modal(_("Plugin Error"), _("The plugin failed to load properly."), "error");
+ }
+ }
+
+ /* set new value */
+ gtk_list_store_set(GTK_LIST_STORE (model), &iter, EXT_COLUMN_ENABLED, enabled, -1);
+
+ /* clean up */
+ gtk_tree_path_free(path);
+}
+
+
+void plugin_execute_action(GtkTreeView* treeview, GtkTreePath* path, GtkTreeViewColumn* col, gpointer userdata)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(treeview);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter(model, &iter, path)) {
+ gchar* plugin_filename;
+ gtk_tree_model_get(model, &iter, EXT_COLUMN_PLUGIN_NAME, &plugin_filename, -1);
+ ext_execute_action(plugin_filename);
+ g_free(plugin_filename);
+ }
+}
+
+static GtkWidget *defpref_page_plugins (struct defpref_data *data)
+{
+ GtkWidget *container;
+ GtkListStore *store;
+ GtkTreeIter it;
+ GtkWidget* view;
+
+ container = gtk_vbox_new(FALSE, 0);
+
+ store = gtk_list_store_new(EXT_NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+ gchar** plugins = ext_list_plugins();
+ gchar** plugins_it;
+ for (plugins_it = plugins; *plugins_it; ++plugins_it) {
+
+ gboolean enabled = ext_is_plugin_loaded(*plugins_it);
+ GHashTable* metadata = ext_read_plugin_metadata(*plugins_it);
+ if (!metadata) {
+ metadata = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ gchar* tmp = NULL;
+
+ // NAME
+ gchar* name = g_hash_table_lookup(metadata, "name");
+ if (!name || *name == '\0') {
+ name = *plugins_it;
+ }
+ name = g_markup_escape_text(name, -1);
+ gchar* label = g_strdup_printf("<b>%s</b>", name);
+ gchar* tooltip = g_strdup_printf("<span size='x-large' weight='bold'>%s</span>", name);
+ g_free(name);
+
+ // VERSION
+ gchar* version = g_hash_table_lookup(metadata, "version");
+ if (version) {
+ version = g_markup_escape_text(version, -1);
+ tmp = label;
+ label = g_strdup_printf("%s %s", tmp, version);
+ g_free(tmp);
+ tmp = tooltip;
+ tooltip = g_strdup_printf("%s %s", tmp, version);
+ g_free(tmp);
+ g_free(version);
+ }
+
+ // ABSTRACT
+ gchar* abstract = g_hash_table_lookup(metadata, "abstract");
+ if (abstract) {
+ abstract = g_markup_escape_text(abstract, -1);
+ tmp = label;
+ label = g_strdup_printf("%s\n%s", tmp, abstract);
+ g_free(tmp);
+ g_free(abstract);
+ }
+
+ // AUTHOR
+ gchar* author = g_hash_table_lookup(metadata, "author");
+ if (author) {
+ author = g_markup_escape_text(author, -1);
+ tmp = tooltip;
+ tooltip = g_strdup_printf("%s\n%s", tmp, author);
+ g_free(tmp);
+ g_free(author);
+ }
+
+ // WEBSITE
+ gchar* website = g_hash_table_lookup(metadata, "website");
+ if (website) {
+ website = g_markup_escape_text(website, -1);
+ tmp = tooltip;
+ tooltip = g_strdup_printf("%s\n<b>%s:</b> %s", tmp, _("Website"), website);
+ g_free(tmp);
+ g_free(website);
+ }
+
+ // FILEPATH
+ tmp = ext_find_plugin(*plugins_it);
+ gchar* full = g_markup_escape_text(tmp, -1);
+ g_free(tmp);
+ tmp = tooltip;
+ tooltip = g_strdup_printf("%s\n<b>%s:</b> %s", tmp, _("File"), full);
+ g_free(tmp);
+ g_free(full);
+
+ g_hash_table_unref(metadata);
+
+ gtk_list_store_append(store, &it);
+ gtk_list_store_set(store, &it,
+ EXT_COLUMN_ENABLED, enabled,
+ EXT_COLUMN_LABEL, label,
+ EXT_COLUMN_TOOLTIP, tooltip,
+ EXT_COLUMN_PLUGIN_NAME, *plugins_it,
+ -1);
+
+ g_free(label);
+ g_free(tooltip);
+ }
+ g_strfreev(plugins);
+
+ view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
+ g_object_unref(store);
+
+ g_signal_connect(view, "row-activated", (GCallback)plugin_execute_action, NULL);
+
+ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), TRUE);
+ gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(view), EXT_COLUMN_TOOLTIP);
+
+
+ GtkTreeViewColumn *col;
+ GtkCellRenderer *renderer;
+
+
+ col = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(col, _("Enabled"));
+ gtk_tree_view_column_set_sort_column_id(col, EXT_COLUMN_ENABLED);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+ renderer = gtk_cell_renderer_toggle_new();
+ gtk_tree_view_column_pack_start(col, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(col, renderer, "active", 0);
+ g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_plugin), store);
+
+ col = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(col, _("Plugin"));
+ gtk_tree_view_column_set_sort_column_id(col, EXT_COLUMN_LABEL);
+ gtk_tree_view_column_set_expand(col, TRUE);
+ /*gtk_tree_view_column_set_sort_order(col, GTK_SORT_ASCENDING);*/
+ gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_pack_start(col, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(col, renderer, "markup", EXT_COLUMN_LABEL);
+
+ data->PI_plugin_columns = view;
+
+ GtkWidget* sw = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(sw), view);
+
+ gtk_box_pack_start(GTK_BOX(container), sw, TRUE, TRUE, 0);
+
+ return(container);
+}
+
+
static void defpref_selection(GtkTreeSelection *treeselection, gpointer user_data)
{
struct defpref_data *data;
GtkWidget *CM_chartlegend;
GtkWidget *CY_dtex_datefmt;
+ GtkWidget *CY_dtex_ofxname;
GtkWidget *CY_dtex_ofxmemo;
+ GtkWidget *CM_dtex_qifmemo;
+ GtkWidget *CM_dtex_qifswap;
+
+ gint country;
- PREF_COLUMNS,
- PREF_DISPLAY,
- PREF_IMPORT,
+ GtkWidget *PI_plugin_columns;
+};
+
+enum
+{
+ PREF_GENERAL,
+ PREF_INTERFACE,
- PREF_EURO,
++ PREF_TRANSACTIONS,
++ PREF_DISPLAY_FORMAT,
++ PREF_IMPORT_EXPORT,
+ PREF_REPORT,
++ PREF_EURO_MINOR,
+ PREF_PLUGINS,
+ PREF_MAX
};
--- /dev/null
+ ## 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