r18610 - gnucash/trunk/src/gnome - Bug #608436: Add auto-clear feature

Christian Stimming cstim at code.gnucash.org
Wed Feb 3 16:28:48 EST 2010


Author: cstim
Date: 2010-02-03 16:28:48 -0500 (Wed, 03 Feb 2010)
New Revision: 18610
Trac: http://svn.gnucash.org/trac/changeset/18610

Added:
   gnucash/trunk/src/gnome/glade/autoclear.glade
   gnucash/trunk/src/gnome/window-autoclear.c
   gnucash/trunk/src/gnome/window-autoclear.h
Modified:
   gnucash/trunk/src/gnome/Makefile.am
   gnucash/trunk/src/gnome/glade/Makefile.am
   gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
   gnucash/trunk/src/gnome/gnc-plugin-page-register.c
   gnucash/trunk/src/gnome/ui/gnc-plugin-page-account-tree-ui.xml
Log:
Bug #608436: Add auto-clear feature

Patch by Cristian KLEIN:

= Usage scenario =
John keeps his personal accounting in GnuCash and writes all credit card
expenses therein. On weekends, we checks his Internet Banking and sees that
some transactions have been recorded. He would like to clear those transactions
in GnuCash, but it is tiresome to go through each Internet Banking transaction
and do manual comparison with GnuCash records, especially since Internet
Banking transactions might be in a different order than in GnuCash.

John would prefer having an "auto-clear" feature. Given the "current amount"
from the Internet Banking, he would like GnuCash to clear the transactions for
him, if and only if, there is a unique combination of transactions that could
achieve this. If there is no solution, or if the solution is not unique,
GnuCash should warn him and John must manually clear the transactions.

Modified: gnucash/trunk/src/gnome/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome/Makefile.am	2010-02-03 21:01:18 UTC (rev 18609)
+++ gnucash/trunk/src/gnome/Makefile.am	2010-02-03 21:28:48 UTC (rev 18610)
@@ -55,7 +55,8 @@
   lot-viewer.c \
   reconcile-list.c \
   top-level.c \
-  window-reconcile.c
+  window-reconcile.c \
+  window-autoclear.c
 
 gnomeappdir = ${datadir}/applications
 
@@ -92,7 +93,8 @@
   lot-viewer.h \
   reconcile-list.h \
   top-level.h \
-  window-reconcile.h
+  window-reconcile.h \
+  window-autoclear.h
 
 if BUILDING_FROM_SVN
 swig-gnome.c: gnome.i dialog-progress.h ${top_srcdir}/src/base-typemaps.i

Modified: gnucash/trunk/src/gnome/glade/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome/glade/Makefile.am	2010-02-03 21:01:18 UTC (rev 18609)
+++ gnucash/trunk/src/gnome/glade/Makefile.am	2010-02-03 21:28:48 UTC (rev 18610)
@@ -2,6 +2,7 @@
 glade_DATA = \
 	account.glade \
 	acctperiod.glade \
+	autoclear.glade \
 	budget.glade \
 	chart-export.glade \
 	commodities.glade \

Added: gnucash/trunk/src/gnome/glade/autoclear.glade
===================================================================
--- gnucash/trunk/src/gnome/glade/autoclear.glade	                        (rev 0)
+++ gnucash/trunk/src/gnome/glade/autoclear.glade	2010-02-03 21:28:48 UTC (rev 18610)
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<glade-interface>
+  <!-- interface-requires gtk+ 2.6 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <widget class="GtkDialog" id="Auto-clear Start Dialog">
+    <property name="visible">True</property>
+    <property name="resizable">False</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox6">
+        <property name="visible">True</property>
+        <property name="spacing">6</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Auto-Clear Information&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="table1">
+                    <property name="visible">True</property>
+                    <property name="border_width">10</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">4</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="end_label">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Ending Balance:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkHBox" id="end_value_box">
+                        <property name="visible">True</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="status_label">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes"></property>
+                      </widget>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="padding">5</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area6">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="label">gtk-cancel</property>
+                <property name="response_id">-6</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="receives_default">False</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkButton" id="ok_button">
+                <property name="label">gtk-ok</property>
+                <property name="response_id">-5</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">True</property>
+                <property name="use_stock">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2010-02-03 21:01:18 UTC (rev 18609)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-account-tree.c	2010-02-03 21:28:48 UTC (rev 18610)
@@ -62,6 +62,7 @@
 #include "gnc-ui-util.h"
 #include "lot-viewer.h"
 #include "window-reconcile.h"
