Transaction Association List Dialog

This new dialog creates a list view of transaction associations and
allows them to be checked to see if they are still available and be able
to jump to the corresponding transaction in the register or open the
associated entry.
This commit is contained in:
Robert Fewell 2016-08-01 14:30:24 +01:00 committed by John Ralls
parent 5f75f106ee
commit a860643922
10 changed files with 614 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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 <gtk/gtk.h>
#include <glib/gi18n.h>
#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(" ");
}

View File

@ -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

View File

@ -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)
{

View File

@ -19,6 +19,7 @@
<child name="new-hierarchy" schema="org.gnucash.dialogs.new-hierarchy"/>
<child name="search" schema="org.gnucash.dialogs.search"/>
<child name="transfer" schema="org.gnucash.dialogs.transfer"/>
<child name="trans-assoc" schema="org.gnucash.dialogs.trans-assoc"/>
</schema>
<schema id="org.gnucash.dialogs.account" path="/org/gnucash/dialogs/account/">
@ -223,4 +224,14 @@
followed by the width and height of the window.</description>
</key>
</schema>
<schema id="org.gnucash.dialogs.trans-assoc" path="/org/gnucash/dialogs/trans-assoc/">
<key type="(iiii)" name="last-geometry">
<default>(-1,-1,-1,-1)</default>
<summary>Last window position and size</summary>
<description>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.</description>
</key>
</schema>
</schemalist>

View File

@ -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 \

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkListStore" id="list-store">
<columns>
<!-- column-name date -->
<column type="gchararray"/>
<!-- column-name desc -->
<column type="gchararray"/>
<!-- column-name uri -->
<column type="gchararray"/>
<!-- column-name available -->
<column type="gchararray"/>
<!-- column-name split -->
<column type="gpointer"/>
</columns>
</object>
<object class="GtkDialog" id="Transaction Association Dialog">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="can_default">True</property>
<property name="border_width">6</property>
<property name="title" translatable="yes">Transaction Association Dialog</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">normal</property>
<signal name="destroy" handler="gnc_assoc_dialog_window_destroy_cb" swapped="no"/>
<signal name="response" handler="gnc_assoc_dialog_response_cb" swapped="no"/>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox2">
<property name="can_focus">False</property>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="Check">
<property name="label" translatable="yes">_Locate Association</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="close_button">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">All Transaction Associations</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">5</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
<object class="GtkTreeView" id="treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">list-store</property>
<child>
<object class="GtkTreeViewColumn" id="trans-date">
<property name="resizable">True</property>
<property name="title" translatable="yes">Date</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="trans-desc">
<property name="resizable">True</property>
<property name="title" translatable="yes">Description</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="uri entry">
<property name="resizable">True</property>
<property name="title" translatable="yes">Association</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext3"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="available">
<property name="resizable">True</property>
<property name="title" translatable="yes">Available ?</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext4">
<property name="xpad">10</property>
</object>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="ypad">5</property>
<property name="label" translatable="yes">To jump to Transaction, double click on Date or Description columns on
row required or Association and Available to Open the Association</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-10">Check</action-widget>
<action-widget response="-6">close_button</action-widget>
</action-widgets>
</object>
</interface>

View File

@ -57,6 +57,7 @@
<menuitem name="ToolsFinancialCalculator" action="ToolsFinancialCalculatorAction"/>
<menuitem name="ToolsBookClose" action="ToolsBookCloseAction"/>
<menuitem name="ToolsImapEditor" action="ToolsImapEditorAction"/>
<menuitem name="ToolsTransAssoc" action="ToolsTransAssocAction"/>
</placeholder>
</menu>