diff --git a/po/POTFILES.in b/po/POTFILES.in index 11174a1a3d..d05232a934 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -220,6 +220,7 @@ src/gnome/dialog-sx-editor.c src/gnome/dialog-sx-from-trans.c src/gnome/dialog-sx-since-last-run.c src/gnome/dialog-tax-info.c +src/gnome/dialog-trans-assoc.c src/gnome/gnc-budget-view.c src/gnome/gnc-plugin-account-tree.c src/gnome/gnc-plugin-basic-commands.c @@ -256,6 +257,7 @@ src/gnome/gtkbuilder/dialog-print-check.glade src/gnome/gtkbuilder/dialog-progress.glade src/gnome/gtkbuilder/dialog-sx.glade src/gnome/gtkbuilder/dialog-tax-info.glade +src/gnome/gtkbuilder/dialog-trans-assoc.glade src/gnome/gtkbuilder/gnc-plugin-page-budget.glade src/gnome/gtkbuilder/gnc-plugin-page-register2.glade src/gnome/gtkbuilder/gnc-plugin-page-register.glade diff --git a/src/gnome/CMakeLists.txt b/src/gnome/CMakeLists.txt index 9079fb091f..d22675c4cd 100644 --- a/src/gnome/CMakeLists.txt +++ b/src/gnome/CMakeLists.txt @@ -20,6 +20,7 @@ SET (gnc_gnome_noinst_HEADERS dialog-sx-editor2.h dialog-sx-from-trans.h dialog-sx-since-last-run.h + dialog-trans-assoc.h gnc-budget-view.h gnc-plugin-account-tree.h gnc-plugin-basic-commands.h @@ -65,6 +66,7 @@ SET (gnc_gnome_SOURCES dialog-sx-from-trans.c dialog-sx-since-last-run.c dialog-tax-info.c + dialog-trans-assoc.c gnc-budget-view.c gnc-plugin-account-tree.c gnc-plugin-basic-commands.c diff --git a/src/gnome/Makefile.am b/src/gnome/Makefile.am index 54d36cc973..e07ae2ab7d 100644 --- a/src/gnome/Makefile.am +++ b/src/gnome/Makefile.am @@ -44,6 +44,7 @@ libgnc_gnome_la_SOURCES = \ dialog-sx-from-trans.c \ dialog-sx-since-last-run.c \ dialog-tax-info.c \ + dialog-trans-assoc.c \ gnc-budget-view.c \ gnc-plugin-account-tree.c \ gnc-plugin-basic-commands.c \ @@ -93,6 +94,7 @@ noinst_HEADERS = \ dialog-sx-editor2.h \ dialog-sx-from-trans.h \ dialog-sx-since-last-run.h \ + dialog-trans-assoc.h \ gnc-budget-view.h \ gnc-plugin-account-tree.h \ gnc-plugin-basic-commands.h \ diff --git a/src/gnome/dialog-trans-assoc.c b/src/gnome/dialog-trans-assoc.c new file mode 100644 index 0000000000..77eeeb3e87 --- /dev/null +++ b/src/gnome/dialog-trans-assoc.c @@ -0,0 +1,367 @@ +/********************************************************************\ + * dialog-trans-assoc.c -- Transaction associations dialog * + * Copyright (C) 2016 Robert Fewell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#include "config.h" + +#include +#include + +#include "dialog-trans-assoc.h" + +#include "dialog-utils.h" +#include "gnc-component-manager.h" +#include "Query.h" +#include "Transaction.h" + +#include "gnc-plugin-page-register.h" +#include "gnc-main-window.h" + +#include "gnc-ui-util.h" +#include "gnc-gnome-utils.h" +#include "Account.h" + +#define DIALOG_ASSOC_CM_CLASS "dialog-trans-assoc" +#define GNC_PREFS_GROUP "dialogs.trans-assoc" + +/** Enumeration for the tree-store */ +enum GncAssocColumn {DATE_TRANS, DESC_TRANS, URI, AVAILABLE, URI_SPLIT}; + +typedef struct +{ + GtkWidget *dialog; + GtkWidget *view; +}AssocDialog; + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = GNC_MOD_GUI; + +void gnc_assoc_dialog_window_destroy_cb (GtkWidget *object, gpointer user_data); +void gnc_assoc_dialog_close_cb (GtkDialog *dialog, gpointer user_data); +void gnc_assoc_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data); + + +void +gnc_assoc_dialog_window_destroy_cb (GtkWidget *object, gpointer user_data) +{ + AssocDialog *assoc_dialog = user_data; + + ENTER(" "); + gnc_unregister_gui_component_by_data (DIALOG_ASSOC_CM_CLASS, assoc_dialog); + + if (assoc_dialog->dialog) + { + gtk_widget_destroy (assoc_dialog->dialog); + assoc_dialog->dialog = NULL; + } + g_free (assoc_dialog); + LEAVE(" "); +} + +void +gnc_assoc_dialog_close_cb (GtkDialog *dialog, gpointer user_data) +{ + AssocDialog *assoc_dialog = user_data; + + ENTER(" "); + gnc_close_gui_component_by_data (DIALOG_ASSOC_CM_CLASS, assoc_dialog); + LEAVE(" "); +} + +static void +assoc_dialog_update (AssocDialog *assoc_dialog) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean valid; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW(assoc_dialog->view)); + + /* Get first row in list store */ + valid = gtk_tree_model_get_iter_first (model, &iter); + + while (valid) + { + GNetworkMonitor *nm; + GSocketConnectable *conn; + gchar *uri; + gchar *filename; + + gtk_tree_model_get (model, &iter, URI, &uri, -1); + + filename = g_filename_from_uri (uri, NULL, NULL); + + if (filename != NULL) + { + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("File Found"), -1); + else + gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("File Not Found"), -1); + } + else + { + nm = g_network_monitor_get_default (); + conn = g_network_address_parse_uri (uri, 80, NULL); + + if (conn != NULL) + { + if (g_network_monitor_can_reach (nm, conn, NULL, NULL)) + gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("Address Found"), -1); + else + gtk_list_store_set (GTK_LIST_STORE(model), &iter, AVAILABLE, _("Address Not Found"), -1); + } + } + g_free (filename); + g_free (uri); + valid = gtk_tree_model_iter_next (model, &iter); + } +} + +void +gnc_assoc_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data) +{ + AssocDialog *assoc_dialog = user_data; + + switch (response_id) + { + case GTK_RESPONSE_APPLY: + assoc_dialog_update (assoc_dialog); + return; + + case GTK_RESPONSE_CLOSE: + default: + gnc_close_gui_component_by_data (DIALOG_ASSOC_CM_CLASS, assoc_dialog); + return; + } +} + +static void +row_selected_cb (GtkTreeView *view, GtkTreePath *path, + GtkTreeViewColumn *col, gpointer user_data) +{ + AssocDialog *assoc_dialog = user_data; + GncPluginPage *page; + GNCSplitReg *gsr; + Account *account; + GtkTreeModel *model; + GtkTreeIter iter; + Split *split; + const gchar *uri; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW(assoc_dialog->view)); + + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; /* path describes a non-existing row - should not happen */ + + gtk_tree_model_get (model, &iter, URI, &uri, URI_SPLIT, &split, -1); + + if ((gtk_tree_view_get_column (GTK_TREE_VIEW(assoc_dialog->view), URI) == col) || + (gtk_tree_view_get_column (GTK_TREE_VIEW(assoc_dialog->view), AVAILABLE) == col)) + { + gnc_launch_assoc (uri); + } + else + { + /* This should never be true, but be paranoid */ + if (split == NULL) + return; + + account = xaccSplitGetAccount (split); + if (!account) + return; + + page = gnc_plugin_page_register_new (account, FALSE); + gnc_main_window_open_page (NULL, page); + gsr = gnc_plugin_page_register_get_gsr (page); + gnc_split_reg_raise (gsr); + + if (gsr == NULL) + return; + + gnc_split_reg_jump_to_split (gsr, split); + } +} + +static void +get_trans_info (AssocDialog *assoc_dialog) +{ + QofBook *book = gnc_get_current_book(); + Account *root = gnc_book_get_root_account (book); + GList *accts, *ptr; + GtkTreeModel *model; + GtkTreeIter iter; + GList *splits, *trans_list = NULL; + + /* Get list of Accounts */ + accts = gnc_account_get_descendants_sorted (root); + + model = gtk_tree_view_get_model (GTK_TREE_VIEW(assoc_dialog->view)); + + /* Go through list of accounts */ + for (ptr = accts; ptr; ptr = g_list_next (ptr)) + { + Query *query = qof_query_create_for (GNC_ID_SPLIT); + Account *acc = ptr->data; + + qof_query_set_book (query, book); + xaccQueryAddSingleAccountMatch (query, acc, QOF_QUERY_AND); + + /* Run the query */ + for (splits = qof_query_run (query); splits; splits = splits->next) + { + Split *split = splits->data; + Transaction *trans = xaccSplitGetParent (split); + const gchar *uri; + + // Look for trans already in trans_list + if (g_list_find (trans_list, trans) != NULL) + continue; + + uri = xaccTransGetAssociation (trans); + + if (g_strcmp0 (uri, "") != 0 && g_strcmp0 (uri, NULL) != 0) + { + Timespec ts = {0,0}; + xaccTransGetDatePostedTS (trans, &ts); + + if (ts.tv_sec == 0) + ts.tv_sec = gnc_time (NULL); + + gtk_list_store_append (GTK_LIST_STORE(model), &iter); + + gtk_list_store_set (GTK_LIST_STORE(model), &iter, + DATE_TRANS, gnc_print_date (ts), + DESC_TRANS, xaccTransGetDescription (trans), + URI, uri, AVAILABLE, _("Unknown"), URI_SPLIT, split, -1); + } + trans_list = g_list_prepend (trans_list, trans); // add trans to trans_list + } + qof_query_destroy (query); + g_list_free (splits); + } + g_list_free (accts); + g_list_free (trans_list); +} + +static void +gnc_assoc_dialog_create (AssocDialog *assoc_dialog) +{ + GtkWidget *dialog; + GtkBuilder *builder; + GtkTreeSelection *selection; + + ENTER(" "); + builder = gtk_builder_new(); + gnc_builder_add_from_file (builder, "dialog-trans-assoc.glade", "list-store"); + + gnc_builder_add_from_file (builder, "dialog-trans-assoc.glade", "Transaction Association Dialog"); + + dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Transaction Association Dialog")); + assoc_dialog->dialog = dialog; + + assoc_dialog->view = GTK_WIDGET(gtk_builder_get_object (builder, "treeview")); + + g_signal_connect (assoc_dialog->view, "row-activated", + G_CALLBACK(row_selected_cb), (gpointer)assoc_dialog); + + /* Enable alternative line colors */ + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(assoc_dialog->view), TRUE); + + /* default to 'close' button */ + gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(assoc_dialog->view)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, assoc_dialog); + + g_object_unref (G_OBJECT(builder)); + + gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(assoc_dialog->dialog)); + get_trans_info (assoc_dialog); + + LEAVE(" "); +} + +static void +close_handler (gpointer user_data) +{ + AssocDialog *assoc_dialog = user_data; + + ENTER(" "); + gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(assoc_dialog->dialog)); + gtk_widget_destroy (GTK_WIDGET(assoc_dialog->dialog)); + LEAVE(" "); +} + +static void +refresh_handler (GHashTable *changes, gpointer user_data) +{ + ENTER(" "); + LEAVE(" "); +} + +static gboolean +show_handler (const char *klass, gint component_id, + gpointer user_data, gpointer iter_data) +{ + AssocDialog *assoc_dialog = user_data; + + ENTER(" "); + if (!assoc_dialog) + { + LEAVE("No data strucure"); + return(FALSE); + } + gtk_window_present (GTK_WINDOW(assoc_dialog->dialog)); + LEAVE(" "); + return(TRUE); +} + +/********************************************************************\ + * gnc_trans_assoc_dialog * + * opens a window showing the Associations of all Transactions * + * * + * Args: parent - the parent of the window to be created * + * Return: nothing * +\********************************************************************/ +void +gnc_trans_assoc_dialog () +{ + AssocDialog *assoc_dialog; + + ENTER(" "); + if (gnc_forall_gui_components (DIALOG_ASSOC_CM_CLASS, show_handler, NULL)) + { + LEAVE("Existing dialog raised"); + return; + } + assoc_dialog = g_new0 (AssocDialog, 1); + + gnc_assoc_dialog_create (assoc_dialog); + + gnc_register_gui_component (DIALOG_ASSOC_CM_CLASS, + refresh_handler, close_handler, + assoc_dialog); + + gtk_widget_show (assoc_dialog->dialog); + LEAVE(" "); +} diff --git a/src/gnome/dialog-trans-assoc.h b/src/gnome/dialog-trans-assoc.h new file mode 100644 index 0000000000..fa82fcb8a5 --- /dev/null +++ b/src/gnome/dialog-trans-assoc.h @@ -0,0 +1,28 @@ +/********************************************************************\ + * dialog-trans-assoc.h -- Transaction associations dialog * + * Copyright (C) 2016 Robert Fewell * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#ifndef DIALOG_TRANS_ASSOC_H +#define DIALOG_TRANS_ASSOC_H + +void gnc_trans_assoc_dialog (void); + +#endif diff --git a/src/gnome/gnc-plugin-basic-commands.c b/src/gnome/gnc-plugin-basic-commands.c index 1d588208c6..dd52ee5662 100644 --- a/src/gnome/gnc-plugin-basic-commands.c +++ b/src/gnome/gnc-plugin-basic-commands.c @@ -47,6 +47,7 @@ #include "dialog-imap-editor.h" #include "dialog-sx-since-last-run.h" #include "dialog-totd.h" +#include "dialog-trans-assoc.h" #include "assistant-acct-period.h" #include "assistant-loan.h" #include "gnc-engine.h" @@ -90,6 +91,7 @@ static void gnc_main_window_cmd_tools_close_book (GtkAction *action, GncMainWind static void gnc_main_window_cmd_tools_find_transactions (GtkAction *action, GncMainWindowActionData *data); static void gnc_main_window_cmd_tools_price_editor (GtkAction *action, GncMainWindowActionData *data); static void gnc_main_window_cmd_tools_imap_editor (GtkAction *action, GncMainWindowActionData *data); +static void gnc_main_window_cmd_tools_trans_assoc (GtkAction *action, GncMainWindowActionData *data); static void gnc_main_window_cmd_tools_commodity_editor (GtkAction *action, GncMainWindowActionData *data); static void gnc_main_window_cmd_help_totd (GtkAction *action, GncMainWindowActionData *data); @@ -208,6 +210,11 @@ static GtkActionEntry gnc_plugin_actions [] = N_("View and Delete Bayesian and Non Bayesian information"), G_CALLBACK (gnc_main_window_cmd_tools_imap_editor) }, + { + "ToolsTransAssocAction", NULL, N_("_Transaction Associations"), NULL, + N_("View all Transaction Associations"), + G_CALLBACK (gnc_main_window_cmd_tools_trans_assoc) + }, /* Help menu */ @@ -617,6 +624,14 @@ gnc_main_window_cmd_tools_imap_editor (GtkAction *action, GncMainWindowActionDat gnc_unset_busy_cursor(NULL); } +static void +gnc_main_window_cmd_tools_trans_assoc (GtkAction *action, GncMainWindowActionData *data) +{ + gnc_set_busy_cursor (NULL, TRUE); + gnc_trans_assoc_dialog (); + gnc_unset_busy_cursor (NULL); +} + static void gnc_main_window_cmd_tools_price_editor (GtkAction *action, GncMainWindowActionData *data) { diff --git a/src/gnome/gschemas/org.gnucash.dialogs.gschema.xml.in.in b/src/gnome/gschemas/org.gnucash.dialogs.gschema.xml.in.in index 36ab8fc30b..52130c6faf 100644 --- a/src/gnome/gschemas/org.gnucash.dialogs.gschema.xml.in.in +++ b/src/gnome/gschemas/org.gnucash.dialogs.gschema.xml.in.in @@ -19,6 +19,7 @@ + @@ -223,4 +224,14 @@ followed by the width and height of the window. + + + + (-1,-1,-1,-1) + Last window position and size + This setting describes the size and position of the window when it was last closed. + The numbers are the X and Y coordinates of the top left corner of the window + followed by the width and height of the window. + + diff --git a/src/gnome/gtkbuilder/Makefile.am b/src/gnome/gtkbuilder/Makefile.am index 110e324500..ebf0dd249d 100644 --- a/src/gnome/gtkbuilder/Makefile.am +++ b/src/gnome/gtkbuilder/Makefile.am @@ -14,6 +14,7 @@ gtkbuilder_DATA = \ dialog-progress.glade \ dialog-sx.glade \ dialog-tax-info.glade \ + dialog-trans-assoc.glade \ gnc-plugin-page-budget.glade \ gnc-plugin-page-register.glade \ gnc-plugin-page-register2.glade \ diff --git a/src/gnome/gtkbuilder/dialog-trans-assoc.glade b/src/gnome/gtkbuilder/dialog-trans-assoc.glade new file mode 100644 index 0000000000..d87d6642f1 --- /dev/null +++ b/src/gnome/gtkbuilder/dialog-trans-assoc.glade @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + True + True + True + True + 6 + Transaction Association Dialog + 600 + 400 + True + normal + + + + + False + + + False + end + + + _Locate Association + True + True + True + True + + + False + False + 0 + + + + + gtk-close + True + True + True + True + False + True + + + False + False + 1 + + + + + False + False + end + 0 + + + + + True + False + All Transaction Associations + + + False + False + 5 + 1 + + + + + True + True + automatic + automatic + + + True + True + list-store + + + True + Date + 0.5 + + + + 0 + + + + + + + True + Description + 0.5 + + + + 1 + + + + + + + True + Association + 0.5 + + + + 2 + + + + + + + True + Available ? + 0.5 + + + 10 + + + 3 + + + + + + + + + True + True + 2 + + + + + True + False + 5 + To jump to Transaction, double click on Date or Description columns on + row required or Association and Available to Open the Association + + + False + False + 3 + + + + + + Check + close_button + + + diff --git a/src/gnome/ui/gnc-plugin-basic-commands-ui.xml b/src/gnome/ui/gnc-plugin-basic-commands-ui.xml index a6a8cc3126..022727c9c0 100644 --- a/src/gnome/ui/gnc-plugin-basic-commands-ui.xml +++ b/src/gnome/ui/gnc-plugin-basic-commands-ui.xml @@ -57,6 +57,7 @@ +