+#include "window-autoclear.h"
 #include "window-main-summarybar.h"
 
 /* This static indicates the debugging module that this .o belongs to.  */
@@ -130,6 +131,7 @@
 static void gnc_plugin_page_account_tree_cmd_renumber_accounts (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_view_filter_by (GtkAction *action, GncPluginPageAccountTree *plugin_page);
 static void gnc_plugin_page_account_tree_cmd_reconcile (GtkAction *action, GncPluginPageAccountTree *page);
+static void gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_stock_split (GtkAction *action, GncPluginPageAccountTree *page);
 static void gnc_plugin_page_account_tree_cmd_lots (GtkAction *action, GncPluginPageAccountTree *page);
@@ -178,6 +180,9 @@
 	{ "ActionsReconcileAction", NULL, N_("_Reconcile..."), NULL,
 	  N_("Reconcile the selected account"),
 	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_reconcile) },
+	{ "ActionsAutoClearAction", NULL, N_("_Auto-clear..."), NULL,
+	  N_("Automatically clear individual transactions, given a cleared amount"),
+	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_autoclear) },
 	{ "ActionsTransferAction", NULL, N_("_Transfer..."), "<control>t",
 	  N_("Transfer funds from one account to another"),
 	  G_CALLBACK (gnc_plugin_page_account_tree_cmd_transfer) },
@@ -210,6 +215,7 @@
 	"EditEditAccountAction",
 	"EditDeleteAccountAction",
 	"ActionsReconcileAction",
+	"ActionsAutoClearAction",
 	"ActionsLotsAction",
 	NULL
 };
@@ -1158,6 +1164,22 @@
 }
 
 static void
+gnc_plugin_page_account_tree_cmd_autoclear (GtkAction *action,
+					    GncPluginPageAccountTree *page)
+{
+	GtkWidget *window;
+	Account *account;
+	AutoClearWindow *autoClearData;
+
+	account = gnc_plugin_page_account_tree_get_current_account (page);
+	g_return_if_fail (account != NULL);
+
+	window = GNC_PLUGIN_PAGE (page)->window;
+	autoClearData = autoClearWindow (window, account);
+	gnc_ui_autoclear_window_raise (autoClearData);
+}
+
+static void
 gnc_plugin_page_account_tree_cmd_transfer (GtkAction *action,
 					   GncPluginPageAccountTree *page)
 {

Modified: gnucash/trunk/src/gnome/gnc-plugin-page-register.c
===================================================================
--- gnucash/trunk/src/gnome/gnc-plugin-page-register.c	2010-02-03 21:01:18 UTC (rev 18609)
+++ gnucash/trunk/src/gnome/gnc-plugin-page-register.c	2010-02-03 21:28:48 UTC (rev 18610)
@@ -73,6 +73,7 @@
 #include "Scrub.h"
 #include "QueryNew.h"
 #include "window-reconcile.h"
+#include "window-autoclear.h"
 #include "window-report.h"
 
 /* This static indicates the debugging module that this .o belongs to.  */
@@ -133,6 +134,7 @@
 static void gnc_plugin_page_register_cmd_style_double_line (GtkToggleAction *action, GncPluginPageRegister *plugin_page);
 
 static void gnc_plugin_page_register_cmd_reconcile (GtkAction *action, GncPluginPageRegister *plugin_page);
+static void gnc_plugin_page_register_cmd_autoclear (GtkAction *action, GncPluginPageRegister *plugin_page);
 static void gnc_plugin_page_register_cmd_transfer (GtkAction *action, GncPluginPageRegister *plugin_page);
 static void gnc_plugin_page_register_cmd_stock_split (GtkAction *action, GncPluginPageRegister *plugin_page);
 static void gnc_plugin_page_register_cmd_lots (GtkAction *action, GncPluginPageRegister *plugin_page);
@@ -241,6 +243,9 @@
 	{ "ActionsReconcileAction", GTK_STOCK_INDEX, N_("_Reconcile..."), NULL,
 	  N_("Reconcile the selected account"),
 	  G_CALLBACK (gnc_plugin_page_register_cmd_reconcile) },
+	{ "ActionsAutoClearAction", GTK_STOCK_INDEX, N_("_Auto-clear..."), NULL,
+	  N_("Automatically clear individual transactions, so as to reach a certain cleared amount"),
+	  G_CALLBACK (gnc_plugin_page_register_cmd_autoclear) },
 	{ "ActionsStockSplitAction", NULL, N_("Stoc_k Split..."), NULL,
 	  N_("Record a stock split or a stock merger"),
 	  G_CALLBACK (gnc_plugin_page_register_cmd_stock_split) },
@@ -315,6 +320,7 @@
 static const gchar *actions_requiring_account[] = {
 	"EditEditAccountAction",
 	"ActionsReconcileAction",
+	"ActionsAutoClearAction",
 	"ActionsLotsAction",
 	NULL
 };
@@ -340,6 +346,7 @@
   { "ScheduleTransactionAction",  N_("Schedule") },
   { "BlankTransactionAction",     N_("Blank") },
   { "ActionsReconcileAction",     N_("Reconcile") },
+  { "ActionsAutoClearAction",     N_("Auto-clear") },
   { NULL, NULL },
 };
 
@@ -2436,6 +2443,26 @@
 }
 
 static void
+gnc_plugin_page_register_cmd_autoclear (GtkAction *action,
+					GncPluginPageRegister *page)
+{
+  Account *account;
+  GtkWindow *window;
+  AutoClearWindow * autoClearData;
+
+  ENTER("(action %p, plugin_page %p)", action, page);
+
+  g_return_if_fail(GNC_IS_PLUGIN_PAGE_REGISTER(page));
+
+  account = gnc_plugin_page_register_get_account (page);
+
+  window = gnc_window_get_gtk_window(GNC_WINDOW(GNC_PLUGIN_PAGE (page)->window));
+  autoClearData = autoClearWindow (GTK_WIDGET(window), account);
+  gnc_ui_autoclear_window_raise (autoClearData);
+  LEAVE(" ");
+}
+
+static void
 gnc_plugin_page_register_cmd_stock_split (GtkAction *action,
 					  GncPluginPageRegister *page)
 {

Modified: gnucash/trunk/src/gnome/ui/gnc-plugin-page-account-tree-ui.xml
===================================================================
--- gnucash/trunk/src/gnome/ui/gnc-plugin-page-account-tree-ui.xml	2010-02-03 21:01:18 UTC (rev 18609)
+++ gnucash/trunk/src/gnome/ui/gnc-plugin-page-account-tree-ui.xml	2010-02-03 21:28:48 UTC (rev 18610)
@@ -26,6 +26,7 @@
         <separator name="ActionsSep1"/>
 	<menuitem name="ActionsTransfer" action="ActionsTransferAction"/>
 	<menuitem name="ActionsReconcile" action="ActionsReconcileAction"/>
+	<menuitem name="ActionsAutoClear" action="ActionsAutoClearAction"/>
 	<menuitem name="ActionsStockSplit" action="ActionsStockSplitAction"/>
 	<menuitem name="ActionLots" action="ActionsLotsAction"/>
 	<separator name="ActionsSep2"/>
@@ -45,6 +46,7 @@
       <menuitem name="AccountEditAccount" action="EditEditAccountAction"/>
       <separator name="AccountSep1"/>
       <menuitem name="AccountReconcile" action="ActionsReconcileAction"/>
+      <menuitem name="AccountAutoClear" action="ActionsAutoClearAction"/>
       <menuitem name="AccountTransfer" action="ActionsTransferAction"/>
       <menuitem name="AccountStockSplit" action="ActionsStockSplitAction"/>
       <menuitem name="AccountLots" action="ActionsLotsAction"/>

Added: gnucash/trunk/src/gnome/window-autoclear.c
===================================================================
--- gnucash/trunk/src/gnome/window-autoclear.c	                        (rev 0)
+++ gnucash/trunk/src/gnome/window-autoclear.c	2010-02-03 21:28:48 UTC (rev 18610)
@@ -0,0 +1,322 @@
+/********************************************************************\
+ * window-autoclear.c -- the autoclear window                       *
+ * Copyright (C) 2010 Cristian KLEIN                                *
+ *                                                                  *
+ * 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 at gnu.org                   *
+\********************************************************************/
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include "glib-compat.h"
+
+#include "Scrub.h"
+#include "Scrub3.h"
+#include "dialog-account.h"
+#include "dialog-transfer.h"
+#include "dialog-utils.h"
+#include "gnc-amount-edit.h"
+#include "gnc-component-manager.h"
+#include "gnc-date-edit.h"
+#include "gnc-event.h"
+#include "gnc-gconf-utils.h"
+#include "gnc-gnome-utils.h"
+#include "gnc-main-window.h"
+#include "gnc-plugin-page-register.h"
+#include "gnc-ui.h"
+#include "guile-util.h"
+#include "window-autoclear.h"
+
+#define WINDOW_AUTOCLEAR_CM_CLASS "window-autoclear"
+
+
+/** STRUCTS *********************************************************/
+struct _AutoClearWindow
+{
+  Account *account;        /* The account that we are auto-clearing */
+
+  gint component_id;       /* id of component                       */
+
+  GtkWidget *window;       /* The auto-clear window                 */
+  GNCAmountEdit *end_value;/* The ending value                      */
+  GtkWidget *ok_button;
+  GtkWidget *cancel_button;
+  GtkLabel *status_label;
+};
+
+/********************************************************************\
+ * gnc_ui_autoclear_window_raise                                    *
+ *   shows and raises an auto-clear window                          * 
+ *                                                                  * 
+ * Args:   autoClearData - the auto-clear window structure          * 
+\********************************************************************/
+void
+gnc_ui_autoclear_window_raise(AutoClearWindow * autoClearData)
+{
+  if (autoClearData == NULL)
+    return;
+
+  if (autoClearData->window == NULL)
+    return;
+
+  gtk_window_present(GTK_WINDOW(autoClearData->window));
+}
+
+static char *
+gnc_autoclear_make_window_name(Account *account)
+{
+  char *fullname;
+  char *title;
+
+  fullname = gnc_account_get_full_name(account);
+  title = g_strconcat(fullname, " - ", _("Auto-clear"), NULL);
+
+  g_free(fullname);
+
+  return title;
+}
+
+static gboolean
+ght_gnc_numeric_equal(gconstpointer v1, gconstpointer v2)
+{
+  gnc_numeric n1 = *(gnc_numeric *)v1, n2 = *(gnc_numeric *)v2;
+  return gnc_numeric_equal(n1, n2);
+}
+
+static guint
+ght_gnc_numeric_hash(gconstpointer v1)
+{
+  gnc_numeric n1 = *(gnc_numeric *)v1;
+  gdouble d1 = gnc_numeric_to_double(n1);
+  return g_double_hash(&d1);
+}
+
+static void
+gnc_autoclear_window_ok_cb (GtkWidget *widget,
+				    AutoClearWindow *data)
+{
+  GList *node, *nc_list = 0, *toclear_list = 0;
+  gnc_numeric toclear_value;
+  GHashTable *sack;
+    
+  gtk_label_set_text(data->status_label, "Searching for splits to clear ...");
+ 
+  /* Value we have to reach */
+  toclear_value = gnc_amount_edit_get_amount(data->end_value);
+  toclear_value = gnc_numeric_convert(toclear_value, xaccAccountGetCommoditySCU(data->account), GNC_RND_NEVER);
+
+  /* Extract which splits are not cleared and compute the amount we have to clear */
+  for (node = xaccAccountGetSplitList(data->account); node; node = node->next)
+  {
+    Split *split = (Split *)node->data;
+    char recn;
+    gnc_numeric value;
+
+    recn = xaccSplitGetReconcile (split);
+    value = xaccSplitGetAmount (split);
+
+    if (recn == NREC)
+      nc_list = g_list_append(nc_list, split);
+    else
+      toclear_value = gnc_numeric_sub_fixed(toclear_value, value);
+  }
+ 
+  /* Pretty print information */
+  printf("Amount to clear: %s\n", gnc_numeric_to_string(toclear_value));
+  printf("Available splits:\n");
+  for (node = nc_list; node; node = node->next)
+  {
+    Split *split = (Split *)node->data;
+    gnc_numeric value = xaccSplitGetAmount (split);
+    printf("  %s\n", gnc_numeric_to_string(value));
+  }
+
+  /* Run knapsack */
+  /* Entries in the hash table are:
+   *  - key   = amount to which we know how to clear (freed by GHashTable)
+   *  - value = last split we used to clear this amount (not managed by GHashTable)
+   */
+  printf("Knapsacking ...\n");
+  sack = g_hash_table_new_full (ght_gnc_numeric_hash, ght_gnc_numeric_equal, g_free, NULL);
+  for (node = nc_list; node; node = node->next)
+  {
+    Split *split = (Split *)node->data;
+    gnc_numeric split_value = xaccSplitGetAmount(split);
+
+    GHashTableIter iter;
+    gnc_numeric *key;
+    GList *reachable_list = 0, *node;
+
+    printf("  Split value: %s\n", gnc_numeric_to_string(split_value));
+
+    /* For each value in the sack */
+    g_hash_table_iter_init (&iter, sack);
+    while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
+    {
+      /* Compute a new reachable value */
+      gnc_numeric reachable_value = gnc_numeric_add_fixed(*key, split_value);
+      reachable_list = g_list_append(reachable_list, g_memdup(&reachable_value, sizeof(gnc_numeric)));
+      printf("    Sack: found %s, added %s\n", gnc_numeric_to_string(*key), gnc_numeric_to_string(reachable_value));
+    }
+
+    /* Add the value of the split itself to the reachable_list */
+    reachable_list = g_list_append(reachable_list, g_memdup(&split_value, sizeof(gnc_numeric)));
+
+    /* Add everything to the sack, looking out for duplicates */
+    for (node = reachable_list; node; node = node->next)
+    {
+      gnc_numeric *reachable_value = node->data;
+      Split *toinsert_split = split;
+
+      printf("    Reachable value: %s ", gnc_numeric_to_string(*reachable_value));
+
+      /* Check if it already exists */
+      if (g_hash_table_lookup_extended(sack, reachable_value, NULL, NULL))
+      {
+        /* If yes, we are in trouble, we reached an amount using two solutions */
+        toinsert_split = NULL;
+	printf("dup");
+      }
+      g_hash_table_insert (sack, reachable_value, toinsert_split);
+      printf("\n");
+    }
+    g_list_free(reachable_list);
+  }
+
+  /* Check solution */
+  printf("Rebuilding solution ...\n");
+  while (!gnc_numeric_zero_p(toclear_value))
+  {
+    Split *split;
+
+    printf("  Left to clear: %s\n", gnc_numeric_to_string(toclear_value));
+    if (g_hash_table_lookup_extended(sack, &toclear_value, NULL, (gpointer *)&split))
+    {
+      if (split != NULL)
+      {
+        toclear_list = g_list_prepend(toclear_list, split);
+	toclear_value = gnc_numeric_sub_fixed(toclear_value, xaccSplitGetAmount(split));
+        printf("    Cleared: %s -> %s\n", gnc_numeric_to_string(xaccSplitGetAmount(split)), gnc_numeric_to_string(toclear_value));
+      }
+      else
+      {
+        /* We couldn't reconstruct the solution */
+        printf("    Solution not unique.\n");
+        gtk_label_set_text(data->status_label, "Cannot uniquely clear splits. Found multiple possibilities.");
+	return;
+      }
+    }
+    else
+    {
+      printf("    No solution found.\n");
+      gtk_label_set_text(data->status_label, "The selected amount cannot be cleared.");
+      return; 
+    }
+  }
+  g_hash_table_destroy (sack);
+
+  /* Show solution */
+  printf("Clearing splits:\n");
+  for (node = toclear_list; node; node = node->next)
+  {
+    Split *split = node->data;
+    char recn;
+	gnc_numeric value;
+    
+	recn = xaccSplitGetReconcile (split);
+	value = xaccSplitGetAmount (split);
+
+	printf("  %c %s\n", recn, gnc_numeric_to_string(value));
+
+        xaccSplitSetReconcile (split, CREC);
+  }
+  if (toclear_list == 0)
+    printf("  None\n");
+
+  /* Free lists */
+  g_list_free(nc_list);
+  g_list_free(toclear_list);
+
+  /* Close window */
+  gtk_widget_destroy(data->window);
+  g_free(data);
+}
+
+static void
+gnc_autoclear_window_cancel_cb (GtkWidget *widget,
+				    AutoClearWindow *data)
+{
+  /* Close window */
+  gtk_widget_destroy(data->window);
+  g_free(data);
+}
+
+/********************************************************************\
+ * autoClearWindow                                                  *
+ *   opens up the window to auto-clear an account                   *
+ *                                                                  *
+ * Args:   parent  - the parent of this window                      *
+ *         account - the account to auto-clear                      *
+ * Return: autoClearData - the instance of this AutoClearWindow     *
+\********************************************************************/
+AutoClearWindow *
+autoClearWindow (GtkWidget *parent, Account *account)
+{
+  GtkWidget *dialog, *box, *label, *end_value;
+  GladeXML *xml;
+  AutoClearWindow *data;
+  char *title;
+
+  data = g_new0 (AutoClearWindow, 1); 
+  data->account = account;
+
+  /* Create the dialog box */
+  xml = gnc_glade_xml_new ("autoclear.glade", "Auto-clear Start Dialog");
+  dialog = glade_xml_get_widget (xml, "Auto-clear Start Dialog");
+  title = gnc_autoclear_make_window_name (account);
+  gtk_window_set_title(GTK_WINDOW(dialog), title);
+  g_free (title);
+
+  /* Add amount edit box */
+  end_value = gnc_amount_edit_new();
+  data->end_value = GNC_AMOUNT_EDIT(end_value);
+  box = glade_xml_get_widget(xml, "end_value_box");
+  gtk_box_pack_start(GTK_BOX(box), end_value, TRUE, TRUE, 0);
+  label = glade_xml_get_widget(xml, "end_label");
+  gtk_label_set_mnemonic_widget(GTK_LABEL(label), end_value);
+  gtk_widget_grab_focus(GTK_WIDGET(end_value));
+
+  data->window = GTK_WIDGET(dialog);
+
+  if (parent != NULL)
+    gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
+  data->ok_button = glade_xml_get_widget(xml, "ok_button");
+  data->cancel_button = glade_xml_get_widget(xml, "cancel_button");
+  data->status_label = GTK_LABEL(glade_xml_get_widget(xml, "status_label"));
+  
+  g_signal_connect(data->ok_button, "clicked",
+      G_CALLBACK(gnc_autoclear_window_ok_cb), data);
+  g_signal_connect(data->end_value, "activate",
+      G_CALLBACK(gnc_autoclear_window_ok_cb), data);
+  g_signal_connect(data->cancel_button, "clicked",
+      G_CALLBACK(gnc_autoclear_window_cancel_cb), data);
+
+  return data;
+}
+

Added: gnucash/trunk/src/gnome/window-autoclear.h
===================================================================
--- gnucash/trunk/src/gnome/window-autoclear.h	                        (rev 0)
+++ gnucash/trunk/src/gnome/window-autoclear.h	2010-02-03 21:28:48 UTC (rev 18610)
@@ -0,0 +1,31 @@
+/********************************************************************\
+ * window-autoclear.h -- the autoclear window                       *
+ * Copyright (C) 2010 Cristian KLEIN                                *
+ *                                                                  *
+ * 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 at gnu.org                   *
+\********************************************************************/
+
+#ifndef WINDOW_AUTOCLEAR_H
+#define WINDOW_AUTOCLEAR_H
+
+typedef struct _AutoClearWindow AutoClearWindow;
+
+AutoClearWindow *autoClearWindow (gncUIWidget parent, Account *account);
+void gnc_ui_autoclear_window_raise(AutoClearWindow * autoClearData);
+
+#endif



More information about the gnucash-changes mailing list