gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Thu May 1 19:50:14 EDT 2014


Updated	 via  https://github.com/Gnucash/gnucash/commit/f49983b8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/207bedb4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6dfb7feb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/44ca7776 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4d511218 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/96106fb8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f1fdeac4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/93f5d48a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/0418280e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/ecee2d96 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d0be95f2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/291a3abf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/6515a8e8 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/38b3961b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7faed654 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/36eba1ac (commit)
	 via  https://github.com/Gnucash/gnucash/commit/272655b6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3a51d704 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/db1b2cae (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2ff48a66 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d2d0f629 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e5e386d6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c9493cfc (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fadc3d70 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/72c7f1d1 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/11aae5b2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/48df2d35 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/dc8e9c0b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4f5e2289 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c748f33b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f29ea9fb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e3e21b60 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8d9d51a7 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9ea98966 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/e58bcaac (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9b51d42e (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d5a9cda7 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/1f3fbf4b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4a4b1805 (commit)
	from  https://github.com/Gnucash/gnucash/commit/acad5a02 (commit)



commit f49983b8012197933c793fe94994ac5afa1d8d75
Merge: acad5a0 207bedb
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu May 1 13:15:29 2014 -0700

    Merge branch 'private-kvp'
    
    Makes all kvp operations private to the object of which the kvp is
    a member. Access from outside of the object is accomplished via
    GObject Properties. A convenience function, qof_instance_set(),
    is provided that wraps g_object_set and marks dirty the instance
    so that it will be saved. It is still necessary to wrap calls in
    begin_edit/commit to accomplish the save to the SQL backend. A
    like-named wrapper, qof_instance_get() is provided to balance the API.
    
    Note that the XML backend retains direct access to KVP to avoid having
    to catalog the properties.

diff --cc src/app-utils/test/Makefile.am
index 3a00263,765aed4..75d0ab8
--- a/src/app-utils/test/Makefile.am
+++ b/src/app-utils/test/Makefile.am
@@@ -52,7 -52,7 +54,7 @@@ check_PROGRAMS = 
    test-print-queries \
    test-sx
  
--EXTRA_DIST = \
++EXTRA_DIST += \
    test-load-module
  
  AM_CPPFLAGS = \
@@@ -64,5 -64,19 +66,19 @@@
    -I${top_srcdir}/src/gnc-module \
    -I${top_srcdir}/src/core-utils \
    -I${top_srcdir}/src/libqof/qof \
 -  ${GUILE_INCS} \
 +  ${GUILE_CFLAGS} \
    ${GLIB_CFLAGS}
+ 
+ TEST_PROGS += test-app-utils
+ 
+ noinst_PROGRAMS = ${TEST_PROGS} ${CHECK_PROGS}
+ 
+ test_app_utils_SOURCES = \
+ 	test-app-utils.c \
+ 	test-option-util.c
+ 
+ test_app_utils_CFLAGS = \
+ 	${DEFAULT_INCLUDES} \
+ 	-I${top_srcdir}/${MODULEPATH}/ \
+ 	-DTESTPROG=test_app_utils \
+ 	${GLIB_CFLAGS}
diff --cc src/backend/xml/gnc-address-xml-v2.c
index 2e84319,bada2bf..1815e0b
--- a/src/backend/xml/gnc-address-xml-v2.c
+++ b/src/backend/xml/gnc-address-xml-v2.c
@@@ -58,6 -58,6 +58,9 @@@ const gchar *address_version_string = "
  #define addr_email_string	"addr:email"
  #define addr_slots_string	"addr:slots"
  
++/* EFFECTIVE FRIEND FUNCTION */
++extern KvpFrame *qof_instance_get_slots (const QofInstance*);
++
  static void
  maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
  {
@@@ -186,10 -175,7 +189,10 @@@ address_email_handler (xmlNodePtr node
  static gboolean
  address_slots_handler (xmlNodePtr node, gpointer addr_pdata)
  {
 -    return TRUE;
 +    struct address_pdata *pdata = addr_pdata;
 +
 +    return dom_tree_to_kvp_frame_given
-            (node, xaccAccountGetSlots (pdata->address));
++        (node, qof_instance_get_slots (QOF_INSTANCE (pdata->address)));
  }
  
  static struct dom_tree_handler address_handlers_v2[] =
diff --cc src/backend/xml/gnc-entry-xml-v2.c
index 713bef9,c7a414f..96d0e3b
--- a/src/backend/xml/gnc-entry-xml-v2.c
+++ b/src/backend/xml/gnc-entry-xml-v2.c
@@@ -92,6 -92,6 +92,9 @@@ const gchar *entry_version_string = "2.
  #define entry_bill_string "entry:bill"
  #define entry_slots_string "entry:slots"
  
++/* EFFECTIVE FRIEND FUNCTION */
++extern KvpFrame *qof_instance_get_slots (const QofInstance*);
++
  static void
  maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
  {
@@@ -672,10 -661,7 +675,10 @@@ entry_price_handler (xmlNodePtr node, g
  static gboolean
  entry_slots_handler (xmlNodePtr node, gpointer entry_pdata)
  {
 -    return TRUE;
 +    struct entry_pdata *pdata = entry_pdata;
 +
 +    return dom_tree_to_kvp_frame_given
-            (node, xaccAccountGetSlots (pdata->entry));
++        (node, qof_instance_get_slots (QOF_INSTANCE (pdata->entry)));
  }
  
  static struct dom_tree_handler entry_handlers_v2[] =
diff --cc src/backend/xml/gnc-job-xml-v2.c
index 1ed84df,d4a5e8f..6a6f513
--- a/src/backend/xml/gnc-job-xml-v2.c
+++ b/src/backend/xml/gnc-job-xml-v2.c
@@@ -62,6 -62,6 +62,9 @@@ const gchar *job_version_string = "2.0.
  #define job_active_string "job:active"
  #define job_slots_string "job:slots"
  
++/* EFFECTIVE FRIEND FUNCTION */
++extern KvpFrame *qof_instance_get_slots (const QofInstance*);
++
  static xmlNodePtr
  job_dom_tree_create (GncJob *job)
  {
@@@ -204,10 -193,7 +207,10 @@@ job_active_handler (xmlNodePtr node, gp
  static gboolean
  job_slots_handler (xmlNodePtr node, gpointer job_pdata)
  {
 -    return TRUE;
 +    struct job_pdata *pdata = job_pdata;
 +
 +    return dom_tree_to_kvp_frame_given
-            (node, xaccAccountGetSlots (pdata->job));
++        (node, qof_instance_get_slots (QOF_INSTANCE (pdata->job)));
  }
  
  static struct dom_tree_handler job_handlers_v2[] =
diff --cc src/backend/xml/gnc-order-xml-v2.c
index c393182,7b58415..cb5fdfb
--- a/src/backend/xml/gnc-order-xml-v2.c
+++ b/src/backend/xml/gnc-order-xml-v2.c
@@@ -46,7 -46,7 +46,7 @@@
  #include "gnc-order-xml-v2.h"
  #include "gnc-owner-xml-v2.h"
  
--#define _GNC_MOD_NAME	GNC_ID_ORDER
++#define _GNC_MOD_NAME   GNC_ID_ORDER
  
  static QofLogModule log_module = GNC_MOD_IO;
  
@@@ -64,6 -64,6 +64,9 @@@ const gchar *order_version_string = "2.
  #define order_active_string "order:active"
  #define order_slots_string "order:slots"
  
++/* EFFECTIVE FRIEND FUNCTION */
++extern KvpFrame *qof_instance_get_slots (const QofInstance*);
++
  static void
  maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
  {
@@@ -245,10 -234,7 +248,10 @@@ order_active_handler (xmlNodePtr node, 
  static gboolean
  order_slots_handler (xmlNodePtr node, gpointer order_pdata)
  {
 -    return TRUE;
 +    struct order_pdata *pdata = order_pdata;
 +
 +    return dom_tree_to_kvp_frame_given
-            (node, xaccAccountGetSlots (pdata->order));
++        (node, qof_instance_get_slots (QOF_INSTANCE (pdata->order)));
  }
  
  static struct dom_tree_handler order_handlers_v2[] =
diff --cc src/backend/xml/gnc-tax-table-xml-v2.c
index aeff781,31b4538..0990e4b
--- a/src/backend/xml/gnc-tax-table-xml-v2.c
+++ b/src/backend/xml/gnc-tax-table-xml-v2.c
@@@ -67,6 -67,6 +67,9 @@@ const gchar *taxtable_version_string = 
  #define ttentry_type_string "tte:type"
  #define ttentry_amount_string "tte:amount"
  
++/* EFFECTIVE FRIEND FUNCTION */
++extern KvpFrame *qof_instance_get_slots (const QofInstance*);
++
  static void
  maybe_add_guid (xmlNodePtr ptr, const char *tag, GncTaxTable *table)
  {
@@@ -379,10 -368,7 +382,10 @@@ taxtable_entries_handler (xmlNodePtr no
  static gboolean
  taxtable_slots_handler (xmlNodePtr node, gpointer taxtable_pdata)
  {
 -    return TRUE;
 +    struct taxtable_pdata *pdata = taxtable_pdata;
 +
 +    return dom_tree_to_kvp_frame_given
-            (node, xaccAccountGetSlots (pdata->table));
++        (node, qof_instance_get_slots (QOF_INSTANCE (pdata->table)));
  }
  
  static struct dom_tree_handler taxtable_handlers_v2[] =
diff --cc src/business/business-gnome/dialog-invoice.c
index 5acee72,75edcf8..c00a5e4
--- a/src/business/business-gnome/dialog-invoice.c
+++ b/src/business/business-gnome/dialog-invoice.c
@@@ -762,13 -757,10 +761,11 @@@ gnc_invoice_post(InvoiceWindow *iw, str
      Timespec ddue, postdate;
      gboolean accumulate;
      QofInstance *owner_inst;
-     KvpFrame *kvpf;
-     KvpValue *kvp_val;
      const char *text;
 -    EntryList *entries, *entries_iter;
 -    GncEntry* entry;
 -    gboolean is_cust_doc, is_cn, auto_pay;
 +    GHashTable *foreign_currs;
 +    GHashTableIter foreign_currs_iter;
 +    gpointer key,value;
 +    gboolean is_cust_doc, auto_pay;
      gboolean show_dialog = TRUE;
      gboolean post_ok = TRUE;
  
diff --cc src/core-utils/gnc-features.c
index 0336fe2,32f20cd..5b341c9
--- a/src/core-utils/gnc-features.c
+++ b/src/core-utils/gnc-features.c
@@@ -92,42 -94,34 +95,34 @@@ static void gnc_features_test_one(gpoin
   */
  gchar *gnc_features_test_unknown (QofBook *book)
  {
-     KvpFrame *frame = qof_book_get_slots (book);
-     KvpValue *value;
+ 
 -    /* Setup the known_features hash table */
 -    gnc_features_init();
 -
+     GList* features_list = NULL;
+     GHashTable *features_used = qof_book_get_features (book);
  
 +    /* Setup the known_features hash table */
 +    gnc_features_init();
 +
-     g_assert(frame);
-     value = kvp_frame_get_value(frame, "features");
- 
-     if (value)
+     /* Iterate over the members of this frame for unknown features */
+     g_hash_table_foreach (features_used, &gnc_features_test_one,
+ 			  &features_list);
+     if (features_list)
      {
-         GList* features_list = NULL;
-         frame = kvp_value_get_frame(value);
-         g_assert(frame);
- 
-         /* Iterate over the members of this frame for unknown features */
-         kvp_frame_for_each_slot(frame, &gnc_features_test_one, &features_list);
-         if (features_list)
-         {
-             GList *i;
-             char* msg = g_strdup(
-                             _("This Dataset contains features not supported by this "
-                               "version of GnuCash. You must use a newer version of "
-                               "GnuCash in order to support the following features:"
+ 	GList *i;
+ 	char* msg = g_strdup(_("This Dataset contains features not supported "
+ 			       "by this version of GnuCash. You must use a "
+ 			       "newer version of GnuCash in order to support "
+ 			       "the following features:"
                               ));
  
-             for (i = features_list; i; i = i->next)
-             {
-                 char *tmp = g_strconcat(msg, "\n* ", i->data, NULL);
-                 g_free (msg);
-                 msg = tmp;
-             }
+ 	for (i = features_list; i; i = i->next)
+ 	{
+ 	    char *tmp = g_strconcat(msg, "\n* ", i->data, NULL);
+ 	    g_free (msg);
+ 	    msg = tmp;
+ 	}
  
-             g_list_free(features_list);
-             return msg;
-         }
+ 	g_list_free(features_list);
+ 	return msg;
      }
  
      return NULL;
diff --cc src/engine/gncJob.c
index fe7043d,1715d3a..d4200a1
--- a/src/engine/gncJob.c
+++ b/src/engine/gncJob.c
@@@ -30,8 -30,8 +30,9 @@@
  
  #include <glib.h>
  #include <string.h>
+ #include <qofinstance-p.h>
  
 +#include "gnc-features.h"
  #include "gncInvoice.h"
  #include "gncJob.h"
  #include "gncJobP.h"
diff --cc src/engine/gncTaxTable.c
index 8650217,234e657..2c525f4
--- a/src/engine/gncTaxTable.c
+++ b/src/engine/gncTaxTable.c
@@@ -26,11 -26,11 +26,12 @@@
   * Author: Derek Atkins <warlord at MIT.EDU>
   */
  
- #include "config.h"
+ #include <config.h>
  
  #include <glib.h>
+ #include <qofinstance-p.h>
  
 +#include "gnc-features.h"
  #include "gncTaxTableP.h"
  
  struct _gncTaxTable
diff --cc src/engine/test/Makefile.am
index ec7bed0,5e216d1..9e1f098
--- a/src/engine/test/Makefile.am
+++ b/src/engine/test/Makefile.am
@@@ -116,7 -115,7 +116,8 @@@ test_engine_SOURCES = 
  	utest-Account.c \
  	utest-Budget.c \
  	utest-Invoice.c \
 -	test-engine-kvp-properties.c
++	test-engine-kvp-properties.c \
 +	dummy.cpp
  
  test_engine_LDADD = \
  	libutest-Split.la \
diff --cc src/import-export/CMakeLists.txt
index 5f93071,b73a4dc..0a21959
--- a/src/import-export/CMakeLists.txt
+++ b/src/import-export/CMakeLists.txt
@@@ -24,7 -24,7 +24,6 @@@ INCLUDE_DIRECTORIES (${CMAKE_SOURCE_DIR
  SET (libgnc_import_SOURCES
    import-utilities.c
    import-settings.c
--  import-match-map.c
  )
  
  # Add dependency on config.h
@@@ -33,7 -33,7 +32,6 @@@ SET_SOURCE_FILES_PROPERTIES (${libgnc_i
  SET (libgnc_import_HEADERS
    import-utilities.h
    import-settings.h
--  import-match-map.h
  )
  
  ADD_LIBRARY (gnc-import
diff --cc src/import-export/import-utilities.c
index 51b8f53,60bf1ae..e55ea20
--- a/src/import-export/import-utilities.c
+++ b/src/import-export/import-utilities.c
@@@ -94,16 -88,11 +88,13 @@@ const gchar * gnc_import_get_split_onli
  }
  /* Used several places in a transaction edit where many other
   * parameters are also being set, so individual commits wouldn't be
-  * appropriate. */
- void gnc_import_set_split_online_id(Split * split,
-                                     const gchar * string_value)
+  * appropriate. Besides, there isn't a function for one.*/
+ void gnc_import_set_split_online_id (Split *split, const gchar *id)
  {
-     kvp_frame * frame;
+     g_return_if_fail (split != NULL);
 +    xaccTransBeginEdit (xaccSplitGetParent (split));
-     frame = xaccSplitGetSlots(split);
-     kvp_frame_set_str (frame, "online_id", string_value);
-     qof_instance_set_dirty (QOF_INSTANCE (split));
+     qof_instance_set (QOF_INSTANCE (split), "online-id", &id, NULL);
 +    xaccTransCommitEdit (xaccSplitGetParent (split));
  }
  
  gboolean gnc_import_split_has_online_id(Split * split)
diff --cc src/import-export/ofx/gnc-ofx-kvp.c
index 05b26e7,e4e5d6f..8b6f670
--- a/src/import-export/ofx/gnc-ofx-kvp.c
+++ b/src/import-export/ofx/gnc-ofx-kvp.c
@@@ -31,20 -32,14 +31,14 @@@ static const char *KEY_ASSOC_INCOME_ACC
  
  Account *gnc_ofx_kvp_get_assoc_account(const Account* investment_account)
  {
-     kvp_frame * acc_frame;
-     kvp_value * kvp_val;
      Account *result = NULL;
- 
+     GncGUID *income_guid= NULL;
      g_assert(investment_account);
- 
-     acc_frame = xaccAccountGetSlots(investment_account);
-     kvp_val = kvp_frame_get_slot(acc_frame, KEY_ASSOC_INCOME_ACCOUNT);
-     if (kvp_val != NULL)
-     {
-         result = xaccAccountLookup(kvp_value_get_guid(kvp_val),
-                                    gnc_account_get_book(investment_account));
-     }
-     return result;
+     qof_instance_get (QOF_INSTANCE (investment_account),
 -		      "ofx-income-account", &income_guid,
++		      KEY_ASSOC_INCOME_ACCOUNT, &income_guid,
+ 		      NULL);
+     return xaccAccountLookup(income_guid,
+ 			       gnc_account_get_book(investment_account));
  }
  
  void gnc_ofx_kvp_set_assoc_account(Account* investment_account,
@@@ -57,13 -50,10 +49,10 @@@
      g_assert(investment_account);
      g_assert(income_account);
  
-     acc_frame = xaccAccountGetSlots(investment_account);
-     g_assert(acc_frame); // Must not be NULL, but the QofInstance doc is unclear about this
      income_acc_guid = xaccAccountGetGUID(income_account);
-     kvp_val = kvp_value_new_guid(income_acc_guid);
      xaccAccountBeginEdit(investment_account);
-     kvp_frame_set_slot_nc(acc_frame, KEY_ASSOC_INCOME_ACCOUNT,
-                           kvp_val);
-     qof_instance_set_dirty(QOF_INSTANCE (investment_account));
+     qof_instance_set (QOF_INSTANCE (investment_account),
 -		      "ofx-income-account", income_acc_guid,
++		      KEY_ASSOC_INCOME_ACCOUNT, income_acc_guid,
+ 		      NULL);
      xaccAccountCommitEdit(investment_account);
  }
diff --cc src/libqof/qof/kvp_frame.h
index 440377a,104a479..12f9ab5
--- a/src/libqof/qof/kvp_frame.h
+++ b/src/libqof/qof/kvp_frame.h
@@@ -594,9 -588,58 +594,62 @@@ gchar* kvp_frame_to_string(const KvpFra
  gchar* binary_to_string(const void *data, guint32 size);
  GHashTable* kvp_frame_get_hash(const KvpFrame *frame);
  
+ /** KvpItem: GValue Exchange
+  * \brief Transfer of KVP to and from GValue, with the key
+  *
+  * Used to parameterize KVP <-> GValue exchanges.
+  */
+ typedef struct
+ {
+     const gchar   *key;
+     GValue        *value;
+ }KvpItem;
+ 
+ /** Return a KvpItem containing the value of a KvpFrame
+  *
+  * Structure types (gnc_numeric, Timespec) are converted to pointers
+  * and must be extracted with g_value_get_boxed. A KVP_TYPE_GLIST will
+  * have all of its contents converted from KvpValues to GValues, so
+  * the return type will be a GValue containing a GList of GValue*, not
+  * GValue.  Use gnc_value_list_free() to free such a list if you take
+  * it out of the GValue.
+  *
+  * \param frame: (transfer-none) The KvpFrame retrieved with kvp_get_frame_foo()
+  * \param key: (transfer-none) A slash-delimited string with the path to
+  * the stored value. Must not be NULL or empty.
+  * \return (transfer-full) A KvpItem* which must be freed with kvp_item_free().
+  */
+ GValue *kvp_frame_get_gvalue (KvpFrame *frame, const gchar *key);
+ 
+ /** Replace or create a Kvp slot from a KvpItem
+  *
+  * Structure types (gnc_numeric, Timespec) should be stored as
+  * boxed-type pointers in the GValue with the appropriate type from
+  * qof.h. Lists should be stored as a GValue containing a GList of
+  * GValues of type convertable to KvpValues. Unsupported types will
+  * emit a warning message and will be skipped.
+  *
+  * \param frame: (transfer none) The KvpFrame into which the value
+  * will be added.
+  * \param key: (transfer none) The subkey of the frame at which to
+  * store the value
+  * \param value: GValue containing the paramter to store.
+  */
+ void kvp_frame_set_gvalue (KvpFrame *frame, const gchar *key, const GValue *value);
+ 
+ /**
+  * \brief Convenience function to release the value in a GValue
+  * acquired by kvp_frame_get_gvalue and to free the GValue.
+  * \param value: A GValue* created by kvp_frame_get_gvalue
+  */
+ void gnc_gvalue_free (GValue *value);
+ 
+ GType gnc_value_list_get_type (void);
+ #define GNC_TYPE_VALUE_LIST (gnc_value_list_get_type ())
+ 
  /** @} */
 +#ifdef __cplusplus
 +}
 +#endif
 +
  #endif
diff --cc src/libqof/qof/qofbook.cpp
index 0ae2b21,4c04542..baaa421
--- a/src/libqof/qof/qofbook.cpp
+++ b/src/libqof/qof/qofbook.cpp
@@@ -58,9 -49,29 +58,30 @@@ extern "C
  #include "qofbookslots.h"
  
  static QofLogModule log_module = QOF_MOD_ENGINE;
+ #define AB_KEY "hbci"
+ #define AB_TEMPLATES "template-list"
+ 
+ enum
+ {
+     PROP_0,
+ //  PROP_ROOT_ACCOUNT,		/* Table */
+ //  PROP_ROOT_TEMPLATE,		/* Table */
+     PROP_OPT_TRADING_ACCOUNTS,	/* KVP */
+     PROP_OPT_AUTO_READONLY_DAYS,/* KVP */
+     PROP_OPT_NUM_FIELD_SOURCE,	/* KVP */
+     PROP_OPT_DEFAULT_BUDGET,	/* KVP */
+     PROP_OPT_FY_END,		/* KVP */
+     PROP_AB_TEMPLATES,		/* KVP */
+     N_PROPERTIES		/* Just a counter */
+ };
  
- QOF_GOBJECT_IMPL(qof_book, QofBook, QOF_TYPE_INSTANCE);
+ QOF_GOBJECT_GET_TYPE(QofBook, qof_book, QOF_TYPE_INSTANCE, {});
+ QOF_GOBJECT_DISPOSE(qof_book);
+ QOF_GOBJECT_FINALIZE(qof_book);
  
+ static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 -
++#undef G_PARAM_READWRITE
++#define G_PARAM_READWRITE static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)
  /* ====================================================================== */
  /* constructor / destructor */
  
@@@ -90,6 -101,186 +111,186 @@@ qof_book_init (QofBook *book
      book->version = 0;
  }
  
+ static void
+ qof_book_get_property (GObject* object,
+ 		       guint prop_id,
+ 		       GValue* value,
+ 		       GParamSpec* pspec)
+ {
+     QofBook *book;
+     gchar *key;
+ 
+     g_return_if_fail (QOF_IS_BOOK (object));
+     book = QOF_BOOK (object);
+     switch (prop_id)
+     {
+     case PROP_OPT_TRADING_ACCOUNTS:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_TRADING_ACCOUNTS);
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_AUTO_READONLY_DAYS:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_AUTO_READONLY_DAYS);
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_NUM_FIELD_SOURCE:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_NUM_FIELD_SOURCE);
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_DEFAULT_BUDGET:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_DEFAULT_BUDGET);
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+     case PROP_OPT_FY_END:
 -	key = "fy_end";
++	key = const_cast<char*>("fy_end");
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	break;
+     case PROP_AB_TEMPLATES:
 -	key = AB_KEY "/" AB_TEMPLATES;
++	key = const_cast<char*>(AB_KEY "/" AB_TEMPLATES);
+ 	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+ 	break;
+     default:
+         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+         break;
+     }
+ }
+ 
+ static void
+ qof_book_set_property (GObject      *object,
+ 		       guint         prop_id,
+ 		       const GValue *value,
+ 		       GParamSpec   *pspec)
+ {
+     QofBook *book;
+     gchar *key;
+ 
+     g_return_if_fail (QOF_IS_BOOK (object));
+     book = QOF_BOOK (object);
+     g_assert (qof_instance_get_editlevel(book));
+ 
+     switch (prop_id)
+     {
+     case PROP_OPT_TRADING_ACCOUNTS:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_TRADING_ACCOUNTS);
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_AUTO_READONLY_DAYS:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_AUTO_READONLY_DAYS);
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_NUM_FIELD_SOURCE:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_NUM_FIELD_SOURCE);
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_DEFAULT_BUDGET:
+ 	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+ 			       OPTION_SECTION_ACCOUNTS,
+ 			       OPTION_NAME_DEFAULT_BUDGET);
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	g_free (key);
+ 	break;
+     case PROP_OPT_FY_END:
 -	key = "fy_end";
++	key = const_cast<char*>("fy_end");
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	break;
+     case PROP_AB_TEMPLATES:
 -	key = AB_KEY "/" AB_TEMPLATES;
++	key = const_cast<char*>(AB_KEY "/" AB_TEMPLATES);
+ 	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+ 	break;
+     default:
+         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+         break;
+     }
+ }
+ 
+ static void
+ qof_book_class_init (QofBookClass *klass)
+ {
+     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+     gobject_class->dispose = qof_book_dispose;
+     gobject_class->finalize = qof_book_finalize;
+     gobject_class->get_property = qof_book_get_property;
+     gobject_class->set_property = qof_book_set_property;
+ 
+     g_object_class_install_property
+     (gobject_class,
+      PROP_OPT_TRADING_ACCOUNTS,
+      g_param_spec_string("trading-accts",
+                          "Use Trading Accounts",
+ 			 "Scheme true ('t') or NULL. If 't', then the book "
+ 			 "uses trading accounts for managing multiple-currency "
+ 			 "transactions.",
+                          NULL,
+                          G_PARAM_READWRITE));
+ 
+     g_object_class_install_property
+     (gobject_class,
+      PROP_OPT_NUM_FIELD_SOURCE,
+      g_param_spec_string("split-action-num-field",
+                          "Use Split-Action in the Num Field",
+ 			 "Scheme true ('t') or NULL. If 't', then the book "
+ 			 "will put the split action value in the Num field.",
+                          NULL,
+                          G_PARAM_READWRITE));
+ 
+     g_object_class_install_property
+     (gobject_class,
+      PROP_OPT_AUTO_READONLY_DAYS,
+      g_param_spec_double("autoreadonly-days",
+                          "Transaction Auto-read-only Days",
+ 			 "Prevent editing of transactions posted more than "
+ 			 "this many days ago.",
+ 			 0,
+                          G_MAXDOUBLE,
+ 			 0,
+                          G_PARAM_READWRITE));
+ 
+     g_object_class_install_property
+     (gobject_class,
+      PROP_OPT_DEFAULT_BUDGET,
+      g_param_spec_boxed("default-budget",
+                         "Book Default Budget",
+                         "The default Budget for this book.",
+                         GNC_TYPE_GUID,
+                         G_PARAM_READWRITE));
+     g_object_class_install_property
+     (gobject_class,
+      PROP_OPT_FY_END,
+      g_param_spec_boxed("fy-end",
+                         "Book Fiscal Year End",
+                         "A GDate with a bogus year having the last Month and "
+ 			"Day of the Fiscal year for the book.",
+                         G_TYPE_DATE,
+                         G_PARAM_READWRITE));
+     g_object_class_install_property
+     (gobject_class,
+      PROP_AB_TEMPLATES,
+      g_param_spec_boxed("ab-templates",
+                         "AQBanking Template List",
+                         "A GList of AQBanking Templates",
+                         GNC_TYPE_VALUE_LIST,
+                         G_PARAM_READWRITE));
+ }
+ 
  QofBook *
  qof_book_new (void)
  {
@@@ -752,7 -906,53 +917,53 @@@ static void commit_err (G_GNUC_UNUSED Q
  //  gnc_engine_signal_commit_error( errcode );
  }
  
+ #define GNC_FEATURES "/features/"
+ static void
+ add_feature_to_hash (const gchar *key, KvpValue *value, gpointer user_data)
+ {
+     gchar *descr = kvp_value_get_string (value);
+     g_hash_table_insert (*(GHashTable**)user_data, (gchar*)key, descr);
+ }
+ 
+ GHashTable *
+ qof_book_get_features (QofBook *book)
+ {
+     KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+     GHashTable *features = g_hash_table_new (g_str_hash, g_str_equal);
+ 
+     frame = kvp_frame_get_frame (frame, GNC_FEATURES);
+     kvp_frame_for_each_slot (frame, &add_feature_to_hash, &features);
+     return features;
+ }
+ 
+ void
+ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
+ {
+     KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+     gchar *path = g_strconcat (GNC_FEATURES, key, NULL);
+     qof_book_begin_edit (book);
+     kvp_frame_set_string (frame, path, descr);
+     qof_instance_set_dirty (QOF_INSTANCE (book));
+     qof_book_commit_edit (book);
+ }
+ 
+ void
+ qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
+ {
+     KvpFrame *slots = qof_instance_get_slots (QOF_INSTANCE (book));
+     load_cb (odb, slots);
+ }
+ 
+ void
+ qof_book_save_options (QofBook *book, GNCOptionSave save_cb,
+ 		       GNCOptionDB* odb, gboolean clear)
+ {
+     KvpFrame *slots = qof_instance_get_slots (QOF_INSTANCE (book));
+     save_cb (odb, slots, clear);
+     qof_instance_set_dirty (QOF_INSTANCE (book));
+ }
+ 
 -static void noop (QofInstance *inst) {}
 +static void noop (G_GNUC_UNUSED QofInstance *inst) {}
  
  void
  qof_book_commit_edit(QofBook *book)
diff --cc src/libqof/qof/qofid.cpp
index 6febf64,7f7f472..6ff6703
--- a/src/libqof/qof/qofid.cpp
+++ b/src/libqof/qof/qofid.cpp
@@@ -32,12 -27,9 +32,13 @@@ extern "C
  #include <string.h>
  #include <glib.h>
  
 +#ifdef __cplusplus
 +}
 +#endif
 +
  #include "qof.h"
  #include "qofid-p.h"
+ #include "qofinstance-p.h"
  
  static QofLogModule log_module = QOF_MOD_ENGINE;
  static gboolean qof_alt_dirty_mode = FALSE;
diff --cc src/libqof/qof/qofinstance-p.h
index aede28c,0306b9e..751b3f0
--- a/src/libqof/qof/qofinstance-p.h
+++ b/src/libqof/qof/qofinstance-p.h
@@@ -54,8 -49,59 +54,64 @@@ void qof_instance_set_last_update (QofI
   *  collection flag at all. */
  void qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag);
  
+ /** Set the GncGUID of this instance */
+ void qof_instance_set_guid (gpointer inst, const GncGUID *guid);
+ 
+ /** Copy the GncGUID from one instance to another.  This routine should
+  *  be used with extreme caution, since GncGUID values are everywhere
+  *  assumed to be unique. */
+ void qof_instance_copy_guid (gpointer to, gconstpointer from);
+ 
+ //QofIdType qof_instance_get_e_type (const QofInstance *inst);
+ //void qof_instance_set_e_type (QofInstance *ent, QofIdType e_type);
+ 
+ /** Return the pointer to the kvp_data */
+ /*@ dependent @*/
+ KvpFrame* qof_instance_get_slots (const QofInstance *);
+ void qof_instance_set_editlevel(gpointer inst, gint level);
+ void qof_instance_increase_editlevel (gpointer ptr);
+ void qof_instance_decrease_editlevel (gpointer ptr);
+ void qof_instance_reset_editlevel (gpointer ptr);
+ /** Set the flag that indicates whether or not this object is about to
+  *  be destroyed.
+  *
+  *  @param ptr The object whose flag should be set.
+  *
+  *  @param value The new value to be set for this object. */
+ void qof_instance_set_destroying (gpointer ptr, gboolean value);
+ 
+ /** \brief Set the dirty flag
+ Sets this instance AND the collection as dirty.
+ */
+ void qof_instance_set_dirty(QofInstance* inst);
+ 
+ /* reset the dirty flag */
+ void qof_instance_mark_clean (QofInstance *);
+ /** Get the version number on this instance.  The version number is
+  *  used to manage multi-user updates. */
+ gint32 qof_instance_get_version (gconstpointer inst);
+ 
+ /** Set the version number on this instance.  The version number is
+  *  used to manage multi-user updates. */
+ void qof_instance_set_version (gpointer inst, gint32 value);
+ /** Copy the version number on this instance.  The version number is
+  *  used to manage multi-user updates. */
+ void qof_instance_copy_version (gpointer to, gconstpointer from);
+ 
+ /** Get the instance version_check number */
+ guint32 qof_instance_get_version_check (gconstpointer inst);
+ /** Set the instance version_check number */
+ void qof_instance_set_version_check (gpointer inst, guint32 value);
+ /** copy the instance version_check number */
+ void qof_instance_copy_version_check (gpointer to, gconstpointer from);
+ void qof_instance_set_idata(gpointer inst, guint32 idata);
+ /* Convenience functions to save some typing in property handlers */
+ void qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value);
+ void qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value);
+ 
 +#ifdef __cplusplus
 +}
 +#endif
 +
++
  #endif /* QOF_INSTANCE_P_H */
diff --cc src/libqof/qof/qofinstance.cpp
index dc32af7,8001d60..b5ac003
--- a/src/libqof/qof/qofinstance.cpp
+++ b/src/libqof/qof/qofinstance.cpp
@@@ -445,21 -414,16 +426,18 @@@ qof_instance_set_property (GObjec
      switch (prop_id)
      {
      case PROP_GUID:
 -        qof_instance_set_guid(inst, g_value_get_boxed(value));
 +        qof_instance_set_guid(inst,
 +			      static_cast<GncGUID*>(g_value_get_boxed(value)));
          break;
      case PROP_COLLECTION:
 -        qof_instance_set_collection(inst, g_value_get_pointer(value));
 +        qof_instance_set_collection(inst, static_cast<QofCollection*>(g_value_get_pointer(value)));
          break;
      case PROP_BOOK:
 -        qof_instance_set_book(inst, g_value_get_object(value));
 +        qof_instance_set_book(inst,
 +			      static_cast<QofBook*>(g_value_get_object(value)));
          break;
-     case PROP_KVP_DATA:
-         qof_instance_set_slots(inst, static_cast<KvpFrame*>(g_value_get_pointer(value)));
-         break;
      case PROP_LAST_UPDATE:
 -        ts = g_value_get_pointer(value);
 +        ts = static_cast<Timespec*>(g_value_get_pointer(value));
          qof_instance_set_last_update(inst, *ts);
          break;
      case PROP_DESTROYING:
diff --cc src/libqof/qof/qoflog.cpp
index bd0f7d5,ea13eef..3475ca3
--- a/src/libqof/qof/qoflog.cpp
+++ b/src/libqof/qof/qoflog.cpp
@@@ -268,6 -258,6 +268,8 @@@ qof_log_prettify (const char *name
      begin = g_strrstr (buffer, "*");
      if (begin == NULL)
  	begin = g_strrstr (buffer, " ");
++    else if (*(begin + 1) == ' ')
++	++ begin;
      if (begin != NULL)
  	p = begin + 1;
      else
diff --cc src/libqof/qof/test/test-kvp_frame.c
index 6267f70,aaf7c74..c1e5f4a
--- a/src/libqof/qof/test/test-kvp_frame.c
+++ b/src/libqof/qof/test/test-kvp_frame.c
@@@ -27,12 -22,7 +27,12 @@@ extern "C
  #include "config.h"
  #include <string.h>
  #include <glib.h>
- #include "unittest-support.h"
+ #include <unittest-support.h>
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
  #include "qof.h"
  
  static const gchar *suitename = "/qof/kvp_frame";
diff --cc src/register/ledger-core/split-register-model-save.c
index b22bdee,6d9ea63..60582d4
--- a/src/register/ledger-core/split-register-model-save.c
+++ b/src/register/ledger-core/split-register-model-save.c
@@@ -748,20 -728,19 +728,20 @@@ gnc_template_register_save_debcred_cel
  
      /* If the value can be parsed into a numeric result, store that
       * numeric value additionally. See above comment.*/
-     parse_result = gnc_exp_parser_parse_separate_vars(value, &new_amount, &error_loc, NULL);
+     parse_result = gnc_exp_parser_parse_separate_vars(debit_formula,
+ 						      &debit_amount,
+ 						      &error_loc, NULL);
      if (!parse_result)
-     {
-         new_amount = gnc_numeric_zero();
-     }
-     kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_amount),
-                              GNC_SX_ID,
-                              GNC_SX_DEBIT_NUMERIC,
-                              NULL);
- 
-     DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));
- 
+         debit_amount = gnc_numeric_zero();
+ 
+     qof_instance_set (QOF_INSTANCE (sd->split),
+ 		      "sx-credit-formula", credit_formula,
+ 		      "sx-credit-numeric", &credit_amount,
+ 		      "sx-debit-formula", debit_formula,
+ 		      "sx-debit-numeric", &debit_amount,
+ 		      NULL);
      /* set the amount to an innocuous value */
 +    /* Note that this marks the split dirty */
      xaccSplitSetValue (sd->split, gnc_numeric_create (0, 1));
  
      sd->handled_dc = TRUE;
@@@ -776,24 -755,12 +756,13 @@@ gnc_template_register_save_shares_cell 
      char *sharesStr = "(x + y)/42";
  
      g_return_if_fail (gnc_basic_cell_has_name (cell, SHRS_CELL));
- 
-     kvpf = xaccSplitGetSlots (sd->split);
- 
      /* FIXME: shares cells are numeric by definition. */
-     DEBUG ("kvp_frame before: %s\n", kvp_frame_to_string (kvpf));
- 
-     /* sharesStr = gnc_numeric_to_string( sharesStr ); */
-     kvp_frame_set_slot_path (kvpf,
-                              kvp_value_new_string (sharesStr),
-                              GNC_SX_ID,
-                              GNC_SX_SHARES,
-                              NULL);
- 
-     DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));
+     qof_instance_set (QOF_INSTANCE (sd->split),
+ 		      "sx-shares", sharesStr,
+ 		      NULL);
  
      /* set the shares to an innocuous value */
 +    /* Note that this marks the split dirty */
      xaccSplitSetSharePriceAndAmount (sd->split,
                                       gnc_numeric_create (0, 1),
                                       gnc_numeric_create (0, 1));
diff --cc src/report/report-gnome/gnc-plugin-page-report.c
index 8878177,5f57c00..219f418
--- a/src/report/report-gnome/gnc-plugin-page-report.c
+++ b/src/report/report-gnome/gnc-plugin-page-report.c
@@@ -1041,8 -1034,8 +1034,8 @@@ static GtkActionEntry report_actions[] 
          G_CALLBACK(gnc_plugin_page_report_save_cb)
      },
      {
-         "ReportSaveAsAction", GTK_STOCK_SAVE_AS, N_("Save Report Configuration As..."), "<control><alt><shift>s",
-         N_("Add the current report's configuration to the `Saved Report Configurations' menu. "
+         "ReportSaveAsAction", GTK_STOCK_SAVE_AS, N_("Save Report As..."), "<control><alt><shift>s",
 -        N_("Add the current report's configuration to the `Custom Reports' menu. "
++        N_("Add the current report's configuration to the `Preconfigured Reports' menu. "
          "The report will be saved in the file ~/.gnucash/saved-reports-2.4. "),
          G_CALLBACK(gnc_plugin_page_report_save_as_cb)
      },

commit 207bedb4c5845291b440a5d115a6734c8f947ebe
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu May 1 12:47:17 2014 -0700

    Replace direct kvp access with qof_book_save_options.

diff --git a/src/gnome/assistant-hierarchy.c b/src/gnome/assistant-hierarchy.c
index 34eeed7..0e277c9 100644
--- a/src/gnome/assistant-hierarchy.c
+++ b/src/gnome/assistant-hierarchy.c
@@ -1005,6 +1005,26 @@ on_cancel (GtkAssistant      *gtkassistant,
 }
 
 static void
+finish_book_options_helper(GNCOptionWin * optionwin,
+                          gpointer user_data)
+{
+    GNCOptionDB * options = user_data;
+    QofBook *book = gnc_get_current_book ();
+    gboolean use_split_action_for_num_before =
+        qof_book_use_split_action_for_num_field (book);
+    gboolean use_split_action_for_num_after;
+
+    if (!options) return;
+
+    gnc_option_db_commit (options);
+    qof_book_save_options (book, gnc_option_db_save_to_kvp, options, TRUE);
+    use_split_action_for_num_after =
+        qof_book_use_split_action_for_num_field (book);
+    if (use_split_action_for_num_before != use_split_action_for_num_after)
+        gnc_book_option_num_field_source_change_cb (use_split_action_for_num_after);
+}
+
+static void
 starting_balance_helper (Account *account, hierarchy_data *data)
 {
     gnc_numeric balance;
@@ -1064,6 +1084,58 @@ on_finish (GtkAssistant  *gtkassistant,
     LEAVE (" ");
 }
 
+/********************************************************
+ * For a new book the assistant will also allow the user
+ * to set default book options, because this impacts how
+ * transactions are created.
+ * Ideally, the book options code can cleanly provide us
+ * with a page to insert in the assistant and be done with
+ * it. Unfortunately this is not possible without a serious
+ * rewrite of the options dialog code.
+ * So instead the following hack is used:
+ * we create the complete dialog, but only use the notebook
+ * part of it to create a new page.
+ * To make sure this dialog is cleaned up properly
+ * when the assistant closes, the close callback is set up anyway
+ * and at the finish we'll send a "close" response signal to the
+ * dialog to make it clean up after itself.
+ */
+static void
+book_options_dialog_close_cb(GNCOptionWin * optionwin,
+                               gpointer user_data)
+{
+    GNCOptionDB * options = user_data;
+
+    gnc_options_dialog_destroy(optionwin);
+    gnc_option_db_destroy(options);
+}
+
+static void
+assistant_instert_book_options_page (hierarchy_data *data)
+{
+    GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
+
+    data->options = gnc_option_db_new_for_type (QOF_ID_BOOK);
+    qof_book_load_options (gnc_get_current_book (),
+			   gnc_option_db_load_from_kvp, data->options);
+    gnc_option_db_clean (data->options);
+
+    data->optionwin = gnc_options_dialog_new_modal (TRUE, _("New Book Options"));
+    gnc_options_dialog_build_contents_full (data->optionwin, data->options, FALSE);
+
+    gnc_options_dialog_set_close_cb (data->optionwin,
+                                     book_options_dialog_close_cb,
+                                     (gpointer)data->options);
+    gnc_options_dialog_set_new_book_option_values (data->options);
+
+    gtk_widget_reparent (gnc_options_dialog_notebook (data->optionwin), vbox);
+    gtk_widget_show_all (vbox);
+    gtk_assistant_insert_page (GTK_ASSISTANT(data->dialog), vbox, 2);
+    gtk_assistant_set_page_title (GTK_ASSISTANT(data->dialog), vbox, _("New Book Options"));
+    gtk_assistant_set_page_complete (GTK_ASSISTANT(data->dialog), vbox, TRUE);
+
+}
+
 static GtkWidget *
 gnc_create_hierarchy_assistant (gboolean use_defaults, GncHierarchyAssistantFinishedCallback when_completed)
 {

commit 6dfb7febf2cc8db60f19cd51ed612661b7ee875f
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu May 1 12:41:06 2014 -0700

    Convert capital gains kvp access to properties on Split.

diff --git a/src/engine/Split.c b/src/engine/Split.c
index 8c9af18..b5e5418 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -73,23 +73,27 @@ static QofLogModule log_module = GNC_MOD_ENGINE;
 enum
 {
     PROP_0,
-    PROP_TX,			/* Table */
-    PROP_ACCOUNT,		/* Table */
-    PROP_MEMO,			/* Table */
-    PROP_ACTION,		/* Table */
-//    PROP_RECONCILE_STATE,	/* Table */
-    PROP_RECONCILE_DATE,	/* Table */
-    PROP_VALUE,			/* Table, in 2 fields */
-    PROP_SX_ACCOUNT,		/* KVP */
-    PROP_SX_CREDIT_FORMULA,	/* KVP */
-    PROP_SX_CREDIT_NUMERIC,	/* KVP */
-    PROP_SX_DEBIT_FORMULA,	/* KVP */
-    PROP_SX_DEBIT_NUMERIC,	/* KVP */
-    PROP_SX_SHARES,		/* KVP */
-    PROP_LOT,			/* KVP */
-    PROP_ONLINE_ACCOUNT,	/* KVP */
+    PROP_TX,                    /* Table */
+    PROP_ACCOUNT,               /* Table */
+    PROP_MEMO,                  /* Table */
+    PROP_ACTION,                /* Table */
+//    PROP_RECONCILE_STATE,     /* Table */
+    PROP_RECONCILE_DATE,        /* Table */
+    PROP_VALUE,                 /* Table, in 2 fields */
+    PROP_SX_ACCOUNT,            /* KVP */
+    PROP_SX_CREDIT_FORMULA,     /* KVP */
+    PROP_SX_CREDIT_NUMERIC,     /* KVP */
+    PROP_SX_DEBIT_FORMULA,      /* KVP */
+    PROP_SX_DEBIT_NUMERIC,      /* KVP */
+    PROP_SX_SHARES,             /* KVP */
+    PROP_LOT,                   /* KVP */
+    PROP_ONLINE_ACCOUNT,        /* KVP */
+    PROP_LOT_SPLIT,             /* KVP */
+    PROP_PEER_GUID,             /* KVP */
+    PROP_GAINS_SPLIT,           /* KVP */
+    PROP_GAINS_SOURCE,          /* KVP */
     PROP_RUNTIME_0,
-    PROP_AMOUNT,		/* Runtime */
+    PROP_AMOUNT,                /* Runtime */
 
 };
 
@@ -178,33 +182,49 @@ gnc_split_get_property(GObject         *object,
         g_value_take_object(value, split->lot);
         break;
     case PROP_SX_CREDIT_FORMULA:
-	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_CREDIT_NUMERIC:
-	key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_DEBIT_FORMULA:
-	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_DEBIT_NUMERIC:
-	key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_ACCOUNT:
-	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_SHARES:
-	key = GNC_SX_ID "/" GNC_SX_SHARES;
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_SHARES;
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_ONLINE_ACCOUNT:
-	key = "online_id";
-	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = "online_id";
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_LOT_SPLIT:
+        key = "lot-split";
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_PEER_GUID:
+        key = "peer_guid";
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_GAINS_SPLIT:
+        key = "gains-split";
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_GAINS_SOURCE:
+        key = "gains-source";
+        qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -225,7 +245,7 @@ gnc_split_set_property(GObject         *object,
 
     split = GNC_SPLIT(object);
     if (prop_id < PROP_RUNTIME_0 && split->parent != NULL)
-	g_assert (qof_instance_get_editlevel(split->parent));
+        g_assert (qof_instance_get_editlevel(split->parent));
 
     switch (prop_id)
     {
@@ -256,34 +276,50 @@ gnc_split_set_property(GObject         *object,
         xaccSplitSetLot(split, g_value_get_object(value));
         break;
     case PROP_SX_CREDIT_FORMULA:
-	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_CREDIT_NUMERIC:
-	key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_DEBIT_FORMULA:
-	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_DEBIT_NUMERIC:
-	key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_ACCOUNT:
-	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_SX_SHARES:
-	key = GNC_SX_ID "/" GNC_SX_SHARES;
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
+        key = GNC_SX_ID "/" GNC_SX_SHARES;
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
     case PROP_ONLINE_ACCOUNT:
-	key = "online_id";
-	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
-	break;
-     default:
+        key = "online_id";
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_LOT_SPLIT:
+        key = "lot-split";
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_PEER_GUID:
+        key = "peer_guid";
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_GAINS_SPLIT:
+        key = "gains-split";
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    case PROP_GAINS_SOURCE:
+        key = "gains-source";
+        qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+        break;
+    default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
     }
@@ -386,9 +422,9 @@ gnc_split_class_init(SplitClass* klass)
      PROP_SX_DEBIT_FORMULA,
      g_param_spec_string("sx-debit-formula",
                          "Schedule Transaction Debit Formula",
-			 "The formula used to calculate the actual debit "
-			 "amount when a real split is generated from this "
-			 "SX split.",
+                         "The formula used to calculate the actual debit "
+                         "amount when a real split is generated from this "
+                         "SX split.",
                          NULL,
                          G_PARAM_READWRITE));
 
@@ -398,7 +434,7 @@ gnc_split_class_init(SplitClass* klass)
      g_param_spec_boxed("sx-debit-numeric",
                         "Scheduled Transaction Debit Numeric",
                         "Numeric value to plug into the Debit Formula when a "
-			"real split is generated from this SX split.",
+                        "real split is generated from this SX split.",
                         GNC_TYPE_NUMERIC,
                         G_PARAM_READWRITE));
 
@@ -407,9 +443,9 @@ gnc_split_class_init(SplitClass* klass)
      PROP_SX_CREDIT_FORMULA,
      g_param_spec_string("sx-credit-formula",
                          "Schedule Transaction Credit Formula",
-			 "The formula used to calculate the actual credit "
-			 "amount when a real split is generated from this "
-			 "SX split.",
+                         "The formula used to calculate the actual credit "
+                         "amount when a real split is generated from this "
+                         "SX split.",
                          NULL,
                          G_PARAM_READWRITE));
 
@@ -419,7 +455,7 @@ gnc_split_class_init(SplitClass* klass)
      g_param_spec_boxed("sx-credit-numeric",
                         "Scheduled Transaction Credit Numeric",
                         "Numeric value to plug into the Credit Formula when a "
-			"real split is generated from this SX split.",
+                        "real split is generated from this SX split.",
                         GNC_TYPE_NUMERIC,
                         G_PARAM_READWRITE));
 /* FIXME: PROP_SX_SHARES should be stored as a gnc_numeric, but the function
@@ -433,7 +469,7 @@ gnc_split_class_init(SplitClass* klass)
      g_param_spec_string("sx-shares",
                         "Scheduled Transaction Shares",
                         "Numeric value of shares to insert in a new split when "
-			"it's generated from this SX split.",
+                        "it's generated from this SX split.",
                         NULL,
                         G_PARAM_READWRITE));
 
@@ -452,9 +488,50 @@ gnc_split_class_init(SplitClass* klass)
      g_param_spec_string ("online-id",
                           "Online Account ID",
                           "The online account which corresponds to this "
-			  "account for OFX/HCBI import",
+                          "account for OFX/HCBI import",
                           NULL,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_LOT_SPLIT,
+     g_param_spec_int64 ("lot-split",
+                         "Lot Split",
+                         "Indicates that the split was divided into two "
+                         "splits in order to balance a lot capital gains "
+                         "transaction. Contains a timestamp of the action.",
+                         G_MININT64, G_MAXINT64, 0,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_PEER_GUID,
+     g_param_spec_boxed ("peer-guid",
+                          "Peer GUID",
+                          "The other split in the division.",
+                          GNC_TYPE_GUID,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_GAINS_SPLIT,
+     g_param_spec_boxed ("gains-split",
+                          "Gains Split",
+                          "The capital gains split associated with this "
+                          "split when this split represents the proceeds "
+                          "from the sale of a commodity inside a Lot.",
+                          GNC_TYPE_GUID,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_GAINS_SOURCE,
+     g_param_spec_boxed ("gains-source",
+                          "Gains Source",
+                          "The source split for which this split this is "
+                          "the gains split. ",
+                          GNC_TYPE_GUID,
+                          G_PARAM_READWRITE));
 }
 
 /********************************************************************\
diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c
index a313d53..8533144 100644
--- a/src/engine/cap-gains.c
+++ b/src/engine/cap-gains.c
@@ -397,22 +397,18 @@ xaccSplitAssignToLot (Split *split, GNCLot *lot)
         ts = xaccSplitRetDateReconciledTS (split);
         xaccSplitSetDateReconciledTS (new_split, &ts);
 
-        /* We do not copy the KVP tree, as it seems like a dangerous
-         * thing to do.  If the user wants to access stuff in the 'old'
-         * kvp tree from the 'new' split, they shoudl follow the
-         * 'split-lot' pointers.  Yes, this is complicated, but what
-         * else can one do ??
+        /* Set the lot-split and peer_guid properties on the two
+         * splits to indicate that they're linked. 
          */
-        /* Add kvp markup to indicate that these two splits used
-         * to be one before being 'split'
-         */
-        gnc_kvp_bag_add (split->inst.kvp_data, "lot-split", now,
-                         "peer_guid", xaccSplitGetGUID (new_split),
-                         NULL);
+        qof_instance_set (QOF_INSTANCE (split),
+                          "lot-split", now,
+                          "peer_guid", xaccSplitGetGUID (new_split),
+                          NULL);
 
-        gnc_kvp_bag_add (new_split->inst.kvp_data, "lot-split", now,
-                         "peer_guid", xaccSplitGetGUID (split),
-                         NULL);
+        qof_instance_set (QOF_INSTANCE (new_split),
+                          "lot-split", now,
+                          "peer_guid", xaccSplitGetGUID (split),
+                          NULL);
 
         xaccAccountInsertSplit (acc, new_split);
         xaccTransAppendSplit (trans, new_split);
@@ -489,15 +485,14 @@ xaccSplitAssign (Split *split)
 Split *
 xaccSplitGetCapGainsSplit (const Split *split)
 {
-    KvpValue *val;
     GncGUID *gains_guid;
     Split *gains_split;
 
     if (!split) return NULL;
 
-    val = kvp_frame_get_slot (split->inst.kvp_data, "gains-split");
-    if (!val) return NULL;
-    gains_guid = kvp_value_get_guid (val);
+    qof_instance_get (QOF_INSTANCE (split),
+                      "gains-split", &gains_guid,
+                      NULL);
     if (!gains_guid) return NULL;
 
     /* Both splits will be in the same collection, so search there. */
@@ -512,15 +507,14 @@ xaccSplitGetCapGainsSplit (const Split *split)
 Split *
 xaccSplitGetGainsSourceSplit (const Split *split)
 {
-    KvpValue *val;
     GncGUID *source_guid;
     Split *source_split;
 
     if (!split) return NULL;
 
-    val = kvp_frame_get_slot (split->inst.kvp_data, "gains-source");
-    if (!val) return NULL;
-    source_guid = kvp_value_get_guid (val);
+    qof_instance_get (QOF_INSTANCE (split),
+                      "gains-source", &source_guid,
+                      NULL);
     if (!source_guid) return NULL;
 
     /* Both splits will be in the same collection, so search there. */
@@ -819,14 +813,18 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
             xaccSplitSetMemo (lot_split, _("Realized Gain/Loss"));
             xaccSplitSetMemo (gain_split, _("Realized Gain/Loss"));
 
-            /* For the new transaction, install KVP markup indicating
+            /* For the new transaction, set the split properties indicating
              * that this is the gains transaction that corresponds
              * to the gains source.
              */
-            kvp_frame_set_guid (split->inst.kvp_data, "gains-split",
-                                xaccSplitGetGUID (lot_split));
-            kvp_frame_set_guid (lot_split->inst.kvp_data, "gains-source",
-                                xaccSplitGetGUID (split));
+            xaccTransBeginEdit (base_txn);
+            qof_instance_set (QOF_INSTANCE (split),
+                              "gains-split", xaccSplitGetGUID (lot_split),
+                              NULL);
+            xaccTransCommitEdit (base_txn);
+            qof_instance_set (QOF_INSTANCE (lot_split),
+                              "gains-source", xaccSplitGetGUID (split),
+                              NULL);
 
         }
         else
@@ -882,7 +880,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
             xaccSplitSetAmount (gain_split, negvalue);
             xaccSplitSetValue (gain_split, negvalue);
 
-            /* Some short-cuts to help avoid the above kvp lookup. */
+            /* Some short-cuts to help avoid the above property lookup. */
             split->gains = GAINS_STATUS_CLEAN;
             split->gains_split = lot_split;
             lot_split->gains = GAINS_STATUS_GAINS;

commit 44ca77766af2ea18efd709fd027262918b7a2804
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 10 13:31:00 2013 -0800

    Fake edit level for tests and SQL backend.
    
    These are cases where we don't want to commit, either because it would be circular (the backend is loading; committing the result back would at best waste time) or because we're testing some narrow functionality.

diff --git a/src/backend/sql/gnc-account-sql.c b/src/backend/sql/gnc-account-sql.c
index fb1ce98..7d6b3a3 100644
--- a/src/backend/sql/gnc-account-sql.c
+++ b/src/backend/sql/gnc-account-sql.c
@@ -294,12 +294,14 @@ load_all_accounts( GncSqlBackend* be )
         {
             acct_balances_t* balances = (acct_balances_t*)bal->data;
 
+	    qof_instance_increase_editlevel (balances->acct);
             g_object_set( balances->acct,
                           "start-balance", &balances->balance,
                           "start-cleared-balance", &balances->cleared_balance,
                           "start-reconciled-balance", &balances->reconciled_balance,
                           NULL);
 
+	    qof_instance_decrease_editlevel (balances->acct);
         }
         if ( bal_slist != NULL )
         {
@@ -418,7 +420,9 @@ load_account_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, account, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-address-sql.c b/src/backend/sql/gnc-address-sql.c
index a29d4aa..a3f3994 100644
--- a/src/backend/sql/gnc-address-sql.c
+++ b/src/backend/sql/gnc-address-sql.c
@@ -115,7 +115,9 @@ load_address( const GncSqlBackend* be, GncSqlRow* row,
     }
     if ( table_row->gobj_param_name != NULL )
     {
+	qof_instance_increase_editlevel (pObject);
         g_object_set( pObject, table_row->gobj_param_name, addr, NULL );
+	qof_instance_decrease_editlevel (pObject);
     }
     else
     {
diff --git a/src/backend/sql/gnc-backend-sql.c b/src/backend/sql/gnc-backend-sql.c
index e6518bb..ed772e5 100644
--- a/src/backend/sql/gnc-backend-sql.c
+++ b/src/backend/sql/gnc-backend-sql.c
@@ -1206,7 +1206,11 @@ const GncSqlColumnTableEntry* table_row )
     s = g_value_get_string( val );
     if ( table_row->gobj_param_name != NULL )
     {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
         g_object_set( pObject, table_row->gobj_param_name, s, NULL );
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
     }
     else
     {
@@ -1310,7 +1314,11 @@ load_int( const GncSqlBackend* be, GncSqlRow* row,
     }
     if ( table_row->gobj_param_name != NULL )
     {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
         g_object_set( pObject, table_row->gobj_param_name, int_value, NULL );
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
     }
     else
     {
@@ -1408,7 +1416,11 @@ load_boolean( const GncSqlBackend* be, GncSqlRow* row,
     }
     if ( table_row->gobj_param_name != NULL )
     {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
         g_object_set( pObject, table_row->gobj_param_name, int_value, NULL );
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
     }
     else
     {
@@ -1501,7 +1513,11 @@ load_int64( const GncSqlBackend* be, GncSqlRow* row,
     }
     if ( table_row->gobj_param_name != NULL )
     {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
         g_object_set( pObject, table_row->gobj_param_name, i64_value, NULL );
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
     }
     else
     {
@@ -1608,7 +1624,11 @@ load_double( const GncSqlBackend* be, GncSqlRow* row,
         }
         if ( table_row->gobj_param_name != NULL )
         {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
             g_object_set( pObject, table_row->gobj_param_name, d_value, NULL );
+	    if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
         }
         else
         {
@@ -1707,7 +1727,11 @@ load_guid( const GncSqlBackend* be, GncSqlRow* row,
     {
         if ( table_row->gobj_param_name != NULL )
         {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
             g_object_set( pObject, table_row->gobj_param_name, pGuid, NULL );
+	    if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
         }
         else
         {
@@ -1914,7 +1938,11 @@ load_timespec( const GncSqlBackend* be, GncSqlRow* row,
     {
         if (table_row->gobj_param_name != NULL)
         {
+	if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
             g_object_set( pObject, table_row->gobj_param_name, &ts, NULL );
+	    if (QOF_IS_INSTANCE (pObject))
+	    qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
         }
         else
         {
@@ -2016,7 +2044,11 @@ load_date( const GncSqlBackend* be, GncSqlRow* row,
 	    g_date_time_unref (gdt);
 	    if ( table_row->gobj_param_name != NULL )
 	    {
+		if (QOF_IS_INSTANCE (pObject))
+		    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
 		g_object_set( pObject, table_row->gobj_param_name, date, NULL );
+		if (QOF_IS_INSTANCE (pObject))
+		    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
 	    }
 	    else
 	    {
@@ -2050,7 +2082,12 @@ load_date( const GncSqlBackend* be, GncSqlRow* row,
                     date = g_date_new_dmy( day, month, year );
                     if ( table_row->gobj_param_name != NULL )
                     {
-                        g_object_set( pObject, table_row->gobj_param_name, date, NULL );
+			if (QOF_IS_INSTANCE (pObject))
+			    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
+                        g_object_set (pObject, table_row->gobj_param_name,
+				      date, NULL);
+			if (QOF_IS_INSTANCE (pObject))
+			    qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
                     }
                     else
                     {
@@ -2189,7 +2226,11 @@ load_numeric( const GncSqlBackend* be, GncSqlRow* row,
     {
         if ( table_row->gobj_param_name != NULL )
         {
+	    if (QOF_IS_INSTANCE (pObject))
+		qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
             g_object_set( pObject, table_row->gobj_param_name, &n, NULL );
+	    if (QOF_IS_INSTANCE (pObject))
+		qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
         }
         else
         {
diff --git a/src/backend/sql/gnc-bill-term-sql.c b/src/backend/sql/gnc-bill-term-sql.c
index 4846b0f..eaf7243 100644
--- a/src/backend/sql/gnc-bill-term-sql.c
+++ b/src/backend/sql/gnc-bill-term-sql.c
@@ -363,7 +363,9 @@ load_billterm_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, term, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-budget-sql.c b/src/backend/sql/gnc-budget-sql.c
index 59a7efb..4c697c9 100644
--- a/src/backend/sql/gnc-budget-sql.c
+++ b/src/backend/sql/gnc-budget-sql.c
@@ -500,7 +500,9 @@ load_budget_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, budget, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-commodity-sql.c b/src/backend/sql/gnc-commodity-sql.c
index 2389946..1f8f556 100644
--- a/src/backend/sql/gnc-commodity-sql.c
+++ b/src/backend/sql/gnc-commodity-sql.c
@@ -283,7 +283,9 @@ load_commodity_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, commodity, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else if ( setter != NULL )
             {
diff --git a/src/backend/sql/gnc-invoice-sql.c b/src/backend/sql/gnc-invoice-sql.c
index 8788960..72c1cd2 100644
--- a/src/backend/sql/gnc-invoice-sql.c
+++ b/src/backend/sql/gnc-invoice-sql.c
@@ -303,7 +303,9 @@ load_invoice_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, invoice, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-lots-sql.c b/src/backend/sql/gnc-lots-sql.c
index a6ee240..22c4a70 100644
--- a/src/backend/sql/gnc-lots-sql.c
+++ b/src/backend/sql/gnc-lots-sql.c
@@ -235,7 +235,9 @@ load_lot_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, lot, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-order-sql.c b/src/backend/sql/gnc-order-sql.c
index 46b0ae0..a7bc177 100644
--- a/src/backend/sql/gnc-order-sql.c
+++ b/src/backend/sql/gnc-order-sql.c
@@ -220,7 +220,9 @@ load_order_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, order, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-owner-sql.c b/src/backend/sql/gnc-owner-sql.c
index 4b89c54..2e779f0 100644
--- a/src/backend/sql/gnc-owner-sql.c
+++ b/src/backend/sql/gnc-owner-sql.c
@@ -156,7 +156,9 @@ load_owner( const GncSqlBackend* be, GncSqlRow* row,
 
     if ( table_row->gobj_param_name != NULL )
     {
+	qof_instance_increase_editlevel (pObject);
         g_object_set( pObject, table_row->gobj_param_name, &owner, NULL );
+	qof_instance_decrease_editlevel (pObject);
     }
     else
     {
diff --git a/src/backend/sql/gnc-tax-table-sql.c b/src/backend/sql/gnc-tax-table-sql.c
index 21466d4..fbf5d37 100644
--- a/src/backend/sql/gnc-tax-table-sql.c
+++ b/src/backend/sql/gnc-tax-table-sql.c
@@ -523,7 +523,9 @@ load_taxtable_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, taxtable, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/backend/sql/gnc-transaction-sql.c b/src/backend/sql/gnc-transaction-sql.c
index eca64cf..8c67c0b 100644
--- a/src/backend/sql/gnc-transaction-sql.c
+++ b/src/backend/sql/gnc-transaction-sql.c
@@ -393,6 +393,7 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
                           "end-reconciled-balance", &pnew_end_r_bal,
                           NULL );
 
+	    qof_instance_increase_editlevel (balns-acc);
             if ( !gnc_numeric_eq( *pnew_end_bal, balns->end_bal ) )
             {
                 adj = gnc_numeric_sub( balns->end_bal, *pnew_end_bal,
@@ -400,6 +401,7 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
                 balns->start_bal = gnc_numeric_add( balns->start_bal, adj,
                                                     GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
                 g_object_set( balns->acc, "start-balance", &balns->start_bal, NULL );
+		qof_instance_decrease_editlevel (balns-acc);
             }
             if ( !gnc_numeric_eq( *pnew_end_c_bal, balns->end_cleared_bal ) )
             {
@@ -417,6 +419,7 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
                                               GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
                 g_object_set( balns->acc, "start-reconciled-balance", &balns->start_reconciled_bal, NULL );
             }
+	    qof_instance_decrease_editlevel (balns-acc);
             xaccAccountRecomputeBalance( balns->acc );
             g_free( pnew_end_bal );
             g_free( pnew_end_c_bal );
@@ -1429,7 +1432,9 @@ load_tx_guid( const GncSqlBackend* be, GncSqlRow* row,
         {
             if ( table_row->gobj_param_name != NULL )
             {
+		qof_instance_increase_editlevel (pObject);
                 g_object_set( pObject, table_row->gobj_param_name, tx, NULL );
+		qof_instance_decrease_editlevel (pObject);
             }
             else
             {
diff --git a/src/engine/test/test-account-object.c b/src/engine/test/test-account-object.c
index 60765b5..b87bb22 100644
--- a/src/engine/test/test-account-object.c
+++ b/src/engine/test/test-account-object.c
@@ -33,6 +33,7 @@
 #include "cashobjects.h"
 #include "test-stuff.h"
 #include "test-engine-stuff.h"
+#include <qofinstance-p.h>
 
 static void
 run_test (void)
@@ -61,7 +62,9 @@ run_test (void)
     /*****/
 
     five = gnc_numeric_create(5, 1);
+    qof_instance_increase_editlevel (acc);
     g_object_set(acc, "start-balance", &five, NULL);
+    qof_instance_decrease_editlevel (acc);
     xaccAccountRecomputeBalance(acc);
     g_object_get(acc, "start-balance", &start, "end-balance", &end, NULL);
     end2 = xaccAccountGetBalance(acc);
diff --git a/src/engine/test/utest-Account.c b/src/engine/test/utest-Account.c
index 07c47c7..f96abf3 100644
--- a/src/engine/test/utest-Account.c
+++ b/src/engine/test/utest-Account.c
@@ -445,11 +445,11 @@ test_gnc_account_name_violations_errmsg ()
     message = gnc_account_name_violations_errmsg (separator, nonames);
     g_assert (message == NULL);
     validation_message = g_strdup_printf (
-                             "The separator character \"%s\" is used in one or more account "
-                             "names.\n\nThis will result in unexpected behaviour. "
-                             "Either change the account names or choose another separator "
-                             "character.\n\nBelow you will find the list of invalid account names:\n"
-                             "%s", separator, account_list);
+        "The separator character \"%s\" is used in one or more account "
+        "names.\n\nThis will result in unexpected behaviour. "
+        "Either change the account names or choose another separator "
+        "character.\n\nBelow you will find the list of invalid account names:\n"
+        "%s", separator, account_list);
     message = gnc_account_name_violations_errmsg (separator, badnames);
     g_assert_cmpstr ( message, == , validation_message);
     g_free (validation_message);
@@ -1357,6 +1357,8 @@ test_xaccAccountOrder ( )
     g_assert (xaccAccountOrder (ab, aa) == 1);
 
     ab = xaccMallocAccount (book);
+    qof_instance_increase_editlevel (aa);
+    qof_instance_increase_editlevel (ab);
     g_object_set (G_OBJECT (aa),
                   "code", "3333",
                   "type", ACCT_TYPE_ASSET,
@@ -1399,6 +1401,8 @@ test_xaccAccountOrder ( )
                   "name", "bar",
                   NULL);
     g_assert_cmpint (xaccAccountOrder (aa, ab), < , 0);
+    qof_instance_decrease_editlevel (aa);
+    qof_instance_decrease_editlevel (ab);
 
     xaccAccountBeginEdit (aa);
     xaccAccountDestroy (aa);
@@ -2158,7 +2162,9 @@ test_xaccAccountType_Stuff (void)
             g_assert_cmpstr (typestr_uc, == , typename);
         g_free (typestr_uc);
 
+	qof_instance_increase_editlevel (acc);
         g_object_set (acc, "type", type, NULL);
+	qof_instance_decrease_editlevel (acc);
         if (type == ACCT_TYPE_STOCK || type == ACCT_TYPE_MUTUAL ||
                 type == ACCT_TYPE_CURRENCY)
             g_assert (xaccAccountIsPriced (acc));
@@ -2402,11 +2408,13 @@ test_gnc_account_merge_children (Fixture *fixture, gconstpointer pData)
     */
     sig4 = test_signal_new (QOF_INSTANCE (div), QOF_EVENT_MODIFY, NULL);
     sig5 = test_signal_new (QOF_INSTANCE (div1), QOF_EVENT_MODIFY, NULL);
+    qof_instance_increase_editlevel (div1);
     g_object_set (div1, "name", "div", NULL);
+    qof_instance_decrease_editlevel (div1);
     gnc_account_merge_children (taxable);
     g_assert_cmpint (gnc_account_n_descendants (taxable), == , taxable_desc - 1);
     test_signal_assert_hits (sig4, 1);
-    test_signal_assert_hits (sig5, 4);
+    test_signal_assert_hits (sig5, 3);
     test_signal_free (sig4);
     test_signal_free (sig5);
     gnc_account_merge_children (expense);
diff --git a/src/engine/test/utest-Split.c b/src/engine/test/utest-Split.c
index 43f01dd..05166e6 100644
--- a/src/engine/test/utest-Split.c
+++ b/src/engine/test/utest-Split.c
@@ -458,9 +458,11 @@ test_xaccSplitEqual (Fixture *fixture, gconstpointer pData)
     split1->parent = fixture->split->parent;
     g_assert (xaccSplitEqual (fixture->split, split1, FALSE, TRUE, TRUE) == TRUE);
     /* Now set the GUIDs equal and see that the comparison passes */
+    qof_instance_increase_editlevel (split1->parent);
     g_object_set (G_OBJECT (split1),
                   "guid", qof_instance_get_guid (QOF_INSTANCE(fixture->split)),
                   NULL);
+    qof_instance_increase_editlevel (split1->parent);
     g_assert (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == TRUE);
     g_assert_cmpint (checkA.hits, ==, 3);
     g_assert_cmpint (checkB.hits, ==, 1);
@@ -597,10 +599,12 @@ test_xaccSplitCommitEdit (Fixture *fixture, gconstpointer pData)
     g_assert_cmpint (checkB.hits, ==, 2);
 
     qof_instance_mark_clean (QOF_INSTANCE (fixture->split->parent));
+    qof_instance_increase_editlevel (fixture->split->acc);
     g_object_set (fixture->split->acc,
                   "sort-dirty", FALSE,
                   "balance-dirty", FALSE,
                   NULL);
+    qof_instance_decrease_editlevel (fixture->split->acc);
 
     qof_instance_set_dirty (QOF_INSTANCE (fixture->split));
     xaccSplitCommitEdit (fixture->split);

commit 4d511218a5470eace9094de57522351370813661
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 10 13:28:29 2013 -0800

    Move edit level assert to persistent class set_property functions.
    
    Checking at qof_instance_set was too broad.
    Requires detecting persistent vs. run-time properties, which is accomplished by reordering the PROP enum and introducing a PROP_RUNTIME_0 separator value.
    
    While at it, identify as comments the persistent properties which aren't yet properties.

diff --git a/src/engine/Account.c b/src/engine/Account.c
index 4324957..9bc7dda 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -61,45 +61,48 @@ enum
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_FULL_NAME,
-    PROP_CODE,
-    PROP_DESCRIPTION,
-    PROP_COLOR,
-    PROP_NOTES,
-    PROP_TYPE,
-
-    PROP_COMMODITY,
-    PROP_COMMODITY_SCU,
-    PROP_NON_STD_SCU,
-    PROP_SORT_DIRTY,
-    PROP_BALANCE_DIRTY,
-    PROP_START_BALANCE,
-    PROP_START_CLEARED_BALANCE,
-    PROP_START_RECONCILED_BALANCE,
-    PROP_END_BALANCE,
-    PROP_END_CLEARED_BALANCE,
-    PROP_END_RECONCILED_BALANCE,
-
-    PROP_POLICY,
-    PROP_MARK,
-    PROP_TAX_RELATED,
-    PROP_TAX_CODE,
-    PROP_TAX_SOURCE,
-    PROP_TAX_COPY_NUMBER,
-
-    PROP_HIDDEN,
-    PROP_PLACEHOLDER,
-    PROP_FILTER,
-    PROP_SORT_ORDER,
-
-    PROP_LOT_NEXT_ID,
-    PROP_ONLINE_ACCOUNT,
-    PROP_OFX_INCOME_ACCOUNT,
-    PROP_AB_ACCOUNT_ID,
-    PROP_AB_ACCOUNT_UID,
-    PROP_AB_BANK_CODE,
-    PROP_AB_TRANS_RETRIEVAL,
+    PROP_NAME,				/* Table */
+    PROP_FULL_NAME,			/* Constructed */
+    PROP_CODE,				/* Table */
+    PROP_DESCRIPTION,			/* Table */
+    PROP_COLOR,				/* KVP */
+    PROP_NOTES,				/* KVP */
+    PROP_TYPE,				/* Table */
+
+//    PROP_PARENT,			/* Table, Not a property */
+    PROP_COMMODITY,			/* Table */
+    PROP_COMMODITY_SCU,			/* Table */
+    PROP_NON_STD_SCU,			/* Table */
+    PROP_END_BALANCE,			/* Constructed */
+    PROP_END_CLEARED_BALANCE,		/* Constructed */
+    PROP_END_RECONCILED_BALANCE,	/* Constructed */
+
+    PROP_TAX_RELATED,			/* KVP */
+    PROP_TAX_CODE,			/* KVP */
+    PROP_TAX_SOURCE,			/* KVP */
+    PROP_TAX_COPY_NUMBER,		/* KVP */
+
+    PROP_HIDDEN,			/* Table slot exists, but in KVP in memory & xml */
+    PROP_PLACEHOLDER,			/* Table slot exists, but in KVP in memory & xml */
+    PROP_FILTER,			/* KVP */
+    PROP_SORT_ORDER,			/* KVP */
+
+    PROP_LOT_NEXT_ID,			/* KVP */
+    PROP_ONLINE_ACCOUNT,		/* KVP */
+    PROP_OFX_INCOME_ACCOUNT,		/* KVP */
+    PROP_AB_ACCOUNT_ID,			/* KVP */
+    PROP_AB_ACCOUNT_UID,		/* KVP */
+    PROP_AB_BANK_CODE,			/* KVP */
+    PROP_AB_TRANS_RETRIEVAL,		/* KVP */
+
+    PROP_RUNTIME_0,
+    PROP_POLICY,			/* Cached Value */
+    PROP_MARK,				/* Runtime Value */
+    PROP_SORT_DIRTY,			/* Runtime Value */
+    PROP_BALANCE_DIRTY,			/* Runtime Value */
+    PROP_START_BALANCE,			/* Runtime Value */
+    PROP_START_CLEARED_BALANCE,		/* Runtime Value */
+    PROP_START_RECONCILED_BALANCE,	/* Runtime Value */
 };
 
 #define GET_PRIVATE(o)  \
@@ -444,6 +447,8 @@ gnc_account_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_ACCOUNT(object));
 
     account = GNC_ACCOUNT(object);
+    if (prop_id < PROP_RUNTIME_0)
+	g_assert (qof_instance_get_editlevel(account));
 
     switch (prop_id)
     {
diff --git a/src/engine/SchedXaction.c b/src/engine/SchedXaction.c
index 8fb487f..27ed84a 100644
--- a/src/engine/SchedXaction.c
+++ b/src/engine/SchedXaction.c
@@ -44,19 +44,19 @@
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_ENABLED,
-    PROP_NUM_OCCURANCE,
-    PROP_REM_OCCURANCE,
-    PROP_AUTO_CREATE,
-    PROP_AUTO_CREATE_NOTIFY,
-    PROP_ADVANCE_CREATION_DAYS,
-    PROP_ADVANCE_REMINDER_DAYS,
-    PROP_START_DATE,
-    PROP_END_DATE,
-    PROP_LAST_OCCURANCE_DATE,
-    PROP_INSTANCE_COUNT,
-    PROP_TEMPLATE_ACCOUNT
+    PROP_NAME,				/* Table */
+    PROP_ENABLED,			/* Table */
+    PROP_START_DATE,			/* Table */
+    PROP_END_DATE,			/* Table */
+    PROP_LAST_OCCURANCE_DATE,		/* Table */
+    PROP_NUM_OCCURANCE,			/* Table */
+    PROP_REM_OCCURANCE,			/* Table */
+    PROP_AUTO_CREATE,			/* Table */
+    PROP_AUTO_CREATE_NOTIFY,		/* Table */
+    PROP_ADVANCE_CREATION_DAYS,		/* Table */
+    PROP_ADVANCE_REMINDER_DAYS,		/* Table */
+    PROP_INSTANCE_COUNT,		/* Table */
+    PROP_TEMPLATE_ACCOUNT		/* Table */
 };
 
 /* GObject initialization */
@@ -174,6 +174,8 @@ gnc_schedxaction_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_SCHEDXACTION(object));
 
     sx = GNC_SCHEDXACTION(object);
+    g_assert (qof_instance_get_editlevel(sx));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/engine/Split.c b/src/engine/Split.c
index 9107e7a..8c9af18 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -73,21 +73,24 @@ static QofLogModule log_module = GNC_MOD_ENGINE;
 enum
 {
     PROP_0,
-    PROP_ACTION,
-    PROP_MEMO,
-    PROP_VALUE,
-    PROP_AMOUNT,
-    PROP_RECONCILE_DATE,
-    PROP_TX,
-    PROP_ACCOUNT,
-    PROP_SX_ACCOUNT,
-    PROP_SX_CREDIT_FORMULA,
-    PROP_SX_CREDIT_NUMERIC,
-    PROP_SX_DEBIT_FORMULA,
-    PROP_SX_DEBIT_NUMERIC,
-    PROP_SX_SHARES,
-    PROP_LOT,
-    PROP_ONLINE_ACCOUNT,
+    PROP_TX,			/* Table */
+    PROP_ACCOUNT,		/* Table */
+    PROP_MEMO,			/* Table */
+    PROP_ACTION,		/* Table */
+//    PROP_RECONCILE_STATE,	/* Table */
+    PROP_RECONCILE_DATE,	/* Table */
+    PROP_VALUE,			/* Table, in 2 fields */
+    PROP_SX_ACCOUNT,		/* KVP */
+    PROP_SX_CREDIT_FORMULA,	/* KVP */
+    PROP_SX_CREDIT_NUMERIC,	/* KVP */
+    PROP_SX_DEBIT_FORMULA,	/* KVP */
+    PROP_SX_DEBIT_NUMERIC,	/* KVP */
+    PROP_SX_SHARES,		/* KVP */
+    PROP_LOT,			/* KVP */
+    PROP_ONLINE_ACCOUNT,	/* KVP */
+    PROP_RUNTIME_0,
+    PROP_AMOUNT,		/* Runtime */
+
 };
 
 /* GObject Initialization */
@@ -221,6 +224,9 @@ gnc_split_set_property(GObject         *object,
     g_return_if_fail(GNC_IS_SPLIT(object));
 
     split = GNC_SPLIT(object);
+    if (prop_id < PROP_RUNTIME_0 && split->parent != NULL)
+	g_assert (qof_instance_get_editlevel(split->parent));
+
     switch (prop_id)
     {
     case PROP_ACTION:
diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index da3947e..c0167dd 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -193,14 +193,14 @@ static QofLogModule log_module = GNC_MOD_ENGINE;
 enum
 {
     PROP_0,
-    PROP_NUM,
-    PROP_DESCRIPTION,
-    PROP_CURRENCY,
-    PROP_POST_DATE,
-    PROP_ENTER_DATE,
-    PROP_INVOICE,
-    PROP_SX_TXN,
-    PROP_ONLINE_ACCOUNT,
+    PROP_CURRENCY,	/* Table */
+    PROP_NUM,		/* Table */
+    PROP_POST_DATE,	/* Table */
+    PROP_ENTER_DATE,	/* Table */
+    PROP_DESCRIPTION,	/* Table */
+    PROP_INVOICE,	/* KVP */
+    PROP_SX_TXN,	/* KVP */
+    PROP_ONLINE_ACCOUNT,/* KVP */
 };
 
 void
@@ -361,6 +361,8 @@ gnc_transaction_set_property(GObject* object,
     g_return_if_fail(GNC_IS_TRANSACTION(object));
 
     tx = GNC_TRANSACTION(object);
+    g_assert (qof_instance_get_editlevel(tx));
+
     switch (prop_id)
     {
     case PROP_NUM:
diff --git a/src/engine/gnc-budget.c b/src/engine/gnc-budget.c
index 3355f7c..7e255b7 100644
--- a/src/engine/gnc-budget.c
+++ b/src/engine/gnc-budget.c
@@ -42,10 +42,11 @@ static QofLogModule log_module = GNC_MOD_ENGINE;
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_DESCRIPTION,
-    PROP_NUM_PERIODS,
-    PROP_RECURRENCE,
+    PROP_NAME,			/* Table */
+    PROP_DESCRIPTION,		/* Table */
+    PROP_NUM_PERIODS,		/* Table */
+    PROP_RUNTIME_0,
+    PROP_RECURRENCE,		/* Cached pointer; Recurrence table holds budget guid */
 };
 
 struct budget_s
@@ -157,6 +158,9 @@ gnc_budget_set_property( GObject* object,
     g_return_if_fail(GNC_IS_BUDGET(object));
 
     budget = GNC_BUDGET(object);
+    if (prop_id < PROP_RUNTIME_0)
+	g_assert (qof_instance_get_editlevel(budget));
+
     switch ( prop_id )
     {
     case PROP_NAME:
diff --git a/src/engine/gnc-commodity.c b/src/engine/gnc-commodity.c
index f23235b..a0eec97 100644
--- a/src/engine/gnc-commodity.c
+++ b/src/engine/gnc-commodity.c
@@ -48,16 +48,16 @@ static QofLogModule log_module = GNC_MOD_COMMODITY;
 enum
 {
     PROP_0,
-    PROP_NAMESPACE,
-    PROP_FULL_NAME,
-    PROP_MNEMONIC,
-    PROP_PRINTNAME,
-    PROP_CUSIP,
-    PROP_FRACTION,
-    PROP_UNIQUE_NAME,
-    PROP_QUOTE_FLAG,
-    PROP_QUOTE_SOURCE,
-    PROP_QUOTE_TZ,
+    PROP_NAMESPACE,	/* Table */
+    PROP_FULL_NAME,	/* Table */
+    PROP_MNEMONIC,	/* Table */
+    PROP_PRINTNAME,	/* Constructed */
+    PROP_CUSIP,		/* Table */
+    PROP_FRACTION,	/* Table */
+    PROP_UNIQUE_NAME,	/* Constructed */
+    PROP_QUOTE_FLAG,	/* Table */
+    PROP_QUOTE_SOURCE,	/* Table */
+    PROP_QUOTE_TZ,	/* Table */
 };
 
 struct gnc_commodity_s
@@ -695,6 +695,7 @@ gnc_commodity_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_COMMODITY(object));
 
     commodity = GNC_COMMODITY(object);
+    g_assert (qof_instance_get_editlevel(commodity));
 
     switch (prop_id)
     {
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index 899a888..d86f0be 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -64,12 +64,15 @@ struct gnc_lot_s
 enum
 {
     PROP_0,
-    PROP_IS_CLOSED,
-    PROP_MARKER,
+//  PROP_ACCOUNT, 	/* Table */
+    PROP_IS_CLOSED,	/* Table */
 
-    PROP_INVOICE,
-    PROP_OWNER_TYPE,
-    PROP_OWNER_GUID,
+    PROP_INVOICE,	/* KVP */
+    PROP_OWNER_TYPE,	/* KVP */
+    PROP_OWNER_GUID,	/* KVP */
+
+    PROP_RUNTIME_0,
+    PROP_MARKER,	/* Runtime */
 };
 
 typedef struct LotPrivate
@@ -170,7 +173,10 @@ gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec*
 }
 
 static void
-gnc_lot_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
+gnc_lot_set_property (GObject* object,
+		      guint prop_id,
+		      const GValue* value,
+		      GParamSpec* pspec)
 {
     GNCLot* lot;
     LotPrivate* priv;
@@ -180,6 +186,9 @@ gnc_lot_set_property(GObject* object, guint prop_id, const GValue* value, GParam
     g_return_if_fail(GNC_IS_LOT(object));
 
     lot = GNC_LOT(object);
+    if (prop_id < PROP_RUNTIME_0)
+	g_assert (qof_instance_get_editlevel(lot));
+
     priv = GET_PRIVATE(lot);
     switch (prop_id)
     {
diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c
index c52aeb9..f84ae28 100644
--- a/src/engine/gnc-pricedb.c
+++ b/src/engine/gnc-pricedb.c
@@ -41,12 +41,12 @@ static GNCPrice *lookup_nearest_in_time(GNCPriceDB *db, const gnc_commodity *c,
 enum
 {
     PROP_0,
-    PROP_COMMODITY,
-    PROP_CURRENCY,
-    PROP_DATE,
-    PROP_SOURCE,
-    PROP_TYPE,
-    PROP_VALUE
+    PROP_COMMODITY,	/* Table */
+    PROP_CURRENCY,	/* Table */
+    PROP_DATE,		/* Table */
+    PROP_SOURCE,	/* Table */
+    PROP_TYPE,		/* Table */
+    PROP_VALUE,		/* Table, 2 fields (numeric) */
 };
 
 /* GObject Initialization */
@@ -123,6 +123,8 @@ gnc_price_set_property(GObject* object, guint prop_id, const GValue* value, GPar
     g_return_if_fail(GNC_IS_PRICE(object));
 
     price = GNC_PRICE(object);
+    g_assert (qof_instance_get_editlevel(price));
+
     switch (prop_id)
     {
     case PROP_SOURCE:
diff --git a/src/engine/gncBillTerm.c b/src/engine/gncBillTerm.c
index 9c8e897..9f2c7b9 100644
--- a/src/engine/gncBillTerm.c
+++ b/src/engine/gncBillTerm.c
@@ -193,6 +193,8 @@ gnc_billterm_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_BILLTERM(object));
 
     bt = GNC_BILLTERM(object);
+    g_assert (qof_instance_get_editlevel(bt));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/engine/gncCustomer.c b/src/engine/gncCustomer.c
index 0c95d4c..5d3d7c5 100644
--- a/src/engine/gncCustomer.c
+++ b/src/engine/gncCustomer.c
@@ -169,6 +169,8 @@ gnc_customer_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_CUSTOMER(object));
 
     cust = GNC_CUSTOMER(object);
+    g_assert (qof_instance_get_editlevel(cust));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/engine/gncEmployee.c b/src/engine/gncEmployee.c
index 299c249..ebfb518 100644
--- a/src/engine/gncEmployee.c
+++ b/src/engine/gncEmployee.c
@@ -80,19 +80,19 @@ void mark_employee (GncEmployee *employee)
 enum
 {
     PROP_0,
-    PROP_USERNAME,
-    PROP_ID,
-    PROP_ACTIVE,
-    PROP_LANGUAGE,
-    PROP_CURRENCY,
-    PROP_ACL,
-    PROP_ADDRESS,
-    PROP_WORKDAY,
-    PROP_RATE,
-    PROP_CCARD,
-    PROP_PDF_DIRNAME,
-    PROP_LAST_POSTED,
-    PROP_PAYMENT_LAST_ACCT,
+    PROP_USERNAME,		/* Table */
+    PROP_ID,			/* Table */
+    PROP_LANGUAGE,		/* Table */
+    PROP_ACL,			/* Table */
+    PROP_ACTIVE,		/* Table */
+    PROP_CURRENCY,		/* Table */
+    PROP_CCARD,			/* Table */
+    PROP_WORKDAY,		/* Table (numeric) */
+    PROP_RATE,			/* Table (numeric) */
+    PROP_ADDRESS,		/* Table, 8 fields */
+    PROP_PDF_DIRNAME,		/* KVP */
+    PROP_LAST_POSTED,		/* KVP */
+    PROP_PAYMENT_LAST_ACCT,	/* KVP */
 };
 
 /* GObject Initialization */
@@ -195,6 +195,8 @@ gnc_employee_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_EMPLOYEE(object));
 
     emp = GNC_EMPLOYEE(object);
+    g_assert (qof_instance_get_editlevel(emp));
+
     switch (prop_id)
     {
     case PROP_USERNAME:
diff --git a/src/engine/gncEntry.c b/src/engine/gncEntry.c
index efdf802..3ac3aab 100644
--- a/src/engine/gncEntry.c
+++ b/src/engine/gncEntry.c
@@ -211,7 +211,32 @@ void mark_entry (GncEntry *entry)
 enum
 {
     PROP_0,
-    PROP_DESCRIPTION
+//  PROP_DATE,		/* Table */
+//  PROP_DATE_ENTERED,	/* Table */
+    PROP_DESCRIPTION,	/* Table */
+//  PROP_ACTION,	/* Table */
+//  PROP_NOTES,		/* Table */
+//  PROP_QUANTITY,	/* Table (numeric) */
+//  PROP_I_ACCT,	/* Table */
+//  PROP_I_PRICE,	/* Table (numeric) */
+//  PROP_I_DISCOUNT,	/* Table (numeric) */
+//  PROP_INVOICE,	/* Table */
+//  PROP_I_DISC_TYPE,	/* Table */
+//  PROP_I_DISC_HOW,	/* Table */
+//  PROP_I_TAXABLE,	/* Table */
+//  PROP_I_TAX_INCL,	/* Table */
+//  PROP_I_TAXTABLE,	/* Table */
+//  PROP_B_ACCT,	/* Table */
+//  PROP_B_PRICE,	/* Table (numeric) */
+//  PROP_BILL,		/* Table */
+//  PROP_B_TAXTABLE_1,	/* Table */
+//  PROP_B_TAX_INCL,	/* Table */
+//  PROP_B_TAXTABLE,	/* Table */
+//  PROP_B_PAYTYPE,	/* Table */
+//  PROP_BILLABLE,	/* Table */
+//  PROP_BILLTO_TYPE,	/* Table */
+//  PROP_BILLTO,	/* Table */
+//  PROP_ORDER,		/* Table */
 };
 
 /* GObject Initialization */
@@ -267,6 +292,8 @@ gnc_entry_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_ENTRY(object));
 
     entry = GNC_ENTRY(object);
+    g_assert (qof_instance_get_editlevel(entry));
+
     switch (prop_id)
     {
     case PROP_DESCRIPTION:
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index 227d3e3..c19d03d 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -112,7 +112,22 @@ QofBook * gncInvoiceGetBook(GncInvoice *x)
 enum
 {
     PROP_0,
-    PROP_NOTES
+//  PROP_ID,		/* Table */
+//  PROP_DATE_OPENED,	/* Table */
+//  PROP_DATE_POSTED,	/* Table */
+    PROP_NOTES,		/* Table */
+//  PROP_ACTIVE,	/* Table */
+//  PROP_CURRENCY,	/* Table */
+//  PROP_OWNER_TYPE,	/* Table */
+//  PROP_OWNER,		/* Table */
+//  PROP_TERMS,		/* Table */
+//  PROP_BILLING_ID,	/* Table */
+//  PROP_POST_TXN,	/* Table */
+//  PROP_POST_LOT,	/* Table */
+//  PROP_POST_ACCOUNT,	/* Table */
+//  PROP_BILLTO_TYPE,	/* Table */
+//  PROP_BILLTO,	/* Table */
+//  PROP_CHARGE_AMOUNT, /* Table, (numeric) */
 };
 
 /* GObject Initialization */
@@ -168,6 +183,8 @@ gnc_invoice_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_INVOICE(object));
 
     inv = GNC_INVOICE(object);
+    g_assert (qof_instance_get_editlevel(inv));
+
     switch (prop_id)
     {
     case PROP_NOTES:
diff --git a/src/engine/gncJob.c b/src/engine/gncJob.c
index 8e5c2ea..1715d3a 100644
--- a/src/engine/gncJob.c
+++ b/src/engine/gncJob.c
@@ -71,8 +71,13 @@ void mark_job (GncJob *job)
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_PDF_DIRNAME,
+//  PROP_ID,		/* Table */
+    PROP_NAME,		/* Table */
+//  PROP_REFERENCE,	/* Table */
+//  PROP_ACTIVE,	/* Table */
+//  PROP_OWNER_TYPE,	/* Table */
+//  PROP_OWNER,		/* Table */
+    PROP_PDF_DIRNAME,	/* KVP */
 };
 
 /* GObject Initialization */
@@ -134,6 +139,8 @@ gnc_job_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_JOB(object));
 
     job = GNC_JOB(object);
+    g_assert (qof_instance_get_editlevel(job));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/engine/gncOrder.c b/src/engine/gncOrder.c
index 1b073e1..2d36b54 100644
--- a/src/engine/gncOrder.c
+++ b/src/engine/gncOrder.c
@@ -85,12 +85,14 @@ void mark_order (GncOrder *order)
 enum
 {
     PROP_0,
-    PROP_ID,
-    PROP_NOTES,
-    PROP_ACTIVE,
-    PROP_DATE_OPENED,
-    PROP_DATE_CLOSED,
-    PROP_REFERENCE
+    PROP_ID,		/* Table */
+    PROP_NOTES,		/* Table */
+    PROP_REFERENCE,	/* Table */
+    PROP_ACTIVE,	/* Table */
+    PROP_DATE_OPENED,	/* Table */
+    PROP_DATE_CLOSED,	/* Table */
+//  PROP_OWNER_TYPE,	/* Table */
+//  PROP_OWNER,		/* Table */
 };
 
 /* GObject Initialization */
@@ -161,6 +163,8 @@ gnc_order_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_ORDER(object));
 
     order = GNC_ORDER(object);
+    g_assert (qof_instance_get_editlevel(order));
+
     switch (prop_id)
     {
     case PROP_ID:
diff --git a/src/engine/gncTaxTable.c b/src/engine/gncTaxTable.c
index 163243a..234e657 100644
--- a/src/engine/gncTaxTable.c
+++ b/src/engine/gncTaxTable.c
@@ -208,9 +208,10 @@ gncTaxTableRemoveChild (GncTaxTable *table, const GncTaxTable *child)
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_INVISIBLE,
-    PROP_REFCOUNT
+    PROP_NAME,		/* Table */
+    PROP_INVISIBLE,	/* Table */
+    PROP_REFCOUNT,	/* Table */
+//  PROP_PARENT,	/* Table */
 };
 
 /* GObject Initialization */
@@ -272,6 +273,8 @@ gnc_taxtable_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_TAXTABLE(object));
 
     tt = GNC_TAXTABLE(object);
+    g_assert (qof_instance_get_editlevel(tt));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/engine/gncVendor.c b/src/engine/gncVendor.c
index c031625..3ebdb2b 100644
--- a/src/engine/gncVendor.c
+++ b/src/engine/gncVendor.c
@@ -89,20 +89,20 @@ void mark_vendor (GncVendor *vendor)
 enum
 {
     PROP_0,
-    PROP_NAME,
-    PROP_ID,
-    PROP_NOTES,
-    PROP_CURRENCY,
-    PROP_ACTIVE,
-    PROP_TAXTABLE_OVERRIDE,
-    PROP_BILLTERMS,
-    PROP_TAXTABLE,
-    PROP_ADDRESS,
-    PROP_TAX_INCLUDED,
-    PROP_TAX_INCLUDED_STR,
-    PROP_PDF_DIRNAME,
-    PROP_LAST_POSTED,
-    PROP_PAYMENT_LAST_ACCT,
+    PROP_NAME,			/* Table */
+    PROP_ID,			/* Table */
+    PROP_NOTES,			/* Table */
+    PROP_CURRENCY,		/* Table */
+    PROP_ACTIVE,		/* Table */
+    PROP_TAXTABLE_OVERRIDE,	/* Table */
+    PROP_BILLTERMS,		/* Table */
+    PROP_TAXTABLE,		/* Table */
+    PROP_ADDRESS,		/* Table, 8 fields */
+    PROP_TAX_INCLUDED,		/* Table */
+    PROP_TAX_INCLUDED_STR,	/* Alternate setter for PROP_TAX_INCLUDED */
+    PROP_PDF_DIRNAME,		/* KVP */
+    PROP_LAST_POSTED,		/* KVP */
+    PROP_PAYMENT_LAST_ACCT,	/* KVP */
 };
 
 /* GObject Initialization */
@@ -208,6 +208,8 @@ gnc_vendor_set_property (GObject         *object,
     g_return_if_fail(GNC_IS_VENDOR(object));
 
     vendor = GNC_VENDOR(object);
+    g_assert (qof_instance_get_editlevel(vendor));
+
     switch (prop_id)
     {
     case PROP_NAME:
diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index fd257c0..4c04542 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -55,13 +55,15 @@ static QofLogModule log_module = QOF_MOD_ENGINE;
 enum
 {
     PROP_0,
-    PROP_OPT_TRADING_ACCOUNTS,
-    PROP_OPT_AUTO_READONLY_DAYS,
-    PROP_OPT_NUM_FIELD_SOURCE,
-    PROP_OPT_DEFAULT_BUDGET,
-    PROP_OPT_FY_END,
-    PROP_AB_TEMPLATES,
-    N_PROPERTIES
+//  PROP_ROOT_ACCOUNT,		/* Table */
+//  PROP_ROOT_TEMPLATE,		/* Table */
+    PROP_OPT_TRADING_ACCOUNTS,	/* KVP */
+    PROP_OPT_AUTO_READONLY_DAYS,/* KVP */
+    PROP_OPT_NUM_FIELD_SOURCE,	/* KVP */
+    PROP_OPT_DEFAULT_BUDGET,	/* KVP */
+    PROP_OPT_FY_END,		/* KVP */
+    PROP_AB_TEMPLATES,		/* KVP */
+    N_PROPERTIES		/* Just a counter */
 };
 
 QOF_GOBJECT_GET_TYPE(QofBook, qof_book, QOF_TYPE_INSTANCE, {});
@@ -164,6 +166,8 @@ qof_book_set_property (GObject      *object,
 
     g_return_if_fail (QOF_IS_BOOK (object));
     book = QOF_BOOK (object);
+    g_assert (qof_instance_get_editlevel(book));
+
     switch (prop_id)
     {
     case PROP_OPT_TRADING_ACCOUNTS:
diff --git a/src/libqof/qof/qofinstance.c b/src/libqof/qof/qofinstance.c
index f652cc8..8001d60 100644
--- a/src/libqof/qof/qofinstance.c
+++ b/src/libqof/qof/qofinstance.c
@@ -943,7 +943,6 @@ qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
     QofInstancePrivate *priv = GET_PRIVATE(inst);
     g_return_if_fail (QOF_IS_INSTANCE (inst));
 
-    g_assert (priv->editlevel > 0);
     qof_instance_set_dirty (inst);
     va_start (ap, first_prop);
     g_object_set_valist (G_OBJECT (inst), first_prop, ap);

commit 96106fb8fa34f3b85fa6cd1034658b816b0db22e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 10 13:22:48 2013 -0800

    Fix Application Menu Preferences Item
    
    Previous fix put it in the wrong place and didn't even fix changing it to "Preferences Gnucash".

diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c
index e0a192c..23d080d 100644
--- a/src/gnome-utils/gnc-main-window.c
+++ b/src/gnome-utils/gnc-main-window.c
@@ -3715,16 +3715,17 @@ gnc_quartz_set_menu(GncMainWindow* window)
                                       "/menubar/Help/HelpAbout");
     if (GTK_IS_MENU_ITEM (item))
     {
-        gtkosx_application_insert_app_menu_item (theApp,
-                gtk_separator_menu_item_new (),
-                0);
         gtkosx_application_insert_app_menu_item (theApp, GTK_WIDGET (item), 0);
     }
 
     item = gtk_ui_manager_get_widget (window->ui_merge,
                                       "/menubar/Edit/EditPreferences");
     if (GTK_IS_MENU_ITEM (item))
-        gtkosx_application_insert_app_menu_item (theApp, GTK_WIDGET (item), 0);
+    {
+        gtkosx_application_insert_app_menu_item (theApp,
+                gtk_separator_menu_item_new (), 1);
+        gtkosx_application_insert_app_menu_item (theApp, GTK_WIDGET (item), 2);
+    }
 
     item = gtk_ui_manager_get_widget (window->ui_merge,
                                       "/menubar/Help");

commit f1fdeac4c95fa37f7c364d3c727bc3255db26b9e
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Nov 10 13:21:16 2013 -0800

    Fix SX value calculation.
    
    Passed in numeric pointer was being set to NULL by qof_instance_get.

diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index 21ff475..ddc24d9 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -924,17 +924,21 @@ _get_sx_formula_value(const SchedXaction* sx,
 {
 
     char *formula_str = NULL, *parseErrorLoc = NULL;
+    gnc_numeric *numeric_val = NULL;
     qof_instance_get (QOF_INSTANCE (template_split),
 		      formula_key, &formula_str,
-		      numeric_key, &numeric,
+		      numeric_key, &numeric_val,
 		      NULL);
 
-    if ((gnc_numeric_check(*numeric) == GNC_ERROR_OK)
-            && !gnc_numeric_zero_p(*numeric))
+    if (numeric_val != NULL &&
+	gnc_numeric_check(*numeric_val) == GNC_ERROR_OK &&
+	!gnc_numeric_zero_p(*numeric_val))
     {
         /* Already a valid non-zero result? Then return and don't
          * parse the string. Luckily we avoid any locale problems with
          * decimal points here! Phew. */
+	numeric->num = numeric_val->num;
+	numeric->denom = numeric_val->denom;
         return;
     }
 

commit 93f5d48a4ae88661230ef58cf371ab8ce4738d23
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 5 13:19:58 2013 -0800

    Fix a qof_instance_set call outside of an edit.

diff --git a/src/app-utils/test/test-option-util.c b/src/app-utils/test/test-option-util.c
index edf2122..dc99f32 100644
--- a/src/app-utils/test/test-option-util.c
+++ b/src/app-utils/test/test-option-util.c
@@ -42,6 +42,7 @@ typedef struct
  * the Book.
  */
 extern KvpFrame *qof_instance_get_slots (QofInstance*);
+
 static void
 setup (Fixture *fixture, gconstpointer pData)
 {
@@ -57,6 +58,7 @@ setup_kvp (Fixture *fixture, gconstpointer pData)
     setup (fixture, pData);
     book = fixture->book;
     slots = qof_instance_get_slots (QOF_INSTANCE (book));
+    qof_begin_edit (QOF_INSTANCE (book));
     qof_instance_set (QOF_INSTANCE (book),
 		      "trading-accts", "t",
 		      "split-action-num-field", "t",
@@ -65,6 +67,7 @@ setup_kvp (Fixture *fixture, gconstpointer pData)
 
     kvp_frame_set_string (slots, "options/Business/Company Name",
 			  "Bogus Company");
+    qof_commit_edit (QOF_INSTANCE (book));
 }
 
 static void

commit 0418280e04b81ae82dd40ab8cfad42e2f56b2c52
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 5 13:19:04 2013 -0800

    Ensure that all qof_instance_get target variables are initialized
    
    If qof_instance_get doesn't complete, perhaps because it was passed an invalid instance, the target variable might otherwise be used uninitialized.

diff --git a/src/app-utils/gnc-accounting-period.c b/src/app-utils/gnc-accounting-period.c
index 254f611..e7dd8e7 100644
--- a/src/app-utils/gnc-accounting-period.c
+++ b/src/app-utils/gnc-accounting-period.c
@@ -102,7 +102,7 @@ get_fy_end(void)
 {
     QofBook *book;
     KvpFrame *book_frame;
-    GDate *date;
+    GDate *date = NULL;
 
     book = gnc_get_current_book();
     qof_instance_get (QOF_INSTANCE (book),
diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index 6e3595b..21ff475 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -177,8 +177,8 @@ _get_vars_helper(Transaction *txn, void *var_hash_data)
     GHashTable *var_hash = (GHashTable*)var_hash_data;
     GList *split_list;
     Split *s;
-    gchar *credit_formula;
-    gchar *debit_formula;
+    gchar *credit_formula = NULL;
+    gchar *debit_formula = NULL;
     gnc_commodity *first_cmdty = NULL;
 
     split_list = xaccTransGetSplitList(txn);
@@ -190,7 +190,7 @@ _get_vars_helper(Transaction *txn, void *var_hash_data)
     for ( ; split_list; split_list = split_list->next)
     {
         gnc_commodity *split_cmdty = NULL;
-        GncGUID *acct_guid;
+        GncGUID *acct_guid = NULL;
         Account *acct;
 
         s = (Split*)split_list->data;
@@ -884,9 +884,12 @@ typedef struct _SxTxnCreationData
 } SxTxnCreationData;
 
 static gboolean
-_get_template_split_account(const SchedXaction* sx, const Split *template_split, Account **split_acct, GList **creation_errors)
+_get_template_split_account(const SchedXaction* sx,
+			    const Split *template_split,
+			    Account **split_acct,
+			    GList **creation_errors)
 {
-    GncGUID *acct_guid;
+    GncGUID *acct_guid = NULL;
     qof_instance_get (QOF_INSTANCE (template_split),
 		      "sx-account", &acct_guid,
 		      NULL);
@@ -911,10 +914,16 @@ _get_template_split_account(const SchedXaction* sx, const Split *template_split,
 }
 
 static void
-_get_sx_formula_value(const SchedXaction* sx, const Split *template_split, gnc_numeric *numeric, GList **creation_errors, const char *formula_key, const char* numeric_key, GHashTable *variable_bindings)
+_get_sx_formula_value(const SchedXaction* sx,
+		      const Split *template_split,
+		      gnc_numeric *numeric,
+		      GList **creation_errors,
+		      const char *formula_key,
+		      const char* numeric_key,
+		      GHashTable *variable_bindings)
 {
 
-    char *formula_str, *parseErrorLoc;
+    char *formula_str = NULL, *parseErrorLoc = NULL;
     qof_instance_get (QOF_INSTANCE (template_split),
 		      formula_key, &formula_str,
 		      numeric_key, &numeric,
diff --git a/src/business/business-gnome/dialog-invoice.c b/src/business/business-gnome/dialog-invoice.c
index f2bceae..75edcf8 100644
--- a/src/business/business-gnome/dialog-invoice.c
+++ b/src/business/business-gnome/dialog-invoice.c
@@ -720,7 +720,7 @@ gnc_dialog_post_invoice(InvoiceWindow *iw, char *message,
     *ddue = *postdate;
     *memo = NULL;
     {
-	GncGUID *guid;
+	GncGUID *guid = NULL;
 	owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
 	qof_instance_get (owner_inst,
 			  "invoice-last-posted-account", &guid,
diff --git a/src/engine/SX-book.c b/src/engine/SX-book.c
index 1d471fe..7440442 100644
--- a/src/engine/SX-book.c
+++ b/src/engine/SX-book.c
@@ -375,7 +375,7 @@ gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct)
         for (; splits != NULL; splits = splits->next)
         {
             Split *s = (Split*)splits->data;
-            GncGUID *guid;
+            GncGUID *guid = NULL;
             qof_instance_get (QOF_INSTANCE (s), "sx-account", &guid, NULL);
             if (guid_equal(acct_guid, guid))
             {
diff --git a/src/engine/gnc-budget.c b/src/engine/gnc-budget.c
index e8eb03d..3355f7c 100644
--- a/src/engine/gnc-budget.c
+++ b/src/engine/gnc-budget.c
@@ -627,7 +627,7 @@ gnc_budget_get_default (QofBook *book)
 {
     QofCollection *col;
     GncBudget *bgt = NULL;
-    const GncGUID *default_budget_guid;
+    const GncGUID *default_budget_guid = NULL;
 
     g_return_val_if_fail(book, NULL);
 
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index 4b2bac4..899a888 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -742,7 +742,7 @@ gboolean gnc_lot_register (void)
 GNCLot * gnc_lot_make_default (Account *acc)
 {
     GNCLot * lot;
-    gint64 id;
+    gint64 id = 0;
     gchar *buff;
 
     lot = gnc_lot_new (qof_instance_get_book(acc));
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index 3972a4e..227d3e3 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -1102,7 +1102,7 @@ gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot)
 
 GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot)
 {
-    GncGUID *guid;
+    GncGUID *guid = NULL;
     QofBook *book;
 
     if (!lot) return NULL;
@@ -1134,7 +1134,7 @@ gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
 GncInvoice *
 gncInvoiceGetInvoiceFromTxn (const Transaction *txn)
 {
-    GncGUID *guid;
+    GncGUID *guid = NULL;
     QofBook *book;
 
     if (!txn) return NULL;
diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index 8ee0bd3..2a143a9 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -610,9 +610,9 @@ void gncOwnerAttachToLot (const GncOwner *owner, GNCLot *lot)
 
 gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
 {
-    GncGUID *guid;
+    GncGUID *guid = NULL;
     QofBook *book;
-    GncOwnerType type;
+    GncOwnerType type = GNC_OWNER_NONE;
 
     if (!lot || !owner) return FALSE;
 
diff --git a/src/gnome-utils/dialog-preferences.c b/src/gnome-utils/dialog-preferences.c
index be7499b..4e371be 100644
--- a/src/gnome-utils/dialog-preferences.c
+++ b/src/gnome-utils/dialog-preferences.c
@@ -1054,7 +1054,7 @@ gnc_preferences_dialog_create(void)
     GtkWidget *dialog, *notebook, *label, *image;
     GtkWidget *box, *date, *period, *currency;
     GHashTable *prefs_table;
-    GDate* gdate;
+    GDate* gdate = NULL;
     gchar buf[128];
     GtkListStore *store;
     GtkTreePath *path;
@@ -1120,6 +1120,7 @@ gnc_preferences_dialog_create(void)
 
 
     book = gnc_get_current_book();
+    g_date_clear (&fy_end, 1);
     qof_instance_get (QOF_INSTANCE (book),
 		      "fy-end", &fy_end,
 		      NULL);
diff --git a/src/gnome-utils/gnc-tree-util-split-reg.c b/src/gnome-utils/gnc-tree-util-split-reg.c
index 9cbcc2b..b5fe6e5 100644
--- a/src/gnome-utils/gnc-tree-util-split-reg.c
+++ b/src/gnome-utils/gnc-tree-util-split-reg.c
@@ -398,7 +398,7 @@ gnc_tree_util_split_reg_template_get_transfer_entry (Split *split)
 {
     static char *name = NULL;
     Account *account;
-    GncGUID *guid;
+    GncGUID *guid = NULL;
 
     /* Callers either g_strdup the return or use it as a temp for comparison,
        so we keep our static ref and free it on every call. */
@@ -419,7 +419,7 @@ gnc_tree_util_split_reg_template_get_transfer_entry (Split *split)
 const char *
 gnc_tree_util_split_reg_template_get_fdebt_entry (Split *split)
 {
-    gchar *formula;
+    gchar *formula = NULL;
 
     g_return_val_if_fail (split != NULL, NULL);
     qof_instance_get (QOF_INSTANCE (split),
@@ -432,7 +432,7 @@ gnc_tree_util_split_reg_template_get_fdebt_entry (Split *split)
 const char *
 gnc_tree_util_split_reg_template_get_fcred_entry (Split *split)
 {
-    gchar *formula;
+    gchar *formula = NULL;
 
     g_return_val_if_fail (split != NULL, NULL);
     qof_instance_get (QOF_INSTANCE (split),
diff --git a/src/gnome-utils/gnc-tree-view-account.c b/src/gnome-utils/gnc-tree-view-account.c
index d41adc8..73307e7 100644
--- a/src/gnome-utils/gnc-tree-view-account.c
+++ b/src/gnome-utils/gnc-tree-view-account.c
@@ -1732,7 +1732,7 @@ account_cell_property_data_func (GtkTreeViewColumn *tree_column,
 				 gpointer key)
 {
     Account *account;
-    gchar *string;
+    gchar *string = NULL;
 
     g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model));
     account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter);
diff --git a/src/gnome/dialog-sx-editor.c b/src/gnome/dialog-sx-editor.c
index 9058776..4b7b95f 100644
--- a/src/gnome/dialog-sx-editor.c
+++ b/src/gnome/dialog-sx-editor.c
@@ -549,7 +549,7 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
         int numIters, i;
         GHashTable *vars, *txns;
         GList *splitList = NULL;
-        gchar *credit_formula, *debit_formula;
+        gchar *credit_formula = NULL, *debit_formula = NULL;
         Split *s;
         Transaction *t;
         gnc_numeric tmp;
@@ -604,10 +604,10 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
 
             for ( ; splitList; splitList = splitList->next )
             {
-                GncGUID *acct_guid;
-                Account *acct;
-                gnc_commodity *split_cmdty;
-                txnCreditDebitSums *tcds;
+                GncGUID *acct_guid = NULL;
+                Account *acct = NULL;
+                gnc_commodity *split_cmdty = NULL;
+                txnCreditDebitSums *tcds = NULL;
 
                 s = (Split*)splitList->data;
                 t = xaccSplitGetParent( s );
diff --git a/src/gnome/dialog-sx-editor2.c b/src/gnome/dialog-sx-editor2.c
index 3f24dae..a5c5d61 100644
--- a/src/gnome/dialog-sx-editor2.c
+++ b/src/gnome/dialog-sx-editor2.c
@@ -546,7 +546,7 @@ gnc_sxed_check_consistent (GncSxEditorDialog2 *sxed)
         int numIters, i;
         GHashTable *vars, *txns;
         GList *splitList = NULL;
-        char *credit_formula, *debit_formula;
+        char *credit_formula = NULL, *debit_formula = NULL;
         Split *s;
         Transaction *t;
         gnc_numeric tmp;
@@ -595,7 +595,7 @@ gnc_sxed_check_consistent (GncSxEditorDialog2 *sxed)
 
             for (; splitList; splitList = splitList->next)
             {
-                GncGUID *acct_guid;
+                GncGUID *acct_guid = NULL;
                 Account *acct;
                 gnc_commodity *split_cmdty;
                 txnCreditDebitSums *tcds;
diff --git a/src/gnome/gnc-plugin-page-register2.c b/src/gnome/gnc-plugin-page-register2.c
index a6c7c91..110342a 100644
--- a/src/gnome/gnc-plugin-page-register2.c
+++ b/src/gnome/gnc-plugin-page-register2.c
@@ -3629,7 +3629,7 @@ gnc_plugin_page_register2_cmd_schedule (GtkAction *action,
     /* If the transaction has a sched-xact KVP frame, then go to the editor
      * for the existing SX; otherwise, do the sx-from-trans dialog. */
     {
-	GncGUID *fromSXId;
+	GncGUID *fromSXId = NULL;
 	SchedXaction *theSX = NULL;
 	GList *sxElts;
 	qof_instance_get (QOF_INSTANCE (trans),
diff --git a/src/gnome/gnc-split-reg.c b/src/gnome/gnc-split-reg.c
index b1aef33..4bf7633 100644
--- a/src/gnome/gnc-split-reg.c
+++ b/src/gnome/gnc-split-reg.c
@@ -1204,7 +1204,7 @@ gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data )
     /* If the transaction has a sched-xact KVP frame, then go to the editor
      * for the existing SX; otherwise, do the sx-from-trans dialog. */
     {
-	GncGUID *fromSXId;
+	GncGUID *fromSXId = NULL;
 	SchedXaction *theSX = NULL;
 	GList *sxElts;
 	qof_instance_get (QOF_INSTANCE (pending_trans),
diff --git a/src/import-export/aqbanking/gnc-ab-kvp.c b/src/import-export/aqbanking/gnc-ab-kvp.c
index 1b1bc5c..b99390b 100644
--- a/src/import-export/aqbanking/gnc-ab-kvp.c
+++ b/src/import-export/aqbanking/gnc-ab-kvp.c
@@ -40,7 +40,7 @@ static kvp_frame *gnc_ab_get_book_kvp(QofBook *b, gboolean create);
 const gchar *
 gnc_ab_get_account_accountid(const Account *a)
 {
-    gchar *id;
+    gchar *id = NULL;
     qof_instance_get (QOF_INSTANCE (a),
 		      "ab-account-id", &id,
 		      NULL);
@@ -60,7 +60,7 @@ gnc_ab_set_account_accountid(Account *a, const gchar *id)
 const gchar *
 gnc_ab_get_account_bankcode(const Account *a)
 {
-    gchar *code;
+    gchar *code = NULL;
     qof_instance_get (QOF_INSTANCE (a),
 		      "ab-bank-code", &code,
 		      NULL);
@@ -80,7 +80,7 @@ gnc_ab_set_account_bankcode(Account *a, const gchar *code)
 guint32
 gnc_ab_get_account_uid(const Account *a)
 {
-    guint64 uid;
+    guint64 uid = 0LL;
     qof_instance_get (QOF_INSTANCE (a),
 		      "ab-account-uid", &uid,
 		      NULL);
@@ -100,7 +100,7 @@ gnc_ab_set_account_uid(Account *a, guint32 uid)
 Timespec
 gnc_ab_get_account_trans_retrieval(const Account *a)
 {
-    Timespec t;
+    Timespec t = {0LL, 0LL};
     qof_instance_get (QOF_INSTANCE (a),
 		      "ab-trans-retrieval", &t,
 		      NULL);
@@ -120,7 +120,7 @@ gnc_ab_set_account_trans_retrieval(Account *a, Timespec time)
 GList *
 gnc_ab_get_book_template_list(QofBook *b)
 {
-    GList *template_list;
+    GList *template_list = NULL;
     qof_instance_get (QOF_INSTANCE (b),
 		      "ab-templates", &template_list,
 		      NULL);
diff --git a/src/import-export/import-utilities.c b/src/import-export/import-utilities.c
index 68b64ef..60bf1ae 100644
--- a/src/import-export/import-utilities.c
+++ b/src/import-export/import-utilities.c
@@ -42,7 +42,7 @@
 
 const gchar * gnc_import_get_acc_online_id (Account * account)
 {
-    gchar *id;
+    gchar *id = NULL;
     qof_instance_get (QOF_INSTANCE (account), "online-id", &id, NULL);
     return id;
 }
@@ -59,7 +59,7 @@ void gnc_import_set_acc_online_id (Account *account, const gchar *id)
 
 const gchar * gnc_import_get_trans_online_id (Transaction * transaction)
 {
-    gchar *id;
+    gchar *id = NULL;
     qof_instance_get (QOF_INSTANCE (transaction), "online-id", &id, NULL);
     return id;
 }
@@ -82,7 +82,7 @@ gboolean gnc_import_trans_has_online_id(Transaction * transaction)
 
 const gchar * gnc_import_get_split_online_id (Split * split)
 {
-    gchar *id;
+    gchar *id = NULL;
     qof_instance_get (QOF_INSTANCE (split), "online-id", &id, NULL);
     return id;
 }
diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index 1783856..fd257c0 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -815,7 +815,7 @@ qof_book_validate_counter_format_internal(const gchar *p,
 gboolean
 qof_book_use_trading_accounts (const QofBook *book)
 {
-    const char *opt;
+    const char *opt = NULL;
     qof_instance_get (QOF_INSTANCE (book),
 		      "trading-accts", &opt,
 		      NULL);
@@ -829,7 +829,7 @@ qof_book_use_trading_accounts (const QofBook *book)
 gboolean
 qof_book_use_split_action_for_num_field (const QofBook *book)
 {
-    const char *opt;
+    const char *opt = NULL;
     qof_instance_get (QOF_INSTANCE (book),
 		      "split-action-num-field", &opt,
 		      NULL);
@@ -848,7 +848,7 @@ gboolean qof_book_uses_autoreadonly (const QofBook *book)
 gint qof_book_get_num_days_autoreadonly (const QofBook *book)
 {
     kvp_value *kvp_val;
-    double tmp;
+    double tmp = 0;
     KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
 
     g_assert(book);
diff --git a/src/register/ledger-core/split-register-model.c b/src/register/ledger-core/split-register-model.c
index 5294b40..3ce912c 100644
--- a/src/register/ledger-core/split-register-model.c
+++ b/src/register/ledger-core/split-register-model.c
@@ -2097,7 +2097,7 @@ gnc_template_register_get_xfrm_entry (VirtualLocation virt_loc,
     SplitRegister *reg = user_data;
     Split *split;
     Account *account;
-    GncGUID *guid;
+    GncGUID *guid = NULL;
 
     split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
     if (!split)
@@ -2124,7 +2124,7 @@ gnc_template_register_get_fdebt_entry (VirtualLocation virt_loc,
 {
     SplitRegister *reg = user_data;
     Split *split = gnc_split_register_get_split(reg, virt_loc.vcell_loc);
-    char *formula;
+    char *formula = NULL;
 
     qof_instance_get (QOF_INSTANCE (split),
 		      "sx-debit-formula", &formula,
@@ -2155,7 +2155,7 @@ gnc_template_register_get_fcred_entry (VirtualLocation virt_loc,
 {
     SplitRegister *reg = user_data;
     Split *split = gnc_split_register_get_split(reg, virt_loc.vcell_loc);
-    char *formula;
+    char *formula = NULL;
 
     qof_instance_get (QOF_INSTANCE (split),
 		      "sx-credit-formula", &formula,
diff --git a/src/report/report-gnome/gnc-plugin-page-report.c b/src/report/report-gnome/gnc-plugin-page-report.c
index 0cd14fc..5f57c00 100644
--- a/src/report/report-gnome/gnc-plugin-page-report.c
+++ b/src/report/report-gnome/gnc-plugin-page-report.c
@@ -1788,7 +1788,7 @@ gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *rep
         if (owner)
         {
 	    QofInstance *inst = qofOwnerGetOwner (owner);
-	    gchar *dirname;
+	    gchar *dirname = NULL;
 	    qof_instance_get (inst, "export-pdf-dir", &dirname, NULL);
             // Yes. In the kvp, look up the key for the Export-PDF output
             // directory. If it exists, prepend this to the job name so that

commit ecee2d963fec537839badcca02a24ae61e853132
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Nov 5 11:32:12 2013 -0800

    Update dependencies and versions

diff --git a/README.dependencies b/README.dependencies
index b190d0b..7710f40 100644
--- a/README.dependencies
+++ b/README.dependencies
@@ -60,518 +60,34 @@ release (or an official package-upgrade path)
 
 Libraries/Deps
 --------------
-  required
-  --------
-gconf2
-glib2
-gtk+2
-guile
-libart2
-libgnomeprint2.2
-libgnomeui2
-[lib]goffice
-libgsf1
-libxml2
-pango
-swig
-webkit
+  required		Version
+  --------		_______
+glib2			2.28.0
+gtk+2			2.24.0
+guile			1.8.5 or 2.0.0
+libgnomecanvas		2.0
+[lib]goffice		0.7.0
+libxml2			2.5.10
+libxslt
+swig			2.0.10			Only required to build from git
+						or SVN.
+webkit			1.0
 
   optional
   --------
-aqbanking: online banking
-libdbi + desired database layer: SQL backend
-libofx
-python: python bindings
-
-  at runtime, suggested
-  ---------------------
-isocodes: translation of currency names 
-
-Interesting libraries
----------------------
-
-swig
-glib
-gtk
-cairo
-goffice, libgsf
-gtkprint
-webkit
+aqbanking		4.0.0			 online banking; also requires
+						 gwehywfar and ktoblzcheck
 
+libdbi			0.8.3			 SQL backend; also requires at
+						 least one of libdbd-sqlite3,
+						 libdbd-mysql, or libdbd-pgsql
 
+libofx			0.9.0			 OFX/QFX import
 
+python			2.4.0			 python bindings; headers
+						 required, not just binaries.
 
+  at runtime, suggested
+  ---------------------
+isocodes: translation of currency names
 
-
----------------------------
-
-The rest of the file collected version listings for rather old
-versions of major distributions, as defined by
-http://distrowatch.com/dwres.php?resource=major:
-
-
-
-libgoffice/libgsf details
--------------------------
-
-- libgoffice-0.4.0
-  - glib-2.0		>= 2.6.4
-  - gobject-2.0		>= 2.6.4
-  - gmodule-2.0		>= 2.6.4
-  - libgsf-1		>= 1.12.2
-    - gobject-2.0 >= 2.6.0
-    - glib-2.0 >= 2.6.0
-    - libxml-2.0 >= 2.4.16
-    - libbonobo-2.0 >= 2.0.0
-    - gnome-vfs-2.0 >= 2.2.0
-    - gnome-vfs-module-2.0 >= 2.2.0
-  - libxml-2.0		>= 2.4.12
-  - pango		>= 1.8.1
-  - pangoft2		>= 1.8.1
-  - cairo		>= 0.5.0 [optional]
-  - gtk+-2.0		>= 2.6.0
-  - libgnomeprint-2.2	>= 2.8.2
-  - libart-2.0		>= 2.3.11
-  - gconf-2.0
-  - libgnomeui-2.0	>= 2.0.0
-  - libgsf-gnome-1	>= 1.12.2
-
-
-Partial update, 2007-06-09; RHEL-only
--------------------------------------
-- RHEL
-  - *RHEL 4 = 2005-02-15		RHEL 5
-
-    - aqbanking: not included		aqbanking-2.2.9 from Fedora Core 7
-    - cairo: not included		cairo-1.4.4     from Fedora Core 7
-    - gconf2-2.8.1			GConf2-2.14.0-9.el5
-    - glib2-2.4.7			glib2-2.12.3-2.fc6
-    - gtk2-2.4.13			gtk2-2.10.4-16.el5
-    - guile-1.6.4			guile-1.8.0--8.20060831cvs
-    - libart_lgpl-2.3.16		libart-lgpl-2.3.17-4
-    - libgnomeprint22-2.8.0		libgnomeprint22-2.12.1-6
-    - libgnomeui-2.8.0			libgnomeui-2.16.0-5.el5
-    - libgsf-1.10.1			libgsf-1.14.1-6.1
-    - libofx: not included		libofx-0.8.3    from Fedora Core 7
-    - libxml2-2.6.16			libxml2-2.6.26-2.1.2	
-    - pango-1.6.0			pango-1.14.9    from Fedora Core 7
-
-
-Status, 2007-01-17
-------------------
-
-1. Ubuntu
-   - 2006.10 [2006/10/26]
-     - gtk+ 2.10.6
-     - swig 1.3.28-1.1ubuntu1
-   - 2006.06 [2006/06/01]
-     - gtk+ 2.8.17
-2. Mandriva Linux
-   - 2007 [2006/10/03]
-     - gtk+ 2.10.3
-   - 2006 [2005/10/06]
-     - gtk+ 2.8.3
-3. Suse
-   - 10.2 [2006/12/07]
-     - gtk+ 2.10.6
-   - 10.1 [2006/05/11]
-     - gtk+ 2.8.10
-4. Fedora Core
-   - FC6 [2006/10/24]
-     - gtk+ 2.10.4
-   - FC5 [2006/03/20]
-     - gtk+ 2.8.15
-5. Debian GNU/Linux
-   - unstable
-     - gtk+ 2.8.20
-   - testing
-     - gtk+ 2.8.20
-   - sarge [2005/06/06]
-     - gtk+ 2.6.4
-
-Status, 2005-11-06
-------------------
-The major distributions, as defined by http://distrowatch.com/dwres.php?resource=major, are:
-
-- Ubuntu - http://www.ubuntu.com/
-  -  5.10 = 2005-10-13 - http://www.ubuntu.com/newsitems/release510
-    [from the {main,multiverse,universe}/binary-i386/Packages.gz files at
-     http://archive.ubuntu.com/ubuntu/dists/breezy/]
-    - aqbanking: libaqbanking0c2-1.5.99+1.6.0beta-1ubuntu1
-    - libcairo-1.0.2-0ubuntu1
-    - gconf2-2.12.0-0ubuntu1
-    - glib2-2.8.3-0ubuntu1
-    - gtk+2-2.8.6-0ubuntu2
-    - guile-1.6.7-1ubuntu3
-    - g-wrap-1.9.6-2ubuntu2
-    - libart2-2.3.17-1
-    - libgnomeprint2.2-2.12.1-0ubuntu1
-    - libgnomeui2-2.12.0-0ubuntu1
-    - libgsf1-1.12.3-3ubuntu3
-    - libofx2-0.8.0-3ubuntu8
-    - libxml2-2.6.21-0ubuntu1
-    - pango-1.10.1-0ubuntu1
-  - *5.04 = 2005-04-08 - http://www.ubuntu.com/504Released
-    [from the {main,multiverse,universe}/binary-i386/Packages.gz files at
-     http://archive.ubuntu.com/ubuntu/dists/hoary/]
-    - aqbanking ??
-    - cairo 0.3.0-1
-    - gconf-2 gconf2_2.10.0-0ubuntu1_i386.deb
-    - glib-2 libglib2.0-0_2.6.3-1_i386.deb
-    - gtk+-2 libgtk2.0-0_2.6.4-0ubuntu3_i386.deb
-    - guile guile-1.6-libs_1.6.7-1ubuntu1_i386.deb
-    - gwrap
-      - gwrapguile-1.3.4
-      - g-wrap-1.9.6
-    - libart-2 libart-2.0-2_2.3.17-1_i386.deb
-    - libgnomeprint-2.2 libgnomeprint2.2-0_2.10.3-0ubuntu1_i386.deb
-    - libgnomeui-2  libgnomeui-0_2.10.0-0ubuntu1_i386.deb
-    - libgsf-1 libgsf-1_1.11.1-1ubuntu1_i386.deb
-    - libofx: none
-    - libxml-2 libxml2_2.6.17-0ubuntu1_i386.deb
-    - pango libpango1.0-0_1.8.1-0ubuntu2
-- Mandriva
-  -  2007.0 = 2007-01-03
-    [from ftp://ftp.proxad.net/pub/Distributions_Linux/MandrivaLinux/official/2007.0/i586/media/main/]
-    - aqbanking-2.2.1
-    - libcairo2-1.2.4
-    - gconf-2.14.0
-    - glib-2.12.3
-    - gtk+-2.10.3
-    - guile-1.6.8
-    - g-wrap-1.9.6
-    - libart-2.3.17
-    - libgnomeprint-2.2-2.12.1
-    - libgnomeui-2.16.0
-    - libgsf-1.14.1
-    - libofx-0.8.0
-    - libxml-2.6.26
-    - pango-1.14.3
-    Note: -devel packages for the libraries above must also be installed.
-  -  2006 = 2005-10-06
-    [from ftp://ftp.rutgers.edu/pub/Mandrakelinux/devel/2006.0/i586/media/main/]
-    - aqbanking-1.2.0
-    - libcairo2-1.0.0
-    - gconf-2.10.1
-    - glib-2.8.1
-    - gtk+-2.8.3
-    - guile-1.6.7
-    - g-wrap-1.3.4
-    - libart-2.3.17
-    - libgnomeprint-2.2-2.10.3
-    - libgnomeui-2.10.2
-    - libgsf-1.12.2
-    - libofx-0.7.0
-    - libxml-2.6.21
-    - pango-1.10.0
-  - *2005 = 2005-04-14
-    [from ftp://ftp.rutgers.edu/pub/Mandrakelinux/devel/2005/i586/media/main/]
-    - aqbanking-1.0.7
-    - libcairo-0.3.0
-    - gconf-2.8.1
-    - glib-2.6.3
-    - gtk+-2.6.4
-    - guile-1.6.7
-    - g-wrap-1.3.4
-    - libart-2.3.17
-    - libgnomeprint-2.2-2.8.2
-    - libgnomeui-2.8.2
-    - libgsf-1.11.1
-    - libofx-0.7.0
-    - libxml-2.6.17
-    - pango-1.8.1
-- SUSE / opensuse
-  -  10.2 = 2006-12-07
-    - aqbanking-2.2.3
-    - cairo-1.2.4
-    - gconf2-2.14.0
-    - glib2-2.12.4
-    - goffice-0.2.1
-    - gtk2-2.10.6
-    - guile-1.8.1
-    - g-wrap: not included
-    - libart_lgpl-2.3.17
-    - libgnomeprint-2.12.1
-    - libgnomeui-2.16.1
-    - libgsf-1.14.2
-    - libofx-0.8.2
-    - libxml2-2.6.26
-    - pango-1.14.5
-    - swig-1.3.29
-  -  10.1 = 2006-05-11
-    - aqbanking-1.2.0 (but package is broken; needs to be replaced by >=1.3.0)
-    - cairo-1.0.2
-    - gconf2-2.12.1
-    - glib2-2.8.5
-    - goffice-0.1.2
-    - gtk2-2.8.10
-    - guile-1.6.7
-    - g-wrap: not included
-    - libart_lgpl-2.3.17
-    - libgnomeprint-2.12.1
-    - libgnomeui-2.12.0
-    - libgsf-1.13.99
-    - libofx-0.8.0
-    - libxml2-2.6.23
-    - pango-1.10.2
-    - swig-1.3.27
-  -  10.0 = 2005-10-06
-    - aqbanking: not included; binary aqbanking-1.6.0 available at ftp://ftp.gwdg.de/linux/misc/suser-crauch/10.0/
-    - cairo-1.0.0
-    - gconf2-2.12.0
-    - glib2-2.8.1
-    - gtk2-2.8.3
-    - guile-1.6.7
-    - g-wrap: not included
-    - libart_lgpl-2.3.17
-    - libgnomeprint-2.12.0
-    - libgnomeui-2.12.0
-    - libgsf-1.12.1
-    - libofx-0.7.0
-    - libxml2-2.6.20
-    - pango-1.10.0
-    - swig-1.3.24
-  - *9.3  = 2005-04-15
-    - aqbanking: not included, but binary aqbanking-1.6.0 provided by upstream
-    - cairo-0.3.0
-    - gconf2-2.10.0
-    - glib2-2.6.3
-    - gtk2-2.6.4
-    - guile-1.6.7
-    - gwrap: not included
-    - libart_lgpl-2.3.17
-    - libgnomeprint-2.10.1
-    - libgnomeui-2.10.0
-    - libgsf-1.11.1
-    - libofx-0.7.0
-    - libxml2-2.6.17
-    - pango-1.8.1
-    - swig-1.3.21
-- Fedora Core
-  - *FC4 = 2005-06-13
-    - aqbanking-1.0.4beta
-    - cairo: not included
-    - g-wrap-1.3.4
-    - gconf2-2.10.0
-    - glib2-2.6.6
-    - gtk2-2.6.10
-    - guile-1.6.7
-    - libart_lgpl-2.3.17
-    - libgnomeprint22-2.10.3
-    - libgnomeui-2.10.0
-    - libgsf-1.11.1
-    - libofx-0.7.0
-    - libxml2-2.6.20
-    - pango-1.8.1
-  -  FC3 = 2004-11-08
-    - aqbanking: not included
-    - cairo: not included
-    - g-wrap-1.3.4
-    - gconf2-2.8.1
-    - glib2-2.4.8
-    - gtk2-2.4.14
-    - guile-1.6.4
-    - libart_lgpl-2.3.16
-    - libgnomeprint22-2.8.0
-    - libgnomeui-2.8.0
-    - libgsf-1.10.1
-    - libofx-0.7.0
-    - libxml2-2.6.16
-    - pango-1.6.0
-- Debian GNU/Linux
-  - 4.x unstable
-    (already includes goffice and will include libqof1)
-    - aqbanking-1.5.99
-    - cairo-1.0.0
-    - gconf2-2.10.1
-    - glib2-2.8.3
-    - gtk2-2.6.10
-    - guile-1.6.7
-    - libart2-2.3.17
-    - libgnomeprint2.2-2.10.3
-    - libgnomeui2-2.10.1
-    - libgsf1-1.12.3
-    - libofx-0.8.0
-    - libxml2-2.6.22
-    - pango-1.8.2
-    - gwrapguile-1.3.4
-    - g-wrap-1.9.6
-  - *3.1 sarge = 2005-06-06  
-    - aqbanking: no
-    - cairo: no
-    - gconf2-2.8.1
-    - glib2-2.6.4
-    - gtk2-2.6.4
-    - guile-1.6.7
-    - libart2-2.3.17
-    - libgnomeprint2.2-2.8.2
-    - libgnomeui2-2.8.1
-    - libgsf1-1.11.1
-    - libofx-0.7.0
-    - libxml2-2.6.16
-    - pango-1.8.1
-    - gwrapguile-1.3.4
-    - g-wrap-1.9.5
-- Knoppix
-  -  4.0.2 = 2005-09-24
-  - *3.9   = 2005-06-01
-  -  3.8.2 = 2005-05-12
-- MEPIS
-  - *3.3.1 = 2005-05-12
-- Gentoo
-  -  2005.1 = 2005-08-08
-    [from http://distro.ibiblio.org/pub/linux/distributions/gentoo/releases/snapshots/2005.1/portage-20050709.tar.bz2]
-    - aqbanking-1.0.8
-    - cairo-0.4.0
-    - g-wrap-1.3.4
-    - gconf-2.10.0
-    - glib-2.6.5
-    - gtk+-2.6.8
-    - guile-1.6.7
-    - libart_lgpl-2.3.17
-    - libgnomeprint-2.10.3
-    - libgnomeui-2.10.0
-    - libgsf-1.12.1
-    - libofx-0.7.0
-    - libxml2-2.6.19
-    - pango-1.8.1-r1
-  -  2005.0 = 2005-03-28
-    [from http://gentoo.osuosl.org/releases/x86/2005.0/packagecd/CONTENTS
-     and http://gentoo.osuosl.org/releases/snapshots/2005.0/portage-20050303.tar.bz2]
-    - aqbanking-1.0.4_beta, -0.9.9
-    - cairo-0.3.0-r1
-    - g-wrap-1.3.4-r1
-    - gconf-2.8.1-r1
-    - glib-2.6.2
-    - guile-1.6.7
-    - libart_gpl-2.3.16
-    - libgnomeprint-2.8.1
-    - libgnomeui-2.8.1-r1
-    - libgsf-1.10.0
-    - libxml2-2.6.16
-    - pango-1.8.0
-- Slackware
-  [Need to check for gnome packages at...
-   - http://dropline-gnome.sourceforge.net/
-   - http://gsb.freerock.org/
-   - http://www.gware.org/]
-  -  10.2 = 2005-09-14
-    [from http://slackware.it/en/pb/]
-    - aqbanking: no
-    - cairo: no
-    - gconf2: no
-    - glib2-2.6.6
-    - gtk+2-2.6.10
-    - guile-1.6.7
-    - gwrap: no
-    - libart2-2.3.17
-    - libgnomeprint2.2: no
-    - libgnomeui2: no
-    - libgsf1-1.12.1
-    - libofx: no
-    - libxml2-2.6.22
-    - pango-1.8.2
-  - *10.1 = 2005-02-07
-    [from http://slackware.it/en/pb/]
-    - aqbanking: no
-    - cairo: no
-    - gconf2-2.6.2
-    - glib2-2.6.4
-    - gtk+2-2.6.7
-    - guile-1.6.5
-    - gwrap: no
-    - libart2-2.3.16
-    - libgnomeprint2.2-2.6.1
-    - libgnomeui2-2.6.1
-    - libgsf1-1.9.1
-    - libofx: no
-    - libxml2-2.6.16
-    - pango-1.8.1
-- Xandros Desktop
-  - *3.0 = 2004-12
-  -  2.5 = 2004-07
-  - ftp://ftp2.xandros.com/src/dists/
-- FreeBSD
-  - *5.4  = 2005-05-09 - http://www.freebsd.org/releases/5.4R/announce.html
-    [from ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/5.4-RELEASE/packages/INDEX]
-    - aqbanking: not included
-    - cairo-0.4.0
-    - gconf2-2.10.0
-    - glib-2.6.3_1
-    - gtk-2.6.4_1
-    - guile-1.6.5
-    - g-wrap-1.3.4_6
-    - libart_lgpl2-2.3.17
-    - libgnomeprint-2.10.1
-    - libgnomeui-2.10.0_1
-    - libgsf-1.11.1
-    - libofx-0.7.0
-    - libxml2-2.6.18
-    - pango-1.8.1
-  -  4.11 = 2005-01-25 - http://www.freebsd.org/releases/4.11R/announce.html
-- Fink/OSX
-  - ??
-- RHEL
-  - *RHEL 4 = 2005-02-15
-    [from http://ftp.redhat.com/pub/redhat/linux/enterprise/4/en/]
-    - aqbanking: not included
-    - cairo: not included
-    - gconf2-2.8.1
-    - glib2-2.4.7
-    - gtk2-2.4.13
-    - guile-1.6.4
-    - gwrap: not included
-    - libart_lgpl-2.3.16
-    - libgnomeprint22-2.8.0
-    - libgnomeui-2.8.0
-    - libgsf-1.10.1
-    - libofx: not included
-    - libxml2-2.6.16
-    - pango-1.6.0
-  -  RHEL 3 = 2003-10-22
-    - aqbanking: not included
-    - cairo: not included
-    - gconf2-2.2.1
-    - glib2-2.2.3
-    - gtk2-2.2.4
-    - guile-1.6.4
-    - g-wrap: not included
-    - libart_lgpl-2.3.11
-    - libgnomeprint22-2.2.1.3
-    - libgnomeui-2.2.1
-    - libgsf-1.6.0
-    - libofx: not included
-    - libxml2-2.5.10
-    - pango-1.2.5
-- CentOS
-  [from http://vault.centos.org/]
-  -  4.2 = 2005-10-12
-    - aqbanking: no
-    - cairo: no 
-    - gconf2-2.8.1
-    - glib2-2.4.7
-    - gtk2-2.4.13
-    - guile-1.6.4
-    - gwrap: no
-    - libart2-2.3.16
-    - libgnomeprint2.2-2.8.0
-    - libgnomeui2-2.8.0
-    - libgsf1-1.10.1
-    - libofx: no 
-    - libxml2-2.6.16
-    - pango-1.6.0
-  - *4.1 = 2005-06-12
-    - aqbanking: no
-    - cairo: no
-    - gconf2-2.8.1
-    - glib2-2.4.7
-    - gtk2-2.4.13
-    - guile-1.6.4
-    - gwrap: no
-    - libart2-2.3.16
-    - libgnomeprint2.2-2.8.0
-    - libgnomeui2-2.8.0
-    - libgsf1-1.10.1
-    - libofx: no
-    - libxml2-2.6.16
-    - pango-1.6.0

commit d0be95f2c6a5b4c4889f008a597afa0a293ae6fb
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Nov 4 11:31:15 2013 -0800

    Assert on entry to qof_instance_set() if editlevel is 0
    
    To ensure that change will be forwarded to the backend

diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index cc8dcdc..8b95526 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -60,7 +60,7 @@ typedef struct
 /* Prototype to shut clang up */
 void test_suite_engine_kvp_properties (void);
 
-/* Private QofInstance function needed for testing */
+/* Private QofInstance functions needed for testing */
 extern void qof_instance_mark_clean (QofInstance*);
 
 const gchar *suitename = "/engine/kvp-properties";
@@ -147,7 +147,7 @@ test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
     Timespec trans_retr = timespec_now ();
     Timespec *trans_retr_r;
 
-
+    xaccAccountBeginEdit (fixture->acct);
     qof_instance_set (QOF_INSTANCE (fixture->acct),
 		      "lot-next-id", next_id,
 		      "online-id", online_id,
@@ -189,6 +189,7 @@ test_trans_kvp_properties (Fixture *fixture, gconstpointer pData)
     gchar *online_id = "my online id";
     gchar *online_id_r;
 
+    xaccTransBeginEdit (fixture->trans);
     qof_instance_set (QOF_INSTANCE (fixture->trans),
 		      "invoice", invoice,
 		      "from-sched-xaction", from_sx,
@@ -229,6 +230,7 @@ test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
     gnc_numeric credit_numeric = gnc_numeric_create (789, 456);
     gnc_numeric *debit_numeric_r, *credit_numeric_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->split));
     qof_instance_set (QOF_INSTANCE (fixture->split),
 		      "sx-debit-formula", debit_formula,
 		      "sx-debit-numeric", &debit_numeric,
@@ -263,6 +265,7 @@ test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
     g_free (debit_numeric_r);
     g_free (credit_formula_r);
     g_free (credit_numeric_r);
+    qof_begin_edit (QOF_INSTANCE (fixture->split));
     qof_instance_set (QOF_INSTANCE (fixture->split),
 		      "sx-credit-formula", NULL,
 		      NULL);
@@ -286,6 +289,7 @@ test_lot_kvp_properties (Fixture *fixture, gconstpointer pData)
     GncGUID *owner = guid_malloc ();
     GncGUID *owner_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->lot));
     qof_instance_set (QOF_INSTANCE (fixture->lot),
 		      "invoice", invoice,
 		      "owner-type", owner_type,
@@ -319,6 +323,7 @@ test_customer_kvp_properties (Fixture *fixture, gconstpointer pData)
     GncGUID *pmt_acct = guid_malloc ();
     GncGUID *inv_acct_r, *pmt_acct_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->cust));
     qof_instance_set (QOF_INSTANCE (fixture->cust),
 		      "export-pdf-dir", pdf_dir,
 		      "invoice-last-posted-account", inv_acct,
@@ -354,6 +359,7 @@ test_employee_kvp_properties (Fixture *fixture, gconstpointer pData)
     GncGUID *pmt_acct = guid_malloc ();
     GncGUID *inv_acct_r, *pmt_acct_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->emp));
     qof_instance_set (QOF_INSTANCE (fixture->emp),
 		      "export-pdf-dir", pdf_dir,
 		      "invoice-last-posted-account", inv_acct,
@@ -386,6 +392,7 @@ test_job_kvp_properties (Fixture *fixture, gconstpointer pData)
     gchar *pdf_dir = "/foo/bar/baz";
     gchar *pdf_dir_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->job));
     qof_instance_set (QOF_INSTANCE (fixture->job),
 		      "export-pdf-dir", pdf_dir,
 		      NULL);
@@ -411,6 +418,7 @@ test_vendor_kvp_properties (Fixture *fixture, gconstpointer pData)
     GncGUID *pmt_acct = guid_malloc ();
     GncGUID *inv_acct_r, *pmt_acct_r;
 
+    qof_begin_edit (QOF_INSTANCE (fixture->vend));
     qof_instance_set (QOF_INSTANCE (fixture->vend),
 		      "export-pdf-dir", pdf_dir,
 		      "invoice-last-posted-account", inv_acct,
diff --git a/src/engine/test/utest-Split.c b/src/engine/test/utest-Split.c
index 0f016a1..43f01dd 100644
--- a/src/engine/test/utest-Split.c
+++ b/src/engine/test/utest-Split.c
@@ -1137,9 +1137,11 @@ test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
 
     /* create correct slot path */
     g_test_message( "Testing with use-split-action-for-num set to true - t" );
+    qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "split-action-num-field", "t",
 		      NULL);
+    qof_book_commit_edit (book);
     g_assert(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == TRUE);
 
     g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);
@@ -1151,9 +1153,11 @@ test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
     o_split->action = NULL;
     split->action = "foo";
     o_split->parent = NULL;
+    qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "split-action-num-field", "f",
 		      NULL);
+    qof_book_commit_edit (book);
     g_assert(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == FALSE);
     split->parent = NULL;
     /* This should return > 0 because o_split has no memo string */
@@ -1782,9 +1786,11 @@ test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
     g_assert (kvp_frame_get_slot (split->inst.kvp_data, "lot-split") == NULL);
     kvp_frame_set_slot (split1->inst.kvp_data, "lot-split", NULL);
     g_assert (kvp_frame_get_slot (split1->inst.kvp_data, "lot-split") == NULL);
+    qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "trading-accts", "t",
 		      NULL);
+    qof_book_commit_edit (book);
     g_assert (xaccTransUseTradingAccounts (txn));
     g_assert (xaccSplitGetOtherSplit (split) == NULL);
     split2->acc = acc2;
diff --git a/src/engine/test/utest-Transaction.c b/src/engine/test/utest-Transaction.c
index 6571f0f..c2a963f 100644
--- a/src/engine/test/utest-Transaction.c
+++ b/src/engine/test/utest-Transaction.c
@@ -1048,10 +1048,11 @@ test_xaccTransGetImbalance_trading (Fixture *fixture,
     Account *acc2 = xaccMallocAccount (book);
     gnc_numeric value;
     MonetaryList *mlist;
-
+    qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "trading-accts", "t",
 		      NULL);
+    qof_book_commit_edit (book);
 
  /* Without trading splits, the list is unbalanced */
     mlist = xaccTransGetImbalance (fixture->txn);
@@ -1134,9 +1135,12 @@ test_xaccTransIsBalanced_trading (Fixture *fixture, gconstpointer pData)
     Account *acc1 = xaccMallocAccount (book);
     Account *acc2 = xaccMallocAccount (book);
 
+    qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "trading-accts", "t",
 		      NULL);
+    qof_book_commit_edit (book);
+
     xaccAccountSetCommodity (acc1, fixture->curr);
     xaccAccountSetCommodity (acc2, fixture->comm);
     xaccAccountSetType (acc1, ACCT_TYPE_TRADING);
@@ -1639,10 +1643,6 @@ test_xaccTransCommitEdit (void)
         xaccTransSetCurrency (txn, curr);
         xaccSplitSetParent (split1, txn);
         xaccSplitSetParent (split2, txn);
-        /* xaccTransCommitEdit doesn't do anything with kvp
-        kvp_frame_set_double (frame, "/qux/quux/corge", 123.456);
-         qof_instance_set_slots (QOF_INSTANCE (txn), frame);
-         */
     }
     /* Setup's done, now test: */
     xaccTransCommitEdit (txn);
diff --git a/src/libqof/qof/qofinstance.c b/src/libqof/qof/qofinstance.c
index dd9e330..f652cc8 100644
--- a/src/libqof/qof/qofinstance.c
+++ b/src/libqof/qof/qofinstance.c
@@ -940,8 +940,10 @@ void
 qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
 {
     va_list ap;
+    QofInstancePrivate *priv = GET_PRIVATE(inst);
     g_return_if_fail (QOF_IS_INSTANCE (inst));
 
+    g_assert (priv->editlevel > 0);
     qof_instance_set_dirty (inst);
     va_start (ap, first_prop);
     g_object_set_valist (G_OBJECT (inst), first_prop, ap);
diff --git a/src/libqof/qof/test/test-qofbook.c b/src/libqof/qof/test/test-qofbook.c
index 6c56858..e9732d1 100644
--- a/src/libqof/qof/test/test-qofbook.c
+++ b/src/libqof/qof/test/test-qofbook.c
@@ -361,6 +361,7 @@ test_book_use_trading_accounts( Fixture *fixture, gconstpointer pData )
     g_assert( qof_book_use_trading_accounts( fixture-> book ) == FALSE );
 
     g_test_message( "Testing with existing trading accounts set to true - t" );
+    qof_book_begin_edit (fixture->book);
     qof_instance_set (QOF_INSTANCE (fixture->book),
 		      "trading-accts", "t",
 		      NULL);
@@ -371,6 +372,7 @@ test_book_use_trading_accounts( Fixture *fixture, gconstpointer pData )
 		      "trading-accts", "tt",
 		      NULL);
     g_assert( qof_book_use_trading_accounts( fixture-> book ) == FALSE );
+    qof_book_commit_edit (fixture->book);
 
 }
 
@@ -384,6 +386,7 @@ test_book_get_num_days_autofreeze( Fixture *fixture, gconstpointer pData )
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == FALSE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 0 );
 
+    qof_book_begin_edit (fixture->book);
     qof_instance_set (QOF_INSTANCE (fixture->book),
 		      "autoreadonly-days", (gdouble)17,
 		      NULL);
@@ -404,6 +407,7 @@ test_book_get_num_days_autofreeze( Fixture *fixture, gconstpointer pData )
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == TRUE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 32 );
 
+    qof_book_commit_edit (fixture->book);
 }
 
 static void
@@ -414,6 +418,7 @@ test_book_use_split_action_for_num_field( Fixture *fixture, gconstpointer pData
 
     g_test_message( "Testing with existing use split action for num set to true - t" );
 
+    qof_book_begin_edit (fixture->book);
     qof_instance_set (QOF_INSTANCE (fixture->book),
 		      "split-action-num-field", "t",
 		      NULL);
@@ -424,6 +429,7 @@ test_book_use_split_action_for_num_field( Fixture *fixture, gconstpointer pData
 		      "split-action-num-field", "tt",
 		      NULL);
     g_assert( qof_book_use_split_action_for_num_field( fixture-> book ) == FALSE );
+    qof_book_commit_edit (fixture->book);
 }
 
 static void

commit 291a3abfa339889ca02abb7a0008255d9bc34cbf
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 13:42:20 2013 -0700

    Add a call to $TESTS_ENVIRONMENT in tests:
    
    So that g_tester-based tests can be set up to use Guile.

diff --git a/test-templates/Makefile.decl b/test-templates/Makefile.decl
index dcc69c1..0f163a3 100644
--- a/test-templates/Makefile.decl
+++ b/test-templates/Makefile.decl
@@ -23,7 +23,7 @@ endif
 # test-nonrecursive: run tests only in cwd
 test-nonrecursive: ${TEST_PROGS}
 if !PLATFORM_WIN32
-	@test -z "${TEST_PROGS}" || MALLOC_CHECK_=2 MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) ${GTESTER} --verbose ${TEST_PROGS}
+	@test -z "${TEST_PROGS}" || MALLOC_CHECK_=2 MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) ${TESTS_ENVIRONMENT} ${GTESTER} --verbose ${TEST_PROGS}
 endif
 
 # test-report: run tests in subdirs and generate report

commit 6515a8e858f55583c7213690c49fe984e0cd47e0
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 13:38:55 2013 -0700

    Contain getting slots for gnc_options_db inside QofBook
    
    Turn gnc_option_db_save_to_kvp and …load_from_kvp into callbacks passed to qof_book_(save|load)_options to avoid adding a dependency between qofbook and option-utils.

diff --git a/src/app-utils/business-helpers.c b/src/app-utils/business-helpers.c
index f4c75fa..618e01e 100644
--- a/src/app-utils/business-helpers.c
+++ b/src/app-utils/business-helpers.c
@@ -33,7 +33,7 @@ GncTaxTable* gnc_business_get_default_tax_table (QofBook *book, GncOwnerType own
     GNCOptionDB *odb;
 
     odb = gnc_option_db_new_for_type (GNC_ID_BOOK);
-    gnc_option_db_load_from_kvp (odb, qof_book_get_slots (book));
+    qof_book_load_options (book, gnc_option_db_load_from_kvp, odb);
 
     switch (ownertype)
     {
diff --git a/src/app-utils/option-util.h b/src/app-utils/option-util.h
index 71c9741..f6e29ee 100644
--- a/src/app-utils/option-util.h
+++ b/src/app-utils/option-util.h
@@ -34,7 +34,7 @@
 
 typedef struct gnc_option GNCOption;
 typedef struct gnc_option_section GNCOptionSection;
-typedef struct gnc_option_db GNCOptionDB;
+/* typedef struct gnc_option_db GNCOptionDB is in qof-book.h */
 
 typedef int GNCOptionDBHandle;
 
diff --git a/src/app-utils/test/Makefile.am b/src/app-utils/test/Makefile.am
index a84d703..765aed4 100644
--- a/src/app-utils/test/Makefile.am
+++ b/src/app-utils/test/Makefile.am
@@ -1,3 +1,5 @@
+include $(top_srcdir)/test-templates/Makefile.decl
+
 TESTS = \
   test-link-module \
   test-load-module \
@@ -64,3 +66,17 @@ AM_CPPFLAGS = \
   -I${top_srcdir}/src/libqof/qof \
   ${GUILE_INCS} \
   ${GLIB_CFLAGS}
+
+TEST_PROGS += test-app-utils
+
+noinst_PROGRAMS = ${TEST_PROGS} ${CHECK_PROGS}
+
+test_app_utils_SOURCES = \
+	test-app-utils.c \
+	test-option-util.c
+
+test_app_utils_CFLAGS = \
+	${DEFAULT_INCLUDES} \
+	-I${top_srcdir}/${MODULEPATH}/ \
+	-DTESTPROG=test_app_utils \
+	${GLIB_CFLAGS}
diff --git a/src/app-utils/test/test-app-utils.c b/src/app-utils/test/test-app-utils.c
new file mode 100644
index 0000000..ee0f274
--- /dev/null
+++ b/src/app-utils/test/test-app-utils.c
@@ -0,0 +1,56 @@
+/********************************************************************
+ * test-app-utils.c: GLib g_test test execution file.		    *
+ * Copyright 2013 John Ralls <jralls at ceridwen.us>		    *
+ *                                                                  *
+ * 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 <glib.h>
+#include <qof.h>
+#include <libguile.h>
+#include <gnc-module.h>
+
+extern void test_suite_option_util (void);
+
+static void
+guile_main (void *closure, int argc, char **argv)
+{
+    GNCModule mod;
+    int retval;
+    gnc_module_system_init ();
+    mod = gnc_module_load ("gnucash/app-utils", 0);
+
+    test_suite_option_util ();
+    retval = g_test_run ();
+
+    exit (retval);
+}
+
+int
+main (int argc, char *argv[])
+{
+    qof_init (); 			/* Initialize the GObject system */
+    qof_log_init_filename_special ("stderr"); /* Init the log system */
+    g_test_init (&argc, &argv, NULL); 	/* initialize test program */
+    //qof_log_set_level("gnc", G_LOG_LEVEL_DEBUG);
+    g_test_bug_base("https://bugzilla.gnome.org/show_bug.cgi?id="); /* init the bugzilla URL */
+    g_setenv ("GNC_UNINSTALLED", "1", TRUE);
+    scm_boot_guile (argc, argv, guile_main, NULL);
+
+}
diff --git a/src/app-utils/test/test-option-util.c b/src/app-utils/test/test-option-util.c
new file mode 100644
index 0000000..edf2122
--- /dev/null
+++ b/src/app-utils/test/test-option-util.c
@@ -0,0 +1,123 @@
+/********************************************************************
+ * test-option-util.c: GLib g_test test suite for Split.c.	    *
+ * Copyright 2013 John Ralls <jralls at ceridwen.us>		    *
+ *                                                                  *
+ * 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, you can retrieve it from        *
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html            *
+ * or 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 <glib.h>
+#include <unittest-support.h>
+#include <qofbookslots.h>
+
+#include "../option-util.h"
+
+static const gchar *suitename = "/app-utils/option-util";
+void test_suite_option_util (void);
+
+typedef struct
+{
+    QofBook *book;
+    GSList *hdlrs;
+} Fixture;
+
+/* Expose a mostly-private QofInstance function to load options into
+ * the Book.
+ */
+extern KvpFrame *qof_instance_get_slots (QofInstance*);
+static void
+setup (Fixture *fixture, gconstpointer pData)
+{
+    fixture->book = qof_book_new ();
+    fixture->hdlrs = NULL;
+}
+
+static void
+setup_kvp (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book;
+    KvpFrame *slots;
+    setup (fixture, pData);
+    book = fixture->book;
+    slots = qof_instance_get_slots (QOF_INSTANCE (book));
+    qof_instance_set (QOF_INSTANCE (book),
+		      "trading-accts", "t",
+		      "split-action-num-field", "t",
+		      "autoreadonly-days", (double)21,
+		      NULL);
+
+    kvp_frame_set_string (slots, "options/Business/Company Name",
+			  "Bogus Company");
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer pData)
+{
+    qof_book_destroy (fixture->book);
+    g_slist_free_full (fixture->hdlrs, test_free_log_handler);
+    test_clear_error_list();
+}
+
+static void
+test_option_load_from_kvp (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = fixture->book;
+    GNCOptionDB *odb = gnc_option_db_new_for_type (QOF_ID_BOOK);
+
+    qof_book_load_options (book, gnc_option_db_load_from_kvp, odb);
+    g_assert (gnc_option_db_lookup_boolean_option (odb, OPTION_SECTION_ACCOUNTS,
+ OPTION_NAME_TRADING_ACCOUNTS, FALSE));
+    g_assert_cmpstr (gnc_option_db_lookup_string_option (odb, "Business", "Company Name", FALSE), ==, "Bogus Company");
+    g_assert_cmpfloat (gnc_option_db_lookup_number_option (odb, OPTION_SECTION_ACCOUNTS, OPTION_NAME_AUTO_READONLY_DAYS, FALSE), ==, 21);
+
+    gnc_option_db_destroy (odb);
+}
+
+static void
+test_option_save_to_kvp (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = fixture->book;
+    GNCOptionDB *odb = gnc_option_db_new_for_type (QOF_ID_BOOK);
+    KvpFrame *slots = qof_instance_get_slots (QOF_INSTANCE (book));
+
+    g_assert (gnc_option_db_set_boolean_option (odb, OPTION_SECTION_ACCOUNTS,
+						OPTION_NAME_TRADING_ACCOUNTS,
+						TRUE));
+    g_assert (gnc_option_db_set_string_option (odb, "Business", "Company Name",
+					       "Bogus Company"));
+    g_assert (gnc_option_db_set_number_option (odb, OPTION_SECTION_ACCOUNTS,
+					       OPTION_NAME_AUTO_READONLY_DAYS,
+					       17));
+    qof_book_save_options (book, gnc_option_db_save_to_kvp, odb, TRUE);
+    g_assert_cmpstr (kvp_frame_get_string (slots,  "options/Accounts/Use Trading Accounts"), == , "t");
+    g_assert_cmpstr (kvp_frame_get_string (slots, "options/Business/Company Name"), ==, "Bogus Company");
+    g_assert_cmpfloat (kvp_frame_get_double (slots, "options/Accounts/Day Threshold for Read-Only Transactions (red line)"), ==, 17);
+
+    gnc_option_db_destroy (odb);
+}
+
+
+void
+test_suite_option_util (void)
+{
+    GNC_TEST_ADD (suitename, "Option DB Load from KVP", Fixture, NULL, setup_kvp, test_option_load_from_kvp, teardown);
+    GNC_TEST_ADD (suitename, "Option DB Save to KVP", Fixture, NULL, setup, test_option_save_to_kvp, teardown);
+
+}
diff --git a/src/backend/xml/gnc-book-xml-v2.c b/src/backend/xml/gnc-book-xml-v2.c
index aa7a14f..6fcae46 100644
--- a/src/backend/xml/gnc-book-xml-v2.c
+++ b/src/backend/xml/gnc-book-xml-v2.c
@@ -109,10 +109,10 @@ gnc_book_dom_tree_create(QofBook *book)
     xmlAddChild(ret, guid_to_dom_tree(book_id_string,
                                       qof_book_get_guid(book)));
 
-    if (qof_book_get_slots(book))
+    if (qof_instance_get_slots (QOF_INSTANCE (book)))
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(book_slots_string,
-                             qof_book_get_slots(book));
+                             qof_instance_get_slots (QOF_INSTANCE (book)));
         if (kvpnode)
             xmlAddChild(ret, kvpnode);
     }
@@ -162,10 +162,10 @@ write_book_parts(FILE *out, QofBook *book)
     if (ferror(out) || fprintf(out, "\n") < 0)
         return FALSE;
 
-    if (qof_book_get_slots(book))
+    if (qof_instance_get_slots (QOF_INSTANCE (book)))
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(book_slots_string,
-                             qof_book_get_slots(book));
+                             qof_instance_get_slots (QOF_INSTANCE (book)));
         if (kvpnode)
         {
             xmlElemDump(out, NULL, kvpnode);
@@ -203,7 +203,7 @@ book_slots_handler (xmlNodePtr node, gpointer book_pdata)
 
     /* the below works only because the get is gaurenteed to return
      * a frame, even if its empty */
-    success = dom_tree_to_kvp_frame_given (node, qof_book_get_slots (book));
+    success = dom_tree_to_kvp_frame_given (node, qof_instance_get_slots (QOF_INSTANCE (book)));
 
     g_return_val_if_fail(success, FALSE);
 
diff --git a/src/gnome-utils/gnc-main-window.c b/src/gnome-utils/gnc-main-window.c
index f2d344e..e0a192c 100644
--- a/src/gnome-utils/gnc-main-window.c
+++ b/src/gnome-utils/gnc-main-window.c
@@ -3936,20 +3936,21 @@ gnc_book_options_dialog_apply_cb(GNCOptionWin * optionwin,
                                  gpointer user_data)
 {
     GNCOptionDB * options = user_data;
-    kvp_frame *slots = qof_book_get_slots (gnc_get_current_book ());
     gboolean use_split_action_for_num_before =
         qof_book_use_split_action_for_num_field (gnc_get_current_book ());
     gboolean use_split_action_for_num_after;
+    QofBook *book = gnc_get_current_book ();
 
     if (!options) return;
 
     gnc_option_db_commit (options);
-    gnc_option_db_save_to_kvp (options, slots, TRUE);
-    qof_book_kvp_changed (gnc_get_current_book());
+    qof_book_begin_edit (book);
+    qof_book_save_options (book, gnc_option_db_save_to_kvp, options, TRUE);
     use_split_action_for_num_after =
         qof_book_use_split_action_for_num_field (gnc_get_current_book ());
     if (use_split_action_for_num_before != use_split_action_for_num_after)
         gnc_book_option_num_field_source_change_cb (use_split_action_for_num_after);
+    qof_book_commit_edit (book);
 }
 
 static void
@@ -3965,12 +3966,12 @@ gnc_book_options_dialog_close_cb(GNCOptionWin * optionwin,
 GtkWidget *
 gnc_book_options_dialog_cb (gboolean modal, gchar *title)
 {
-    kvp_frame *slots = qof_book_get_slots (gnc_get_current_book ());
+    QofBook *book = gnc_get_current_book ();
     GNCOptionDB *options;
     GNCOptionWin *optionwin;
 
     options = gnc_option_db_new_for_type (QOF_ID_BOOK);
-    gnc_option_db_load_from_kvp (options, slots);
+    qof_book_load_options (book, gnc_option_db_load_from_kvp, options);
     gnc_option_db_clean (options);
 
     optionwin = gnc_options_dialog_new_modal (modal,
diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index a75e1c3..1783856 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -932,6 +932,22 @@ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
     qof_book_commit_edit (book);
 }
 
+void
+qof_book_load_options (QofBook *book, GNCOptionLoad load_cb, GNCOptionDB *odb)
+{
+    KvpFrame *slots = qof_instance_get_slots (QOF_INSTANCE (book));
+    load_cb (odb, slots);
+}
+
+void
+qof_book_save_options (QofBook *book, GNCOptionSave save_cb,
+		       GNCOptionDB* odb, gboolean clear)
+{
+    KvpFrame *slots = qof_instance_get_slots (QOF_INSTANCE (book));
+    save_cb (odb, slots, clear);
+    qof_instance_set_dirty (QOF_INSTANCE (book));
+}
+
 static void noop (QofInstance *inst) {}
 
 void
diff --git a/src/libqof/qof/qofbook.h b/src/libqof/qof/qofbook.h
index 6774ab6..6e44a69 100644
--- a/src/libqof/qof/qofbook.h
+++ b/src/libqof/qof/qofbook.h
@@ -64,6 +64,11 @@ typedef struct _QofBookClass  QofBookClass;
 
 typedef void (*QofBookDirtyCB) (QofBook *, gboolean dirty, gpointer user_data);
 
+typedef struct gnc_option_db GNCOptionDB;
+
+typedef void (*GNCOptionSave) (GNCOptionDB*, KvpFrame*, gboolean);
+typedef void (*GNCOptionLoad) (GNCOptionDB*, KvpFrame*);
+
 /* Book structure */
 struct _QofBook
 {
@@ -328,6 +333,14 @@ void qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr);
 void qof_book_begin_edit(QofBook *book);
 void qof_book_commit_edit(QofBook *book);
 
+/* Access functions for loading and saving the file options */
+void qof_book_load_options (QofBook *book, GNCOptionLoad load_cb,
+			    GNCOptionDB *odb);
+void
+qof_book_save_options (QofBook *book, GNCOptionSave save_cb,
+		       GNCOptionDB* odb, gboolean clear);
+
+
 /** deprecated */
 #define qof_book_get_guid(X) qof_entity_get_guid (QOF_INSTANCE(X))
 

commit 38b3961bb8a17fda132dfc82c8b0e798f1ada76d
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 13:31:47 2013 -0700

    replace qof_book_kvp_changed with qof_instance_set_dirty

diff --git a/src/backend/xml/io-gncxml-v2.c b/src/backend/xml/io-gncxml-v2.c
index cc02d95..bfd8ed9 100644
--- a/src/backend/xml/io-gncxml-v2.c
+++ b/src/backend/xml/io-gncxml-v2.c
@@ -2111,7 +2111,7 @@ gnc_xml2_parse_with_subst (FileBackend *fbe, QofBook *book, GHashTable *subst)
                   push_data, GNC_BOOK_XML2_FILE);
 
     if (success)
-        qof_book_kvp_changed(book);
+	qof_instance_set_dirty (QOF_INSTANCE (book));
 
     return success;
 }

commit 7faed6540162ccd1fe34ad9ea425164c3a61cdd6
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat Oct 26 15:00:53 2013 -0700

    Remove QofBook KVP access for several options
    
    Replace them with GObject Properties. Note that the setters for these properties are handled in Scheme and still use the raw KVP access.

diff --git a/src/app-utils/gnc-accounting-period.c b/src/app-utils/gnc-accounting-period.c
index 3c17ac9..254f611 100644
--- a/src/app-utils/gnc-accounting-period.c
+++ b/src/app-utils/gnc-accounting-period.c
@@ -102,15 +102,13 @@ get_fy_end(void)
 {
     QofBook *book;
     KvpFrame *book_frame;
-    gint64 month, day;
+    GDate *date;
 
     book = gnc_get_current_book();
-    book_frame = qof_book_get_slots(book);
-    month = kvp_frame_get_gint64(book_frame, "/book/fyear_end/month");
-    day = kvp_frame_get_gint64(book_frame, "/book/fyear_end/day");
-    if (g_date_valid_dmy(day, month, 2005 /* not leap year */))
-        return g_date_new_dmy(day, month, G_DATE_BAD_YEAR);
-    return NULL;
+    qof_instance_get (QOF_INSTANCE (book),
+		      "fy-end", &date,
+		      NULL);
+    return date;
 }
 
 time64
diff --git a/src/engine/engine.i b/src/engine/engine.i
index 0bb93ab..0617c2e 100644
--- a/src/engine/engine.i
+++ b/src/engine/engine.i
@@ -136,10 +136,18 @@ functions. */
 
 QofSession * qof_session_new (void);
 QofBook * qof_session_get_book (QofSession *session);
-
-// TODO: Maybe unroll
-void qof_book_kvp_changed (QofBook *book);
-
+/* This horror is to permit the scheme options in
+ * src/app-utils/options.scm to read and write the book's KVP (another
+ * horror) directly. It should be refactored into book functions that
+ * handle the KVP access.
+ */
+%inline {
+  KvpFrame *qof_book_get_slots (QofBook *book);
+  extern KvpFrame *qof_instance_get_slots (QofInstance*);
+  KvpFrame *qof_book_get_slots (QofBook *book) {
+       return qof_instance_get_slots (QOF_INSTANCE (book));
+  }
+}
 // TODO: Unroll/remove
 const char *qof_session_get_url (QofSession *session);
 
@@ -169,7 +177,6 @@ SplitList * qof_query_run_subquery (QofQuery *q, const QofQuery *q);
 %include <qofbookslots.h>
 %include <qofbook.h>
 
-KvpFrame* qof_book_get_slots(QofBook* book);
 %ignore GNC_DENOM_AUTO;
 %ignore GNCNumericErrorCodes;
 %ignore GNC_ERROR_OK;
diff --git a/src/engine/gnc-budget.c b/src/engine/gnc-budget.c
index 47cbeab..e8eb03d 100644
--- a/src/engine/gnc-budget.c
+++ b/src/engine/gnc-budget.c
@@ -627,31 +627,23 @@ gnc_budget_get_default (QofBook *book)
 {
     QofCollection *col;
     GncBudget *bgt = NULL;
-    kvp_value *kvp_default_budget;
     const GncGUID *default_budget_guid;
 
     g_return_val_if_fail(book, NULL);
 
     /* See if there is a budget selected in the KVP perferences */
 
-    kvp_default_budget = kvp_frame_get_slot_path(qof_book_get_slots (book),
-                         KVP_OPTION_PATH,
-                         OPTION_SECTION_BUDGETING,
-                         OPTION_NAME_DEFAULT_BUDGET,
-                         NULL);
-
-    if (kvp_default_budget != NULL )
+    qof_instance_get (QOF_INSTANCE (book),
+		      "default-budget", &default_budget_guid,
+		      NULL);
+    if (default_budget_guid != NULL)
     {
-        default_budget_guid = kvp_value_get_guid(kvp_default_budget);
-        if (default_budget_guid != NULL)
-        {
-            col = qof_book_get_collection(book, GNC_ID_BUDGET);
-            bgt = (GncBudget *) qof_collection_lookup_entity(col,
-                    default_budget_guid);
-        }
+	col = qof_book_get_collection(book, GNC_ID_BUDGET);
+	bgt = (GncBudget *) qof_collection_lookup_entity(col,
+							 default_budget_guid);
     }
 
-    /* Revert to 2.2.x behavior if there is no defined budget in KVP */
+    /* Revert to 2.2.x behavior if the book has no default budget. */
 
     if ( bgt == NULL )
     {
diff --git a/src/engine/test/utest-Split.c b/src/engine/test/utest-Split.c
index 6b4bb98..0f016a1 100644
--- a/src/engine/test/utest-Split.c
+++ b/src/engine/test/utest-Split.c
@@ -33,7 +33,6 @@
 #include <TransactionP.h>
 #include <gnc-lot.h>
 #include <gnc-event.h>
-#include <qofbookslots.h>
 #include <qofinstance-p.h>
 
 #ifdef HAVE_GLIB_2_38
@@ -1096,8 +1095,9 @@ test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
 {
     const char *slot_path;
     Split *split = fixture->split;
-    Split *o_split = xaccMallocSplit (xaccSplitGetBook (split));
-    Transaction *o_txn = xaccMallocTransaction (xaccSplitGetBook (split));
+    QofBook *book = xaccSplitGetBook (split);
+    Split *o_split = xaccMallocSplit (book);
+    Transaction *o_txn = xaccMallocTransaction (book);
     Transaction *txn = split->parent;
 
     g_assert_cmpint (xaccSplitOrder (split, split), ==, 0);
@@ -1136,11 +1136,10 @@ test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
      */
 
     /* create correct slot path */
-    slot_path = (const char *) g_strconcat( KVP_OPTION_PATH, "/",
-                                            OPTION_SECTION_ACCOUNTS, "/", OPTION_NAME_NUM_FIELD_SOURCE, NULL );
-    g_assert( slot_path != NULL );
     g_test_message( "Testing with use-split-action-for-num set to true - t" );
-    qof_book_set_string_option( xaccSplitGetBook (split), slot_path, "t" );
+    qof_instance_set (QOF_INSTANCE (book),
+		      "split-action-num-field", "t",
+		      NULL);
     g_assert(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == TRUE);
 
     g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);
@@ -1152,7 +1151,9 @@ test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
     o_split->action = NULL;
     split->action = "foo";
     o_split->parent = NULL;
-    qof_book_set_string_option( xaccSplitGetBook (split), slot_path, "f" );
+    qof_instance_set (QOF_INSTANCE (book),
+		      "split-action-num-field", "f",
+		      NULL);
     g_assert(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == FALSE);
     split->parent = NULL;
     /* This should return > 0 because o_split has no memo string */
@@ -1753,7 +1754,6 @@ test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
     Split *split2 = xaccMallocSplit (book);
     Account *acc2 = xaccMallocAccount (book);
     KvpValue *kvptrue = kvp_value_new_string ("t");
-    KvpFrame *book_slots = qof_book_get_slots (book);
 
     g_assert (xaccSplitGetOtherSplit (NULL) == NULL);
     g_assert (xaccSplitGetOtherSplit (split1) == NULL);
@@ -1782,9 +1782,9 @@ test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
     g_assert (kvp_frame_get_slot (split->inst.kvp_data, "lot-split") == NULL);
     kvp_frame_set_slot (split1->inst.kvp_data, "lot-split", NULL);
     g_assert (kvp_frame_get_slot (split1->inst.kvp_data, "lot-split") == NULL);
-    kvp_frame_set_slot_path (book_slots, kvptrue, KVP_OPTION_PATH,
-                             OPTION_SECTION_ACCOUNTS,
-                             OPTION_NAME_TRADING_ACCOUNTS, NULL);
+    qof_instance_set (QOF_INSTANCE (book),
+		      "trading-accts", "t",
+		      NULL);
     g_assert (xaccTransUseTradingAccounts (txn));
     g_assert (xaccSplitGetOtherSplit (split) == NULL);
     split2->acc = acc2;
diff --git a/src/engine/test/utest-Transaction.c b/src/engine/test/utest-Transaction.c
index b5c24b9..6571f0f 100644
--- a/src/engine/test/utest-Transaction.c
+++ b/src/engine/test/utest-Transaction.c
@@ -1,5 +1,5 @@
 /********************************************************************
- * utest-Transaction.c: GLib g_test test suite for Transaction.c.		    *
+ * utest-Transaction.c: GLib g_test test suite for Transaction.c.   *
  * Copyright 2012 John Ralls <jralls at ceridwen.us>		    *
  *                                                                  *
  * This program is free software; you can redistribute it and/or    *
@@ -33,7 +33,6 @@
 #include "../gnc-lot.h"
 #include "../gnc-event.h"
 #include <qof.h>
-#include <qofbookslots.h>
 #include <qofbackend-p.h>
 
 #ifdef HAVE_GLIB_2_38
@@ -1048,14 +1047,13 @@ test_xaccTransGetImbalance_trading (Fixture *fixture,
     Account *acc1 = xaccMallocAccount (book);
     Account *acc2 = xaccMallocAccount (book);
     gnc_numeric value;
-    gchar *trading_account_path = g_strdup_printf("%s/%s/%s", KVP_OPTION_PATH,
-                                  OPTION_SECTION_ACCOUNTS,
-                                  OPTION_NAME_TRADING_ACCOUNTS);
     MonetaryList *mlist;
 
-    qof_book_set_string_option( book, trading_account_path, "t" );
-    g_free (trading_account_path);
-    /* Without trading splits, the list is unbalanced */
+    qof_instance_set (QOF_INSTANCE (book),
+		      "trading-accts", "t",
+		      NULL);
+
+ /* Without trading splits, the list is unbalanced */
     mlist = xaccTransGetImbalance (fixture->txn);
     g_assert_cmpint (g_list_length (mlist), ==, 2);
     gnc_monetary_list_free (mlist);
@@ -1135,12 +1133,10 @@ test_xaccTransIsBalanced_trading (Fixture *fixture, gconstpointer pData)
     Split *split2 = xaccMallocSplit (book);
     Account *acc1 = xaccMallocAccount (book);
     Account *acc2 = xaccMallocAccount (book);
-    gchar *trading_account_path = g_strdup_printf("%s/%s/%s", KVP_OPTION_PATH,
-                                  OPTION_SECTION_ACCOUNTS,
-                                  OPTION_NAME_TRADING_ACCOUNTS);
 
-    qof_book_set_string_option( book, trading_account_path, "t" );
-    g_free (trading_account_path);
+    qof_instance_set (QOF_INSTANCE (book),
+		      "trading-accts", "t",
+		      NULL);
     xaccAccountSetCommodity (acc1, fixture->curr);
     xaccAccountSetCommodity (acc2, fixture->comm);
     xaccAccountSetType (acc1, ACCT_TYPE_TRADING);
diff --git a/src/gnome-utils/dialog-preferences.c b/src/gnome-utils/dialog-preferences.c
index 53f2e94..be7499b 100644
--- a/src/gnome-utils/dialog-preferences.c
+++ b/src/gnome-utils/dialog-preferences.c
@@ -1120,16 +1120,9 @@ gnc_preferences_dialog_create(void)
 
 
     book = gnc_get_current_book();
-    book_frame = qof_book_get_slots(book);
-    month = kvp_frame_get_gint64(book_frame, "/book/fyear_end/month");
-    day = kvp_frame_get_gint64(book_frame, "/book/fyear_end/day");
-    date_is_valid = g_date_valid_dmy(day, month, 2005 /* not leap year */);
-    if (date_is_valid)
-    {
-        g_date_clear(&fy_end, 1);
-        g_date_set_dmy(&fy_end, day, month, G_DATE_BAD_YEAR);
-    }
-
+    qof_instance_get (QOF_INSTANCE (book),
+		      "fy-end", &fy_end,
+		      NULL);
     box = GTK_WIDGET(gtk_builder_get_object (builder,
                      "pref/" GNC_PREFS_GROUP_ACCT_SUMMARY "/" GNC_PREF_START_PERIOD));
     period = gnc_period_select_new(TRUE);
diff --git a/src/import-export/aqbanking/gnc-ab-kvp.c b/src/import-export/aqbanking/gnc-ab-kvp.c
index db7c0f5..1b1bc5c 100644
--- a/src/import-export/aqbanking/gnc-ab-kvp.c
+++ b/src/import-export/aqbanking/gnc-ab-kvp.c
@@ -32,9 +32,6 @@
 
 #include "gnc-ab-kvp.h"
 
-#define AB_KEY "hbci"
-#define AB_TEMPLATES "template-list"
-
 /* This static indicates the debugging module that this .o belongs to.  */
 G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
 
@@ -123,29 +120,17 @@ gnc_ab_set_account_trans_retrieval(Account *a, Timespec time)
 GList *
 gnc_ab_get_book_template_list(QofBook *b)
 {
-    kvp_frame *frame = gnc_ab_get_book_kvp(b, FALSE);
-    kvp_value *value = kvp_frame_get_slot(frame, AB_TEMPLATES);
-    return kvp_value_get_glist(value);
+    GList *template_list;
+    qof_instance_get (QOF_INSTANCE (b),
+		      "ab-templates", &template_list,
+		      NULL);
+    return template_list;
 }
 
 void
 gnc_ab_set_book_template_list(QofBook *b, GList *template_list)
 {
-    kvp_frame *frame = gnc_ab_get_book_kvp(b, TRUE);
-    kvp_value *value = kvp_value_new_glist_nc(template_list);
-    kvp_frame_set_slot_nc(frame, AB_TEMPLATES, value);
-    qof_book_kvp_changed (b);
-}
-
-static kvp_frame *
-gnc_ab_get_book_kvp(QofBook *b, gboolean create)
-{
-    kvp_frame *toplevel = qof_book_get_slots(b);
-    kvp_frame *result = kvp_frame_get_frame(toplevel, AB_KEY);
-    if (!result && create)
-    {
-        result = kvp_frame_new();
-        kvp_frame_add_frame_nc(toplevel, AB_KEY, result);
-    }
-    return result;
+    qof_instance_set (QOF_INSTANCE (b),
+		      "ab-templates", &template_list,
+		      NULL);
 }
diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index 58777c0..a75e1c3 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -49,8 +49,26 @@
 #include "qofbookslots.h"
 
 static QofLogModule log_module = QOF_MOD_ENGINE;
+#define AB_KEY "hbci"
+#define AB_TEMPLATES "template-list"
+
+enum
+{
+    PROP_0,
+    PROP_OPT_TRADING_ACCOUNTS,
+    PROP_OPT_AUTO_READONLY_DAYS,
+    PROP_OPT_NUM_FIELD_SOURCE,
+    PROP_OPT_DEFAULT_BUDGET,
+    PROP_OPT_FY_END,
+    PROP_AB_TEMPLATES,
+    N_PROPERTIES
+};
+
+QOF_GOBJECT_GET_TYPE(QofBook, qof_book, QOF_TYPE_INSTANCE, {});
+QOF_GOBJECT_DISPOSE(qof_book);
+QOF_GOBJECT_FINALIZE(qof_book);
 
-QOF_GOBJECT_IMPL(qof_book, QofBook, QOF_TYPE_INSTANCE);
+static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
 /* ====================================================================== */
 /* constructor / destructor */
@@ -81,6 +99,184 @@ qof_book_init (QofBook *book)
     book->version = 0;
 }
 
+static void
+qof_book_get_property (GObject* object,
+		       guint prop_id,
+		       GValue* value,
+		       GParamSpec* pspec)
+{
+    QofBook *book;
+    gchar *key;
+
+    g_return_if_fail (QOF_IS_BOOK (object));
+    book = QOF_BOOK (object);
+    switch (prop_id)
+    {
+    case PROP_OPT_TRADING_ACCOUNTS:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_TRADING_ACCOUNTS);
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_AUTO_READONLY_DAYS:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_AUTO_READONLY_DAYS);
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_NUM_FIELD_SOURCE:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_NUM_FIELD_SOURCE);
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_DEFAULT_BUDGET:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_DEFAULT_BUDGET);
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+    case PROP_OPT_FY_END:
+	key = "fy_end";
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	break;
+    case PROP_AB_TEMPLATES:
+	key = AB_KEY "/" AB_TEMPLATES;
+	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
+	break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+qof_book_set_property (GObject      *object,
+		       guint         prop_id,
+		       const GValue *value,
+		       GParamSpec   *pspec)
+{
+    QofBook *book;
+    gchar *key;
+
+    g_return_if_fail (QOF_IS_BOOK (object));
+    book = QOF_BOOK (object);
+    switch (prop_id)
+    {
+    case PROP_OPT_TRADING_ACCOUNTS:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_TRADING_ACCOUNTS);
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_AUTO_READONLY_DAYS:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_AUTO_READONLY_DAYS);
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_NUM_FIELD_SOURCE:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_NUM_FIELD_SOURCE);
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_DEFAULT_BUDGET:
+	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
+			       OPTION_SECTION_ACCOUNTS,
+			       OPTION_NAME_DEFAULT_BUDGET);
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	g_free (key);
+	break;
+    case PROP_OPT_FY_END:
+	key = "fy_end";
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	break;
+    case PROP_AB_TEMPLATES:
+	key = AB_KEY "/" AB_TEMPLATES;
+	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
+	break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+qof_book_class_init (QofBookClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    gobject_class->dispose = qof_book_dispose;
+    gobject_class->finalize = qof_book_finalize;
+    gobject_class->get_property = qof_book_get_property;
+    gobject_class->set_property = qof_book_set_property;
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_OPT_TRADING_ACCOUNTS,
+     g_param_spec_string("trading-accts",
+                         "Use Trading Accounts",
+			 "Scheme true ('t') or NULL. If 't', then the book "
+			 "uses trading accounts for managing multiple-currency "
+			 "transactions.",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_OPT_NUM_FIELD_SOURCE,
+     g_param_spec_string("split-action-num-field",
+                         "Use Split-Action in the Num Field",
+			 "Scheme true ('t') or NULL. If 't', then the book "
+			 "will put the split action value in the Num field.",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_OPT_AUTO_READONLY_DAYS,
+     g_param_spec_double("autoreadonly-days",
+                         "Transaction Auto-read-only Days",
+			 "Prevent editing of transactions posted more than "
+			 "this many days ago.",
+			 0,
+                         G_MAXDOUBLE,
+			 0,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_OPT_DEFAULT_BUDGET,
+     g_param_spec_boxed("default-budget",
+                        "Book Default Budget",
+                        "The default Budget for this book.",
+                        GNC_TYPE_GUID,
+                        G_PARAM_READWRITE));
+    g_object_class_install_property
+    (gobject_class,
+     PROP_OPT_FY_END,
+     g_param_spec_boxed("fy-end",
+                        "Book Fiscal Year End",
+                        "A GDate with a bogus year having the last Month and "
+			"Day of the Fiscal year for the book.",
+                        G_TYPE_DATE,
+                        G_PARAM_READWRITE));
+    g_object_class_install_property
+    (gobject_class,
+     PROP_AB_TEMPLATES,
+     g_param_spec_boxed("ab-templates",
+                        "AQBanking Template List",
+                        "A GList of AQBanking Templates",
+                        GNC_TYPE_VALUE_LIST,
+                        G_PARAM_READWRITE));
+}
+
 QofBook *
 qof_book_new (void)
 {
@@ -152,6 +348,7 @@ qof_book_destroy (QofBook *book)
 
     LEAVE ("book=%p", book);
 }
+
 /* ====================================================================== */
 
 gboolean
@@ -619,19 +816,9 @@ gboolean
 qof_book_use_trading_accounts (const QofBook *book)
 {
     const char *opt;
-    kvp_value *kvp_val;
-    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
-
-    kvp_val = kvp_frame_get_slot_path (frame,
-                                       KVP_OPTION_PATH,
-                                       OPTION_SECTION_ACCOUNTS,
-                                       OPTION_NAME_TRADING_ACCOUNTS,
-                                       NULL);
-    if (kvp_val == NULL)
-        return FALSE;
-
-    opt = kvp_value_get_string (kvp_val);
-
+    qof_instance_get (QOF_INSTANCE (book),
+		      "trading-accts", &opt,
+		      NULL);
     if (opt && opt[0] == 't' && opt[1] == 0)
         return TRUE;
     return FALSE;
@@ -643,19 +830,9 @@ gboolean
 qof_book_use_split_action_for_num_field (const QofBook *book)
 {
     const char *opt;
-    kvp_value *kvp_val;
-    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
-
-    g_assert(book);
-    kvp_val = kvp_frame_get_slot_path (frame,
-                                       KVP_OPTION_PATH,
-                                       OPTION_SECTION_ACCOUNTS,
-                                       OPTION_NAME_NUM_FIELD_SOURCE,
-                                       NULL);
-    if (kvp_val == NULL)
-        return FALSE;
-
-    opt = kvp_value_get_string (kvp_val);
+    qof_instance_get (QOF_INSTANCE (book),
+		      "split-action-num-field", &opt,
+		      NULL);
 
     if (opt && opt[0] == 't' && opt[1] == 0)
         return TRUE;
@@ -675,19 +852,9 @@ gint qof_book_get_num_days_autoreadonly (const QofBook *book)
     KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
 
     g_assert(book);
-    kvp_val = kvp_frame_get_slot_path (frame,
-                                       KVP_OPTION_PATH,
-                                       OPTION_SECTION_ACCOUNTS,
-                                       OPTION_NAME_AUTO_READONLY_DAYS,
-                                       NULL);
-
-    if (kvp_val == NULL)
-    {
-        //PWARN("kvp_val for slot '%s' is NULL", OPTION_NAME_AUTO_READONLY_DAYS);
-        return 0;
-    }
-
-    tmp = kvp_value_get_double (kvp_val);
+    qof_instance_get (QOF_INSTANCE (book),
+		      "autoreadonly-days", &tmp,
+		      NULL);
     return (gint) tmp;
 }
 
diff --git a/src/libqof/qof/test/test-qofbook.c b/src/libqof/qof/test/test-qofbook.c
index 87f8ce0..6c56858 100644
--- a/src/libqof/qof/test/test-qofbook.c
+++ b/src/libqof/qof/test/test-qofbook.c
@@ -356,36 +356,20 @@ test_book_increment_and_format_counter ( Fixture *fixture, gconstpointer pData )
 }
 
 static void
-test_book_kvp_changed( Fixture *fixture, gconstpointer pData )
-{
-    g_test_message( "Testing book is marked dirty after kvp_changed" );
-    g_assert( !qof_instance_is_dirty (QOF_INSTANCE (fixture->book)) );
-    qof_book_kvp_changed( fixture->book );
-    g_assert( qof_instance_is_dirty (QOF_INSTANCE (fixture->book)) );
-}
-
-static void
 test_book_use_trading_accounts( Fixture *fixture, gconstpointer pData )
 {
-    const char *slot_path;
-
-    /* create correct slot path */
-    slot_path = (const char *) g_strconcat( KVP_OPTION_PATH, "/", OPTION_SECTION_ACCOUNTS, "/", OPTION_NAME_TRADING_ACCOUNTS, NULL );
-    g_assert( slot_path != NULL );
-
-    g_test_message( "Testing when no trading accounts are used" );
-    g_assert( qof_book_use_trading_accounts( fixture-> book ) == FALSE );
-
-    g_test_message( "Testing with incorrect slot path and correct value - t" );
-    qof_book_set_string_option( fixture->book, OPTION_NAME_TRADING_ACCOUNTS, "t" );
     g_assert( qof_book_use_trading_accounts( fixture-> book ) == FALSE );
 
     g_test_message( "Testing with existing trading accounts set to true - t" );
-    qof_book_set_string_option( fixture->book, slot_path, "t" );
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "trading-accts", "t",
+		      NULL);
     g_assert( qof_book_use_trading_accounts( fixture-> book ) == TRUE );
 
     g_test_message( "Testing with existing trading accounts and incorrect value - tt" );
-    qof_book_set_string_option( fixture->book, slot_path, "tt" );
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "trading-accts", "tt",
+		      NULL);
     g_assert( qof_book_use_trading_accounts( fixture-> book ) == FALSE );
 
 }
@@ -393,33 +377,30 @@ test_book_use_trading_accounts( Fixture *fixture, gconstpointer pData )
 static void
 test_book_get_num_days_autofreeze( Fixture *fixture, gconstpointer pData )
 {
-    const char *slot_path;
-
-    /* create correct slot path */
-    slot_path = (const char *) g_strconcat( KVP_OPTION_PATH, "/", OPTION_SECTION_ACCOUNTS, "/", OPTION_NAME_AUTO_READONLY_DAYS, NULL );
-    g_assert( slot_path != NULL );
-
     g_test_message( "Testing default: No auto-freeze days are set" );
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == FALSE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 0 );
 
-    g_test_message( "Testing with incorrect slot path and some correct value - 17" );
-    kvp_frame_set_double(qof_book_get_slots(fixture->book), OPTION_NAME_AUTO_READONLY_DAYS, 17);
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == FALSE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 0 );
 
-    g_test_message( "Testing when setting this correctly with some correct value - 17" );
-    kvp_frame_set_double(qof_book_get_slots(fixture->book), slot_path, 17);
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "autoreadonly-days", (gdouble)17,
+		      NULL);
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == TRUE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 17 );
 
     g_test_message( "Testing when setting this correctly to zero again" );
-    kvp_frame_set_double(qof_book_get_slots(fixture->book), slot_path, 0);
+
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "autoreadonly-days", (gdouble)0,
+		      NULL);
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == FALSE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 0 );
 
-    g_test_message( "Testing when setting this correctly with some correct value - 32" );
-    kvp_frame_set_double(qof_book_get_slots(fixture->book), slot_path, 32);
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "autoreadonly-days", (gdouble)32,
+		      NULL);
     g_assert( qof_book_uses_autoreadonly( fixture-> book ) == TRUE );
     g_assert( qof_book_get_num_days_autoreadonly( fixture-> book ) == 32 );
 
@@ -428,26 +409,20 @@ test_book_get_num_days_autofreeze( Fixture *fixture, gconstpointer pData )
 static void
 test_book_use_split_action_for_num_field( Fixture *fixture, gconstpointer pData )
 {
-    const char *slot_path;
-
-    /* create correct slot path */
-    slot_path = (const char *) g_strconcat( KVP_OPTION_PATH, "/",
-                                            OPTION_SECTION_ACCOUNTS, "/", OPTION_NAME_NUM_FIELD_SOURCE, NULL );
-    g_assert( slot_path != NULL );
-
     g_test_message( "Testing default: No selection has been specified" );
     g_assert( qof_book_use_split_action_for_num_field( fixture-> book ) == FALSE );
 
-    g_test_message( "Testing with incorrect slot path and correct value - t" );
-    qof_book_set_string_option( fixture->book, OPTION_NAME_NUM_FIELD_SOURCE, "t" );
-    g_assert( qof_book_use_split_action_for_num_field( fixture-> book ) == FALSE );
-
     g_test_message( "Testing with existing use split action for num set to true - t" );
-    qof_book_set_string_option( fixture->book, slot_path, "t" );
+
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "split-action-num-field", "t",
+		      NULL);
     g_assert( qof_book_use_split_action_for_num_field( fixture-> book ) == TRUE );
 
     g_test_message( "Testing with existing use split action for num and incorrect value - tt" );
-    qof_book_set_string_option( fixture->book, slot_path, "tt" );
+    qof_instance_set (QOF_INSTANCE (fixture->book),
+		      "split-action-num-field", "tt",
+		      NULL);
     g_assert( qof_book_use_split_action_for_num_field( fixture-> book ) == FALSE );
 }
 
@@ -765,7 +740,6 @@ test_suite_qofbook ( void )
     GNC_TEST_ADD( suitename, "get counter", Fixture, NULL, setup, test_book_get_counter, teardown );
     GNC_TEST_ADD( suitename, "get counter format", Fixture, NULL, setup, test_book_get_counter_format, teardown );
     GNC_TEST_ADD( suitename, "increment and format counter", Fixture, NULL, setup, test_book_increment_and_format_counter, teardown );
-    GNC_TEST_ADD( suitename, "kvp changed", Fixture, NULL, setup, test_book_kvp_changed, teardown );
     GNC_TEST_ADD( suitename, "use trading accounts", Fixture, NULL, setup, test_book_use_trading_accounts, teardown );
     GNC_TEST_ADD( suitename, "get autofreeze days", Fixture, NULL, setup, test_book_get_num_days_autofreeze, teardown );
     GNC_TEST_ADD( suitename, "use split action for num field", Fixture, NULL, setup, test_book_use_split_action_for_num_field, teardown );

commit 36eba1ac42114636ba813d3de9e8de139829e52f
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 15:29:53 2013 -0700

    Replace business kvp access with properties.

diff --git a/src/business/business-gnome/dialog-invoice.c b/src/business/business-gnome/dialog-invoice.c
index 59705a4..f2bceae 100644
--- a/src/business/business-gnome/dialog-invoice.c
+++ b/src/business/business-gnome/dialog-invoice.c
@@ -90,8 +90,6 @@
 #define GNC_PREF_ACCUM_SPLITS    "accumulate-splits"
 #define GNC_PREF_DAYS_IN_ADVANCE "days-in-advance"
 
-#define LAST_POSTED_TO_ACCT "last-posted-to-acct"
-
 void gnc_invoice_window_ok_cb (GtkWidget *widget, gpointer data);
 void gnc_invoice_window_cancel_cb (GtkWidget *widget, gpointer data);
 void gnc_invoice_window_help_cb (GtkWidget *widget, gpointer data);
@@ -677,7 +675,6 @@ gnc_dialog_post_invoice(InvoiceWindow *iw, char *message,
     GList * acct_types = NULL;
     GList * acct_commodities = NULL;
     QofInstance *owner_inst;
-    KvpFrame *kvpf;
     EntryList *entries, *entries_iter;
 
     invoice = iw_get_invoice (iw);
@@ -722,12 +719,14 @@ gnc_dialog_post_invoice(InvoiceWindow *iw, char *message,
     /* Get the due date and posted account */
     *ddue = *postdate;
     *memo = NULL;
-
-    owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
-    kvpf = qof_instance_get_slots (owner_inst);
-    *acc = xaccAccountLookup (kvp_frame_get_guid (kvpf, LAST_POSTED_TO_ACCT),
-                              iw->book);
-
+    {
+	GncGUID *guid;
+	owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
+	qof_instance_get (owner_inst,
+			  "invoice-last-posted-account", &guid,
+			  NULL);
+	*acc = xaccAccountLookup (guid, iw->book);
+    }
     /* Get the default for the accumulate option */
     *accumulate = gnc_prefs_get_bool(GNC_PREFS_GROUP_INVOICE, GNC_PREF_ACCUM_SPLITS);
 
@@ -758,8 +757,6 @@ gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
     Timespec ddue, postdate;
     gboolean accumulate;
     QofInstance *owner_inst;
-    KvpFrame *kvpf;
-    KvpValue *kvp_val;
     const char *text;
     EntryList *entries, *entries_iter;
     GncEntry* entry;
@@ -920,14 +917,18 @@ gnc_invoice_post(InvoiceWindow *iw, struct post_invoice_params *post_params)
     }
 
 
-    /* Save account as last used account in the kvp frame of the invoice owner */
+    /* Save account as last used account in the owner's
+     * invoice-last-posted-account property.
+     */
     owner_inst = qofOwnerGetOwner (gncOwnerGetEndOwner (&(iw->owner)));
-    kvpf = qof_instance_get_slots (owner_inst);
-    kvp_val = kvp_value_new_guid (qof_instance_get_guid (QOF_INSTANCE (acc)));;
-    qof_begin_edit (owner_inst);
-    kvp_frame_set_slot_nc (kvpf, LAST_POSTED_TO_ACCT, kvp_val);
-    qof_instance_set_dirty (owner_inst);
-    qof_commit_edit (owner_inst);
+    {
+	const GncGUID *guid = qof_instance_get_guid (QOF_INSTANCE (acc));
+	qof_begin_edit (owner_inst);
+	qof_instance_set (owner_inst,
+			  "invoice-last-posted-account", guid,
+			  NULL);
+	qof_commit_edit (owner_inst);
+    }
 
     /* ... post it ... */
     if (is_cust_doc)
diff --git a/src/business/business-gnome/dialog-payment.c b/src/business/business-gnome/dialog-payment.c
index 1c7c41a..60279af 100644
--- a/src/business/business-gnome/dialog-payment.c
+++ b/src/business/business-gnome/dialog-payment.c
@@ -374,23 +374,15 @@ gnc_payment_dialog_owner_changed (PaymentWindow *pw)
 {
     Account *last_acct = NULL;
     GncGUID *guid = NULL;
-    KvpValue* value;
-    KvpFrame* slots;
     GncOwner *owner = &pw->owner;
 
     /* If the owner changed, the initial invoice is no longer valid */
     pw->invoice = NULL;
 
     /* Now handle the account tree */
-    slots = gncOwnerGetSlots(owner);
-    if (slots)
-    {
-        value = kvp_frame_get_slot_path(slots, "payment", "last_acct", NULL);
-        if (value)
-        {
-            guid = kvp_value_get_guid(value);
-        }
-    }
+    qof_instance_get (QOF_INSTANCE (owner),
+		      "payment-last-account", &guid,
+		      NULL);
 
     /* refresh the post and acc available accounts, but cleanup first */
     if (pw->acct_types)
@@ -436,20 +428,17 @@ gnc_payment_dialog_post_to_changed (PaymentWindow *pw)
 static void
 gnc_payment_dialog_remember_account (PaymentWindow *pw, Account *acc)
 {
-    KvpValue* value;
-    KvpFrame* slots = gncOwnerGetSlots(&pw->owner);
+    GncOwner *owner = &pw->owner;
+    const GncGUID *guid;
 
     if (!acc) return;
-    if (!slots) return;
-
-    value = kvp_value_new_guid(xaccAccountGetGUID(acc));
-    if (!value) return;
 
-    xaccAccountBeginEdit (acc);
-    kvp_frame_set_slot_path(slots, value, "payment", "last_acct", NULL);
-    qof_instance_set_dirty (QOF_INSTANCE (acc));
-    xaccAccountCommitEdit (acc);
-    kvp_value_delete(value);
+    guid = xaccAccountGetGUID(acc);
+    qof_begin_edit (QOF_INSTANCE (owner));
+    qof_instance_set (QOF_INSTANCE (owner),
+		      "payment-last-account", guid,
+		      NULL);
+    qof_commit_edit (QOF_INSTANCE (owner));
 }
 
 
diff --git a/src/engine/gnc-engine.h b/src/engine/gnc-engine.h
index d4db2c1..4522e1e 100644
--- a/src/engine/gnc-engine.h
+++ b/src/engine/gnc-engine.h
@@ -256,9 +256,10 @@ void gnc_engine_signal_commit_error( QofBackendError errcode );
  */
 #define GNC_INVOICE_ID    "gncInvoice"
 #define GNC_INVOICE_GUID  "invoice-guid"
-#define GNC_OWNER_ID    "gncOwner"
-#define GNC_OWNER_TYPE  "owner-type"
-#define GNC_OWNER_GUID  "owner-guid"
+#define GNC_OWNER_ID      "gncOwner"
+#define GNC_OWNER_TYPE    "owner-type"
+#define GNC_OWNER_GUID    "owner-guid"
+#define GNC_SX_ID         "sched-xaction"
 
 
 #endif
diff --git a/src/engine/gncBusiness.h b/src/engine/gncBusiness.h
index b9a960f..11584b7 100644
--- a/src/engine/gncBusiness.h
+++ b/src/engine/gncBusiness.h
@@ -37,6 +37,12 @@
 #include <glib.h>
 #include "qof.h"
 
+/* KVP key for report PDF directories */
+#define OWNER_EXPORT_PDF_DIRNAME "export-pdf-directory"
+#define LAST_POSTED_TO_ACCT "last-posted-to-acct"
+#define GNC_PAYMENT "payment"
+#define GNC_LAST_ACCOUNT "last_acct"
+
 /* @deprecated backwards-compat definitions */
 #define GNC_BILLTERM_MODULE_NAME GNC_ID_BILLTERM
 #define GNC_CUSTOMER_MODULE_NAME GNC_ID_CUSTOMER
diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index ee2fa05..8ee0bd3 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -98,6 +98,36 @@ void gncOwnerBeginEdit (GncOwner *owner)
     }
 }
 
+void gncOwnerCommitEdit (GncOwner *owner)
+{
+    if (!owner) return;
+    switch (owner->type)
+    {
+    case GNC_OWNER_NONE :
+    case GNC_OWNER_UNDEFINED :
+        break;
+    case GNC_OWNER_CUSTOMER :
+    {
+        gncCustomerCommitEdit(owner->owner.customer);
+        break;
+    }
+    case GNC_OWNER_JOB :
+    {
+        gncJobCommitEdit(owner->owner.job);
+        break;
+    }
+    case GNC_OWNER_VENDOR :
+    {
+        gncVendorCommitEdit(owner->owner.vendor);
+        break;
+    }
+    case GNC_OWNER_EMPLOYEE :
+    {
+        gncEmployeeCommitEdit(owner->owner.employee);
+        break;
+    }
+    }
+}
 
 void gncOwnerDestroy (GncOwner *owner)
 {
diff --git a/src/engine/gncOwner.h b/src/engine/gncOwner.h
index d94edd3..0874102 100644
--- a/src/engine/gncOwner.h
+++ b/src/engine/gncOwner.h
@@ -304,6 +304,7 @@ void gncOwnerFree (GncOwner *owner);
  * without knowing its type.
  */
 void gncOwnerBeginEdit (GncOwner *owner);
+void gncOwnerCommitEdit (GncOwner *owner);
 void gncOwnerDestroy (GncOwner *owner);
 
 #endif /* GNC_OWNER_H_ */
diff --git a/src/report/report-gnome/gnc-plugin-page-report.c b/src/report/report-gnome/gnc-plugin-page-report.c
index 5ebe906..0cd14fc 100644
--- a/src/report/report-gnome/gnc-plugin-page-report.c
+++ b/src/report/report-gnome/gnc-plugin-page-report.c
@@ -1771,8 +1771,6 @@ gnc_plugin_page_report_print_cb( GtkAction *action, GncPluginPageReport *report
     g_free (job_name);
 }
 
-#define KVP_OWNER_EXPORT_PDF_DIRNAME "export-pdf-directory"
-
 static void
 gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *report )
 {
@@ -1780,7 +1778,6 @@ gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *rep
     gchar *job_name = report_create_jobname(priv);
     GncInvoice *invoice;
     GncOwner *owner = NULL;
-    KvpFrame *kvp = NULL;
 
     // Do we have an invoice report?
     invoice = lookup_invoice(priv);
@@ -1790,20 +1787,19 @@ gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *rep
         owner = (GncOwner*) gncInvoiceGetOwner(invoice);
         if (owner)
         {
+	    QofInstance *inst = qofOwnerGetOwner (owner);
+	    gchar *dirname;
+	    qof_instance_get (inst, "export-pdf-dir", &dirname, NULL);
             // Yes. In the kvp, look up the key for the Export-PDF output
             // directory. If it exists, prepend this to the job name so that
             // we can export to PDF.
-            kvp = gncOwnerGetSlots(owner);
-            if (kvp)
-            {
-                const char *dirname = kvp_frame_get_string(kvp, KVP_OWNER_EXPORT_PDF_DIRNAME);
-                if (dirname && g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
-                {
-                    gchar *tmp = g_build_filename(dirname, job_name, NULL);
-                    g_free(job_name);
-                    job_name = tmp;
-                }
-            }
+	    if (dirname && g_file_test(dirname,
+				       G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
+	    {
+		gchar *tmp = g_build_filename(dirname, job_name, NULL);
+		g_free(job_name);
+		job_name = tmp;
+	    }
         }
     }
 
@@ -1811,24 +1807,26 @@ gnc_plugin_page_report_exportpdf_cb( GtkAction *action, GncPluginPageReport *rep
 
     gnc_html_print(priv->html, job_name, TRUE);
 
-    if (owner && kvp)
+    if (owner)
     {
-        // As this is an invoice report with some owner, we will try to look up the
-        // chosen output directory from the print settings and store it again in the owner kvp.
+	/* As this is an invoice report with some owner, we will try
+	 * to look up the chosen output directory from the print
+	 * settings and store it again in the owner kvp.
+	 */
         GtkPrintSettings *print_settings = gnc_print_get_settings();
-        if (print_settings && gtk_print_settings_has_key(print_settings, GNC_GTK_PRINT_SETTINGS_EXPORT_DIR))
+        if (print_settings &&
+	    gtk_print_settings_has_key(print_settings,
+				       GNC_GTK_PRINT_SETTINGS_EXPORT_DIR))
         {
             const char* dirname = gtk_print_settings_get(print_settings,
                                   GNC_GTK_PRINT_SETTINGS_EXPORT_DIR);
             // Only store the directory if it exists.
             if (g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
             {
-                QofInstance *qofinstance = qofOwnerGetOwner(owner);
-                //gncOwnerBeginEdit(owner);
-                kvp_frame_set_string(kvp, KVP_OWNER_EXPORT_PDF_DIRNAME, dirname);
-                if (qofinstance)
-                    qof_instance_set_dirty(qofinstance);
-                // shoot... there is no such thing as: gncOwnerCommitEdit(owner);
+                QofInstance *inst = qofOwnerGetOwner(owner);
+                gncOwnerBeginEdit(owner);
+		qof_instance_set (inst, "export-pdf-dir", dirname);
+		gncOwnerCommitEdit(owner);
             }
         }
     }

commit 272655b60c0e30726fd5870a441478e717e2b8df
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 15:25:03 2013 -0700

    Replace Import KVP access with properties.

diff --git a/src/import-export/aqbanking/gnc-ab-kvp.c b/src/import-export/aqbanking/gnc-ab-kvp.c
index 074a37b..db7c0f5 100644
--- a/src/import-export/aqbanking/gnc-ab-kvp.c
+++ b/src/import-export/aqbanking/gnc-ab-kvp.c
@@ -33,91 +33,90 @@
 #include "gnc-ab-kvp.h"
 
 #define AB_KEY "hbci"
-#define AB_ACCOUNT_ID "account-id"
-#define AB_ACCOUNT_UID "account-uid"
-#define AB_BANK_CODE "bank-code"
-#define AB_TRANS_RETRIEVAL "trans-retrieval"
 #define AB_TEMPLATES "template-list"
 
 /* This static indicates the debugging module that this .o belongs to.  */
 G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
 
-static kvp_frame *gnc_ab_get_account_kvp(const Account *a, gboolean create);
 static kvp_frame *gnc_ab_get_book_kvp(QofBook *b, gboolean create);
 
 const gchar *
 gnc_ab_get_account_accountid(const Account *a)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE);
-    kvp_value *value = kvp_frame_get_slot(frame, AB_ACCOUNT_ID);
-    return kvp_value_get_string(value);
+    gchar *id;
+    qof_instance_get (QOF_INSTANCE (a),
+		      "ab-account-id", &id,
+		      NULL);
+    return id;
 }
 
 void
 gnc_ab_set_account_accountid(Account *a, const gchar *id)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE);
-    kvp_value *value = kvp_value_new_string(id);
     xaccAccountBeginEdit(a);
-    kvp_frame_set_slot_nc(frame, AB_ACCOUNT_ID, value);
-    qof_instance_set_dirty(QOF_INSTANCE (a));
+    qof_instance_set (QOF_INSTANCE (a),
+		      "ab-account-id", id,
+		      NULL);
     xaccAccountCommitEdit(a);
 }
 
 const gchar *
 gnc_ab_get_account_bankcode(const Account *a)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE);
-    kvp_value *value = kvp_frame_get_slot(frame, AB_BANK_CODE);
-    return kvp_value_get_string(value);
+    gchar *code;
+    qof_instance_get (QOF_INSTANCE (a),
+		      "ab-bank-code", &code,
+		      NULL);
+    return code;
 }
 
 void
 gnc_ab_set_account_bankcode(Account *a, const gchar *code)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE);
-    kvp_value *value = kvp_value_new_string(code);
     xaccAccountBeginEdit(a);
-    kvp_frame_set_slot_nc(frame, AB_BANK_CODE, value);
-    qof_instance_set_dirty(QOF_INSTANCE (a));
+    qof_instance_set (QOF_INSTANCE (a),
+		      "ab-bank-code", code,
+		      NULL);
     xaccAccountCommitEdit(a);
 }
 
 guint32
 gnc_ab_get_account_uid(const Account *a)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE);
-    kvp_value *value = kvp_frame_get_slot(frame, AB_ACCOUNT_UID);
-    return (guint32) kvp_value_get_gint64(value);
+    guint64 uid;
+    qof_instance_get (QOF_INSTANCE (a),
+		      "ab-account-uid", &uid,
+		      NULL);
+    return (guint32)uid;
 }
 
 void
 gnc_ab_set_account_uid(Account *a, guint32 uid)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE);
-    kvp_value *value = kvp_value_new_gint64(uid);
     xaccAccountBeginEdit(a);
-    kvp_frame_set_slot_nc(frame, AB_ACCOUNT_UID, value);
-    qof_instance_set_dirty(QOF_INSTANCE (a));
+    qof_instance_set (QOF_INSTANCE (a),
+		      "ab-account-uid", (guint64)uid,
+		      NULL);
     xaccAccountCommitEdit(a);
 }
 
 Timespec
 gnc_ab_get_account_trans_retrieval(const Account *a)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE);
-    kvp_value *value = kvp_frame_get_slot(frame, AB_TRANS_RETRIEVAL);
-    return kvp_value_get_timespec(value);
+    Timespec t;
+    qof_instance_get (QOF_INSTANCE (a),
+		      "ab-trans-retrieval", &t,
+		      NULL);
+    return t;
 }
 
 void
 gnc_ab_set_account_trans_retrieval(Account *a, Timespec time)
 {
-    kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE);
-    kvp_value *value = kvp_value_new_timespec(time);
     xaccAccountBeginEdit(a);
-    kvp_frame_set_slot_nc(frame, AB_TRANS_RETRIEVAL, value);
-    qof_instance_set_dirty(QOF_INSTANCE (a));
+    qof_instance_set (QOF_INSTANCE (a),
+		      "ab-trans-retrieval", &time,
+		      NULL);
     xaccAccountCommitEdit(a);
 }
 
@@ -139,19 +138,6 @@ gnc_ab_set_book_template_list(QofBook *b, GList *template_list)
 }
 
 static kvp_frame *
-gnc_ab_get_account_kvp(const Account *a, gboolean create)
-{
-    kvp_frame *toplevel = xaccAccountGetSlots(a);
-    kvp_frame *result = kvp_frame_get_frame(toplevel, AB_KEY);
-    if (!result && create)
-    {
-        result = kvp_frame_new();
-        kvp_frame_add_frame_nc(toplevel, AB_KEY, result);
-    }
-    return result;
-}
-
-static kvp_frame *
 gnc_ab_get_book_kvp(QofBook *b, gboolean create)
 {
     kvp_frame *toplevel = qof_book_get_slots(b);
diff --git a/src/import-export/ofx/gnc-ofx-kvp.c b/src/import-export/ofx/gnc-ofx-kvp.c
index bdcd022..e4e5d6f 100644
--- a/src/import-export/ofx/gnc-ofx-kvp.c
+++ b/src/import-export/ofx/gnc-ofx-kvp.c
@@ -26,59 +26,34 @@
 #include "config.h"
 #include "gnc-ofx-kvp.h"
 
-static const char *KEY_ASSOC_INCOME_ACCOUNT = "ofx/associated-income-account";
 static void force_account_dirty(Account *acct);
+/* OUTSIDE SLOT ACCESS */
 
 
 Account *gnc_ofx_kvp_get_assoc_account(const Account* investment_account)
 {
-    kvp_frame * acc_frame;
-    kvp_value * kvp_val;
     Account *result = NULL;
-
+    GncGUID *income_guid= NULL;
     g_assert(investment_account);
-
-    acc_frame = xaccAccountGetSlots(investment_account);
-    kvp_val = kvp_frame_get_slot(acc_frame, KEY_ASSOC_INCOME_ACCOUNT);
-    if (kvp_val != NULL)
-    {
-        result = xaccAccountLookup(kvp_value_get_guid(kvp_val),
-                                   gnc_account_get_book(investment_account));
-    }
-    return result;
+    qof_instance_get (QOF_INSTANCE (investment_account),
+		      "ofx-income-account", &income_guid,
+		      NULL);
+    return xaccAccountLookup(income_guid,
+			       gnc_account_get_book(investment_account));
 }
 
 void gnc_ofx_kvp_set_assoc_account(Account* investment_account,
                                    const Account *income_account)
 {
-    kvp_frame * acc_frame;
-    kvp_value * kvp_val;
     const GncGUID * income_acc_guid;
 
     g_assert(investment_account);
     g_assert(income_account);
 
-    acc_frame = xaccAccountGetSlots(investment_account);
-    g_assert(acc_frame); // Must not be NULL, but the QofInstance doc is unclear about this
     income_acc_guid = xaccAccountGetGUID(income_account);
-    kvp_val = kvp_value_new_guid(income_acc_guid);
     xaccAccountBeginEdit(investment_account);
-    kvp_frame_set_slot_nc(acc_frame, KEY_ASSOC_INCOME_ACCOUNT,
-                          kvp_val);
-    force_account_dirty(investment_account);
+    qof_instance_set (QOF_INSTANCE (investment_account),
+		      "ofx-income-account", income_acc_guid,
+		      NULL);
     xaccAccountCommitEdit(investment_account);
 }
-
-// copied from gnc-ab-kvp.c
-static void
-force_account_dirty(Account *acct)
-{
-    gchar *name = g_strdup(xaccAccountGetName(acct));
-
-    /* This is necessary because modifying the KvpFrames doesn't mark
-     * accounts dirty, which means the changes wont be propagated to the
-     * backend.
-     */
-    xaccAccountSetName(acct, name);
-    g_free(name);
-}

commit 3a51d704c892029d82d3e56827f8f98c63d8f26b
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 15:16:45 2013 -0700

    Replace usage of SX kvp access with SX properties.

diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index 0965076..6e3595b 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -176,10 +176,9 @@ _get_vars_helper(Transaction *txn, void *var_hash_data)
 {
     GHashTable *var_hash = (GHashTable*)var_hash_data;
     GList *split_list;
-    kvp_frame *kvpf;
-    kvp_value *kvp_val;
     Split *s;
-    char *str;
+    gchar *credit_formula;
+    gchar *debit_formula;
     gnc_commodity *first_cmdty = NULL;
 
     split_list = xaccTransGetSplitList(txn);
@@ -195,12 +194,12 @@ _get_vars_helper(Transaction *txn, void *var_hash_data)
         Account *acct;
 
         s = (Split*)split_list->data;
-        kvpf = xaccSplitGetSlots(s);
-        kvp_val = kvp_frame_get_slot_path(kvpf,
-                                          GNC_SX_ID,
-                                          GNC_SX_ACCOUNT,
-                                          NULL);
-        acct_guid = kvp_value_get_guid(kvp_val);
+
+        qof_instance_get (QOF_INSTANCE (s),
+			  "sx-account", &acct_guid,
+			  "sx-credit-formula", &credit_formula,
+			  "sx-debit-formula", &debit_formula,
+			  NULL);
         acct = xaccAccountLookup(acct_guid, gnc_get_current_book());
         split_cmdty = xaccAccountGetCommodity(acct);
         if (first_cmdty == NULL)
@@ -226,31 +225,16 @@ _get_vars_helper(Transaction *txn, void *var_hash_data)
         }
 
         // existing... ------------------------------------------
-        kvp_val = kvp_frame_get_slot_path(kvpf,
-                                          GNC_SX_ID,
-                                          GNC_SX_CREDIT_FORMULA,
-                                          NULL);
-        if (kvp_val != NULL)
-        {
-            str = kvp_value_get_string(kvp_val);
-            if (str && strlen(str) != 0)
-            {
-                gnc_sx_parse_vars_from_formula(str, var_hash, NULL);
-            }
-        }
-
-        kvp_val = kvp_frame_get_slot_path(kvpf,
-                                          GNC_SX_ID,
-                                          GNC_SX_DEBIT_FORMULA,
-                                          NULL);
-        if (kvp_val != NULL)
-        {
-            str = kvp_value_get_string(kvp_val);
-            if (str && strlen(str) != 0)
-            {
-                gnc_sx_parse_vars_from_formula(str, var_hash, NULL);
-            }
-        }
+	if (credit_formula && strlen(credit_formula) != 0)
+	{
+	    gnc_sx_parse_vars_from_formula(credit_formula, var_hash, NULL);
+	}
+	if (debit_formula && strlen(debit_formula) != 0)
+	{
+	    gnc_sx_parse_vars_from_formula(debit_formula, var_hash, NULL);
+	}
+	g_free (credit_formula);
+	g_free (debit_formula);
     }
 
     return 0;
@@ -903,28 +887,9 @@ static gboolean
 _get_template_split_account(const SchedXaction* sx, const Split *template_split, Account **split_acct, GList **creation_errors)
 {
     GncGUID *acct_guid;
-    kvp_frame *split_kvpf;
-    kvp_value *kvp_val;
-
-    split_kvpf = xaccSplitGetSlots(template_split);
-    /* contains the guid of the split's actual account. */
-    kvp_val = kvp_frame_get_slot_path(split_kvpf,
-                                      GNC_SX_ID,
-                                      GNC_SX_ACCOUNT,
-                                      NULL);
-    if (kvp_val == NULL)
-    {
-        GString *err = g_string_new("");
-        g_string_printf(err, "Null account kvp value for SX [%s], cancelling creation.",
-                        xaccSchedXactionGetName(sx));
-        g_critical("%s", err->str);
-        if (creation_errors != NULL)
-            *creation_errors = g_list_append(*creation_errors, err);
-        else
-            g_string_free(err, TRUE);
-        return FALSE;
-    }
-    acct_guid = kvp_value_get_guid( kvp_val );
+    qof_instance_get (QOF_INSTANCE (template_split),
+		      "sx-account", &acct_guid,
+		      NULL);
     *split_acct = xaccAccountLookup(acct_guid, gnc_get_current_book());
     if (*split_acct == NULL)
     {
@@ -948,18 +913,13 @@ _get_template_split_account(const SchedXaction* sx, const Split *template_split,
 static void
 _get_sx_formula_value(const SchedXaction* sx, const Split *template_split, gnc_numeric *numeric, GList **creation_errors, const char *formula_key, const char* numeric_key, GHashTable *variable_bindings)
 {
-    kvp_frame *split_kvpf;
-    kvp_value *kvp_val;
-    char *formula_str, *parseErrorLoc;
 
-    split_kvpf = xaccSplitGetSlots(template_split);
+    char *formula_str, *parseErrorLoc;
+    qof_instance_get (QOF_INSTANCE (template_split),
+		      formula_key, &formula_str,
+		      numeric_key, &numeric,
+		      NULL);
 
-    /* First look up the gnc_numeric value in the template split */
-    kvp_val = kvp_frame_get_slot_path(split_kvpf,
-                                      GNC_SX_ID,
-                                      numeric_key,
-                                      NULL);
-    *numeric = kvp_value_get_numeric(kvp_val);
     if ((gnc_numeric_check(*numeric) == GNC_ERROR_OK)
             && !gnc_numeric_zero_p(*numeric))
     {
@@ -969,11 +929,6 @@ _get_sx_formula_value(const SchedXaction* sx, const Split *template_split, gnc_n
         return;
     }
 
-    kvp_val = kvp_frame_get_slot_path(split_kvpf,
-                                      GNC_SX_ID,
-                                      formula_key,
-                                      NULL);
-    formula_str = kvp_value_get_string(kvp_val);
     if (formula_str != NULL && strlen(formula_str) != 0)
     {
         GHashTable *parser_vars = NULL;
@@ -1010,13 +965,17 @@ _get_sx_formula_value(const SchedXaction* sx, const Split *template_split, gnc_n
 static void
 _get_credit_formula_value(GncSxInstance *instance, const Split *template_split, gnc_numeric *credit_num, GList **creation_errors)
 {
-    _get_sx_formula_value(instance->parent->sx, template_split, credit_num, creation_errors, GNC_SX_CREDIT_FORMULA, GNC_SX_CREDIT_NUMERIC, instance->variable_bindings);
+    _get_sx_formula_value(instance->parent->sx, template_split, credit_num,
+			  creation_errors, "sx-credit-formula",
+			  "sx-credit-numeric", instance->variable_bindings);
 }
 
 static void
 _get_debit_formula_value(GncSxInstance *instance, const Split *template_split, gnc_numeric *debit_num, GList **creation_errors)
 {
-    _get_sx_formula_value(instance->parent->sx, template_split, debit_num, creation_errors, GNC_SX_DEBIT_FORMULA, GNC_SX_DEBIT_NUMERIC, instance->variable_bindings);
+    _get_sx_formula_value(instance->parent->sx, template_split, debit_num,
+			  creation_errors, "sx-debit-formula",
+			  "sx-debit-numeric", instance->variable_bindings);
 }
 
 static gboolean
@@ -1087,9 +1046,6 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
             break;
         }
 
-        /* clear out any copied Split frame data. */
-        qof_instance_set_slots(QOF_INSTANCE(copying_split), kvp_frame_new());
-
         split_cmdty = xaccAccountGetCommodity(split_acct);
         if (first_cmdty == NULL)
         {
@@ -1212,9 +1168,10 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
     }
 
     {
-        kvp_frame *txn_frame;
-        txn_frame = xaccTransGetSlots(new_txn);
-        kvp_frame_set_guid(txn_frame, "from-sched-xaction", xaccSchedXactionGetGUID(creation_data->instance->parent->sx));
+	qof_instance_set (QOF_INSTANCE (new_txn),
+			  "from-sched-xaction",
+			  xaccSchedXactionGetGUID(creation_data->instance->parent->sx),
+			  NULL);
     }
 
     xaccTransCommitEdit(new_txn);
@@ -1617,9 +1574,14 @@ create_cashflow_helper(Transaction *template_txn, void *user_data)
             gint gncn_error;
 
             /* Credit value */
-            _get_sx_formula_value(creation_data->sx, template_split, &credit_num, creation_data->creation_errors, GNC_SX_CREDIT_FORMULA, GNC_SX_CREDIT_NUMERIC, NULL);
+            _get_sx_formula_value(creation_data->sx, template_split,
+				  &credit_num, creation_data->creation_errors,
+				  "sx-credit-formula", "sx-credit-numeric",
+				  NULL);
             /* Debit value */
-            _get_sx_formula_value(creation_data->sx, template_split, &debit_num, creation_data->creation_errors, GNC_SX_DEBIT_FORMULA, GNC_SX_DEBIT_NUMERIC, NULL);
+            _get_sx_formula_value(creation_data->sx, template_split,
+				  &debit_num, creation_data->creation_errors,
+				  "sx-debit-formula", "sx-debit-numeric", NULL);
 
             /* The resulting cash flow number: debit minus credit,
              * multiplied with the count factor. */
diff --git a/src/engine/SchedXaction.h b/src/engine/SchedXaction.h
index d78b975..c02183e 100644
--- a/src/engine/SchedXaction.h
+++ b/src/engine/SchedXaction.h
@@ -304,12 +304,7 @@ void gnc_sx_remove_defer_instance( SchedXaction *sx, void *deferStateData );
 GList *gnc_sx_get_defer_instances( SchedXaction *sx );
 
 /* #defines for KvpFrame strings and QOF */
-#define GNC_SX_ID                    "sched-xaction"
-#define GNC_SX_CREDIT_NUMERIC        "credit-numeric"
-#define GNC_SX_DEBIT_NUMERIC         "debit-numeric"
 #define GNC_SX_SHARES                "shares"
-#define GNC_SX_AMOUNT                "amnt"
-#define GNC_SX_FROM_SCHED_XACTION    "from-sched-xaction"
 #define GNC_SX_FREQ_SPEC             "scheduled-frequency"
 #define GNC_SX_NAME                  "sched-xname"
 #define GNC_SX_START_DATE            "sched-start-date"
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index a763c89..cc8dcdc 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -263,6 +263,13 @@ test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
     g_free (debit_numeric_r);
     g_free (credit_formula_r);
     g_free (credit_numeric_r);
+    qof_instance_set (QOF_INSTANCE (fixture->split),
+		      "sx-credit-formula", NULL,
+		      NULL);
+    qof_instance_get (QOF_INSTANCE (fixture->split),
+		      "sx-credit-formula", &credit_numeric_r,
+		      NULL);
+    g_assert (credit_numeric_r == NULL);
     g_free (sx_shares_r);
     g_free (online_id_r);
     guid_free (sx_account);
diff --git a/src/gnome-utils/gnc-tree-util-split-reg.c b/src/gnome-utils/gnc-tree-util-split-reg.c
index c8d7e09..9cbcc2b 100644
--- a/src/gnome-utils/gnc-tree-util-split-reg.c
+++ b/src/gnome-utils/gnc-tree-util-split-reg.c
@@ -397,30 +397,20 @@ const char *
 gnc_tree_util_split_reg_template_get_transfer_entry (Split *split)
 {
     static char *name = NULL;
+    Account *account;
+    GncGUID *guid;
 
-    kvp_frame *kvpf;
+    /* Callers either g_strdup the return or use it as a temp for comparison,
+       so we keep our static ref and free it on every call. */
+    g_free (name);
 
     if (!split)
         return NULL;
-
-    kvpf = xaccSplitGetSlots (split);
-
-    g_free (name);
-
-    if (kvpf)
-    {
-        Account *account;
-        GncGUID *guid;
-
-        guid = kvp_value_get_guid(
-                   kvp_frame_get_slot_path (kvpf, "sched-xaction", "account", NULL));
-
-        account = xaccAccountLookup (guid, gnc_get_current_book ());
-
-        name = account ? gnc_get_account_name_for_register (account) : NULL;
-    }
-    else
-        name = NULL;
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-account", &guid,
+		      NULL);
+    account = xaccAccountLookup (guid, gnc_get_current_book ());
+    name = account ? gnc_get_account_name_for_register (account) : NULL;
 
     return name;
 }
@@ -429,20 +419,27 @@ gnc_tree_util_split_reg_template_get_transfer_entry (Split *split)
 const char *
 gnc_tree_util_split_reg_template_get_fdebt_entry (Split *split)
 {
-    kvp_frame *kvpf = xaccSplitGetSlots (split);
+    gchar *formula;
 
-    return kvp_value_get_string(
-               kvp_frame_get_slot_path (kvpf, "sched-xaction", "debit-formula", NULL));
-}
+    g_return_val_if_fail (split != NULL, NULL);
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-debit-formula", &formula,
+		      NULL);
 
+    return formula;
+}
 
 const char *
 gnc_tree_util_split_reg_template_get_fcred_entry (Split *split)
 {
-    kvp_frame *kvpf = xaccSplitGetSlots (split);
+    gchar *formula;
+
+    g_return_val_if_fail (split != NULL, NULL);
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-credit-formula", &formula,
+		      NULL);
 
-    return kvp_value_get_string(
-               kvp_frame_get_slot_path (kvpf, "sched-xaction", "credit-formula", NULL));
+    return formula;
 }
 
 
diff --git a/src/gnome-utils/gnc-tree-view-split-reg.c b/src/gnome-utils/gnc-tree-view-split-reg.c
index c1836c5..2a6ecdb 100644
--- a/src/gnome-utils/gnc-tree-view-split-reg.c
+++ b/src/gnome-utils/gnc-tree-view-split-reg.c
@@ -4803,9 +4803,8 @@ gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
             if (viewcol == COL_TRANSFERVOID)
             {
                 Account *template_acc;
+		Account *acct;
                 const GncGUID *acctGUID;
-                kvp_frame *kvpf;
-                Account *acct;
 
                 /* save the account GncGUID into the kvp_data. */
                 view->priv->stop_cell_move = FALSE;
@@ -4824,9 +4823,9 @@ gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
                 }
 
                 acctGUID = xaccAccountGetGUID (acct);
-                kvpf = xaccSplitGetSlots (split);
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_guid (acctGUID),
-                             GNC_SX_ID, GNC_SX_ACCOUNT, NULL);
+		qof_instance_set (QOF_INSTANCE (split),
+				  "sx-account", acctGUID,
+				  NULL);
 
                 template_acc = gnc_tree_model_split_reg_get_template_account (model);
 
@@ -4846,20 +4845,11 @@ gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
             /* Setup the debit and credit fields */
             if (viewcol == COL_DEBIT)
             {
-                kvp_frame *kvpf;
                 char *error_loc;
                 gnc_numeric new_value;
                 gboolean parse_result;
 
-                kvpf = xaccSplitGetSlots (split);
-
-                DEBUG ("kvp_frame debit before: %s\n", kvp_frame_to_string (kvpf));
-
                 /* Setup the debit formula */
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_string (new_text),
-                                         GNC_SX_ID,
-                                         GNC_SX_DEBIT_FORMULA,
-                                         NULL);
 
                 /* If the value can be parsed into a numeric result, store that
                  * numeric value additionally. See above comment.*/
@@ -4868,45 +4858,22 @@ gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
                 {
                     new_value = gnc_numeric_zero();
                 }
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_value),
-                                         GNC_SX_ID,
-                                         GNC_SX_DEBIT_NUMERIC,
-                                         NULL);
-
-                DEBUG ("kvp_frame debit after: %s\n", kvp_frame_to_string (kvpf));
-
-                /* Blank the credit formula */
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_string (NULL),
-                                         GNC_SX_ID,
-                                         GNC_SX_CREDIT_FORMULA,
-                                         NULL);
-
-                new_value = gnc_numeric_zero();
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_value),
-                                         GNC_SX_ID,
-                                         GNC_SX_CREDIT_NUMERIC,
-                                         NULL);
+		qof_instance_set (QOF_INSTANCE (split),
+				  "sx-debit-formula", new_text,
+				  "sx-debit-numeric", &new_value,
+				  "sx-credit-formula", NULL,
+				  "sx-credit-numeric", NULL,
+				  NULL);
             }
 
             /* Setup the debit and credit fields */
             if (viewcol == COL_CREDIT)
             {
-                kvp_frame *kvpf;
                 char *error_loc;
                 gnc_numeric new_value;
                 gboolean parse_result;
 
-                kvpf = xaccSplitGetSlots (split);
-
-                DEBUG ("kvp_frame credit before: %s\n", kvp_frame_to_string (kvpf));
-
-                /* Setup the credit formula */
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_string (new_text),
-                                             GNC_SX_ID,
-                                             GNC_SX_CREDIT_FORMULA,
-                                             NULL);
-
-                /* If the value can be parsed into a numeric result (without any
+               /* If the value can be parsed into a numeric result (without any
                  * further variable definitions), store that numeric value
                  * additionally in the kvp. Otherwise store a zero numeric
                  * there.*/
@@ -4915,24 +4882,12 @@ gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
                 {
                     new_value = gnc_numeric_zero();
                 }
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_value),
-                                         GNC_SX_ID,
-                                         GNC_SX_CREDIT_NUMERIC,
-                                         NULL);
-
-                DEBUG ("kvp_frame credit after: %s\n", kvp_frame_to_string (kvpf));
-
-                /* Blank the debit formula */
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_string (NULL),
-                                         GNC_SX_ID,
-                                         GNC_SX_DEBIT_FORMULA,
-                                         NULL);
-
-                new_value = gnc_numeric_zero();
-                kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_value),
-                                         GNC_SX_ID,
-                                         GNC_SX_DEBIT_NUMERIC,
-                                         NULL);
+		qof_instance_set (QOF_INSTANCE (split),
+				  "sx-credit-formula", new_text,
+				  "sx-credit-numeric", &new_value,
+				  "sx-debit-formula", NULL,
+				  "sx-debit-numeric", NULL,
+				  NULL);
             }
             /* set the amount to an innocuous value */
             xaccSplitSetValue (split, gnc_numeric_create (0, 1));
diff --git a/src/gnome/dialog-sx-editor.c b/src/gnome/dialog-sx-editor.c
index b3fb1e8..9058776 100644
--- a/src/gnome/dialog-sx-editor.c
+++ b/src/gnome/dialog-sx-editor.c
@@ -549,9 +549,7 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
         int numIters, i;
         GHashTable *vars, *txns;
         GList *splitList = NULL;
-        char *str;
-        kvp_frame *f;
-        kvp_value *v;
+        gchar *credit_formula, *debit_formula;
         Split *s;
         Transaction *t;
         gnc_numeric tmp;
@@ -559,8 +557,10 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
         gpointer unusedKey, unusedValue;
 
         unbalanceable = FALSE; /* innocent until proven guilty */
-        vars = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)gnc_sx_variable_free);
-        txns = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
+        vars = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+				     (GDestroyNotify)gnc_sx_variable_free);
+        txns = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+				     g_free);
         numIters = NUM_ITERS_NO_VARS;
         /**
          * Plan:
@@ -622,14 +622,11 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
                     g_hash_table_insert( txns, (gpointer)t, (gpointer)tcds );
                 }
 
-                f = xaccSplitGetSlots( s );
-
-                /* contains the guid of the split's actual account. */
-                v = kvp_frame_get_slot_path(f,
-                                            GNC_SX_ID,
-                                            GNC_SX_ACCOUNT,
-                                            NULL);
-                acct_guid = kvp_value_get_guid( v );
+		qof_instance_get (QOF_INSTANCE (s),
+				  "sx-account", &acct_guid,
+				  "sx-credit-formula", &credit_formula,
+				  "sx-debit-formula", &debit_formula,
+				  NULL);
                 acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
                 split_cmdty = xaccAccountGetCommodity(acct);
                 if (base_cmdty == NULL)
@@ -638,62 +635,48 @@ gnc_sxed_check_consistent( GncSxEditorDialog *sxed )
                 }
                 multi_commodity |= !gnc_commodity_equal(split_cmdty, base_cmdty);
 
-                v = kvp_frame_get_slot_path( f,
-                                             GNC_SX_ID,
-                                             GNC_SX_CREDIT_FORMULA,
-                                             NULL );
-                if ( v
-                        && (str = kvp_value_get_string(v))
-                        && strlen( str ) != 0 )
-                {
-                    if ( gnc_sx_parse_vars_from_formula( str, vars, &tmp ) < 0 )
-                    {
-                        GString *errStr;
-
-                        errStr = g_string_sized_new( 32 );
-                        g_string_printf( errStr,
-                                         _( "Couldn't parse credit formula for "
-                                            "split \"%s\"." ),
-                                         xaccSplitGetMemo( s ) );
-                        gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
-                                          errStr->str );
-                        g_string_free( errStr, TRUE );
-
-                        return FALSE;
-                    }
-                    tcds->creditSum =
-                        gnc_numeric_add( tcds->creditSum, tmp, 100,
-                                         (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
-                    tmp = gnc_numeric_zero();
-                }
-                v = kvp_frame_get_slot_path( f,
-                                             GNC_SX_ID,
-                                             GNC_SX_DEBIT_FORMULA,
-                                             NULL );
-                if ( v
-                        && (str = kvp_value_get_string(v))
-                        && strlen(str) != 0 )
-                {
-                    if ( gnc_sx_parse_vars_from_formula( str, vars, &tmp ) < 0 )
-                    {
-                        GString *errStr;
-
-                        errStr = g_string_sized_new( 32 );
-                        g_string_printf( errStr,
-                                         _( "Couldn't parse debit formula for "
-                                            "split \"%s\"." ),
-                                         xaccSplitGetMemo( s ) );
-                        gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
-                                          (gchar*)errStr->str );
-                        g_string_free( errStr, TRUE );
-
-                        return FALSE;
-                    }
-                    tcds->debitSum = gnc_numeric_add( tcds->debitSum, tmp, 100,
-                                                      (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
-                    tmp = gnc_numeric_zero();
-                }
-            }
+		if ( g_strcmp0 (credit_formula, "") != 0 &&
+		     gnc_sx_parse_vars_from_formula(credit_formula, vars,
+						    &tmp ) < 0 )
+		{
+		    GString *errStr;
+
+		    errStr = g_string_sized_new( 32 );
+		    g_string_printf( errStr,
+				     _( "Couldn't parse credit formula for "
+					"split \"%s\"." ),
+				     xaccSplitGetMemo( s ) );
+		    gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
+				      errStr->str );
+		    g_string_free( errStr, TRUE );
+
+		    return FALSE;
+		}
+		tcds->creditSum =
+		    gnc_numeric_add( tcds->creditSum, tmp, 100,
+				     (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
+		tmp = gnc_numeric_zero();
+		if ( g_strcmp0 (debit_formula, "") != 0 &&
+		     gnc_sx_parse_vars_from_formula( debit_formula, vars,
+						     &tmp ) < 0 )
+		{
+		    GString *errStr;
+
+		    errStr = g_string_sized_new( 32 );
+		    g_string_printf( errStr,
+				     _( "Couldn't parse debit formula for "
+					"split \"%s\"." ),
+				     xaccSplitGetMemo( s ) );
+		    gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
+				      (gchar*)errStr->str );
+		    g_string_free( errStr, TRUE );
+
+		    return FALSE;
+		}
+		tcds->debitSum = gnc_numeric_add( tcds->debitSum, tmp, 100,
+						  (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
+		tmp = gnc_numeric_zero();
+	    }
 
             g_hash_table_foreach( txns,
                                   check_credit_debit_balance,
diff --git a/src/gnome/dialog-sx-editor2.c b/src/gnome/dialog-sx-editor2.c
index c9de4dc..3f24dae 100644
--- a/src/gnome/dialog-sx-editor2.c
+++ b/src/gnome/dialog-sx-editor2.c
@@ -546,9 +546,7 @@ gnc_sxed_check_consistent (GncSxEditorDialog2 *sxed)
         int numIters, i;
         GHashTable *vars, *txns;
         GList *splitList = NULL;
-        char *str;
-        kvp_frame *f;
-        kvp_value *v;
+        char *credit_formula, *debit_formula;
         Split *s;
         Transaction *t;
         gnc_numeric tmp;
@@ -615,77 +613,60 @@ gnc_sxed_check_consistent (GncSxEditorDialog2 *sxed)
                     g_hash_table_insert (txns, (gpointer)t, (gpointer)tcds);
                 }
 
-                f = xaccSplitGetSlots (s);
-
-                /* contains the guid of the split's actual account. */
-                v = kvp_frame_get_slot_path (f,
-                                            GNC_SX_ID,
-                                            GNC_SX_ACCOUNT,
-                                            NULL);
-                acct_guid = kvp_value_get_guid (v);
-                acct = xaccAccountLookup (acct_guid, gnc_get_current_book ());
-                split_cmdty = xaccAccountGetCommodity (acct);
+		qof_instance_get (QOF_INSTANCE (s),
+				  "sx-account", &acct_guid,
+				  "sx-credit-formula", &credit_formula,
+				  "sx-debit-formula", &debit_formula,
+				  NULL);
+                acct = xaccAccountLookup( acct_guid, gnc_get_current_book ());
+                split_cmdty = xaccAccountGetCommodity(acct);
                 if (base_cmdty == NULL)
                 {
                     base_cmdty = split_cmdty;
                 }
-                multi_commodity |= !gnc_commodity_equal (split_cmdty, base_cmdty);
-
-                v = kvp_frame_get_slot_path (f,
-                                             GNC_SX_ID,
-                                             GNC_SX_CREDIT_FORMULA,
-                                             NULL);
-                if (v
-                        && (str = kvp_value_get_string (v))
-                        && strlen( str ) != 0)
-                {
-                    if (gnc_sx_parse_vars_from_formula (str, vars, &tmp ) < 0)
-                    {
-                        GString *errStr;
-
-                        errStr = g_string_sized_new (32);
-                        g_string_printf (errStr,
-                                         _( "Couldn't parse credit formula for "
-                                            "split \"%s\"."),
-                                         xaccSplitGetMemo (s));
-                        gnc_error_dialog (GTK_WIDGET (sxed->dialog), "%s",
-                                          errStr->str);
-                        g_string_free (errStr, TRUE);
-
-                        return FALSE;
-                    }
-                    tcds->creditSum =
-                        gnc_numeric_add (tcds->creditSum, tmp, 100,
-                                         (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD));
-                    tmp = gnc_numeric_zero();
-                }
-                v = kvp_frame_get_slot_path (f,
-                                             GNC_SX_ID,
-                                             GNC_SX_DEBIT_FORMULA,
-                                             NULL);
-                if (v
-                        && (str = kvp_value_get_string (v))
-                        && strlen(str) != 0 )
-                {
-                    if (gnc_sx_parse_vars_from_formula (str, vars, &tmp ) < 0)
-                    {
-                        GString *errStr;
-
-                        errStr = g_string_sized_new (32);
-                        g_string_printf (errStr,
-                                         _( "Couldn't parse debit formula for "
-                                            "split \"%s\"."),
-                                         xaccSplitGetMemo (s));
-                        gnc_error_dialog (GTK_WIDGET (sxed->dialog), "%s",
-                                          (gchar*)errStr->str);
-                        g_string_free (errStr, TRUE);
-
-                        return FALSE;
-                    }
-                    tcds->debitSum = gnc_numeric_add (tcds->debitSum, tmp, 100,
-                                                      (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD));
-                    tmp = gnc_numeric_zero();
-                }
+                multi_commodity |= !gnc_commodity_equal(split_cmdty, base_cmdty);
+
+		if ( g_strcmp0 (credit_formula, "") != 0 &&
+		     gnc_sx_parse_vars_from_formula(credit_formula, vars,
+						    &tmp ) < 0 )
+		{
+		    GString *errStr;
+
+		    errStr = g_string_sized_new( 32 );
+		    g_string_printf( errStr,
+				     _( "Couldn't parse credit formula for "
+					"split \"%s\"." ),
+				     xaccSplitGetMemo( s ) );
+		    gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
+				      errStr->str );
+		    g_string_free( errStr, TRUE );
+
+		    return FALSE;
+		}
+		tcds->creditSum =
+		    gnc_numeric_add( tcds->creditSum, tmp, 100,
+				     (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
+		tmp = gnc_numeric_zero();
+		if ( g_strcmp0 (debit_formula, "") != 0 &&
+		     gnc_sx_parse_vars_from_formula( debit_formula, vars,
+						     &tmp ) < 0 )
+		{
+		    GString *errStr;
+
+		    errStr = g_string_sized_new( 32 );
+		    g_string_printf( errStr,
+				     _( "Couldn't parse debit formula for "
+					"split \"%s\"." ),
+				     xaccSplitGetMemo( s ) );
+		    gnc_error_dialog( GTK_WIDGET(sxed->dialog), "%s",
+				      (gchar*)errStr->str );
+		    g_string_free( errStr, TRUE );
+
+		    return FALSE;
+		}
+		tcds->debitSum = gnc_numeric_add( tcds->debitSum, tmp, 100,
+						  (GNC_DENOM_AUTO | GNC_HOW_DENOM_LCD) );
+		tmp = gnc_numeric_zero();
             }
 
             g_hash_table_foreach (txns,
diff --git a/src/gnome/gnc-plugin-page-register2.c b/src/gnome/gnc-plugin-page-register2.c
index bfbbdc7..a6c7c91 100644
--- a/src/gnome/gnc-plugin-page-register2.c
+++ b/src/gnome/gnc-plugin-page-register2.c
@@ -3629,39 +3629,30 @@ gnc_plugin_page_register2_cmd_schedule (GtkAction *action,
     /* If the transaction has a sched-xact KVP frame, then go to the editor
      * for the existing SX; otherwise, do the sx-from-trans dialog. */
     {
-        kvp_frame *txn_frame;
-        kvp_value *kvp_val;
-        /* set a kvp-frame element in the transaction indicating and
-         * pointing-to the SX this was created from. */
-        txn_frame = xaccTransGetSlots (trans);
-        if ( txn_frame != NULL )
-        {
-            kvp_val = kvp_frame_get_slot (txn_frame, "from-sched-xaction");
-            if (kvp_val)
-            {
-                GncGUID *fromSXId = kvp_value_get_guid (kvp_val);
-                SchedXaction *theSX = NULL;
-                GList *sxElts;
-
-                /* Get the correct SX */
-                for ( sxElts = gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
-                        (!theSX) && sxElts;
-                        sxElts = sxElts->next )
-                {
-                    SchedXaction *sx = (SchedXaction*)sxElts->data;
-                    theSX =
-                        ((guid_equal (xaccSchedXactionGetGUID (sx), fromSXId))
-                          ? sx : NULL);
-                }
-
-                if (theSX)
-                {
-                    gnc_ui_scheduled_xaction_editor_dialog_create2 (theSX, FALSE);
-                    LEAVE(" ");
-                    return;
-                }
-            }
-        }
+	GncGUID *fromSXId;
+	SchedXaction *theSX = NULL;
+	GList *sxElts;
+	qof_instance_get (QOF_INSTANCE (trans),
+			  "from-sched-xaction", &fromSXId,
+			  NULL);
+
+	/* Get the correct SX */
+	for ( sxElts = gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
+	      (!theSX) && sxElts;
+	      sxElts = sxElts->next )
+	{
+	    SchedXaction *sx = (SchedXaction*)sxElts->data;
+	    theSX =
+		((guid_equal (xaccSchedXactionGetGUID (sx), fromSXId))
+		 ? sx : NULL);
+	}
+
+	if (theSX)
+	{
+	    gnc_ui_scheduled_xaction_editor_dialog_create2 (theSX, FALSE);
+	    LEAVE(" ");
+	    return;
+	}
     }
     gnc_sx_create_from_trans (trans);
     LEAVE(" ");
diff --git a/src/gnome/gnc-split-reg.c b/src/gnome/gnc-split-reg.c
index 0c66364..b1aef33 100644
--- a/src/gnome/gnc-split-reg.c
+++ b/src/gnome/gnc-split-reg.c
@@ -1204,38 +1204,29 @@ gsr_default_schedule_handler( GNCSplitReg *gsr, gpointer data )
     /* If the transaction has a sched-xact KVP frame, then go to the editor
      * for the existing SX; otherwise, do the sx-from-trans dialog. */
     {
-        kvp_frame *txn_frame;
-        kvp_value *kvp_val;
-        /* set a kvp-frame element in the transaction indicating and
-         * pointing-to the SX this was created from. */
-        txn_frame = xaccTransGetSlots( pending_trans );
-        if ( txn_frame != NULL )
-        {
-            kvp_val = kvp_frame_get_slot( txn_frame, "from-sched-xaction" );
-            if ( kvp_val )
-            {
-                GncGUID *fromSXId = kvp_value_get_guid( kvp_val );
-                SchedXaction *theSX = NULL;
-                GList *sxElts;
-
-                /* Get the correct SX */
-                for ( sxElts = gnc_book_get_schedxactions(gnc_get_current_book())->sx_list;
-                        (!theSX) && sxElts;
-                        sxElts = sxElts->next )
-                {
-                    SchedXaction *sx = (SchedXaction*)sxElts->data;
-                    theSX =
-                        ( ( guid_equal( xaccSchedXactionGetGUID( sx ), fromSXId ) )
-                          ? sx : NULL );
-                }
-
-                if ( theSX )
-                {
-                    gnc_ui_scheduled_xaction_editor_dialog_create(theSX, FALSE);
-                    return;
-                }
-            }
-        }
+	GncGUID *fromSXId;
+	SchedXaction *theSX = NULL;
+	GList *sxElts;
+	qof_instance_get (QOF_INSTANCE (pending_trans),
+			  "from-sched-xaction", &fromSXId,
+			  NULL);
+
+	/* Get the correct SX */
+	for ( sxElts = gnc_book_get_schedxactions (gnc_get_current_book())->sx_list;
+	      (!theSX) && sxElts;
+	      sxElts = sxElts->next )
+	{
+	    SchedXaction *sx = (SchedXaction*)sxElts->data;
+	    theSX =
+		((guid_equal (xaccSchedXactionGetGUID (sx), fromSXId))
+		 ? sx : NULL);
+	}
+
+	if ( theSX )
+	{
+	    gnc_ui_scheduled_xaction_editor_dialog_create(theSX, FALSE);
+	    return;
+	}
     }
 
     gnc_sx_create_from_trans(pending_trans);
diff --git a/src/register/ledger-core/split-register-model-save.c b/src/register/ledger-core/split-register-model-save.c
index 281477f..6d9ea63 100644
--- a/src/register/ledger-core/split-register-model-save.c
+++ b/src/register/ledger-core/split-register-model-save.c
@@ -674,10 +674,9 @@ gnc_template_register_save_xfrm_cell (BasicCell * cell,
     }
 
     acctGUID = xaccAccountGetGUID (acct);
-    kvpf = xaccSplitGetSlots (sd->split);
-    kvp_frame_set_slot_path (kvpf, kvp_value_new_guid(acctGUID),
-                             GNC_SX_ID, GNC_SX_ACCOUNT, NULL);
-
+    qof_instance_set (QOF_INSTANCE (sd->split),
+		      "sx-account", acctGUID,
+		      NULL);
     template_acc = xaccAccountLookup (&info->template_account,
                                       gnc_get_current_book ());
 
@@ -699,10 +698,9 @@ gnc_template_register_save_debcred_cell (BasicCell * cell,
 {
     SRSaveData *sd = save_data;
     SplitRegister *reg = user_data;
-    kvp_frame *kvpf;
-    const char *value;
+    const char *credit_formula, *debit_formula;
     char *error_loc;
-    gnc_numeric new_amount;
+    gnc_numeric credit_amount, debit_amount;
     gboolean parse_result;
 
     g_return_if_fail (gnc_basic_cell_has_name (cell, FDEBT_CELL) ||
@@ -711,54 +709,37 @@ gnc_template_register_save_debcred_cell (BasicCell * cell,
     if (sd->handled_dc)
         return;
 
-    kvpf = xaccSplitGetSlots (sd->split);
-
-    DEBUG ("kvp_frame before: %s\n", kvp_frame_to_string (kvpf));
-
     /* amountStr = gnc_numeric_to_string (new_amount); */
 
-    value = gnc_table_layout_get_cell_value (reg->table->layout, FCRED_CELL);
-    kvp_frame_set_slot_path (kvpf, kvp_value_new_string (value),
-                             GNC_SX_ID,
-                             GNC_SX_CREDIT_FORMULA,
-                             NULL);
-
+    credit_formula = gnc_table_layout_get_cell_value (reg->table->layout,
+						      FCRED_CELL);
     /* If the value can be parsed into a numeric result (without any
      * further variable definitions), store that numeric value
      * additionally in the kvp. Otherwise store a zero numeric
      * there.*/
-    parse_result = gnc_exp_parser_parse_separate_vars(value, &new_amount, &error_loc, NULL);
+    parse_result = gnc_exp_parser_parse_separate_vars(credit_formula,
+						      &credit_amount,
+						      &error_loc, NULL);
     if (!parse_result)
-    {
-        new_amount = gnc_numeric_zero();
-    }
-    kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_amount),
-                             GNC_SX_ID,
-                             GNC_SX_CREDIT_NUMERIC,
-                             NULL);
-
-    value = gnc_table_layout_get_cell_value (reg->table->layout, FDEBT_CELL);
+        credit_amount = gnc_numeric_zero();
 
-    kvp_frame_set_slot_path (kvpf,
-                             kvp_value_new_string (value),
-                             GNC_SX_ID,
-                             GNC_SX_DEBIT_FORMULA,
-                             NULL);
+    debit_formula = gnc_table_layout_get_cell_value (reg->table->layout,
+						     FDEBT_CELL);
 
     /* If the value can be parsed into a numeric result, store that
      * numeric value additionally. See above comment.*/
-    parse_result = gnc_exp_parser_parse_separate_vars(value, &new_amount, &error_loc, NULL);
+    parse_result = gnc_exp_parser_parse_separate_vars(debit_formula,
+						      &debit_amount,
+						      &error_loc, NULL);
     if (!parse_result)
-    {
-        new_amount = gnc_numeric_zero();
-    }
-    kvp_frame_set_slot_path (kvpf, kvp_value_new_numeric (new_amount),
-                             GNC_SX_ID,
-                             GNC_SX_DEBIT_NUMERIC,
-                             NULL);
-
-    DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));
-
+        debit_amount = gnc_numeric_zero();
+
+    qof_instance_set (QOF_INSTANCE (sd->split),
+		      "sx-credit-formula", credit_formula,
+		      "sx-credit-numeric", &credit_amount,
+		      "sx-debit-formula", debit_formula,
+		      "sx-debit-numeric", &debit_amount,
+		      NULL);
     /* set the amount to an innocuous value */
     xaccSplitSetValue (sd->split, gnc_numeric_create (0, 1));
 
@@ -771,24 +752,13 @@ gnc_template_register_save_shares_cell (BasicCell * cell,
                                         gpointer user_data)
 {
     SRSaveData *sd = save_data;
-    kvp_frame *kvpf;
     char *sharesStr = "(x + y)/42";
 
     g_return_if_fail (gnc_basic_cell_has_name (cell, SHRS_CELL));
-
-    kvpf = xaccSplitGetSlots (sd->split);
-
     /* FIXME: shares cells are numeric by definition. */
-    DEBUG ("kvp_frame before: %s\n", kvp_frame_to_string (kvpf));
-
-    /* sharesStr = gnc_numeric_to_string( sharesStr ); */
-    kvp_frame_set_slot_path (kvpf,
-                             kvp_value_new_string (sharesStr),
-                             GNC_SX_ID,
-                             GNC_SX_SHARES,
-                             NULL);
-
-    DEBUG ("kvp_frame  after: %s\n", kvp_frame_to_string (kvpf));
+    qof_instance_set (QOF_INSTANCE (sd->split),
+		      "sx-shares", sharesStr,
+		      NULL);
 
     /* set the shares to an innocuous value */
     xaccSplitSetSharePriceAndAmount (sd->split,
diff --git a/src/register/ledger-core/split-register-model.c b/src/register/ledger-core/split-register-model.c
index 859b20e..5294b40 100644
--- a/src/register/ledger-core/split-register-model.c
+++ b/src/register/ledger-core/split-register-model.c
@@ -2095,31 +2095,23 @@ gnc_template_register_get_xfrm_entry (VirtualLocation virt_loc,
     static char *name = NULL;
 
     SplitRegister *reg = user_data;
-    kvp_frame *kvpf;
     Split *split;
+    Account *account;
+    GncGUID *guid;
 
     split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
     if (!split)
         return NULL;
-
-    kvpf = xaccSplitGetSlots (split);
-
+    /* Caller either uses the return as a temporary in a boolean
+     * expression or g_strdups it, so we keep it static and free the
+     * old one on every call to avoid leaks. Ugly, but it works.
+     */
     g_free (name);
-
-    if (kvpf)
-    {
-        Account *account;
-        GncGUID *guid;
-
-        guid = kvp_value_get_guid(
-                   kvp_frame_get_slot_path(kvpf, "sched-xaction", "account", NULL));
-
-        account = xaccAccountLookup (guid, gnc_get_current_book ());
-
-        name = account ? gnc_get_account_name_for_register (account) : NULL;
-    }
-    else
-        name = NULL;
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-account", &guid,
+		      NULL);
+    account = xaccAccountLookup (guid, gnc_get_current_book ());
+    name = account ? gnc_get_account_name_for_register (account) : NULL;
 
     return name;
 }
@@ -2132,10 +2124,13 @@ gnc_template_register_get_fdebt_entry (VirtualLocation virt_loc,
 {
     SplitRegister *reg = user_data;
     Split *split = gnc_split_register_get_split(reg, virt_loc.vcell_loc);
-    kvp_frame *kvpf = xaccSplitGetSlots(split);
+    char *formula;
+
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-debit-formula", &formula,
+		      NULL);
 
-    return kvp_value_get_string(
-               kvp_frame_get_slot_path (kvpf, "sched-xaction", "debit-formula", NULL));
+    return formula;
 }
 
 static char *
@@ -2159,14 +2154,15 @@ gnc_template_register_get_fcred_entry (VirtualLocation virt_loc,
                                        gpointer user_data)
 {
     SplitRegister *reg = user_data;
-    kvp_frame *kvpf;
-    Split *split;
+    Split *split = gnc_split_register_get_split(reg, virt_loc.vcell_loc);
+    char *formula;
 
-    split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
-    kvpf = xaccSplitGetSlots (split);
+    qof_instance_get (QOF_INSTANCE (split),
+		      "sx-credit-formula", &formula,
+		      NULL);
+
+    return formula;
 
-    return kvp_value_get_string(
-               kvp_frame_get_slot_path (kvpf, "sched-xaction", "credit-formula", NULL));
 }
 
 static char *
@@ -2198,8 +2194,13 @@ gnc_template_register_get_debcred_entry (VirtualLocation virt_loc,
         gboolean *conditionally_changed,
         gpointer user_data)
 {
+    PERR("The function called always returned either NULL or an empty string "
+	 "while issuing dire warnings about how incorrect it is. That code "
+	 "has been removed and the function if called raises this error and "
+	 "returns NULL");
+    return NULL;
+#if 0
     SplitRegister *reg = user_data;
-    kvp_frame *kvpf;
     Split *split;
 
     split = gnc_split_register_get_split (reg, virt_loc.vcell_loc);
@@ -2245,6 +2246,7 @@ gnc_template_register_get_debcred_entry (VirtualLocation virt_loc,
     }
 
     return NULL;
+#endif
 }
 
 static void

commit db1b2caebf2ffc3c82c8c244ad749293b9102acc
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 14:23:15 2013 -0700

    Add GncOwner kvp properties
    
    export-pdf-dir, invoice-last-posted-account, payment-last-account
    
    Since GncOwner isn't in the class hierarchy these properties must be implemented exactly alike in the three classes where they're appropriate.

diff --git a/src/engine/gncCustomer.c b/src/engine/gncCustomer.c
index 2336cd6..0c95d4c 100644
--- a/src/engine/gncCustomer.c
+++ b/src/engine/gncCustomer.c
@@ -97,7 +97,10 @@ void mark_customer (GncCustomer *customer)
 enum
 {
     PROP_0,
-    PROP_NAME
+    PROP_NAME,
+    PROP_PDF_DIRNAME,
+    PROP_LAST_POSTED,
+    PROP_PAYMENT_LAST_ACCT,
 };
 
 /* GObject Initialization */
@@ -127,7 +130,7 @@ gnc_customer_get_property (GObject         *object,
                            GParamSpec      *pspec)
 {
     GncCustomer *cust;
-
+    gchar *key;
     g_return_if_fail(GNC_IS_CUSTOMER(object));
 
     cust = GNC_CUSTOMER(object);
@@ -136,6 +139,18 @@ gnc_customer_get_property (GObject         *object,
     case PROP_NAME:
         g_value_set_string(value, cust->name);
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -145,10 +160,11 @@ gnc_customer_get_property (GObject         *object,
 static void
 gnc_customer_set_property (GObject         *object,
                            guint            prop_id,
-                           const GValue          *value,
+                           const GValue    *value,
                            GParamSpec      *pspec)
 {
     GncCustomer *cust;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_CUSTOMER(object));
 
@@ -158,6 +174,18 @@ gnc_customer_set_property (GObject         *object,
     case PROP_NAME:
         gncCustomerSetName(cust, g_value_get_string(value));
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -243,6 +271,39 @@ gnc_customer_class_init (GncCustomerClass *klass)
                           "customer name.",
                           NULL,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_PDF_DIRNAME,
+     g_param_spec_string ("export-pdf-dir",
+                          "Export PDF Directory Name",
+                          "A subdirectory for exporting PDF reports which is "
+			  "appended to the target directory when writing them "
+			  "out. It is retrieved from preferences and stored on "
+			  "each 'Owner' object which prints items after "
+			  "printing.",
+                          NULL,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_LAST_POSTED,
+       g_param_spec_boxed("invoice-last-posted-account",
+			  "Invoice Last Posted Account",
+			  "The last account to which an invoice belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_PAYMENT_LAST_ACCT,
+       g_param_spec_boxed("payment-last-account",
+			  "Payment Last Account",
+			  "The last account to which an payment belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
 }
 
 /* Create/Destroy Functions */
diff --git a/src/engine/gncEmployee.c b/src/engine/gncEmployee.c
index 46c3e40..299c249 100644
--- a/src/engine/gncEmployee.c
+++ b/src/engine/gncEmployee.c
@@ -89,7 +89,10 @@ enum
     PROP_ADDRESS,
     PROP_WORKDAY,
     PROP_RATE,
-    PROP_CCARD
+    PROP_CCARD,
+    PROP_PDF_DIRNAME,
+    PROP_LAST_POSTED,
+    PROP_PAYMENT_LAST_ACCT,
 };
 
 /* GObject Initialization */
@@ -125,6 +128,7 @@ gnc_employee_get_property (GObject         *object,
                            GParamSpec      *pspec)
 {
     GncEmployee *emp;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_EMPLOYEE(object));
 
@@ -161,6 +165,18 @@ gnc_employee_get_property (GObject         *object,
     case PROP_CCARD:
         g_value_take_object(value, emp->ccard_acc);
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -174,6 +190,7 @@ gnc_employee_set_property (GObject         *object,
                            GParamSpec      *pspec)
 {
     GncEmployee *emp;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_EMPLOYEE(object));
 
@@ -210,6 +227,18 @@ gnc_employee_set_property (GObject         *object,
     case PROP_CCARD:
         gncEmployeeSetCCard(emp, g_value_get_object(value));
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -368,6 +397,39 @@ gnc_employee_class_init (GncEmployeeClass *klass)
                           "The credit card account for this employee.",
                           GNC_TYPE_ACCOUNT,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_PDF_DIRNAME,
+     g_param_spec_string ("export-pdf-dir",
+                          "Export PDF Directory Name",
+                          "A subdirectory for exporting PDF reports which is "
+			  "appended to the target directory when writing them "
+			  "out. It is retrieved from preferences and stored on "
+			  "each 'Owner' object which prints items after "
+			  "printing.",
+                          NULL,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_LAST_POSTED,
+       g_param_spec_boxed("invoice-last-posted-account",
+			  "Invoice Last Posted Account",
+			  "The last account to which an invoice belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_PAYMENT_LAST_ACCT,
+       g_param_spec_boxed("payment-last-account",
+			  "Payment Last Account",
+			  "The last account to which an payment belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
 }
 
 /* Create/Destroy Functions */
diff --git a/src/engine/gncJob.c b/src/engine/gncJob.c
index e65eca6..8e5c2ea 100644
--- a/src/engine/gncJob.c
+++ b/src/engine/gncJob.c
@@ -71,7 +71,8 @@ void mark_job (GncJob *job)
 enum
 {
     PROP_0,
-    PROP_NAME
+    PROP_NAME,
+    PROP_PDF_DIRNAME,
 };
 
 /* GObject Initialization */
@@ -101,6 +102,7 @@ gnc_job_get_property (GObject         *object,
                       GParamSpec      *pspec)
 {
     GncJob *job;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_JOB(object));
 
@@ -110,6 +112,10 @@ gnc_job_get_property (GObject         *object,
     case PROP_NAME:
         g_value_set_string(value, job->name);
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_get_kvp (QOF_INSTANCE (job), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -123,6 +129,7 @@ gnc_job_set_property (GObject         *object,
                       GParamSpec      *pspec)
 {
     GncJob *job;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_JOB(object));
 
@@ -132,6 +139,10 @@ gnc_job_set_property (GObject         *object,
     case PROP_NAME:
         gncJobSetName(job, g_value_get_string(value));
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_set_kvp (QOF_INSTANCE (job), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -177,6 +188,19 @@ gnc_job_class_init (GncJobClass *klass)
                           "by the GUI as the job mnemonic.",
                           NULL,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_PDF_DIRNAME,
+     g_param_spec_string ("export-pdf-dir",
+                          "Export PDF Directory Name",
+                          "A subdirectory for exporting PDF reports which is "
+			  "appended to the target directory when writing them "
+			  "out. It is retrieved from preferences and stored on "
+			  "each 'Owner' object which prints items after "
+			  "printing.",
+                          NULL,
+                          G_PARAM_READWRITE));
 }
 
 /* Create/Destroy Functions */
diff --git a/src/engine/gncVendor.c b/src/engine/gncVendor.c
index a57124c..c031625 100644
--- a/src/engine/gncVendor.c
+++ b/src/engine/gncVendor.c
@@ -99,7 +99,10 @@ enum
     PROP_TAXTABLE,
     PROP_ADDRESS,
     PROP_TAX_INCLUDED,
-    PROP_TAX_INCLUDED_STR
+    PROP_TAX_INCLUDED_STR,
+    PROP_PDF_DIRNAME,
+    PROP_LAST_POSTED,
+    PROP_PAYMENT_LAST_ACCT,
 };
 
 /* GObject Initialization */
@@ -135,6 +138,7 @@ gnc_vendor_get_property (GObject         *object,
                          GParamSpec      *pspec)
 {
     GncVendor *vendor;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_VENDOR(object));
 
@@ -174,6 +178,18 @@ gnc_vendor_get_property (GObject         *object,
     case PROP_TAX_INCLUDED_STR:
         g_value_set_string(value, qofVendorGetTaxIncluded(vendor));
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -187,6 +203,7 @@ gnc_vendor_set_property (GObject         *object,
                          GParamSpec      *pspec)
 {
     GncVendor *vendor;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_VENDOR(object));
 
@@ -226,6 +243,18 @@ gnc_vendor_set_property (GObject         *object,
     case PROP_TAX_INCLUDED_STR:
         qofVendorSetTaxIncluded(vendor, g_value_get_string(value));
         break;
+    case PROP_PDF_DIRNAME:
+	key = OWNER_EXPORT_PDF_DIRNAME;
+	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
+    case PROP_LAST_POSTED:
+	key = LAST_POSTED_TO_ACCT;
+	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
+    case PROP_PAYMENT_LAST_ACCT:
+	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
+	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -391,6 +420,38 @@ gnc_vendor_class_init (GncVendorClass *klass)
                          "The tax-included-string property contains a character version of tax-included.",
                          FALSE,
                          G_PARAM_READWRITE));
+    g_object_class_install_property
+    (gobject_class,
+     PROP_PDF_DIRNAME,
+     g_param_spec_string ("export-pdf-dir",
+                          "Export PDF Directory Name",
+                          "A subdirectory for exporting PDF reports which is "
+			  "appended to the target directory when writing them "
+			  "out. It is retrieved from preferences and stored on "
+			  "each 'Owner' object which prints items after "
+			  "printing.",
+                          NULL,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_LAST_POSTED,
+       g_param_spec_boxed("invoice-last-posted-account",
+			  "Invoice Last Posted Account",
+			  "The last account to which an invoice belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
+
+    g_object_class_install_property(
+       gobject_class,
+       PROP_PAYMENT_LAST_ACCT,
+       g_param_spec_boxed("payment-last-account",
+			  "Payment Last Account",
+			  "The last account to which an payment belonging to "
+			  "this owner was posted.",
+			  GNC_TYPE_GUID,
+			  G_PARAM_READWRITE));
 }
 
 /* Create/Destroy Functions */
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index e6d9176..a763c89 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -94,6 +94,34 @@ setup_lot (Fixture *fixture, gconstpointer pData)
 }
 
 static void
+setup_customer (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->cust = gncCustomerCreate (book);
+}
+
+static void
+setup_employee (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->emp = gncEmployeeCreate (book);
+}
+
+static void
+setup_job (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->job = gncJobCreate (book);
+}
+
+static void
+setup_vendor (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->vend = gncVendorCreate (book);
+}
+
+static void
 teardown (Fixture *fixture, gconstpointer pData)
 {
 /* It doesn't actually matter which union member we use here, they're
@@ -275,10 +303,141 @@ test_lot_kvp_properties (Fixture *fixture, gconstpointer pData)
     guid_free (owner_r);
 }
 
+static void
+test_customer_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gchar *pdf_dir = "/foo/bar/baz";
+    gchar *pdf_dir_r;
+    GncGUID *inv_acct = guid_malloc ();
+    GncGUID *pmt_acct = guid_malloc ();
+    GncGUID *inv_acct_r, *pmt_acct_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->cust),
+		      "export-pdf-dir", pdf_dir,
+		      "invoice-last-posted-account", inv_acct,
+		      "payment-last-account", pmt_acct,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->cust)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->cust));
+
+    qof_instance_get (QOF_INSTANCE (fixture->cust),
+		      "export-pdf-dir", &pdf_dir_r,
+		      "invoice-last-posted-account", &inv_acct_r,
+		      "payment-last-account", &pmt_acct_r,
+		      NULL);
+
+    g_assert_cmpstr (pdf_dir, ==, pdf_dir_r);
+    g_assert (guid_equal (inv_acct, inv_acct_r));
+    g_assert (guid_equal (pmt_acct, pmt_acct_r));
+    guid_free (inv_acct);
+    guid_free (inv_acct_r);
+    guid_free (pmt_acct);
+    guid_free (pmt_acct_r);
+    g_free (pdf_dir_r);
+
+}
+
+static void
+test_employee_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gchar *pdf_dir = "/foo/bar/baz";
+    gchar *pdf_dir_r;
+    GncGUID *inv_acct = guid_malloc ();
+    GncGUID *pmt_acct = guid_malloc ();
+    GncGUID *inv_acct_r, *pmt_acct_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->emp),
+		      "export-pdf-dir", pdf_dir,
+		      "invoice-last-posted-account", inv_acct,
+		      "payment-last-account", pmt_acct,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->emp)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->emp));
+
+    qof_instance_get (QOF_INSTANCE (fixture->emp),
+		      "export-pdf-dir", &pdf_dir_r,
+		      "invoice-last-posted-account", &inv_acct_r,
+		      "payment-last-account", &pmt_acct_r,
+		      NULL);
+
+    g_assert_cmpstr (pdf_dir, ==, pdf_dir_r);
+    g_assert (guid_equal (inv_acct, inv_acct_r));
+    g_assert (guid_equal (pmt_acct, pmt_acct_r));
+    guid_free (inv_acct);
+    guid_free (inv_acct_r);
+    guid_free (pmt_acct);
+    guid_free (pmt_acct_r);
+    g_free (pdf_dir_r);
+
+}
+
+static void
+test_job_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gchar *pdf_dir = "/foo/bar/baz";
+    gchar *pdf_dir_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->job),
+		      "export-pdf-dir", pdf_dir,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->job)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->job));
+
+    qof_instance_get (QOF_INSTANCE (fixture->job),
+		      "export-pdf-dir", &pdf_dir_r,
+		      NULL);
+
+    g_assert_cmpstr (pdf_dir, ==, pdf_dir_r);
+    g_free (pdf_dir_r);
+
+}
+
+static void
+test_vendor_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gchar *pdf_dir = "/foo/bar/baz";
+    gchar *pdf_dir_r;
+    GncGUID *inv_acct = guid_malloc ();
+    GncGUID *pmt_acct = guid_malloc ();
+    GncGUID *inv_acct_r, *pmt_acct_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->vend),
+		      "export-pdf-dir", pdf_dir,
+		      "invoice-last-posted-account", inv_acct,
+		      "payment-last-account", pmt_acct,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->vend)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->vend));
+
+    qof_instance_get (QOF_INSTANCE (fixture->vend),
+		      "export-pdf-dir", &pdf_dir_r,
+		      "invoice-last-posted-account", &inv_acct_r,
+		      "payment-last-account", &pmt_acct_r,
+		      NULL);
+
+    g_assert_cmpstr (pdf_dir, ==, pdf_dir_r);
+    g_assert (guid_equal (inv_acct, inv_acct_r));
+    g_assert (guid_equal (pmt_acct, pmt_acct_r));
+    guid_free (inv_acct);
+    guid_free (inv_acct_r);
+    guid_free (pmt_acct);
+    guid_free (pmt_acct_r);
+    g_free (pdf_dir_r);
+
+}
+
 void test_suite_engine_kvp_properties (void)
 {
     GNC_TEST_ADD (suitename, "Account", Fixture, NULL, setup_account, test_account_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Transaction", Fixture, NULL, setup_trans, test_trans_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Split", Fixture, NULL, setup_split, test_split_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Lot", Fixture, NULL, setup_lot, test_lot_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Customer", Fixture, NULL, setup_customer, test_customer_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Employee", Fixture, NULL, setup_employee, test_employee_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Job", Fixture, NULL, setup_job, test_job_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Vendor", Fixture, NULL, setup_vendor, test_vendor_kvp_properties, teardown);
 }

commit 2ff48a66a599999cb754c9d4956e36605b0da467
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 14:00:21 2013 -0700

    Add Transaction kvp properties from-sched-xaction, online-id.

diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index 5ca1e5c..da3947e 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -183,6 +183,7 @@ const char *trans_is_closing_str = "book_closing";
 #define TRANS_TXN_TYPE_KVP       "trans-txn-type"
 #define TRANS_READ_ONLY_REASON   "trans-read-only"
 #define TRANS_REVERSED_BY        "reversed-by"
+#define GNC_SX_FROM              "from-sched-xaction"
 
 #define ISO_DATELENGTH 32 /* length of an iso 8601 date string. */
 
@@ -198,6 +199,8 @@ enum
     PROP_POST_DATE,
     PROP_ENTER_DATE,
     PROP_INVOICE,
+    PROP_SX_TXN,
+    PROP_ONLINE_ACCOUNT,
 };
 
 void
@@ -331,6 +334,14 @@ gnc_transaction_get_property(GObject* object,
 	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
 	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
 	break;
+    case PROP_SX_TXN:
+	key = GNC_SX_FROM;
+	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
+	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -371,6 +382,14 @@ gnc_transaction_set_property(GObject* object,
 	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
 	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
 	break;
+    case PROP_SX_TXN:
+	key = GNC_SX_FROM;
+	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
+	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -448,6 +467,27 @@ gnc_transaction_class_init(TransactionClass* klass)
 			   "Used by GncInvoice",
 			   GNC_TYPE_GUID,
 			   G_PARAM_READWRITE));
+
+     g_object_class_install_property(
+       gobject_class,
+        PROP_SX_TXN,
+        g_param_spec_boxed("from-sched-xaction",
+			   "From Scheduled Transaction",
+			   "Used by Scheduled Transastions to record the "
+			   "originating template transaction for created "
+			   "transactions",
+			   GNC_TYPE_GUID,
+			   G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_ONLINE_ACCOUNT,
+     g_param_spec_string ("online-id",
+                          "Online Account ID",
+                          "The online account which corresponds to this "
+			  "account for OFX/HCBI import",
+                          NULL,
+                          G_PARAM_READWRITE));
 }
 
 /********************************************************************\
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index b71b8e5..e6d9176 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -155,23 +155,35 @@ test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
 static void
 test_trans_kvp_properties (Fixture *fixture, gconstpointer pData)
 {
-    GncGUID *guid = guid_malloc ();
-    GncGUID *guid_r;
+    GncGUID *invoice = guid_malloc ();
+    GncGUID *from_sx = guid_malloc ();
+    GncGUID *invoice_r, *from_sx_r;
+    gchar *online_id = "my online id";
+    gchar *online_id_r;
 
     qof_instance_set (QOF_INSTANCE (fixture->trans),
-		      "invoice", guid,
+		      "invoice", invoice,
+		      "from-sched-xaction", from_sx,
+		      "online-id", online_id,
 		      NULL);
 
     g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->trans)));
     qof_instance_mark_clean (QOF_INSTANCE (fixture->trans));
 
     qof_instance_get (QOF_INSTANCE (fixture->trans),
-		      "invoice", &guid_r,
+		      "invoice", &invoice_r,
+		      "from-sched-xaction", &from_sx_r,
+		      "online-id", &online_id_r,
 		      NULL);
-    g_assert (guid_equal (guid, guid_r));
+    g_assert (guid_equal (invoice, invoice_r));
+    g_assert (guid_equal (from_sx, from_sx_r));
+    g_assert_cmpstr (online_id, ==, online_id_r);
     g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->trans)));
-    guid_free (guid);
-    guid_free (guid_r);
+    guid_free (invoice);
+    guid_free (invoice_r);
+    guid_free (from_sx);
+    guid_free (from_sx_r);
+    g_free (online_id_r);
 }
 
 static void

commit d2d0f6290a31ce3e22d8c330029f6011a24f9d9c
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 13:50:58 2013 -0700

    Add several kvp properties to Account
    
    online-id, ofd-income-account, an-account-id, an-bank-code, ab-account-uid, ab-trans-retrieval

diff --git a/src/engine/Account.c b/src/engine/Account.c
index 82650bd..4324957 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -45,6 +45,13 @@ static QofLogModule log_module = GNC_MOD_ACCOUNT;
 /* The Canonical Account Separator.  Pre-Initialized. */
 static gchar account_separator[8] = ".";
 static gunichar account_uc_separator = ':';
+/* Predefined KVP paths */
+static const char *KEY_ASSOC_INCOME_ACCOUNT = "ofx/associated-income-account";
+#define AB_KEY "hbci"
+#define AB_ACCOUNT_ID "account-id"
+#define AB_ACCOUNT_UID "account-uid"
+#define AB_BANK_CODE "bank-code"
+#define AB_TRANS_RETRIEVAL "trans-retrieval"
 
 enum
 {
@@ -87,6 +94,12 @@ enum
     PROP_SORT_ORDER,
 
     PROP_LOT_NEXT_ID,
+    PROP_ONLINE_ACCOUNT,
+    PROP_OFX_INCOME_ACCOUNT,
+    PROP_AB_ACCOUNT_ID,
+    PROP_AB_ACCOUNT_UID,
+    PROP_AB_BANK_CODE,
+    PROP_AB_TRANS_RETRIEVAL,
 };
 
 #define GET_PRIVATE(o)  \
@@ -388,6 +401,30 @@ gnc_account_get_property (GObject         *object,
 	g_value_set_int64 (value, 0);
 	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
 	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_OFX_INCOME_ACCOUNT:
+	key = KEY_ASSOC_INCOME_ACCOUNT;
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_ACCOUNT_ID:
+	key = AB_KEY "/" AB_ACCOUNT_ID;
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_ACCOUNT_UID:
+	key = AB_KEY "/" AB_ACCOUNT_UID;
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_BANK_CODE:
+	key = AB_KEY "/" AB_BANK_CODE;
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_TRANS_RETRIEVAL:
+	key = AB_KEY "/" AB_TRANS_RETRIEVAL;
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -402,7 +439,7 @@ gnc_account_set_property (GObject         *object,
 {
     Account *account;
     gnc_numeric *number;
-    gchar *key = NULL;
+    const gchar *key = NULL;
 
     g_return_if_fail(GNC_IS_ACCOUNT(object));
 
@@ -492,6 +529,30 @@ gnc_account_set_property (GObject         *object,
 	key = "lot-mgmt/next-id";
 	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
 	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_OFX_INCOME_ACCOUNT:
+	key = KEY_ASSOC_INCOME_ACCOUNT;
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_ACCOUNT_ID:
+	key = AB_KEY "/" AB_ACCOUNT_ID;
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_ACCOUNT_UID:
+	key = AB_KEY "/" AB_ACCOUNT_UID;
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_BANK_CODE:
+	key = AB_KEY "/" AB_BANK_CODE;
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
+    case PROP_AB_TRANS_RETRIEVAL:
+	key = AB_KEY "/" AB_TRANS_RETRIEVAL;
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -860,6 +921,66 @@ gnc_account_class_init (AccountClass *klass)
                          G_MAXINT64,
                          (gint64)1,
                          G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_ONLINE_ACCOUNT,
+     g_param_spec_string ("online-id",
+                          "Online Account ID",
+                          "The online account which corresponds to this "
+			  "account for OFX import",
+                          NULL,
+                          G_PARAM_READWRITE));
+
+     g_object_class_install_property(
+       gobject_class,
+       PROP_OFX_INCOME_ACCOUNT,
+        g_param_spec_boxed("ofx-income-account",
+			   "Associated income account",
+			   "Used by the OFX importer.",
+			   GNC_TYPE_GUID,
+			   G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_AB_ACCOUNT_ID,
+     g_param_spec_string ("ab-account-id",
+                          "AQBanking Account ID",
+                          "The AqBanking account which corresponds to this "
+			  "account for AQBanking import",
+                          NULL,
+                          G_PARAM_READWRITE));
+    g_object_class_install_property
+    (gobject_class,
+     PROP_AB_BANK_CODE,
+     g_param_spec_string ("ab-bank-code",
+                          "AQBanking Bank Code",
+                          "The online account which corresponds to this "
+			  "account for AQBanking import",
+                          NULL,
+                          G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_AB_ACCOUNT_UID,
+     g_param_spec_int64 ("ab-account-uid",
+                         "AQBanking Account UID",
+                         "Tracks the next id to use in gnc_lot_make_default.",
+                         (gint64)1,
+                         G_MAXINT64,
+                         (gint64)1,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_AB_TRANS_RETRIEVAL,
+     g_param_spec_boxed("ab-trans-retrieval",
+                        "AQBanking Last Transaction Retrieval",
+                        "The time of the last transaction retrieval for this "
+			"account.",
+                        GNC_TYPE_TIMESPEC,
+                        G_PARAM_READWRITE));
+
 }
 
 static void
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index 861531f..b71b8e5 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -108,10 +108,26 @@ static void
 test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
 {
     gint64 next_id = 12345678909876;
-    gint64 next_id_r;
+    gint64 ab_acct_uid = 67890987654321;
+    gint64 next_id_r, ab_acct_uid_r;
+    gchar *online_id = "my online id";
+    gchar *ab_acct_id = "1234-5678-9087";
+    gchar *ab_bank_code = "0032340";
+    gchar *online_id_r, *ab_acct_id_r, *ab_bank_code_r;
+    GncGUID *ofx_income_acct = guid_malloc ();
+    GncGUID *ofx_income_acct_r;
+    Timespec trans_retr = timespec_now ();
+    Timespec *trans_retr_r;
+
 
     qof_instance_set (QOF_INSTANCE (fixture->acct),
 		      "lot-next-id", next_id,
+		      "online-id", online_id,
+		      "ofx-income-account", ofx_income_acct,
+		      "ab-account-id", ab_acct_id,
+		      "ab-bank-code", ab_bank_code,
+		      "ab-account-uid", ab_acct_uid,
+		      "ab-trans-retrieval", &trans_retr,
 		      NULL);
 
     g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->acct)));
@@ -119,8 +135,20 @@ test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
 
     qof_instance_get (QOF_INSTANCE (fixture->acct),
 		      "lot-next-id", &next_id_r,
+		      "online-id", &online_id_r,
+		      "ofx-income-account", &ofx_income_acct_r,
+		      "ab-account-id", &ab_acct_id_r,
+		      "ab-bank-code", &ab_bank_code_r,
+		      "ab-account-uid", &ab_acct_uid_r,
+		      "ab-trans-retrieval", &trans_retr_r,
 		      NULL);
     g_assert_cmpint (next_id, ==, next_id_r);
+    g_assert_cmpstr (online_id, ==, online_id_r);
+    g_assert (guid_equal (ofx_income_acct, ofx_income_acct_r));
+    g_assert_cmpstr (ab_acct_id, ==, ab_acct_id_r);
+    g_assert_cmpstr (ab_bank_code, ==, ab_bank_code_r);
+    g_assert_cmpint (ab_acct_uid, ==, ab_acct_uid_r);
+    g_assert (timespec_equal (&trans_retr, trans_retr_r));
     g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->acct)));
 }
 

commit e5e386d6b14dc7bf9366045c45094760a2753a67
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon Oct 21 13:10:14 2013 -0700

    Add kvp properties sx-credit-numeric, sx-debit-numeric, ax-shares, and online-id to Split.

diff --git a/src/engine/Split.c b/src/engine/Split.c
index 47d2d20..9107e7a 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -66,6 +66,9 @@ static QofLogModule log_module = GNC_MOD_ENGINE;
 #define GNC_SX_ACCOUNT               "account"
 #define GNC_SX_CREDIT_FORMULA        "credit-formula"
 #define GNC_SX_DEBIT_FORMULA         "debit-formula"
+#define GNC_SX_CREDIT_NUMERIC        "credit-numeric"
+#define GNC_SX_DEBIT_NUMERIC         "debit-numeric"
+#define GNC_SX_SHARES                "shares"
 
 enum
 {
@@ -77,10 +80,14 @@ enum
     PROP_RECONCILE_DATE,
     PROP_TX,
     PROP_ACCOUNT,
+    PROP_SX_ACCOUNT,
     PROP_SX_CREDIT_FORMULA,
+    PROP_SX_CREDIT_NUMERIC,
     PROP_SX_DEBIT_FORMULA,
-    PROP_SX_ACCOUNT,
+    PROP_SX_DEBIT_NUMERIC,
+    PROP_SX_SHARES,
     PROP_LOT,
+    PROP_ONLINE_ACCOUNT,
 };
 
 /* GObject Initialization */
@@ -171,14 +178,30 @@ gnc_split_get_property(GObject         *object,
 	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
 	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_CREDIT_NUMERIC:
+	key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
     case PROP_SX_DEBIT_FORMULA:
 	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
 	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_DEBIT_NUMERIC:
+	key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
     case PROP_SX_ACCOUNT:
 	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
 	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_SHARES:
+	key = GNC_SX_ID "/" GNC_SX_SHARES;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -230,14 +253,30 @@ gnc_split_set_property(GObject         *object,
 	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
 	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_CREDIT_NUMERIC:
+	key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
     case PROP_SX_DEBIT_FORMULA:
 	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
 	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_DEBIT_NUMERIC:
+	key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
     case PROP_SX_ACCOUNT:
 	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
 	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
 	break;
+    case PROP_SX_SHARES:
+	key = GNC_SX_ID "/" GNC_SX_SHARES;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_ONLINE_ACCOUNT:
+	key = "online_id";
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
      default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -338,7 +377,7 @@ gnc_split_class_init(SplitClass* klass)
 
     g_object_class_install_property
     (gobject_class,
-     PROP_MEMO,
+     PROP_SX_DEBIT_FORMULA,
      g_param_spec_string("sx-debit-formula",
                          "Schedule Transaction Debit Formula",
 			 "The formula used to calculate the actual debit "
@@ -349,7 +388,17 @@ gnc_split_class_init(SplitClass* klass)
 
     g_object_class_install_property
     (gobject_class,
-     PROP_MEMO,
+     PROP_SX_DEBIT_NUMERIC,
+     g_param_spec_boxed("sx-debit-numeric",
+                        "Scheduled Transaction Debit Numeric",
+                        "Numeric value to plug into the Debit Formula when a "
+			"real split is generated from this SX split.",
+                        GNC_TYPE_NUMERIC,
+                        G_PARAM_READWRITE));
+
+     g_object_class_install_property
+    (gobject_class,
+     PROP_SX_CREDIT_FORMULA,
      g_param_spec_string("sx-credit-formula",
                          "Schedule Transaction Credit Formula",
 			 "The formula used to calculate the actual credit "
@@ -360,12 +409,46 @@ gnc_split_class_init(SplitClass* klass)
 
     g_object_class_install_property
     (gobject_class,
+     PROP_SX_CREDIT_NUMERIC,
+     g_param_spec_boxed("sx-credit-numeric",
+                        "Scheduled Transaction Credit Numeric",
+                        "Numeric value to plug into the Credit Formula when a "
+			"real split is generated from this SX split.",
+                        GNC_TYPE_NUMERIC,
+                        G_PARAM_READWRITE));
+/* FIXME: PROP_SX_SHARES should be stored as a gnc_numeric, but the function
+ * which uses it, gnc_template_register_save_shares_cell, stores a
+ * phony string. This is maintained until backwards compatibility can
+ * be established.
+ */
+    g_object_class_install_property
+    (gobject_class,
+     PROP_SX_SHARES,
+     g_param_spec_string("sx-shares",
+                        "Scheduled Transaction Shares",
+                        "Numeric value of shares to insert in a new split when "
+			"it's generated from this SX split.",
+                        NULL,
+                        G_PARAM_READWRITE));
+
+     g_object_class_install_property
+    (gobject_class,
      PROP_SX_ACCOUNT,
      g_param_spec_boxed("sx-account",
                         "Scheduled Transaction Account",
                         "The target account for a scheduled transaction split.",
                         GNC_TYPE_GUID,
                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_ONLINE_ACCOUNT,
+     g_param_spec_string ("online-id",
+                          "Online Account ID",
+                          "The online account which corresponds to this "
+			  "account for OFX/HCBI import",
+                          NULL,
+                          G_PARAM_READWRITE));
 }
 
 /********************************************************************\
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index 509bafc..861531f 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -151,14 +151,24 @@ test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
 {
     gchar *debit_formula = "e^xdydx";
     gchar *credit_formula = "seccostansin";
-    gchar *debit_formula_r, *credit_formula_r;
+    gchar *sx_shares = "43";
+    gchar *online_id = "my_online_id";
+    gchar *debit_formula_r, *credit_formula_r, *sx_shares_r;
+    gchar *online_id_r;
     GncGUID *sx_account = guid_malloc ();
     GncGUID *sx_account_r;
+    gnc_numeric debit_numeric = gnc_numeric_create (123, 456);
+    gnc_numeric credit_numeric = gnc_numeric_create (789, 456);
+    gnc_numeric *debit_numeric_r, *credit_numeric_r;
 
     qof_instance_set (QOF_INSTANCE (fixture->split),
 		      "sx-debit-formula", debit_formula,
+		      "sx-debit-numeric", &debit_numeric,
 		      "sx-credit-formula", credit_formula,
+		      "sx-credit-numeric", &credit_numeric,
 		      "sx-account", sx_account,
+		      "sx-shares", sx_shares,
+		      "online-id", online_id,
 		      NULL);
 
     g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
@@ -166,15 +176,27 @@ test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
 
     qof_instance_get (QOF_INSTANCE (fixture->split),
 		      "sx-debit-formula", &debit_formula_r,
+		      "sx-debit-numeric", &debit_numeric_r,
 		      "sx-credit-formula", &credit_formula_r,
+		      "sx-credit-numeric", &credit_numeric_r,
 		      "sx-account", &sx_account_r,
+		      "sx-shares", &sx_shares_r,
+		      "online-id", &online_id_r,
 		      NULL);
     g_assert_cmpstr (debit_formula, ==, debit_formula_r);
+    g_assert (gnc_numeric_equal (debit_numeric, *debit_numeric_r));
     g_assert_cmpstr (credit_formula, ==, credit_formula_r);
+    g_assert (gnc_numeric_equal (credit_numeric, *credit_numeric_r));
     g_assert (guid_equal (sx_account, sx_account_r));
+    g_assert_cmpstr (sx_shares, ==, sx_shares_r);
+    g_assert_cmpstr (online_id, ==, online_id_r);
     g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
     g_free (debit_formula_r);
+    g_free (debit_numeric_r);
     g_free (credit_formula_r);
+    g_free (credit_numeric_r);
+    g_free (sx_shares_r);
+    g_free (online_id_r);
     guid_free (sx_account);
     guid_free (sx_account_r);
 }

commit c9493cfcf5d12d62d1f407437459d348c20e9d07
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 15:37:42 2013 -0700

    Transfer the account-matching functions from import-export to Account
    
    I would have preferred to separate the data-retrieval from the actual
    bayesian routines but I didn't think that I could do so without losing
    backwards data compatibility.

diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3326879..f8bf012 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -386,7 +386,6 @@ src/import-export/import-backend.c
 src/import-export/import-commodity-matcher.c
 src/import-export/import-format-dialog.c
 src/import-export/import-main-matcher.c
-src/import-export/import-match-map.c
 src/import-export/import-match-picker.c
 src/import-export/import-parse.c
 src/import-export/import-settings.c
diff --git a/src/engine/Account.c b/src/engine/Account.c
index 21333eb..82650bd 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -4820,6 +4820,508 @@ xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
 }
 
 /* ================================================================ */
+/* The following functions are used by
+ * src/import-export/import-backend.c to manipulate the contra-account
+ * matching data. See src/import-export/import-backend.c for explanations.
+ */
+/* FIXME: These data are stored per-account in KVP and the functions
+ * work directly on KVP data structures. This prevents moving KVP to a
+ * backend-only abstraction.
+ */
+
+
+typedef struct _GncImportMatchMap
+{
+    kvp_frame *	frame;
+    Account *	acc;
+    QofBook *	book;
+} GncImportMatchMap;
+
+#define IMAP_FRAME		"import-map"
+#define IMAP_FRAME_BAYES	"import-map-bayes"
+GncImportMatchMap * gnc_account_create_imap (Account *acc);
+Account* gnc_imap_find_account(GncImportMatchMap *imap, const char* category,
+                               const char *key);
+void gnc_imap_add_account (GncImportMatchMap *imap, const char *category,
+                           const char *key, Account *acc);
+Account* gnc_imap_find_account_bayes (GncImportMatchMap *imap, GList* tokens);
+void gnc_imap_add_account_bayes (GncImportMatchMap *imap, GList* tokens,
+                                 Account *acc);
+
+/* Obtain an ImportMatchMap object from an Account or a Book */
+GncImportMatchMap *
+gnc_account_create_imap (Account *acc)
+{
+    GncImportMatchMap *imap;
+    kvp_frame *frame;
+
+    if (!acc) return NULL;
+    frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    g_return_val_if_fail (frame != NULL, NULL);
+    g_return_val_if_fail (frame != NULL, NULL);
+
+    imap = g_new0(GncImportMatchMap, 1);
+    imap->frame = frame;
+
+    /* Cache the book for easy lookups; store the account/book for
+     * marking dirtiness
+     */
+    imap->acc = acc;
+    imap->book = gnc_account_get_book (acc);
+
+    return imap;
+}
+
+/* Look up an Account in the map */
+Account*
+gnc_imap_find_account (GncImportMatchMap *imap,
+		       const char *category,
+		       const char *key)
+{
+    kvp_value *value;
+    GncGUID * guid;
+
+    if (!imap || !key) return NULL;
+    if (!category)
+    {
+        category = key;
+        key = NULL;
+    }
+
+    value = kvp_frame_get_slot_path (imap->frame, IMAP_FRAME,
+				     category, key, NULL);
+    if (!value) return NULL;
+
+    guid = kvp_value_get_guid (value);
+    return xaccAccountLookup (guid, imap->book);
+}
+
+/* Store an Account in the map */
+void
+gnc_imap_add_account (GncImportMatchMap *imap,
+		      const char *category,
+		      const char *key,
+		      Account *acc)
+{
+    kvp_value *value;
+
+    if (!imap || !key || !acc || (strlen (key) == 0)) return;
+    if (!category)
+    {
+        category = key;
+        key = NULL;
+    }
+    g_return_if_fail (acc != NULL);
+
+    value = kvp_value_new_guid (xaccAccountGetGUID (acc));
+    g_return_if_fail (value != NULL);
+    xaccAccountBeginEdit (imap->acc);
+    kvp_frame_set_slot_path (imap->frame, value, IMAP_FRAME, category, key, NULL);
+    qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
+    xaccAccountCommitEdit (imap->acc);
+    kvp_value_delete (value);
+
+    /* XXX Mark the account (or book) as dirty! */
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+ Below here is the bayes transaction to account matching system
+--------------------------------------------------------------------------*/
+
+
+struct account_token_count
+{
+    char* account_name;
+    gint64 token_count; /**< occurances of a given token for this account_name */
+};
+
+/** total_count and the token_count for a given account let us calculate the
+ * probability of a given account with any single token
+ */
+struct token_accounts_info
+{
+    GList *accounts; /**< array of struct account_token_count */
+    gint64 total_count;
+};
+
+/** gpointer is a pointer to a struct token_accounts_info
+ * \note Can always assume that keys are unique, reduces code in this function
+ */
+static void
+buildTokenInfo(const char *key, kvp_value *value, gpointer data)
+{
+    struct token_accounts_info *tokenInfo = (struct token_accounts_info*)data;
+    struct account_token_count* this_account;
+
+    //  PINFO("buildTokenInfo: account '%s', token_count: '%ld'\n", (char*)key,
+    //			(long)kvp_value_get_gint64(value));
+
+    /* add the count to the total_count */
+    tokenInfo->total_count += kvp_value_get_gint64(value);
+
+    /* allocate a new structure for this account and it's token count */
+    this_account = (struct account_token_count*)
+                   g_new0(struct account_token_count, 1);
+
+    /* fill in the account name and number of tokens found for this account name */
+    this_account->account_name = (char*)key;
+    this_account->token_count = kvp_value_get_gint64(value);
+
+    /* append onto the glist a pointer to the new account_token_count structure */
+    tokenInfo->accounts = g_list_prepend(tokenInfo->accounts, this_account);
+}
+
+/** intermediate values used to calculate the bayes probability of a given account
+  where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
+  product_difference is (1-a) * (1-b)
+ */
+struct account_probability
+{
+    double product; /* product of probabilities */
+    double product_difference; /* product of (1-probabilities) */
+};
+
+/** convert a hash table of account names and (struct account_probability*)
+  into a hash table of 100000x the percentage match value, ie. 10% would be
+  0.10 * 100000 = 10000
+ */
+#define PROBABILITY_FACTOR 100000
+static void
+buildProbabilities(gpointer key, gpointer value, gpointer data)
+{
+    GHashTable *final_probabilities = (GHashTable*)data;
+    struct account_probability *account_p = (struct account_probability*)value;
+
+    /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
+     * NOTE: so we only keep track of a running product(A*B*C...)
+     * and product difference ((1-A)(1-B)...)
+     */
+    gint32 probability =
+        (account_p->product /
+         (account_p->product + account_p->product_difference))
+        * PROBABILITY_FACTOR;
+
+    PINFO("P('%s') = '%d'\n", (char*)key, probability);
+
+    g_hash_table_insert(final_probabilities, key, GINT_TO_POINTER(probability));
+}
+
+/** Frees an array of the same time that buildProperties built */
+static void
+freeProbabilities(gpointer key, gpointer value, gpointer data)
+{
+    /* free up the struct account_probability that was allocated
+     * in gnc_account_find_account_bayes()
+     */
+    g_free(value);
+}
+
+/** holds an account name and its corresponding integer probability
+  the integer probability is some factor of 10
+ */
+struct account_info
+{
+    char* account_name;
+    gint32 probability;
+};
+
+/** Find the highest probability and the corresponding account name
+    store in data, a (struct account_info*)
+    NOTE: this is a g_hash_table_foreach() function for a hash table of entries
+    key is a  pointer to the account name, value is a gint32, 100000x
+    the probability for this account
+*/
+static void
+highestProbability(gpointer key, gpointer value, gpointer data)
+{
+    struct account_info *account_i = (struct account_info*)data;
+
+    /* if the current probability is greater than the stored, store the current */
+    if (GPOINTER_TO_INT(value) > account_i->probability)
+    {
+        /* Save the new highest probability and the assoaciated account name */
+        account_i->probability = GPOINTER_TO_INT(value);
+        account_i->account_name = key;
+    }
+}
+
+
+#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
+
+/** Look up an Account in the map */
+Account*
+gnc_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
+{
+    struct token_accounts_info tokenInfo; /**< holds the accounts and total
+					   * token count for a single token */
+    GList *current_token;		  /**< pointer to the current
+					   * token from the input GList
+					   * tokens */
+    GList *current_account_token;	  /**< pointer to the struct
+					   * account_token_count */
+    struct account_token_count *account_c; /**< an account name and the number
+					    * of times a token has appeared
+					    * for the account */
+    struct account_probability *account_p; /**< intermediate storage of values
+					    * to compute the bayes probability
+					    * of an account */
+    GHashTable *running_probabilities = g_hash_table_new(g_str_hash,
+							 g_str_equal);
+    GHashTable *final_probabilities = g_hash_table_new(g_str_hash,
+						       g_str_equal);
+    struct account_info account_i;
+    kvp_value* value;
+    kvp_frame* token_frame;
+
+    ENTER(" ");
+
+    /* check to see if the imap is NULL */
+    if (!imap)
+    {
+        PINFO("imap is null, returning null");
+        LEAVE(" ");
+        return NULL;
+    }
+
+    /* find the probability for each account that contains any of the tokens
+     * in the input tokens list
+     */
+    for (current_token = tokens; current_token;
+	 current_token = current_token->next)
+    {
+        /* zero out the token_accounts_info structure */
+        memset(&tokenInfo, 0, sizeof(struct token_accounts_info));
+
+        PINFO("token: '%s'", (char*)current_token->data);
+
+        /* find the slot for the given token off of the source account
+         * for these tokens, search off of the IMAP_FRAME_BAYES path so
+         * we aren't looking from the parent of the entire kvp tree
+         */
+        value = kvp_frame_get_slot_path(imap->frame, IMAP_FRAME_BAYES,
+                                        (char*)current_token->data, NULL);
+
+        /* if value is null we should skip over this token */
+        if (!value)
+            continue;
+
+        /* convert the slot(value) into a the frame that contains the
+         * list of accounts
+         */
+        token_frame = kvp_value_get_frame(value);
+
+        /* token_frame should NEVER be null */
+        if (!token_frame)
+        {
+            PERR("token '%s' has no accounts", (char*)current_token->data);
+            continue; /* skip over this token */
+        }
+
+        /* process the accounts for this token, adding the account if it
+         * doesn't already exist or adding to the existing accounts token
+         * count if it does
+         */
+        kvp_frame_for_each_slot(token_frame, buildTokenInfo, &tokenInfo);
+
+        /* for each account we have just found, see if the account
+         * already exists in the list of account probabilities, if not
+         * add it
+         */
+        for (current_account_token = tokenInfo.accounts; current_account_token;
+                current_account_token = current_account_token->next)
+        {
+            /* get the account name and corresponding token count */
+            account_c = (struct account_token_count*)current_account_token->data;
+
+            PINFO("account_c->account_name('%s'), "
+                  "account_c->token_count('%ld')/total_count('%ld')",
+                  account_c->account_name, (long)account_c->token_count,
+                  (long)tokenInfo.total_count);
+
+            account_p = g_hash_table_lookup(running_probabilities,
+                                            account_c->account_name);
+
+            /* if the account exists in the list then continue
+             * the running probablities
+             */
+            if (account_p)
+            {
+                account_p->product = (((double)account_c->token_count /
+				      (double)tokenInfo.total_count)
+				      * account_p->product);
+                account_p->product_difference =
+                    ((double)1 - ((double)account_c->token_count /
+                                  (double)tokenInfo.total_count))
+                    * account_p->product_difference;
+                PINFO("product == %f, product_difference == %f",
+                      account_p->product, account_p->product_difference);
+            }
+            else
+            {
+                /* add a new entry */
+                PINFO("adding a new entry for this account");
+                account_p = (struct account_probability*)
+                            g_new0(struct account_probability, 1);
+
+                /* set the product and product difference values */
+                account_p->product = ((double)account_c->token_count /
+                                      (double)tokenInfo.total_count);
+                account_p->product_difference =
+                    (double)1 - ((double)account_c->token_count /
+                                 (double)tokenInfo.total_count);
+
+                PINFO("product == %f, product_difference == %f",
+                      account_p->product, account_p->product_difference);
+
+                /* add the account name and (struct account_probability*)
+                 * to the hash table */
+                g_hash_table_insert(running_probabilities,
+                                    account_c->account_name, account_p);
+            }
+        } /* for all accounts in tokenInfo */
+
+        /* free the data in tokenInfo */
+        for (current_account_token = tokenInfo.accounts; current_account_token;
+                current_account_token = current_account_token->next)
+        {
+            /* free up each struct account_token_count we allocated */
+            g_free((struct account_token_count*)current_account_token->data);
+        }
+
+        g_list_free(tokenInfo.accounts); /* free the accounts GList */
+    }
+
+    /* build a hash table of account names and their final probabilities
+     * from each entry in the running_probabilties hash table
+     */
+    g_hash_table_foreach(running_probabilities, buildProbabilities,
+                         final_probabilities);
+
+    /* find the highest probabilty and the corresponding account */
+    memset(&account_i, 0, sizeof(struct account_info));
+    g_hash_table_foreach(final_probabilities, highestProbability, &account_i);
+
+    /* free each element of the running_probabilities hash */
+    g_hash_table_foreach(running_probabilities, freeProbabilities, NULL);
+
+    /* free the hash tables */
+    g_hash_table_destroy(running_probabilities);
+    g_hash_table_destroy(final_probabilities);
+
+    PINFO("highest P('%s') = '%d'",
+          account_i.account_name ? account_i.account_name : "(null)",
+          account_i.probability);
+
+    /* has this probability met our threshold? */
+    if (account_i.probability >= threshold)
+    {
+        PINFO("found match");
+        LEAVE(" ");
+        return gnc_account_lookup_by_full_name(gnc_book_get_root_account(imap->book),
+                                               account_i.account_name);
+    }
+
+    PINFO("no match");
+    LEAVE(" ");
+
+    return NULL; /* we didn't meet our threshold, return NULL for an account */
+}
+
+
+/** Updates the imap for a given account using a list of tokens */
+void
+gnc_imap_add_account_bayes(GncImportMatchMap *imap,
+			   GList *tokens,
+			   Account *acc)
+{
+    GList *current_token;
+    kvp_value *value;
+    gint64 token_count;
+    char* account_fullname;
+    kvp_value *new_value; /* the value that will be added back into
+			   * the kvp tree */
+
+    ENTER(" ");
+
+    /* if imap is null return */
+    if (!imap)
+    {
+        LEAVE(" ");
+        return;
+    }
+
+    g_return_if_fail (acc != NULL);
+    account_fullname = gnc_account_get_full_name(acc);
+    xaccAccountBeginEdit (imap->acc);
+
+    PINFO("account name: '%s'\n", account_fullname);
+
+    /* process each token in the list */
+    for (current_token = g_list_first(tokens); current_token;
+            current_token = current_token->next)
+    {
+        /* Jump to next iteration if the pointer is not valid or if the
+        	 string is empty. In HBCI import we almost always get an empty
+        	 string, which doesn't work in the kvp loopkup later. So we
+        	 skip this case here. */
+        if (!current_token->data || (*((char*)current_token->data) == '\0'))
+            continue;
+
+        /* start off with no tokens for this account */
+        token_count = 0;
+
+        PINFO("adding token '%s'\n", (char*)current_token->data);
+
+        /* is this token/account_name already in the kvp tree? */
+        value = kvp_frame_get_slot_path(imap->frame, IMAP_FRAME_BAYES,
+                                        (char*)current_token->data,
+					account_fullname,
+                                        NULL);
+
+        /* if the token/account is already in the tree, read the current
+         * value from the tree and use this for the basis of the value we
+         * are putting back
+         */
+        if (value)
+        {
+            PINFO("found existing value of '%ld'\n",
+                  (long)kvp_value_get_gint64(value));
+
+            /* convert this value back into an integer */
+            token_count += kvp_value_get_gint64(value);
+        }
+
+        /* increment the token count */
+        token_count++;
+
+        /* create a new value */
+        new_value = kvp_value_new_gint64(token_count);
+
+        /* insert the value into the kvp tree at
+         * /imap->frame/IMAP_FRAME/token_string/account_name_string
+         */
+        kvp_frame_set_slot_path(imap->frame, new_value,
+				IMAP_FRAME_BAYES,
+                                (char*)current_token->data,
+				account_fullname,
+				NULL);
+        /* kvp_frame_set_slot_path() copied the value so we
+         * need to delete this one ;-) */
+        kvp_value_delete(new_value);
+    }
+
+    /* free up the account fullname string */
+    qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
+    xaccAccountCommitEdit (imap->acc);
+    g_free(account_fullname);
+
+    LEAVE(" ");
+}
+
+/* ================================================================ */
 /* QofObject function implementation and registration */
 
 static void
diff --git a/src/gnome-utils/gnc-tree-view-account.c b/src/gnome-utils/gnc-tree-view-account.c
index f9971f0..d41adc8 100644
--- a/src/gnome-utils/gnc-tree-view-account.c
+++ b/src/gnome-utils/gnc-tree-view-account.c
@@ -1721,43 +1721,44 @@ gtva_currency_changed_cb (void)
         gtva_update_column_names (ptr->data);
     }
 }
-/* This function implements a custom mapping between an account's KVP
- * and the cell renderer's 'text' property. */
+/* Retrieve a specified account string property and put the result
+ * into the tree column's text property.
+ */
 static void
-account_cell_kvp_data_func (GtkTreeViewColumn *tree_column,
-                            GtkCellRenderer *cell,
-                            GtkTreeModel *s_model,
-                            GtkTreeIter *s_iter,
-                            gpointer key)
+account_cell_property_data_func (GtkTreeViewColumn *tree_column,
+				 GtkCellRenderer *cell,
+				 GtkTreeModel *s_model,
+				 GtkTreeIter *s_iter,
+				 gpointer key)
 {
     Account *account;
-    kvp_frame * frame;
+    gchar *string;
 
     g_return_if_fail (GTK_IS_TREE_MODEL_SORT (s_model));
     account = gnc_tree_view_account_get_account_from_iter(s_model, s_iter);
-    frame = xaccAccountGetSlots(account);
-
-    g_object_set (G_OBJECT (cell),
-                  "text", kvp_frame_get_string(frame, (gchar *)key),
-                  "xalign", 0.0,
-                  NULL);
+    qof_instance_get (QOF_INSTANCE (account),
+		      key, &string,
+		      NULL);
+    if (string == NULL)
+	string = "";
 
+    g_object_set (G_OBJECT (cell), "text", string, "xalign", 0.0, NULL);
 }
 
 
 GtkTreeViewColumn *
-gnc_tree_view_account_add_kvp_column (GncTreeViewAccount *view,
+gnc_tree_view_account_add_property_column (GncTreeViewAccount *view,
                                       const gchar *column_title,
-                                      const gchar *kvp_key)
+                                      const gchar *propname)
 {
     GtkCellRenderer *renderer;
     GtkTreeViewColumn *column;
 
     g_return_val_if_fail (GNC_IS_TREE_VIEW_ACCOUNT (view), NULL);
-    g_return_val_if_fail (kvp_key != NULL, NULL);
+    g_return_val_if_fail (propname != NULL, NULL);
 
     column = gnc_tree_view_add_text_column(GNC_TREE_VIEW(view), column_title,
-                                           kvp_key, NULL, "Sample text",
+                                           propname, NULL, "Sample text",
                                            -1, -1, NULL);
 
     /* This new kvp column has only had one renderer added to it so
@@ -1766,8 +1767,8 @@ gnc_tree_view_account_add_kvp_column (GncTreeViewAccount *view,
     g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
 
     gtk_tree_view_column_set_cell_data_func (column, renderer,
-            account_cell_kvp_data_func,
-            g_strdup(kvp_key), g_free);
+            account_cell_property_data_func,
+            g_strdup(propname), g_free);
     return column;
 }
 
diff --git a/src/gnome-utils/gnc-tree-view-account.h b/src/gnome-utils/gnc-tree-view-account.h
index 87778cd..5088b75 100644
--- a/src/gnome-utils/gnc-tree-view-account.h
+++ b/src/gnome-utils/gnc-tree-view-account.h
@@ -203,20 +203,19 @@ void gnc_tree_view_account_notes_edited_cb(Account *account, GtkTreeViewColumn *
 
 /** Add a new column to the set of columns in an account tree view.
  *  This column will be visible as soon as it is added and will
- *  display the contents of the specified KVP slot.
+ *  display the contents of the specified account property
  *
  *  @param view A pointer to an account tree view.
  *
  *  @param column_title The title for this new column.
  *
- *  @param kvp_key The lookup key to use for looking up data in the
- *  account KVP structures. The value associated with this key is what
- *  will be displayed in the column.
+ *  @param propname The g_object_property name of the desired
+ *  value. This must be a string property.
  */
 GtkTreeViewColumn *
-gnc_tree_view_account_add_kvp_column (GncTreeViewAccount *view,
-                                      const gchar *column_title,
-                                      const gchar *kvp_key);
+gnc_tree_view_account_add_property_column (GncTreeViewAccount *view,
+					   const gchar *column_title,
+					   const gchar *propname);
 
 /** @} */
 
diff --git a/src/import-export/Makefile.am b/src/import-export/Makefile.am
index 24f47d6..7630c51 100644
--- a/src/import-export/Makefile.am
+++ b/src/import-export/Makefile.am
@@ -18,13 +18,11 @@ libgncmod_generic_import_la_SOURCES = \
 	import-parse.c \
 	import-utilities.c \
 	import-settings.c \
-	import-match-map.c \
 	import-main-matcher.c \
 	gncmod-generic-import.c
 
 gncincludedir = ${GNC_INCLUDE_DIR}
 gncinclude_HEADERS = \
-  import-match-map.h \
   import-parse.h
 
 noinst_HEADERS = \
@@ -32,7 +30,6 @@ noinst_HEADERS = \
   import-backend.h \
   import-commodity-matcher.h \
   import-main-matcher.h \
-  import-match-map.h \
   import-match-picker.h \
   import-settings.h \
   import-utilities.h
diff --git a/src/import-export/import-backend.c b/src/import-export/import-backend.c
index 4e0d34e..a372bc4 100644
--- a/src/import-export/import-backend.c
+++ b/src/import-export/import-backend.c
@@ -44,6 +44,40 @@
 #include "gnc-prefs.h"
 #include "gnc-ui-util.h"
 
+/* Private interface to Account GncImportMatchMap functions */
+
+/** @{
+Obtain an ImportMatchMap object from an Account */
+extern GncImportMatchMap * gnc_account_create_imap (Account *acc);
+/*@}*/
+
+/* Look up an Account in the map */
+extern Account* gnc_imap_find_account(GncImportMatchMap *imap,
+				      const char* category,
+				      const char *key);
+
+/* Store an Account in the map. This mapping is immediatly stored in
+  the underlying kvp frame, regardless of whether the MatchMap is
+  destroyed later or not. */
+extern void gnc_imap_add_account (GncImportMatchMap *imap,
+				  const char *category,
+				  const char *key, Account *acc);
+
+/* Look up an Account in the map from a GList* of pointers to strings(tokens)
+  from the current transaction */
+extern Account* gnc_imap_find_account_bayes (GncImportMatchMap *imap,
+					     GList* tokens);
+
+/* Store an Account in the map. This mapping is immediatly stored in
+  the underlying kvp frame, regardless of whether the MatchMap is
+  destroyed later or not. */
+extern void gnc_imap_add_account_bayes (GncImportMatchMap *imap,
+					GList* tokens,
+					Account *acc);
+
+#define GNCIMPORT_DESC    "desc"
+#define GNCIMPORT_MEMO    "memo"
+#define GNCIMPORT_PAYEE    "payee"
 
 /********************************************************************\
  *   Constants                                                      *
@@ -457,6 +491,15 @@ TransactionGetTokens(GNCImportTransInfo *info)
     /* return the pointer to the GList */
     return tokens;
 }
+/* Destroy an import map. But all stored entries will still continue
+ * to exist in the underlying kvp frame of the account.
+ */
+static void
+gnc_imap_destroy (GncImportMatchMap *imap)
+{
+    if (!imap) return;
+    g_free (imap);
+}
 
 /* searches using the GNCImportTransInfo through all existing transactions
  * if there is an exact match of the description and memo
@@ -471,7 +514,7 @@ matchmap_find_destination (GncImportMatchMap *matchmap, GNCImportTransInfo *info
 
     g_assert (info);
     tmp_map = ((matchmap != NULL) ? matchmap :
-               gnc_imap_create_from_account
+               gnc_account_create_imap
                (xaccSplitGetAccount
                 (gnc_import_TransInfo_get_fsplit (info))));
 
@@ -541,7 +584,7 @@ matchmap_store_destination (GncImportMatchMap *matchmap,
 
     tmp_matchmap = ((matchmap != NULL) ?
                     matchmap :
-                    gnc_imap_create_from_account
+                    gnc_account_create_imap
                     (xaccSplitGetAccount
                      (gnc_import_TransInfo_get_fsplit (trans_info))));
 
diff --git a/src/import-export/import-backend.h b/src/import-export/import-backend.h
index 2978fd5..99e6421 100644
--- a/src/import-export/import-backend.h
+++ b/src/import-export/import-backend.h
@@ -29,11 +29,11 @@
 #define TRANSACTION_MATCHER_H
 
 #include "Transaction.h"
-#include "import-match-map.h"
 #include "import-settings.h"
 
 typedef struct _transactioninfo GNCImportTransInfo;
 typedef struct _matchinfo GNCImportMatchInfo;
+typedef struct _GncImportMatchMap GncImportMatchMap;
 
 typedef enum _action
 {
diff --git a/src/import-export/import-main-matcher.c b/src/import-export/import-main-matcher.c
index 3793212..24b8b63 100644
--- a/src/import-export/import-main-matcher.c
+++ b/src/import-export/import-main-matcher.c
@@ -44,7 +44,6 @@
 #include "gnc-ui-util.h"
 #include "gnc-engine.h"
 #include "import-settings.h"
-#include "import-match-map.h"
 #include "import-match-picker.h"
 #include "import-backend.h"
 #include "import-account-matcher.h"
diff --git a/src/import-export/import-match-map.c b/src/import-export/import-match-map.c
deleted file mode 100644
index 3e96b05..0000000
--- a/src/import-export/import-match-map.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/********************************************************************\
- * 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                   *
-\********************************************************************/
-/** @addtogroup Import_Export
-    @{ */
-/** @internal
-	@file import-match-map.c
-    @brief Generic import mapper service, maps strings->accounts
-    *
-    An import mapper service that stores Account Maps for the
-    generic importer.  This allows importers to map various
-    "strings" to Gnucash accounts in a generic manner.
-    @author Copyright (C) 2002,2003 Derek Atkins <derek at ihtfp.com>
- */
-#include "config.h"
-#include <string.h>
-#include <glib.h>
-#include "import-match-map.h"
-#include "gnc-ui-util.h"
-#include "gnc-engine.h"
-
-/********************************************************************\
- *   Constants   *
-\********************************************************************/
-
-static QofLogModule log_module = GNC_MOD_IMPORT;
-
-
-struct _GncImportMatchMap
-{
-    kvp_frame *	frame;
-    Account *	acc;
-    QofBook *	book;
-};
-
-#define IMAP_FRAME		"import-map"
-#define IMAP_FRAME_BAYES	"import-map-bayes"
-
-static GncImportMatchMap *
-gnc_imap_create_from_frame (kvp_frame *frame, Account *acc, QofBook *book)
-{
-    GncImportMatchMap *imap;
-
-    g_return_val_if_fail (frame != NULL, NULL);
-    g_return_val_if_fail ((acc && !book) || (!acc && book), NULL);
-
-    imap = g_new0(GncImportMatchMap, 1);
-    imap->frame = frame;
-
-    /* Cache the book for easy lookups; store the account/book for
-     * marking dirtiness
-     */
-    if (acc)
-        book = gnc_account_get_book (acc);
-    imap->acc = acc;
-    imap->book = book;
-
-    return imap;
-}
-
-/** Obtain an ImportMatchMap object from an Account or a Book */
-GncImportMatchMap * gnc_imap_create_from_account (Account *acc)
-{
-    kvp_frame * frame;
-
-    if (!acc) return NULL;
-    frame = xaccAccountGetSlots (acc);
-    g_return_val_if_fail (frame != NULL, NULL);
-
-    return gnc_imap_create_from_frame (frame, acc, NULL);
-}
-
-GncImportMatchMap * gnc_imap_create_from_book (QofBook *book)
-{
-    kvp_frame * frame;
-
-    if (!book) return NULL;
-    frame = qof_book_get_slots (book);
-    g_return_val_if_fail (frame != NULL, NULL);
-
-    return gnc_imap_create_from_frame (frame, NULL, book);
-}
-
-/** Destroy an import map */
-void gnc_imap_destroy (GncImportMatchMap *imap)
-{
-    if (!imap) return;
-    g_free (imap);
-}
-
-/** Clear an import map -- this removes ALL entries in the map */
-void gnc_imap_clear (GncImportMatchMap *imap)
-{
-    if (!imap) return;
-
-    /* Clear the IMAP_FRAME kvp */
-    kvp_frame_set_slot_path (imap->frame, NULL, IMAP_FRAME);
-
-    /* Clear the bayes kvp, IMAP_FRAME_BAYES */
-    kvp_frame_set_slot_path (imap->frame, NULL, IMAP_FRAME_BAYES);
-
-    /* XXX: mark the account (or book) as dirty! */
-}
-
-/** Look up an Account in the map */
-Account * gnc_imap_find_account (GncImportMatchMap *imap, const char *category,
-                                 const char *key)
-{
-    kvp_value *value;
-    GncGUID * guid;
-
-    if (!imap || !key) return NULL;
-    if (!category)
-    {
-        category = key;
-        key = NULL;
-    }
-
-    value = kvp_frame_get_slot_path (imap->frame, IMAP_FRAME, category, key, NULL);
-    if (!value) return NULL;
-
-    guid = kvp_value_get_guid (value);
-    return xaccAccountLookup (guid, imap->book);
-}
-
-/** Store an Account in the map */
-void gnc_imap_add_account (GncImportMatchMap *imap, const char *category,
-                           const char *key, Account *acc)
-{
-    kvp_value *value;
-
-    if (!imap || !key || !acc || (strlen (key) == 0)) return;
-    if (!category)
-    {
-        category = key;
-        key = NULL;
-    }
-    g_return_if_fail (acc != NULL);
-
-    value = kvp_value_new_guid (xaccAccountGetGUID (acc));
-    g_return_if_fail (value != NULL);
-    xaccAccountBeginEdit (imap->acc);
-    kvp_frame_set_slot_path (imap->frame, value, IMAP_FRAME, category, key, NULL);
-    qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
-    xaccAccountCommitEdit (imap->acc);
-    kvp_value_delete (value);
-
-    /* XXX Mark the account (or book) as dirty! */
-}
-
-
-
-
-/*--------------------------------------------------------------------------
- Below here is the bayes transaction to account matching system
---------------------------------------------------------------------------*/
-
-
-struct account_token_count
-{
-    char* account_name;
-    gint64 token_count; /**< occurances of a given token for this account_name */
-};
-
-/** total_count and the token_count for a given account let us calculate the
- * probability of a given account with any single token
- */
-struct token_accounts_info
-{
-    GList *accounts; /**< array of struct account_token_count */
-    gint64 total_count;
-};
-
-/** gpointer is a pointer to a struct token_accounts_info
- * \note Can always assume that keys are unique, reduces code in this function
- */
-static void buildTokenInfo(const char *key, kvp_value *value, gpointer data)
-{
-    struct token_accounts_info *tokenInfo = (struct token_accounts_info*)data;
-    struct account_token_count* this_account;
-
-    //  PINFO("buildTokenInfo: account '%s', token_count: '%ld'\n", (char*)key,
-    //			(long)kvp_value_get_gint64(value));
-
-    /* add the count to the total_count */
-    tokenInfo->total_count += kvp_value_get_gint64(value);
-
-    /* allocate a new structure for this account and it's token count */
-    this_account = (struct account_token_count*)
-                   g_new0(struct account_token_count, 1);
-
-    /* fill in the account name and number of tokens found for this account name */
-    this_account->account_name = (char*)key;
-    this_account->token_count = kvp_value_get_gint64(value);
-
-    /* append onto the glist a pointer to the new account_token_count structure */
-    tokenInfo->accounts = g_list_prepend(tokenInfo->accounts, this_account);
-}
-
-/** intermediate values used to calculate the bayes probability of a given account
-  where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
-  product_difference is (1-a) * (1-b)
- */
-struct account_probability
-{
-    double product; /* product of probabilities */
-    double product_difference; /* product of (1-probabilities) */
-};
-
-/** convert a hash table of account names and (struct account_probability*)
-  into a hash table of 100000x the percentage match value, ie. 10% would be
-  0.10 * 100000 = 10000
- */
-#define PROBABILITY_FACTOR 100000
-static void buildProbabilities(gpointer key, gpointer value, gpointer data)
-{
-    GHashTable *final_probabilities = (GHashTable*)data;
-    struct account_probability *account_p = (struct account_probability*)value;
-
-    /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
-     * NOTE: so we only keep track of a running product(A*B*C...)
-     * and product difference ((1-A)(1-B)...)
-     */
-    gint32 probability =
-        (account_p->product /
-         (account_p->product + account_p->product_difference))
-        * PROBABILITY_FACTOR;
-
-    PINFO("P('%s') = '%d'\n", (char*)key, probability);
-
-    g_hash_table_insert(final_probabilities, key, GINT_TO_POINTER(probability));
-}
-
-/** Frees an array of the same time that buildProperties built */
-static void freeProbabilities(gpointer key, gpointer value, gpointer data)
-{
-    /* free up the struct account_probability that was allocated
-     * in gnc_imap_find_account_bayes()
-     */
-    g_free(value);
-}
-
-/** holds an account name and its corresponding integer probability
-  the integer probability is some factor of 10
- */
-struct account_info
-{
-    char* account_name;
-    gint32 probability;
-};
-
-/** Find the highest probability and the corresponding account name
-    store in data, a (struct account_info*)
-    NOTE: this is a g_hash_table_foreach() function for a hash table of entries
-    key is a  pointer to the account name, value is a gint32, 100000x
-    the probability for this account
-*/
-static void highestProbability(gpointer key, gpointer value, gpointer data)
-{
-    struct account_info *account_i = (struct account_info*)data;
-
-    /* if the current probability is greater than the stored, store the current */
-    if (GPOINTER_TO_INT(value) > account_i->probability)
-    {
-        /* Save the new highest probability and the assoaciated account name */
-        account_i->probability = GPOINTER_TO_INT(value);
-        account_i->account_name = key;
-    }
-}
-
-
-#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
-
-/** Look up an Account in the map */
-Account* gnc_imap_find_account_bayes(GncImportMatchMap *imap, GList *tokens)
-{
-    struct token_accounts_info tokenInfo; /**< holds the accounts and total
-					 * token count for a single token */
-    GList *current_token;		        /**< pointer to the current token from the
-				         * input GList *tokens */
-    GList *current_account_token;		/**< pointer to the struct
-					 * account_token_count */
-    struct account_token_count *account_c; /**< an account name and the number
-					  * of times a token has appeared
-					  * for the account */
-    struct account_probability *account_p; /**< intermediate storage of values
-					  * to compute the bayes probability
-					  * of an account */
-    GHashTable *running_probabilities = g_hash_table_new(g_str_hash, g_str_equal);
-    GHashTable *final_probabilities = g_hash_table_new(g_str_hash, g_str_equal);
-    struct account_info account_i;
-    kvp_value* value;
-    kvp_frame* token_frame;
-
-    ENTER(" ");
-
-    /* check to see if the imap is NULL */
-    if (!imap)
-    {
-        PINFO("imap is null, returning null");
-        LEAVE(" ");
-        return NULL;
-    }
-
-    /* find the probability for each account that contains any of the tokens
-     * in the input tokens list
-     */
-    for (current_token = tokens; current_token; current_token = current_token->next)
-    {
-        /* zero out the token_accounts_info structure */
-        memset(&tokenInfo, 0, sizeof(struct token_accounts_info));
-
-        PINFO("token: '%s'", (char*)current_token->data);
-
-        /* find the slot for the given token off of the source account
-         * for these tokens, search off of the IMAP_FRAME_BAYES path so
-         * we aren't looking from the parent of the entire kvp tree
-         */
-        value = kvp_frame_get_slot_path(imap->frame, IMAP_FRAME_BAYES,
-                                        (char*)current_token->data, NULL);
-
-        /* if value is null we should skip over this token */
-        if (!value)
-            continue;
-
-        /* convert the slot(value) into a the frame that contains the
-         * list of accounts
-         */
-        token_frame = kvp_value_get_frame(value);
-
-        /* token_frame should NEVER be null */
-        if (!token_frame)
-        {
-            PERR("token '%s' has no accounts", (char*)current_token->data);
-            continue; /* skip over this token */
-        }
-
-        /* process the accounts for this token, adding the account if it
-         * doesn't already exist or adding to the existing accounts token
-         * count if it does
-         */
-        kvp_frame_for_each_slot(token_frame, buildTokenInfo, &tokenInfo);
-
-        /* for each account we have just found, see if the account already exists
-         * in the list of account probabilities, if not add it
-         */
-        for (current_account_token = tokenInfo.accounts; current_account_token;
-                current_account_token = current_account_token->next)
-        {
-            /* get the account name and corresponding token count */
-            account_c = (struct account_token_count*)current_account_token->data;
-
-            PINFO("account_c->account_name('%s'), "
-                  "account_c->token_count('%ld')/total_count('%ld')",
-                  account_c->account_name, (long)account_c->token_count,
-                  (long)tokenInfo.total_count);
-
-            account_p = g_hash_table_lookup(running_probabilities,
-                                            account_c->account_name);
-
-            /* if the account exists in the list then continue
-             * the running probablities
-             */
-            if (account_p)
-            {
-                account_p->product =
-                    ((double)account_c->token_count / (double)tokenInfo.total_count)
-                    * account_p->product;
-                account_p->product_difference =
-                    ((double)1 - ((double)account_c->token_count /
-                                  (double)tokenInfo.total_count))
-                    * account_p->product_difference;
-                PINFO("product == %f, product_difference == %f",
-                      account_p->product, account_p->product_difference);
-            }
-            else
-            {
-                /* add a new entry */
-                PINFO("adding a new entry for this account");
-                account_p = (struct account_probability*)
-                            g_new0(struct account_probability, 1);
-
-                /* set the product and product difference values */
-                account_p->product = ((double)account_c->token_count /
-                                      (double)tokenInfo.total_count);
-                account_p->product_difference =
-                    (double)1 - ((double)account_c->token_count /
-                                 (double)tokenInfo.total_count);
-
-                PINFO("product == %f, product_difference == %f",
-                      account_p->product, account_p->product_difference);
-
-                /* add the account name and (struct account_probability*)
-                 * to the hash table */
-                g_hash_table_insert(running_probabilities,
-                                    account_c->account_name, account_p);
-            }
-        } /* for all accounts in tokenInfo */
-
-        /* free the data in tokenInfo */
-        for (current_account_token = tokenInfo.accounts; current_account_token;
-                current_account_token = current_account_token->next)
-        {
-            /* free up each struct account_token_count we allocated */
-            g_free((struct account_token_count*)current_account_token->data);
-        }
-
-        g_list_free(tokenInfo.accounts); /* free the accounts GList */
-    }
-
-    /* build a hash table of account names and their final probabilities
-     * from each entry in the running_probabilties hash table
-     */
-    g_hash_table_foreach(running_probabilities, buildProbabilities,
-                         final_probabilities);
-
-    /* find the highest probabilty and the corresponding account */
-    memset(&account_i, 0, sizeof(struct account_info));
-    g_hash_table_foreach(final_probabilities, highestProbability, &account_i);
-
-    /* free each element of the running_probabilities hash */
-    g_hash_table_foreach(running_probabilities, freeProbabilities, NULL);
-
-    /* free the hash tables */
-    g_hash_table_destroy(running_probabilities);
-    g_hash_table_destroy(final_probabilities);
-
-    PINFO("highest P('%s') = '%d'",
-          account_i.account_name ? account_i.account_name : "(null)",
-          account_i.probability);
-
-    /* has this probability met our threshold? */
-    if (account_i.probability >= threshold)
-    {
-        PINFO("found match");
-        LEAVE(" ");
-        return gnc_account_lookup_by_full_name(gnc_book_get_root_account(imap->book),
-                                               account_i.account_name);
-    }
-
-    PINFO("no match");
-    LEAVE(" ");
-
-    return NULL; /* we didn't meet our threshold, return NULL for an account */
-}
-
-
-/** Updates the imap for a given account using a list of tokens */
-void gnc_imap_add_account_bayes(GncImportMatchMap *imap, GList *tokens, Account *acc)
-{
-    GList *current_token;
-    kvp_value *value;
-    gint64 token_count;
-    char* account_fullname;
-    kvp_value *new_value; /* the value that will be added back into the kvp tree */
-
-    ENTER(" ");
-
-    /* if imap is null return */
-    if (!imap)
-    {
-        LEAVE(" ");
-        return;
-    }
-
-    g_return_if_fail (acc != NULL);
-    account_fullname = gnc_account_get_full_name(acc);
-    xaccAccountBeginEdit (imap->acc);
-
-    PINFO("account name: '%s'\n", account_fullname);
-
-    /* process each token in the list */
-    for (current_token = g_list_first(tokens); current_token;
-            current_token = current_token->next)
-    {
-        /* Jump to next iteration if the pointer is not valid or if the
-        	 string is empty. In HBCI import we almost always get an empty
-        	 string, which doesn't work in the kvp loopkup later. So we
-        	 skip this case here. */
-        if (!current_token->data || (*((char*)current_token->data) == '\0'))
-            continue;
-
-        /* start off with no tokens for this account */
-        token_count = 0;
-
-        PINFO("adding token '%s'\n", (char*)current_token->data);
-
-        /* is this token/account_name already in the kvp tree? */
-        value = kvp_frame_get_slot_path(imap->frame, IMAP_FRAME_BAYES,
-                                        (char*)current_token->data, account_fullname,
-                                        NULL);
-
-        /* if the token/account is already in the tree, read the current
-         * value from the tree and use this for the basis of the value we
-         * are putting back
-         */
-        if (value)
-        {
-            PINFO("found existing value of '%ld'\n",
-                  (long)kvp_value_get_gint64(value));
-
-            /* convert this value back into an integer */
-            token_count += kvp_value_get_gint64(value);
-        }
-
-        /* increment the token count */
-        token_count++;
-
-        /* create a new value */
-        new_value = kvp_value_new_gint64(token_count);
-
-        /* insert the value into the kvp tree at
-         * /imap->frame/IMAP_FRAME/token_string/account_name_string
-         */
-        kvp_frame_set_slot_path(imap->frame, new_value, IMAP_FRAME_BAYES,
-                                (char*)current_token->data, account_fullname, NULL);
-        /* kvp_frame_set_slot_path() copied the value so we
-         * need to delete this one ;-) */
-        kvp_value_delete(new_value);
-    }
-
-    /* free up the account fullname string */
-    qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
-    xaccAccountCommitEdit (imap->acc);
-    g_free(account_fullname);
-
-    LEAVE(" ");
-}
-
-/** @} */
diff --git a/src/import-export/import-match-map.h b/src/import-export/import-match-map.h
deleted file mode 100644
index 88c6945..0000000
--- a/src/import-export/import-match-map.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/********************************************************************\
- * 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                   *
-\********************************************************************/
-/** @addtogroup Import_Export
-    @{ */
-/** @file import-match-map.h
-    @brief Generic import mapper service, maps strings->accounts
-    *
-    An import mapper service that stores Account Maps for the
-    generic importer.  This allows importers to map various
-    "strings" to Gnucash accounts in a generic manner.
-    @author Copyright (C) 2002,2003 Derek Atkins <derek at ihtfp.com>
- */
-#ifndef GNC_IMPORT_MATCH_MAP_H
-#define GNC_IMPORT_MATCH_MAP_H
-
-typedef struct _GncImportMatchMap GncImportMatchMap;
-
-#include "Account.h"
-
-/** @{
-Obtain an ImportMatchMap object from an Account or a Book */
-GncImportMatchMap * gnc_imap_create_from_account (Account *acc);
-GncImportMatchMap * gnc_imap_create_from_book (QofBook *book);
-/*@}*/
-
-/** Destroy an import map. But all stored entries will still continue
- to exist in the underlying kvp frame of the account or book. */
-void gnc_imap_destroy (GncImportMatchMap *imap);
-
-/** Clear an import map -- this removes ALL entries in the map */
-void gnc_imap_clear (GncImportMatchMap *imap);
-
-/** Look up an Account in the map */
-Account* gnc_imap_find_account(GncImportMatchMap *imap, const char* category,
-                               const char *key);
-
-/** Store an Account in the map. This mapping is immediatly stored in
-  the underlying kvp frame, regardless of whether the MatchMap is
-  destroyed later or not. */
-void gnc_imap_add_account (GncImportMatchMap *imap, const char *category,
-                           const char *key, Account *acc);
-
-/** Look up an Account in the map from a GList* of pointers to strings(tokens)
-  from the current transaction */
-Account* gnc_imap_find_account_bayes (GncImportMatchMap *imap, GList* tokens);
-
-/** Store an Account in the map. This mapping is immediatly stored in
-  the underlying kvp frame, regardless of whether the MatchMap is
-  destroyed later or not. */
-void gnc_imap_add_account_bayes (GncImportMatchMap *imap, GList* tokens,
-                                 Account *acc);
-
-
-/** @name Some well-known categories
-
-  NOTE: You DO NOT have to use these values in your importer -- these
-  are just "well known" values, not "mandatory" values.  You are free
-  to use these if they apply, map your own fields to these labels, or
-  create your own category strings.
-*/
-/** @{*/
-#define GNCIMPORT_DESC	"desc"
-#define GNCIMPORT_MEMO	"memo"
-#define GNCIMPORT_PAYEE	"payee"
-/**@}*/
-
-#endif /* GNC_IMPORT_MATCH_MAP_H */
-/**@}*/

commit fadc3d7082e0a7ba11647a2ecf8c4af53cd6b50b
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 15:36:29 2013 -0700

    Use online-id properties of Account, Transaction, & Split

diff --git a/src/import-export/import-account-matcher.c b/src/import-export/import-account-matcher.c
index a828311..27d7fe3 100644
--- a/src/import-export/import-account-matcher.c
+++ b/src/import-export/import-account-matcher.c
@@ -114,8 +114,8 @@ build_acct_tree(AccountPickerDialog *picker)
     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
 
     /* Add our custom column. */
-    col = gnc_tree_view_account_add_kvp_column (picker->account_tree,
-            _("Account ID"), "online_id");
+    col = gnc_tree_view_account_add_property_column (picker->account_tree,
+            _("Account ID"), "online-id");
     g_object_set_data(G_OBJECT(col), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
 
     gtk_container_add(GTK_CONTAINER(picker->account_tree_sw),
diff --git a/src/import-export/import-utilities.c b/src/import-export/import-utilities.c
index 4d7756a..68b64ef 100644
--- a/src/import-export/import-utilities.c
+++ b/src/import-export/import-utilities.c
@@ -40,40 +40,37 @@
  * Account, Transaction and Split
 \********************************************************************/
 
-const gchar * gnc_import_get_acc_online_id(Account * account)
+const gchar * gnc_import_get_acc_online_id (Account * account)
 {
-    kvp_frame * frame;
-    frame = xaccAccountGetSlots(account);
-    return kvp_frame_get_string(frame, "online_id");
+    gchar *id;
+    qof_instance_get (QOF_INSTANCE (account), "online-id", &id, NULL);
+    return id;
 }
 
 /* Used in the midst of editing a transaction; make it save the
  * account data. */
-void gnc_import_set_acc_online_id(Account * account,
-                                  const gchar * string_value)
+void gnc_import_set_acc_online_id (Account *account, const gchar *id)
 {
-    kvp_frame * frame;
     g_return_if_fail (account != NULL);
-    frame = xaccAccountGetSlots(account);
     xaccAccountBeginEdit (account);
-    kvp_frame_set_str(frame, "online_id", string_value);
-    qof_instance_set_dirty (QOF_INSTANCE (account));
+    qof_instance_set (QOF_INSTANCE (account), "online-id", &id, NULL);
     xaccAccountCommitEdit (account);
 }
 
-const gchar * gnc_import_get_trans_online_id(Transaction * transaction)
+const gchar * gnc_import_get_trans_online_id (Transaction * transaction)
 {
-    kvp_frame * frame;
-    frame = xaccTransGetSlots(transaction);
-    return kvp_frame_get_string(frame, "online_id");
+    gchar *id;
+    qof_instance_get (QOF_INSTANCE (transaction), "online-id", &id, NULL);
+    return id;
 }
 /* Not actually used */
-void gnc_import_set_trans_online_id(Transaction * transaction,
-                                    const gchar * string_value)
+void gnc_import_set_trans_online_id (Transaction *transaction,
+				     const gchar *id)
 {
-    kvp_frame * frame;
-    frame = xaccTransGetSlots(transaction);
-    kvp_frame_set_str (frame, "online_id", string_value);
+    g_return_if_fail (transaction != NULL);
+    xaccTransBeginEdit (transaction);
+    qof_instance_set (QOF_INSTANCE (transaction), "online-id", &id, NULL);
+    xaccTransCommitEdit (transaction);
 }
 
 gboolean gnc_import_trans_has_online_id(Transaction * transaction)
@@ -83,21 +80,19 @@ gboolean gnc_import_trans_has_online_id(Transaction * transaction)
     return (online_id != NULL && strlen(online_id) > 0);
 }
 
-const gchar * gnc_import_get_split_online_id(Split * split)
+const gchar * gnc_import_get_split_online_id (Split * split)
 {
-    kvp_frame * frame;
-    frame = xaccSplitGetSlots(split);
-    return kvp_frame_get_string(frame, "online_id");
+    gchar *id;
+    qof_instance_get (QOF_INSTANCE (split), "online-id", &id, NULL);
+    return id;
 }
 /* Used several places in a transaction edit where many other
  * parameters are also being set, so individual commits wouldn't be
- * appropriate. */
-void gnc_import_set_split_online_id(Split * split,
-                                    const gchar * string_value)
+ * appropriate. Besides, there isn't a function for one.*/
+void gnc_import_set_split_online_id (Split *split, const gchar *id)
 {
-    kvp_frame * frame;
-    frame = xaccSplitGetSlots(split);
-    kvp_frame_set_str (frame, "online_id", string_value);
+    g_return_if_fail (split != NULL);
+    qof_instance_set (QOF_INSTANCE (split), "online-id", &id, NULL);
 }
 
 gboolean gnc_import_split_has_online_id(Split * split)

commit 72c7f1d101e5bf508e2ec30ef207dad40734d630
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 15:31:39 2013 -0700

    Remove QofBook functions qof_book_get_slots & qof_book_kvp_changed

diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index 3488a62..58777c0 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -244,20 +244,7 @@ qof_book_set_backend (QofBook *book, QofBackend *be)
     LEAVE (" ");
 }
 
-void qof_book_kvp_changed (QofBook *book)
-{
-    qof_book_begin_edit(book);
-    qof_instance_set_dirty (QOF_INSTANCE (book));
-    qof_book_commit_edit(book);
-}
-
 /* ====================================================================== */
-
-KvpFrame *qof_book_get_slots(const QofBook *book)
-{
-    return qof_instance_get_slots(QOF_INSTANCE(book));
-}
-
 /* Store arbitrary pointers in the QofBook for data storage extensibility */
 /* XXX if data is NULL, we should remove the key from the hash table!
  */
@@ -379,7 +366,7 @@ qof_book_get_counter (QofBook *book, const char *counter_name)
     }
 
     /* Use the KVP in the book */
-    kvp = qof_book_get_slots (book);
+    kvp = qof_instance_get_slots (QOF_INSTANCE (book));
 
     if (!kvp)
     {
@@ -431,7 +418,7 @@ qof_book_increment_and_format_counter (QofBook *book, const char *counter_name)
     counter++;
 
     /* Get the KVP from the current book */
-    kvp = qof_book_get_slots (book);
+    kvp = qof_instance_get_slots (QOF_INSTANCE (book));
 
     if (!kvp)
     {
@@ -480,7 +467,7 @@ qof_book_get_counter_format(const QofBook *book, const char *counter_name)
     }
 
     /* Get the KVP from the current book */
-    kvp = qof_book_get_slots (book);
+    kvp = qof_instance_get_slots (QOF_INSTANCE (book));
 
     if (!kvp)
     {
@@ -633,8 +620,9 @@ qof_book_use_trading_accounts (const QofBook *book)
 {
     const char *opt;
     kvp_value *kvp_val;
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
 
-    kvp_val = kvp_frame_get_slot_path (qof_book_get_slots (book),
+    kvp_val = kvp_frame_get_slot_path (frame,
                                        KVP_OPTION_PATH,
                                        OPTION_SECTION_ACCOUNTS,
                                        OPTION_NAME_TRADING_ACCOUNTS,
@@ -656,9 +644,10 @@ qof_book_use_split_action_for_num_field (const QofBook *book)
 {
     const char *opt;
     kvp_value *kvp_val;
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
 
     g_assert(book);
-    kvp_val = kvp_frame_get_slot_path (qof_book_get_slots (book),
+    kvp_val = kvp_frame_get_slot_path (frame,
                                        KVP_OPTION_PATH,
                                        OPTION_SECTION_ACCOUNTS,
                                        OPTION_NAME_NUM_FIELD_SOURCE,
@@ -683,8 +672,10 @@ gint qof_book_get_num_days_autoreadonly (const QofBook *book)
 {
     kvp_value *kvp_val;
     double tmp;
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+
     g_assert(book);
-    kvp_val = kvp_frame_get_slot_path (qof_book_get_slots (book),
+    kvp_val = kvp_frame_get_slot_path (frame,
                                        KVP_OPTION_PATH,
                                        OPTION_SECTION_ACCOUNTS,
                                        OPTION_NAME_AUTO_READONLY_DAYS,
@@ -718,14 +709,16 @@ GDate* qof_book_get_autoreadonly_gdate (const QofBook *book)
 const char*
 qof_book_get_string_option(const QofBook* book, const char* opt_name)
 {
-    return kvp_frame_get_string(qof_book_get_slots(book), opt_name);
+    return kvp_frame_get_string(qof_instance_get_slots(QOF_INSTANCE (book)),
+				opt_name);
 }
 
 void
 qof_book_set_string_option(QofBook* book, const char* opt_name, const char* opt_val)
 {
     qof_book_begin_edit(book);
-    kvp_frame_set_string(qof_book_get_slots(book), opt_name, opt_val);
+    kvp_frame_set_string(qof_instance_get_slots(QOF_INSTANCE (book)),
+						opt_name, opt_val);
     qof_instance_set_dirty (QOF_INSTANCE (book));
     qof_book_commit_edit(book);
 }
diff --git a/src/libqof/qof/qofbook.h b/src/libqof/qof/qofbook.h
index a66139f..6774ab6 100644
--- a/src/libqof/qof/qofbook.h
+++ b/src/libqof/qof/qofbook.h
@@ -206,24 +206,11 @@ QofCollection  * qof_book_get_collection (const QofBook *, QofIdType);
 typedef void (*QofCollectionForeachCB) (QofCollection *, gpointer user_data);
 void qof_book_foreach_collection (const QofBook *, QofCollectionForeachCB, gpointer);
 
-/** Return The kvp data for the book.
- *  Note that the book KVP data is persistent, and is stored/retrieved
- *  from the file/database.  Thus, the book KVP is the correct place to
- *  store data that needs to be persistent accross sessions (or shared
- *  between multiple users).  To store application runtime data, use
- *  qof_book_set_data() instead.
- */
-KvpFrame *qof_book_get_slots(const QofBook *book);
-
 /** The qof_book_set_data() allows arbitrary pointers to structs
  *    to be stored in QofBook. This is the "preferred" method for
  *    extending QofBook to hold new data types.  This is also
  *    the ideal location to store other arbitrary runtime data
  *    that the application may need.
- *
- *    The book data differs from the book KVP in that the contents
- *    of the book KVP are persistent (are saved and restored to file
- *    or database), whereas the data pointers exist only at runtime.
  */
 void qof_book_set_data (QofBook *book, const gchar *key, gpointer data);
 
@@ -307,10 +294,6 @@ time64 qof_book_get_session_dirty_time(const QofBook *book);
  */
 void qof_book_set_dirty_cb(QofBook *book, QofBookDirtyCB cb, gpointer user_data);
 
-/** Call this function when you change the book kvp, to make sure the book
- * is marked 'dirty'. */
-void qof_book_kvp_changed (QofBook *book);
-
 /** This will get the named counter for this book. The return value is
  *    -1 on error or the current value of the counter.
  */

commit 11aae5b2b9366122e5216a959d05e5e4f7a2c0db
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Oct 27 15:28:37 2013 -0700

    Move features hash creation to QofBook
    
    So that the KVP stays private.

diff --git a/src/core-utils/gnc-features.c b/src/core-utils/gnc-features.c
index c6dd34e..32f20cd 100644
--- a/src/core-utils/gnc-features.c
+++ b/src/core-utils/gnc-features.c
@@ -66,10 +66,12 @@ static void gnc_features_init ()
                              g_strdup (known_features[i].desc));
 }
 
-static void gnc_features_test_one(const gchar *key, KvpValue *value, gpointer data)
+static void gnc_features_test_one(gpointer pkey, gpointer value,
+				  gpointer data)
 {
+    const gchar *key = (const gchar*)pkey;
+    const gchar *feature_desc = (const gchar*)value;
     GList **unknown_features;
-    gchar *feature_desc;
 
     g_assert(data);
     unknown_features = (GList**) data;
@@ -79,54 +81,47 @@ static void gnc_features_test_one(const gchar *key, KvpValue *value, gpointer da
         return;
 
     /* It is unknown, so add the description to the unknown features list: */
-    feature_desc = kvp_value_get_string(value);
     g_assert(feature_desc);
 
-    *unknown_features = g_list_prepend(*unknown_features, feature_desc);
+    *unknown_features = g_list_prepend(*unknown_features,
+				       (gpointer)feature_desc);
 }
 
 /* Check if the session requires features unknown to this version of GnuCash.
  *
- * Returns a message to display if we found unknown features, NULL if we're okay.
+ * Returns a message to display if we found unknown features, NULL if
+ * we're okay.
  */
 gchar *gnc_features_test_unknown (QofBook *book)
 {
-    KvpFrame *frame = qof_book_get_slots (book);
-    KvpValue *value;
 
     /* Setup the known_features hash table */
     gnc_features_init();
 
-    g_assert(frame);
-    value = kvp_frame_get_value(frame, "features");
+    GList* features_list = NULL;
+    GHashTable *features_used = qof_book_get_features (book);
 
-    if (value)
+    /* Iterate over the members of this frame for unknown features */
+    g_hash_table_foreach (features_used, &gnc_features_test_one,
+			  &features_list);
+    if (features_list)
     {
-        GList* features_list = NULL;
-        frame = kvp_value_get_frame(value);
-        g_assert(frame);
-
-        /* Iterate over the members of this frame for unknown features */
-        kvp_frame_for_each_slot(frame, &gnc_features_test_one, &features_list);
-        if (features_list)
-        {
-            GList *i;
-            char* msg = g_strdup(
-                            _("This Dataset contains features not supported by this "
-                              "version of GnuCash. You must use a newer version of "
-                              "GnuCash in order to support the following features:"
+	GList *i;
+	char* msg = g_strdup(_("This Dataset contains features not supported "
+			       "by this version of GnuCash. You must use a "
+			       "newer version of GnuCash in order to support "
+			       "the following features:"
                              ));
 
-            for (i = features_list; i; i = i->next)
-            {
-                char *tmp = g_strconcat(msg, "\n* ", i->data, NULL);
-                g_free (msg);
-                msg = tmp;
-            }
+	for (i = features_list; i; i = i->next)
+	{
+	    char *tmp = g_strconcat(msg, "\n* ", i->data, NULL);
+	    g_free (msg);
+	    msg = tmp;
+	}
 
-            g_list_free(features_list);
-            return msg;
-        }
+	g_list_free(features_list);
+	return msg;
     }
 
     return NULL;
@@ -134,9 +129,7 @@ gchar *gnc_features_test_unknown (QofBook *book)
 
 void gnc_features_set_used (QofBook *book, const gchar *feature)
 {
-    KvpFrame *frame;
     const gchar *description;
-    gchar *kvp_path;
 
     g_return_if_fail (book);
     g_return_if_fail (feature);
@@ -151,10 +144,7 @@ void gnc_features_set_used (QofBook *book, const gchar *feature)
         return;
     }
 
-    frame = qof_book_get_slots (book);
-    kvp_path = g_strconcat ("/features/", feature, NULL);
-    kvp_frame_set_string (frame, kvp_path, description);
-    qof_book_kvp_changed (book);
+    qof_book_set_feature (book, feature, description);
 
 
 }
diff --git a/src/libqof/qof/qofbook.c b/src/libqof/qof/qofbook.c
index e2b6aa2..3488a62 100644
--- a/src/libqof/qof/qofbook.c
+++ b/src/libqof/qof/qofbook.c
@@ -742,6 +742,36 @@ static void commit_err (QofInstance *inst, QofBackendError errcode)
 //  gnc_engine_signal_commit_error( errcode );
 }
 
+#define GNC_FEATURES "/features/"
+static void
+add_feature_to_hash (const gchar *key, KvpValue *value, gpointer user_data)
+{
+    gchar *descr = kvp_value_get_string (value);
+    g_hash_table_insert (*(GHashTable**)user_data, (gchar*)key, descr);
+}
+
+GHashTable *
+qof_book_get_features (QofBook *book)
+{
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+    GHashTable *features = g_hash_table_new (g_str_hash, g_str_equal);
+
+    frame = kvp_frame_get_frame (frame, GNC_FEATURES);
+    kvp_frame_for_each_slot (frame, &add_feature_to_hash, &features);
+    return features;
+}
+
+void
+qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
+{
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
+    gchar *path = g_strconcat (GNC_FEATURES, key, NULL);
+    qof_book_begin_edit (book);
+    kvp_frame_set_string (frame, path, descr);
+    qof_instance_set_dirty (QOF_INSTANCE (book));
+    qof_book_commit_edit (book);
+}
+
 static void noop (QofInstance *inst) {}
 
 void
diff --git a/src/libqof/qof/qofbook.h b/src/libqof/qof/qofbook.h
index fef6d92..a66139f 100644
--- a/src/libqof/qof/qofbook.h
+++ b/src/libqof/qof/qofbook.h
@@ -337,6 +337,11 @@ gchar *qof_book_get_counter_format (const QofBook *book, const char *counter_nam
 const char* qof_book_get_string_option(const QofBook* book, const char* opt_name);
 void qof_book_set_string_option(QofBook* book, const char* opt_name, const char* opt_val);
 
+/** Access functions for reading and setting the used-features on this book.
+ */
+GHashTable *qof_book_get_features (QofBook *book);
+void qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr);
+
 void qof_book_begin_edit(QofBook *book);
 void qof_book_commit_edit(QofBook *book);
 

commit 48df2d356990803e54c73a78b940617ac88d5dd0
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Oct 17 10:03:04 2013 -0700

    New Split properties sx-account, sx-credit-formula, sx-debit-formula

diff --git a/src/engine/SX-book.c b/src/engine/SX-book.c
index 62be033..1d471fe 100644
--- a/src/engine/SX-book.c
+++ b/src/engine/SX-book.c
@@ -375,9 +375,9 @@ gnc_sx_get_sxes_referencing_account(QofBook *book, Account *acct)
         for (; splits != NULL; splits = splits->next)
         {
             Split *s = (Split*)splits->data;
-            KvpFrame *frame = kvp_frame_get_frame(xaccSplitGetSlots(s), GNC_SX_ID);
-            GncGUID *sx_split_acct_guid = kvp_frame_get_guid(frame, GNC_SX_ACCOUNT);
-            if (guid_equal(acct_guid, sx_split_acct_guid))
+            GncGUID *guid;
+            qof_instance_get (QOF_INSTANCE (s), "sx-account", &guid, NULL);
+            if (guid_equal(acct_guid, guid))
             {
                 rtn = g_list_append(rtn, sx);
             }
diff --git a/src/engine/SchedXaction.c b/src/engine/SchedXaction.c
index b342358..8fb487f 100644
--- a/src/engine/SchedXaction.c
+++ b/src/engine/SchedXaction.c
@@ -1041,8 +1041,8 @@ pack_split_info (TTSplitInfo *s_info, Account *parent_acct,
                  Transaction *parent_trans, QofBook *book)
 {
     Split *split;
-    KvpFrame *split_frame;
-    KvpValue *tmp_value;
+    const gchar *credit_formula;
+    const gchar *debit_formula;
     const GncGUID *acc_guid;
 
     split = xaccMallocSplit(book);
@@ -1058,40 +1058,14 @@ pack_split_info (TTSplitInfo *s_info, Account *parent_acct,
     xaccAccountInsertSplit(parent_acct,
                            split);
 
-    split_frame = xaccSplitGetSlots(split);
-
-    tmp_value
-    = kvp_value_new_string(gnc_ttsplitinfo_get_credit_formula(s_info));
-
-    kvp_frame_set_slot_path(split_frame,
-                            tmp_value,
-                            GNC_SX_ID,
-                            GNC_SX_CREDIT_FORMULA,
-                            NULL);
-    kvp_value_delete(tmp_value);
-
-    tmp_value
-    = kvp_value_new_string(gnc_ttsplitinfo_get_debit_formula(s_info));
-
-    kvp_frame_set_slot_path(split_frame,
-                            tmp_value,
-                            GNC_SX_ID,
-                            GNC_SX_DEBIT_FORMULA,
-                            NULL);
-
-    kvp_value_delete(tmp_value);
-
+    credit_formula = gnc_ttsplitinfo_get_credit_formula(s_info);
+    debit_formula = gnc_ttsplitinfo_get_debit_formula(s_info);
     acc_guid = qof_entity_get_guid(QOF_INSTANCE(gnc_ttsplitinfo_get_account(s_info)));
-
-    tmp_value = kvp_value_new_guid(acc_guid);
-
-    kvp_frame_set_slot_path(split_frame,
-                            tmp_value,
-                            GNC_SX_ID,
-                            GNC_SX_ACCOUNT,
-                            NULL);
-
-    kvp_value_delete(tmp_value);
+    qof_instance_set (QOF_INSTANCE (split),
+		      "sx-credit-formula", credit_formula,
+		      "sx-debit-formula", debit_formula,
+		      "sx-account", acc_guid,
+		      NULL);
 
     return split;
 }
diff --git a/src/engine/SchedXaction.h b/src/engine/SchedXaction.h
index 08031e1..d78b975 100644
--- a/src/engine/SchedXaction.h
+++ b/src/engine/SchedXaction.h
@@ -305,9 +305,6 @@ GList *gnc_sx_get_defer_instances( SchedXaction *sx );
 
 /* #defines for KvpFrame strings and QOF */
 #define GNC_SX_ID                    "sched-xaction"
-#define GNC_SX_ACCOUNT               "account"
-#define GNC_SX_CREDIT_FORMULA        "credit-formula"
-#define GNC_SX_DEBIT_FORMULA         "debit-formula"
 #define GNC_SX_CREDIT_NUMERIC        "credit-numeric"
 #define GNC_SX_DEBIT_NUMERIC         "debit-numeric"
 #define GNC_SX_SHARES                "shares"
diff --git a/src/engine/Split.c b/src/engine/Split.c
index 87b36d9..47d2d20 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -61,6 +61,12 @@ const char *void_former_val_str = "void-former-value";
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = GNC_MOD_ENGINE;
 
+/* KVP key values used for SX info stored Split's slots. */
+#define GNC_SX_ID                    "sched-xaction"
+#define GNC_SX_ACCOUNT               "account"
+#define GNC_SX_CREDIT_FORMULA        "credit-formula"
+#define GNC_SX_DEBIT_FORMULA         "debit-formula"
+
 enum
 {
     PROP_0,
@@ -71,7 +77,10 @@ enum
     PROP_RECONCILE_DATE,
     PROP_TX,
     PROP_ACCOUNT,
-    PROP_LOT
+    PROP_SX_CREDIT_FORMULA,
+    PROP_SX_DEBIT_FORMULA,
+    PROP_SX_ACCOUNT,
+    PROP_LOT,
 };
 
 /* GObject Initialization */
@@ -127,6 +136,7 @@ gnc_split_get_property(GObject         *object,
                        GParamSpec      *pspec)
 {
     Split *split;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_SPLIT(object));
 
@@ -157,6 +167,18 @@ gnc_split_get_property(GObject         *object,
     case PROP_LOT:
         g_value_take_object(value, split->lot);
         break;
+    case PROP_SX_CREDIT_FORMULA:
+	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_SX_DEBIT_FORMULA:
+	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_SX_ACCOUNT:
+	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
+	qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -171,6 +193,7 @@ gnc_split_set_property(GObject         *object,
 {
     Split *split;
     gnc_numeric* number;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_SPLIT(object));
 
@@ -203,7 +226,19 @@ gnc_split_set_property(GObject         *object,
     case PROP_LOT:
         xaccSplitSetLot(split, g_value_get_object(value));
         break;
-    default:
+    case PROP_SX_CREDIT_FORMULA:
+	key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_SX_DEBIT_FORMULA:
+	key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
+    case PROP_SX_ACCOUNT:
+	key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
+	qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+	break;
+     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
     }
@@ -300,6 +335,37 @@ gnc_split_class_init(SplitClass* klass)
                           "The lot that this split belongs to.",
                           GNC_TYPE_LOT,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_MEMO,
+     g_param_spec_string("sx-debit-formula",
+                         "Schedule Transaction Debit Formula",
+			 "The formula used to calculate the actual debit "
+			 "amount when a real split is generated from this "
+			 "SX split.",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_MEMO,
+     g_param_spec_string("sx-credit-formula",
+                         "Schedule Transaction Credit Formula",
+			 "The formula used to calculate the actual credit "
+			 "amount when a real split is generated from this "
+			 "SX split.",
+                         NULL,
+                         G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_SX_ACCOUNT,
+     g_param_spec_boxed("sx-account",
+                        "Scheduled Transaction Account",
+                        "The target account for a scheduled transaction split.",
+                        GNC_TYPE_GUID,
+                        G_PARAM_READWRITE));
 }
 
 /********************************************************************\
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index ba74edd..509bafc 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -47,13 +47,14 @@ typedef struct
     {
 	Account      *acct;
 	Transaction  *trans;
+	Split        *split;
 	GNCLot       *lot;
 	GncCustomer  *cust;
 	GncEmployee  *emp;
 	GncJob       *job;
 	GncVendor    *vend;
     };
-    GSList *split;
+    GSList *hdlrs;
 } Fixture;
 
 /* Prototype to shut clang up */
@@ -79,6 +80,13 @@ setup_trans (Fixture *fixture, gconstpointer pData)
 }
 
 static void
+setup_split (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->split = xaccMallocSplit (book);
+}
+
+static void
 setup_lot (Fixture *fixture, gconstpointer pData)
 {
     QofBook *book = qof_book_new ();
@@ -139,6 +147,39 @@ test_trans_kvp_properties (Fixture *fixture, gconstpointer pData)
 }
 
 static void
+test_split_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gchar *debit_formula = "e^xdydx";
+    gchar *credit_formula = "seccostansin";
+    gchar *debit_formula_r, *credit_formula_r;
+    GncGUID *sx_account = guid_malloc ();
+    GncGUID *sx_account_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->split),
+		      "sx-debit-formula", debit_formula,
+		      "sx-credit-formula", credit_formula,
+		      "sx-account", sx_account,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
+
+    qof_instance_get (QOF_INSTANCE (fixture->split),
+		      "sx-debit-formula", &debit_formula_r,
+		      "sx-credit-formula", &credit_formula_r,
+		      "sx-account", &sx_account_r,
+		      NULL);
+    g_assert_cmpstr (debit_formula, ==, debit_formula_r);
+    g_assert_cmpstr (credit_formula, ==, credit_formula_r);
+    g_assert (guid_equal (sx_account, sx_account_r));
+    g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
+    g_free (debit_formula_r);
+    g_free (credit_formula_r);
+    guid_free (sx_account);
+    guid_free (sx_account_r);
+}
+
+static void
 test_lot_kvp_properties (Fixture *fixture, gconstpointer pData)
 {
     GncGUID *invoice = guid_malloc ();
@@ -176,5 +217,6 @@ void test_suite_engine_kvp_properties (void)
 {
     GNC_TEST_ADD (suitename, "Account", Fixture, NULL, setup_account, test_account_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Transaction", Fixture, NULL, setup_trans, test_trans_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Split", Fixture, NULL, setup_split, test_split_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Lot", Fixture, NULL, setup_lot, test_lot_kvp_properties, teardown);
 }

commit dc8e9c0b00d8ae210c4b2c77ff86c72d0ff18537
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Oct 17 10:00:27 2013 -0700

    Remove kvp-data as a QofInstance object property
    
    Not actually used anywhere, but yet another back door into private data.

diff --git a/src/libqof/qof/qofinstance.c b/src/libqof/qof/qofinstance.c
index e0f5dfe..dd9e330 100644
--- a/src/libqof/qof/qofinstance.c
+++ b/src/libqof/qof/qofinstance.c
@@ -52,7 +52,6 @@ enum
     PROP_GUID,
     PROP_COLLECTION,
     PROP_BOOK,
-    PROP_KVP_DATA,
     PROP_LAST_UPDATE,
     PROP_EDITLEVEL,
     PROP_DESTROYING,
@@ -73,12 +72,6 @@ typedef struct QofInstancePrivate
     /* The entity_table in which this instance is stored */
     QofBook * book;
 
-    /* kvp_data is a key-value pair database for storing arbirtary
-     * information associated with this instance.
-     * See src/engine/kvp_doc.txt for a list and description of the
-     * important keys. */
-//    KvpFrame *kvp_data;
-
     /*  Timestamp used to track the last modification to this
      *  instance.  Typically used to compare two versions of the
      *  same object, to see which is newer.  When used with the
@@ -170,15 +163,6 @@ static void qof_instance_class_init(QofInstanceClass *klass)
 
     g_object_class_install_property
     (object_class,
-     PROP_KVP_DATA,
-     g_param_spec_pointer ("kvp-data",
-                           "Object KVP Data",
-                           "A pointer to the key-value data associated "
-                           "with this object.",
-                           G_PARAM_READWRITE));
-
-    g_object_class_install_property
-    (object_class,
      PROP_LAST_UPDATE,
      g_param_spec_pointer ("last-update",
                            "Object Last Update",
@@ -384,9 +368,6 @@ qof_instance_get_property (GObject         *object,
     case PROP_BOOK:
         g_value_take_object(value, priv->book);
         break;
-    case PROP_KVP_DATA:
-        g_value_set_pointer(value, inst->kvp_data);
-        break;
     case PROP_LAST_UPDATE:
         g_value_set_pointer(value, &priv->last_update);
         break;
@@ -441,9 +422,6 @@ qof_instance_set_property (GObject         *object,
     case PROP_BOOK:
         qof_instance_set_book(inst, g_value_get_object(value));
         break;
-    case PROP_KVP_DATA:
-        qof_instance_set_slots(inst, g_value_get_pointer(value));
-        break;
     case PROP_LAST_UPDATE:
         ts = g_value_get_pointer(value);
         qof_instance_set_last_update(inst, *ts);

commit 4f5e22890391922349237212c5ec3923844399c1
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Oct 17 09:51:55 2013 -0700

    Replace xaccSplitCopy with xaccSplitCopyNoKvp and xaccSplitCopyKvp
    
    Provides ability to copy a split without its KVP instead of having to directly access the KVP and replace it with an empty frame.

diff --git a/src/engine/Split.c b/src/engine/Split.c
index e1fcbca..87b36d9 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -407,7 +407,7 @@ xaccDupeSplit (const Split *s)
 }
 
 Split *
-xaccSplitClone (const Split *s)
+xaccSplitCloneNoKvp (const Split *s)
 {
     Split *split = g_object_new (GNC_TYPE_SPLIT, NULL);
 
@@ -425,10 +425,8 @@ xaccSplitClone (const Split *s)
     split->gains = GAINS_STATUS_UNKNOWN;
     split->gains_split = NULL;
 
-    qof_instance_init_data(&split->inst, GNC_ID_SPLIT, qof_instance_get_book(s));
-    kvp_frame_delete(split->inst.kvp_data);
-    split->inst.kvp_data = kvp_frame_copy(s->inst.kvp_data);
-
+    qof_instance_init_data(&split->inst, GNC_ID_SPLIT,
+                           qof_instance_get_book(s));
     xaccAccountInsertSplit(s->acc, split);
     if (s->lot)
     {
@@ -438,6 +436,11 @@ xaccSplitClone (const Split *s)
     return split;
 }
 
+void
+xaccSplitCopyKvp (const Split *from, Split *to)
+{
+    to->inst.kvp_data = kvp_frame_copy(from->inst.kvp_data);
+}
 
 /*################## Added for Reg2 #################*/
 
diff --git a/src/engine/SplitP.h b/src/engine/SplitP.h
index 93f0ed5..2832dc8 100644
--- a/src/engine/SplitP.h
+++ b/src/engine/SplitP.h
@@ -146,7 +146,8 @@ struct _SplitClass
  */
 void  xaccFreeSplit (Split *split);    /* frees memory */
 
-Split * xaccSplitClone (const Split *s);
+Split *xaccSplitCloneNoKvp (const Split *s);
+void xaccSplitCopyKvp (const Split *from, Split *to);
 
 Split *xaccDupeSplit (const Split *s);
 void mark_split (Split *s);
diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index 8d2375d..5ca1e5c 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -621,7 +621,7 @@ xaccTransCloneNoKvp (const Transaction *from)
     xaccTransBeginEdit(to);
     for (node = from->splits; node; node = node->next)
     {
-        split = xaccSplitClone(node->data);
+        split = xaccSplitCloneNoKvp(node->data);
         split->parent = to;
         to->splits = g_list_append (to->splits, split);
     }
@@ -636,8 +636,15 @@ Transaction *
 xaccTransClone (const Transaction *from)
 {
     Transaction *to = xaccTransCloneNoKvp (from);
+    int i = 0;
+    int length = g_list_length (from->splits);
+
     xaccTransBeginEdit (to);
     to->inst.kvp_data = kvp_frame_copy (from->inst.kvp_data);
+    g_assert (g_list_length (to->splits) == length);
+    for (i = 0; i < length; ++i)
+	xaccSplitCopyKvp (g_list_nth_data (from->splits, i),
+			    g_list_nth_data (to->splits, i));
     xaccTransCommitEdit (to);
     return to;
 }
diff --git a/src/engine/test/utest-Split.c b/src/engine/test/utest-Split.c
index 4bff6cc..6b4bb98 100644
--- a/src/engine/test/utest-Split.c
+++ b/src/engine/test/utest-Split.c
@@ -310,15 +310,15 @@ test_xaccDupeSplit (Fixture *fixture, gconstpointer pData)
     g_assert (split->gains_split != f_split->gains_split);
 
 }
-/* xaccSplitClone
+/* xaccSplitCloneNoKvp
 Split *
-xaccSplitClone (const Split *s)// C: 1
+xaccSplitCloneNoKvp (const Split *s)// C: 1 
 */
 static void
-test_xaccSplitClone (Fixture *fixture, gconstpointer pData)
+test_xaccSplitCloneNoKvp (Fixture *fixture, gconstpointer pData)
 {
     Split *f_split = fixture->split;
-    Split *split = xaccSplitClone (f_split);
+    Split *split = xaccSplitCloneNoKvp (f_split);
 
     g_assert (split != fixture->split);
     g_assert (qof_instance_get_guid (split) != qof_instance_get_guid (f_split));
@@ -331,7 +331,7 @@ test_xaccSplitClone (Fixture *fixture, gconstpointer pData)
     g_assert (split->lot == f_split->lot);
     g_assert_cmpstr (split->memo, ==, f_split->memo);
     g_assert_cmpstr (split->action, ==, f_split->action);
-    g_assert (kvp_frame_compare (split->inst.kvp_data, f_split->inst.kvp_data) == 0);
+    g_assert (kvp_frame_is_empty (split->inst.kvp_data));
     g_assert_cmpint (split->reconciled, ==, f_split->reconciled);
     g_assert (timespec_equal (&(split->date_reconciled), &(f_split->date_reconciled)));
     g_assert (gnc_numeric_equal (split->value, f_split->value));
@@ -408,7 +408,7 @@ xaccSplitEqual(const Split *sa, const Split *sb,// C: 2 in 2 SCM: 1
 static void
 test_xaccSplitEqual (Fixture *fixture, gconstpointer pData)
 {
-    Split *split1 = xaccSplitClone (fixture->split);
+    Split *split1 = xaccSplitCloneNoKvp (fixture->split);
     Split *split2 = xaccDupeSplit (fixture->split);
     gchar *msg01 = "[xaccSplitEqual] one is NULL";
     gchar *msg02 = "[xaccSplitEqual] GUIDs differ";
@@ -771,16 +771,6 @@ test_get_commodity_denom (Fixture *fixture, gconstpointer pData)
     fixture->split->acc = acc;
     g_assert_cmpint (fixture->func->get_commodity_denom (fixture->split), ==, denom);
 }
-/* xaccSplitGetSlots
-KvpFrame *
-xaccSplitGetSlots (const Split * s)// C: 17 in 8
-Simple passthrough, no test.
-*/
-// Not Used
-/* xaccSplitSetSlots_nc
-void
-xaccSplitSetSlots_nc(Split *s, KvpFrame *frm)//
-*/
 /* xaccSplitSetSharePriceAndAmount
 void
 xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)// C: 1
@@ -1873,7 +1863,7 @@ test_suite_split (void)
     GNC_TEST_ADD_FUNC (suitename, "gnc split set & get property", test_gnc_split_set_get_property);
     GNC_TEST_ADD (suitename, "xaccMallocSplit", Fixture, NULL, setup, test_xaccMallocSplit, teardown);
     GNC_TEST_ADD (suitename, "xaccDupeSplit", Fixture, NULL, setup, test_xaccDupeSplit, teardown);
-    GNC_TEST_ADD (suitename, "xaccSplitClone", Fixture, NULL, setup, test_xaccSplitClone, teardown);
+    GNC_TEST_ADD (suitename, "xaccSplitCloneNoKvp", Fixture, NULL, setup, test_xaccSplitCloneNoKvp, teardown);
     GNC_TEST_ADD (suitename, "mark split", Fixture, NULL, setup, test_mark_split, teardown);
     GNC_TEST_ADD (suitename, "xaccSplitEqualCheckBal", Fixture, NULL, setup, test_xaccSplitEqualCheckBal, teardown);
     GNC_TEST_ADD (suitename, "xaccSplitEqual", Fixture, NULL, setup, test_xaccSplitEqual, teardown);

commit c748f33b92a4f1bd8d053366f1550576d62fcfca
Author: John Ralls <jralls at ceridwen.us>
Date:   Wed Oct 16 16:40:05 2013 -0700

    Add xaccTransCopyNoKvm
    
    To avoid having to expose the KVM pointer in order to clear it.
    Also rename xaccDupeTransaction to dupe_trans and make it static,
    because it doesn't commit the new transaction.

diff --git a/src/app-utils/gnc-sx-instance-model.c b/src/app-utils/gnc-sx-instance-model.c
index a3e2586..0965076 100644
--- a/src/app-utils/gnc-sx-instance-model.c
+++ b/src/app-utils/gnc-sx-instance-model.c
@@ -1035,7 +1035,7 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
        as not finding the approrpiate Accounts and not being able to
        parse the formula|credit/debit strings. */
 
-    new_txn = xaccTransClone(template_txn);
+    new_txn = xaccTransCloneNoKvp(template_txn);
     xaccTransBeginEdit(new_txn);
 
     g_debug("creating template txn desc [%s] for sx [%s]",
@@ -1044,9 +1044,6 @@ create_each_transaction_helper(Transaction *template_txn, void *user_data)
 
     g_debug("template txn currency is %s", gnc_commodity_get_mnemonic(xaccTransGetCurrency (template_txn)));
 
-    /* clear any copied KVP data */
-    qof_instance_set_slots(QOF_INSTANCE(new_txn), kvp_frame_new());
-
     /* Bug#500427: copy the notes, if any */
     if (xaccTransGetNotes(template_txn) != NULL)
     {
diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index 259c921..8d2375d 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -554,9 +554,8 @@ xaccTransSortSplits (Transaction *trans)
  * This routine is prone to programmer snafu if not used correctly.
  * It is used only by the edit-rollback code.
  */
-/* Actually, it *is* public, and used by Period.c */
-Transaction *
-xaccDupeTransaction (const Transaction *from)
+static Transaction *
+dupe_trans (const Transaction *from)
 {
     Transaction *to;
     GList *node;
@@ -593,10 +592,11 @@ xaccDupeTransaction (const Transaction *from)
 
 /********************************************************************\
  * Use this routine to externally duplicate a transaction.  It creates
- * a full fledged transaction with unique guid, splits, etc.
+ * a full fledged transaction with unique guid, splits, etc. and
+ * writes it to the database.
 \********************************************************************/
 Transaction *
-xaccTransClone (const Transaction *from)
+xaccTransCloneNoKvp (const Transaction *from)
 {
     Transaction *to;
     Split *split;
@@ -615,9 +615,8 @@ xaccTransClone (const Transaction *from)
 
     to->orig            = NULL;
 
-    qof_instance_init_data (&to->inst, GNC_ID_TRANS, qof_instance_get_book(from));
-    kvp_frame_delete (to->inst.kvp_data);
-    to->inst.kvp_data    = kvp_frame_copy (from->inst.kvp_data);
+    qof_instance_init_data (&to->inst, GNC_ID_TRANS,
+			    qof_instance_get_book(from));
 
     xaccTransBeginEdit(to);
     for (node = from->splits; node; node = node->next)
@@ -633,11 +632,21 @@ xaccTransClone (const Transaction *from)
     return to;
 }
 
+Transaction *
+xaccTransClone (const Transaction *from)
+{
+    Transaction *to = xaccTransCloneNoKvp (from);
+    xaccTransBeginEdit (to);
+    to->inst.kvp_data = kvp_frame_copy (from->inst.kvp_data);
+    xaccTransCommitEdit (to);
+    return to;
+}
+
 /*################## Added for Reg2 #################*/
 
 /********************************************************************\
  * Copy a transaction to the 'clipboard' transaction using
- *  xaccDupeTransaction. The 'clipboard' transaction must never
+ *  dupe_trans. The 'clipboard' transaction must never
  *  be dereferenced.
 \********************************************************************/
 Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
@@ -647,7 +656,7 @@ Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
     if (!from_trans)
         return NULL;
 
-    to_trans = xaccDupeTransaction(from_trans);
+    to_trans = dupe_trans(from_trans);
     return to_trans;
 }
 
@@ -664,7 +673,7 @@ xaccTransCopyOnto(const Transaction *from_trans, Transaction *to_trans)
 /********************************************************************\
  * This function explicitly must robustly handle some unusual input.
  *
- *  'from_trans' may be a duped trans (see xaccDupeTransaction), so its
+ *  'from_trans' may be a duped trans (see dupe_trans), so its
  *   splits may not really belong to the accounts that they say they do.
  *
  *  'from_acc' need not be a valid account. It may be an already freed
@@ -1330,7 +1339,7 @@ xaccTransBeginEdit (Transaction *trans)
 
     /* Make a clone of the transaction; we will use this
      * in case we need to roll-back the edit. */
-    trans->orig = xaccDupeTransaction (trans);
+    trans->orig = dupe_trans (trans);
 }
 
 /********************************************************************\
@@ -2774,6 +2783,7 @@ _utest_trans_fill_functions (void)
     func->trans_on_error = trans_on_error;
     func->trans_cleanup_commit = trans_cleanup_commit;
     func->xaccTransScrubGainsDate = xaccTransScrubGainsDate;
+    func->dupe_trans = dupe_trans;
     return func;
 }
 
diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h
index 7fe4069..d956e28 100644
--- a/src/engine/Transaction.h
+++ b/src/engine/Transaction.h
@@ -156,6 +156,12 @@ void          xaccTransDestroy (Transaction *trans);
  */
 Transaction * xaccTransClone (const Transaction *t);
 
+/**
+ The xaccTransCloneNoKvp() method will create a complete copy of an
+ existing transaction except that the KVP slots will be empty.
+ */
+Transaction * xaccTransCloneNoKvp (const Transaction *t);
+
 /** Equality.
  *
  * @param ta First transaction to compare
@@ -223,7 +229,7 @@ Transaction * xaccTransLookup (const GncGUID *guid, QofBook *book);
 /*################## Added for Reg2 #################*/
 
 /** Copy a transaction to the 'clipboard' transaction using
- *  xaccDupeTransaction. The 'clipboard' transaction must never
+ *  dupe_transaction. The 'clipboard' transaction must never
  *  be dereferenced.
  */
 Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans);
diff --git a/src/engine/TransactionP.h b/src/engine/TransactionP.h
index d7935e8..87b89bf 100644
--- a/src/engine/TransactionP.h
+++ b/src/engine/TransactionP.h
@@ -186,6 +186,7 @@ typedef struct
     void (*trans_on_error)(Transaction*, QofBackendError);
     void (*trans_cleanup_commit)(Transaction*);
     void (*xaccTransScrubGainsDate)(Transaction*);
+    Transaction *(*dupe_trans)(const Transaction*);
 
 } TransTestFunctions;
 
diff --git a/src/engine/test/utest-Transaction.c b/src/engine/test/utest-Transaction.c
index 35330a4..b5c24b9 100644
--- a/src/engine/test/utest-Transaction.c
+++ b/src/engine/test/utest-Transaction.c
@@ -569,12 +569,12 @@ test_xaccTransSortSplits (Fixture *fixture, gconstpointer pData)
 
     xaccTransCommitEdit (txn);
 }
-/* xaccDupeTransaction
-Transaction *
-xaccDupeTransaction (const Transaction *from)// Local: 1:0:0
+/* dupe_trans
+static Transaction *
+dupe_trans (const Transaction *from)// Local: 1:0:0
 */
 static void
-test_xaccDupeTransaction (Fixture *fixture, gconstpointer pData)
+test_dupe_trans (Fixture *fixture, gconstpointer pData)
 {
     Timespec posted = gnc_dmy2timespec (12, 7, 2011);
     Timespec entered = gnc_dmy2timespec (14, 7, 2011);
@@ -587,7 +587,7 @@ test_xaccDupeTransaction (Fixture *fixture, gconstpointer pData)
     kvp_frame_set_string (old->inst.kvp_data, "/foo/bar/baz",
                           "The Great Waldo Pepper");
 
-    new = xaccDupeTransaction (old);
+    new = fixture->func->dupe_trans (old);
 
     g_assert_cmpstr (new->num, ==, old->num);
     g_assert_cmpstr (new->description, ==, old->description);
@@ -1398,29 +1398,27 @@ void
 xaccTransDestroy (Transaction *trans)// C: 26 in 15 SCM: 4 in 4 Local: 3:0:0
 */
 static void
-test_xaccTransDestroy ()
+test_xaccTransDestroy (Fixture *fixture, gconstpointer pData)
 {
-    QofBook *book = qof_book_new ();
-    Transaction *txn = xaccMallocTransaction (book);
-    Transaction *dupe = xaccDupeTransaction (txn);
+    Transaction *txn = fixture->txn;
+    QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
+    Transaction *dupe = xaccTransClone (txn);
 
     xaccTransBeginEdit (txn);
     g_assert (!qof_instance_get_destroying (QOF_INSTANCE (txn)));
-    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, TRUE, TRUE));
+    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
     xaccTransDestroy (txn);
     g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
-    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, TRUE, TRUE));
+    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
     xaccTransRollbackEdit (txn);
     qof_book_mark_readonly (book);
     xaccTransBeginEdit (txn);
     xaccTransDestroy (txn);
     g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
-    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, TRUE, TRUE));
+    g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
     xaccTransRollbackEdit (txn);
 
-    test_destroy (txn);
     test_destroy (dupe);
-    test_destroy (book);
 }
 /* destroy_gains
 static void
@@ -1790,7 +1788,7 @@ static void
 test_xaccTransOrder_num_action (Fixture *fixture, gconstpointer pData)
 {
     Transaction *txnA = fixture->txn;
-    Transaction *txnB = xaccDupeTransaction (txnA);
+    Transaction *txnB = fixture->func->dupe_trans (txnA);
 
     g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, NULL, NULL), ==, -1);
     g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, txnA, NULL), ==, 1);
@@ -2042,7 +2040,7 @@ test_suite_transaction (void)
     GNC_TEST_ADD (suitename, "gnc transaction set/get property", Fixture, NULL, setup, test_gnc_transaction_set_get_property, teardown);
     GNC_TEST_ADD (suitename, "xaccMallocTransaction", Fixture, NULL, setup, test_xaccMallocTransaction, teardown);
     GNC_TEST_ADD (suitename, "xaccTransSortSplits", Fixture, NULL, setup, test_xaccTransSortSplits, teardown);
-    GNC_TEST_ADD (suitename, "xaccDupeTransaction", Fixture, NULL, setup, test_xaccDupeTransaction, teardown);
+    GNC_TEST_ADD (suitename, "dupe_trans", Fixture, NULL, setup, test_dupe_trans, teardown);
     GNC_TEST_ADD (suitename, "xaccTransClone", Fixture, NULL, setup, test_xaccTransClone, teardown);
     GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard, teardown);
     GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard No-Start", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard_no_start, teardown);
@@ -2063,7 +2061,7 @@ test_suite_transaction (void)
 
     GNC_TEST_ADD (suitename, "xaccTransSetCurrency", Fixture, NULL, setup, test_xaccTransSetCurrency, teardown);
     GNC_TEST_ADD_FUNC (suitename, "xaccTransBeginEdit", test_xaccTransBeginEdit);
-    GNC_TEST_ADD_FUNC (suitename, "xaccTransDestroy", test_xaccTransDestroy);
+    GNC_TEST_ADD (suitename, "xaccTransDestroy", Fixture, NULL, setup, test_xaccTransDestroy, teardown);
     GNC_TEST_ADD (suitename, "destroy gains", GainsFixture, NULL, setup_with_gains, test_destroy_gains, teardown_with_gains);
     GNC_TEST_ADD (suitename, "do destroy", GainsFixture, NULL, setup_with_gains, test_do_destroy, teardown_with_gains);
     GNC_TEST_ADD (suitename, "was trans emptied", Fixture, NULL, setup, test_was_trans_emptied, teardown);

commit f29ea9fbe9e1b90257bcc9da8126abdc4d39a481
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 17:11:01 2013 -0700

    Add properties "invoice", "owner-type", and "owner-guid"
    
    Replaces direct KVP access.

diff --git a/src/engine/gnc-engine.h b/src/engine/gnc-engine.h
index 1d0deab..d4db2c1 100644
--- a/src/engine/gnc-engine.h
+++ b/src/engine/gnc-engine.h
@@ -256,5 +256,10 @@ void gnc_engine_signal_commit_error( QofBackendError errcode );
  */
 #define GNC_INVOICE_ID    "gncInvoice"
 #define GNC_INVOICE_GUID  "invoice-guid"
+#define GNC_OWNER_ID    "gncOwner"
+#define GNC_OWNER_TYPE  "owner-type"
+#define GNC_OWNER_GUID  "owner-guid"
+
+
 #endif
 /** @} */
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index d630b1d..4b2bac4 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -65,7 +65,11 @@ enum
 {
     PROP_0,
     PROP_IS_CLOSED,
-    PROP_MARKER
+    PROP_MARKER,
+
+    PROP_INVOICE,
+    PROP_OWNER_TYPE,
+    PROP_OWNER_GUID,
 };
 
 typedef struct LotPrivate
@@ -94,6 +98,11 @@ typedef struct LotPrivate
 
 /* ============================================================= */
 
+static void gnc_lot_set_invoice (GNCLot* lot, GncGUID *guid);
+static GncGUID *gnc_lot_get_invoice (GNCLot* lot);
+
+/* ============================================================= */
+
 /* GObject Initialization */
 G_DEFINE_TYPE(GNCLot, gnc_lot, QOF_TYPE_INSTANCE)
 
@@ -126,6 +135,9 @@ gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec*
 {
     GNCLot* lot;
     LotPrivate* priv;
+    KvpFrame *frame;
+    gchar *key;
+    GValue *temp;
 
     g_return_if_fail(GNC_IS_LOT(object));
 
@@ -139,6 +151,21 @@ gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec*
     case PROP_MARKER:
         g_value_set_int(value, priv->marker);
         break;
+    case PROP_INVOICE:
+	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
+	qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    case PROP_OWNER_TYPE:
+	key = GNC_OWNER_ID"/" GNC_OWNER_TYPE;
+	qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    case PROP_OWNER_GUID:
+	key = GNC_OWNER_ID "/" GNC_OWNER_GUID;
+	qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
     }
 }
 
@@ -147,6 +174,8 @@ gnc_lot_set_property(GObject* object, guint prop_id, const GValue* value, GParam
 {
     GNCLot* lot;
     LotPrivate* priv;
+    KvpFrame *frame;
+    gchar *key = NULL;
 
     g_return_if_fail(GNC_IS_LOT(object));
 
@@ -160,7 +189,22 @@ gnc_lot_set_property(GObject* object, guint prop_id, const GValue* value, GParam
     case PROP_MARKER:
         priv->marker = g_value_get_int(value);
         break;
-    }
+    case PROP_INVOICE:
+	key = GNC_INVOICE_ID"/" GNC_INVOICE_GUID;
+	qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    case PROP_OWNER_TYPE:
+	key = GNC_OWNER_ID "/" GNC_OWNER_TYPE;
+	qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    case PROP_OWNER_GUID:
+	key = GNC_OWNER_ID "/" GNC_OWNER_GUID;
+	qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+	break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+     }
 }
 
 static void
@@ -194,8 +238,32 @@ gnc_lot_class_init(GNCLotClass* klass)
                          0, G_MAXINT8, 0,
                          G_PARAM_READWRITE));
 
-
-
+     g_object_class_install_property(
+       gobject_class,
+        PROP_INVOICE,
+        g_param_spec_boxed("invoice",
+			   "Invoice attached to lot",
+			   "Used by GncInvoice",
+			   GNC_TYPE_GUID,
+			   G_PARAM_READWRITE));
+
+     g_object_class_install_property(
+       gobject_class,
+        PROP_OWNER_TYPE,
+        g_param_spec_int64("owner-type",
+			   "Owning Entity Type of  lot",
+			   "Used by GncOwner",
+			   0, G_MAXINT64, 0,
+			   G_PARAM_READWRITE));
+
+     g_object_class_install_property(
+       gobject_class,
+        PROP_OWNER_GUID,
+        g_param_spec_boxed("owner-guid",
+			   "Owner attached to lot",
+			   "Used by GncOwner",
+			   GNC_TYPE_GUID,
+			   G_PARAM_READWRITE));
 }
 
 GNCLot *
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index 2ac268f..3972a4e 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -82,8 +82,6 @@ static QofLogModule log_module = GNC_MOD_BUSINESS;
 
 #define _GNC_MOD_NAME     GNC_ID_INVOICE
 
-#define GNC_INVOICE_ID    "gncInvoice"
-#define GNC_INVOICE_GUID  "invoice-guid"
 #define GNC_INVOICE_IS_CN "credit-note"
 
 #define SET_STR(obj, member, str) { \
@@ -1080,52 +1078,37 @@ qofInvoiceSetJob (GncInvoice *invoice, GncJob *job)
 static void
 gncInvoiceDetachFromLot (GNCLot *lot)
 {
-    KvpFrame *kvp;
-
     if (!lot) return;
+
     gnc_lot_begin_edit (lot);
-    kvp = gnc_lot_get_slots (lot);
-    kvp_frame_set_slot_path (kvp, NULL, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
-    qof_instance_set_dirty (QOF_INSTANCE (lot));
+    qof_instance_set (QOF_INSTANCE (lot), "invoice", NULL, NULL);
     gnc_lot_commit_edit (lot);
 }
 
 static void
 gncInvoiceAttachToLot (GncInvoice *invoice, GNCLot *lot)
 {
-    KvpFrame *kvp;
-    KvpValue *value;
-
+    GncGUID *guid;
     if (!invoice || !lot)
         return;
 
     if (invoice->posted_lot) return;	/* Cannot reset invoice's lot */
-
+    guid  = (GncGUID*)qof_instance_get_guid (QOF_INSTANCE (invoice));
     gnc_lot_begin_edit (lot);
-    kvp = gnc_lot_get_slots (lot);
-    value = kvp_value_new_guid (qof_instance_get_guid (QOF_INSTANCE(invoice)));
-    kvp_frame_set_slot_path (kvp, value, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
-    qof_instance_set_dirty (QOF_INSTANCE (lot));
+    qof_instance_set (QOF_INSTANCE (lot), "invoice", guid, NULL);
     gnc_lot_commit_edit (lot);
-    kvp_value_delete (value);
     gncInvoiceSetPostedLot (invoice, lot);
 }
 
 GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot)
 {
-    KvpFrame *kvp;
-    KvpValue *value;
     GncGUID *guid;
     QofBook *book;
 
     if (!lot) return NULL;
 
     book = gnc_lot_get_book (lot);
-    kvp = gnc_lot_get_slots (lot);
-    value = kvp_frame_get_slot_path (kvp, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
-    if (!value) return NULL;
-
-    guid = kvp_value_get_guid (value);
+    qof_instance_get (QOF_INSTANCE (lot), "invoice", &guid, NULL);
     return gncInvoiceLookup(book, guid);
 }
 
diff --git a/src/engine/gncInvoice.h b/src/engine/gncInvoice.h
index 4cd32b8..b7a29c4 100644
--- a/src/engine/gncInvoice.h
+++ b/src/engine/gncInvoice.h
@@ -251,6 +251,7 @@ GncInvoice * gncInvoiceGetInvoiceFromLot (GNCLot *lot);
  */
 static inline GncInvoice * gncInvoiceLookup (const QofBook *book, const GncGUID *guid)
 {
+    if (book == NULL || guid == NULL) return NULL;
     QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_INVOICE, GncInvoice);
 }
 
@@ -288,7 +289,6 @@ QofBook *gncInvoiceGetBook(GncInvoice *x);
 /** deprecated functions */
 #define gncInvoiceGetGUID(x) qof_instance_get_guid(QOF_INSTANCE(x))
 #define gncInvoiceRetGUID(x) (x ? *(qof_instance_get_guid(QOF_INSTANCE(x))) : *(guid_null()))
-#define gncInvoiceLookupDirect(G,B) gncInvoiceLookup((B),&(G))
 
 /** Test support function used by test-dbi-business-stuff.c */
 gboolean gncInvoiceEqual(const GncInvoice *a, const GncInvoice *b);
diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index c4ad44f..ee2fa05 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -51,8 +51,6 @@
 #define _GNC_MOD_NAME   GNC_ID_OWNER
 
 #define GNC_OWNER_ID    "gncOwner"
-#define GNC_OWNER_TYPE  "owner-type"
-#define GNC_OWNER_GUID  "owner-guid"
 
 GncOwner * gncOwnerNew (void)
 {
@@ -568,31 +566,20 @@ const GncGUID * gncOwnerGetEndGUID (const GncOwner *owner)
 
 void gncOwnerAttachToLot (const GncOwner *owner, GNCLot *lot)
 {
-    KvpFrame *kvp;
-    KvpValue *value;
-
-    if (!owner || !lot)
+     if (!owner || !lot)
         return;
 
-    kvp = gnc_lot_get_slots (lot);
     gnc_lot_begin_edit (lot);
 
-    value = kvp_value_new_gint64 (gncOwnerGetType (owner));
-    kvp_frame_set_slot_path (kvp, value, GNC_OWNER_ID, GNC_OWNER_TYPE, NULL);
-    kvp_value_delete (value);
-
-    value = kvp_value_new_guid (gncOwnerGetGUID (owner));
-    kvp_frame_set_slot_path (kvp, value, GNC_OWNER_ID, GNC_OWNER_GUID, NULL);
-    qof_instance_set_dirty (QOF_INSTANCE (lot));
+    qof_instance_set (QOF_INSTANCE (lot),
+		      "owner-type", (gint64)gncOwnerGetType (owner),
+		      "owner-guid", gncOwnerGetGUID (owner),
+		      NULL);
     gnc_lot_commit_edit (lot);
-    kvp_value_delete (value);
-
 }
 
 gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
 {
-    KvpFrame *kvp;
-    KvpValue *value;
     GncGUID *guid;
     QofBook *book;
     GncOwnerType type;
@@ -600,20 +587,10 @@ gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner)
     if (!lot || !owner) return FALSE;
 
     book = gnc_lot_get_book (lot);
-    kvp = gnc_lot_get_slots (lot);
-
-    value = kvp_frame_get_slot_path (kvp, GNC_OWNER_ID, GNC_OWNER_TYPE, NULL);
-    if (!value) return FALSE;
-
-    type = kvp_value_get_gint64 (value);
-
-    value = kvp_frame_get_slot_path (kvp, GNC_OWNER_ID, GNC_OWNER_GUID, NULL);
-    if (!value) return FALSE;
-
-    guid = kvp_value_get_guid (value);
-    if (!guid)
-        return FALSE;
-
+    qof_instance_get (QOF_INSTANCE (lot),
+		      "owner-type", &type,
+		      "owner-guid", &guid,
+		      NULL);
     switch (type)
     {
     case GNC_OWNER_CUSTOMER:
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index ec0f3c5..ba74edd 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -47,6 +47,7 @@ typedef struct
     {
 	Account      *acct;
 	Transaction  *trans;
+	GNCLot       *lot;
 	GncCustomer  *cust;
 	GncEmployee  *emp;
 	GncJob       *job;
@@ -78,6 +79,13 @@ setup_trans (Fixture *fixture, gconstpointer pData)
 }
 
 static void
+setup_lot (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->lot = gnc_lot_new (book);
+}
+
+static void
 teardown (Fixture *fixture, gconstpointer pData)
 {
 /* It doesn't actually matter which union member we use here, they're
@@ -130,8 +138,43 @@ test_trans_kvp_properties (Fixture *fixture, gconstpointer pData)
     guid_free (guid_r);
 }
 
+static void
+test_lot_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    GncGUID *invoice = guid_malloc ();
+    GncGUID *invoice_r;
+    gint64 owner_type = 47;
+    gint64 owner_type_r;
+    GncGUID *owner = guid_malloc ();
+    GncGUID *owner_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->lot),
+		      "invoice", invoice,
+		      "owner-type", owner_type,
+		      "owner-guid", owner,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->lot)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->lot));
+
+    qof_instance_get (QOF_INSTANCE (fixture->lot),
+		      "invoice", &invoice_r,
+		      "owner-type", &owner_type_r,
+		      "owner-guid", &owner_r,
+		      NULL);
+    g_assert (guid_equal (invoice, invoice_r));
+    g_assert_cmpint (owner_type, ==, owner_type_r);
+    g_assert (guid_equal (owner, owner_r));
+    g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->lot)));
+    guid_free (invoice);
+    guid_free (invoice_r);
+    guid_free (owner);
+    guid_free (owner_r);
+}
+
 void test_suite_engine_kvp_properties (void)
 {
     GNC_TEST_ADD (suitename, "Account", Fixture, NULL, setup_account, test_account_kvp_properties, teardown);
     GNC_TEST_ADD (suitename, "Transaction", Fixture, NULL, setup_trans, test_trans_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Lot", Fixture, NULL, setup_lot, test_lot_kvp_properties, teardown);
 }

commit e3e21b602b32fd5f6b587940363f6fb0318dc6ab
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 17:07:35 2013 -0700

    Add Transaction property "invoice"
    
    Replaces direct KVP access.

diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c
index 567a275..259c921 100644
--- a/src/engine/Transaction.c
+++ b/src/engine/Transaction.c
@@ -196,7 +196,8 @@ enum
     PROP_DESCRIPTION,
     PROP_CURRENCY,
     PROP_POST_DATE,
-    PROP_ENTER_DATE
+    PROP_ENTER_DATE,
+    PROP_INVOICE,
 };
 
 void
@@ -302,6 +303,9 @@ gnc_transaction_get_property(GObject* object,
                              GParamSpec* pspec)
 {
     Transaction* tx;
+    KvpFrame *frame;
+    gchar *key;
+    GValue *temp;
 
     g_return_if_fail(GNC_IS_TRANSACTION(object));
 
@@ -323,6 +327,10 @@ gnc_transaction_get_property(GObject* object,
     case PROP_ENTER_DATE:
         g_value_set_boxed(value, &tx->date_entered);
         break;
+    case PROP_INVOICE:
+	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
+	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -336,6 +344,8 @@ gnc_transaction_set_property(GObject* object,
                              GParamSpec* pspec)
 {
     Transaction* tx;
+    KvpFrame *frame;
+    gchar *key;
 
     g_return_if_fail(GNC_IS_TRANSACTION(object));
 
@@ -357,6 +367,10 @@ gnc_transaction_set_property(GObject* object,
     case PROP_ENTER_DATE:
         xaccTransSetDateEnteredTS(tx, g_value_get_boxed(value));
         break;
+    case PROP_INVOICE:
+	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
+	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -425,6 +439,15 @@ gnc_transaction_class_init(TransactionClass* klass)
                         "The date the transaction was entered.",
                         GNC_TYPE_TIMESPEC,
                         G_PARAM_READWRITE));
+
+     g_object_class_install_property(
+       gobject_class,
+        PROP_INVOICE,
+        g_param_spec_boxed("invoice",
+			   "Invoice attached to lot",
+			   "Used by GncInvoice",
+			   GNC_TYPE_GUID,
+			   G_PARAM_READWRITE));
 }
 
 /********************************************************************\
@@ -2594,6 +2617,7 @@ xaccTransFindSplitByAccount(const Transaction *trans, const Account *acc)
     return NULL;
 }
 
+
 /********************************************************************\
 \********************************************************************/
 /* QofObject function implementation */
diff --git a/src/engine/gnc-engine.h b/src/engine/gnc-engine.h
index f4943fb..1d0deab 100644
--- a/src/engine/gnc-engine.h
+++ b/src/engine/gnc-engine.h
@@ -251,5 +251,10 @@ void gnc_engine_add_commit_error_callback( EngineCommitErrorCallback cb, gpointe
 
 void gnc_engine_signal_commit_error( QofBackendError errcode );
 
+/** STRING CONSTANTS **********************************************
+ * Used to declare constant KVP keys used in more than one class
+ */
+#define GNC_INVOICE_ID    "gncInvoice"
+#define GNC_INVOICE_GUID  "invoice-guid"
 #endif
 /** @} */
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index 2f41025..2ac268f 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -1141,10 +1141,8 @@ gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
     if (invoice->posted_txn) return;	/* Cannot reset invoice's txn */
 
     xaccTransBeginEdit (txn);
-    kvp = xaccTransGetSlots (txn);
-    value = kvp_value_new_guid (qof_instance_get_guid(QOF_INSTANCE(invoice)));
-    kvp_frame_set_slot_path (kvp, value, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
-    kvp_value_delete (value);
+    qof_instance_set (QOF_INSTANCE (txn), "invoice",
+		      qof_instance_get_guid (QOF_INSTANCE (invoice)), NULL);
     xaccTransSetTxnType (txn, TXN_TYPE_INVOICE);
     xaccTransCommitEdit (txn);
     gncInvoiceSetPostedTxn (invoice, txn);
@@ -1153,19 +1151,13 @@ gncInvoiceAttachToTxn (GncInvoice *invoice, Transaction *txn)
 GncInvoice *
 gncInvoiceGetInvoiceFromTxn (const Transaction *txn)
 {
-    KvpFrame *kvp;
-    KvpValue *value;
     GncGUID *guid;
     QofBook *book;
 
     if (!txn) return NULL;
 
     book = xaccTransGetBook (txn);
-    kvp = xaccTransGetSlots (txn);
-    value = kvp_frame_get_slot_path (kvp, GNC_INVOICE_ID, GNC_INVOICE_GUID, NULL);
-    if (!value) return NULL;
-
-    guid = kvp_value_get_guid (value);
+    qof_instance_get (QOF_INSTANCE (txn), "invoice", &guid, NULL);
     return gncInvoiceLookup(book, guid);
 }
 
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
index 9dda2f8..ec0f3c5 100644
--- a/src/engine/test/test-engine-kvp-properties.c
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -71,6 +71,13 @@ setup_account (Fixture *fixture, gconstpointer pData)
 }
 
 static void
+setup_trans (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->trans = xaccMallocTransaction (book);
+}
+
+static void
 teardown (Fixture *fixture, gconstpointer pData)
 {
 /* It doesn't actually matter which union member we use here, they're
@@ -101,7 +108,30 @@ test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
     g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->acct)));
 }
 
+static void
+test_trans_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    GncGUID *guid = guid_malloc ();
+    GncGUID *guid_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->trans),
+		      "invoice", guid,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->trans)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->trans));
+
+    qof_instance_get (QOF_INSTANCE (fixture->trans),
+		      "invoice", &guid_r,
+		      NULL);
+    g_assert (guid_equal (guid, guid_r));
+    g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->trans)));
+    guid_free (guid);
+    guid_free (guid_r);
+}
+
 void test_suite_engine_kvp_properties (void)
 {
     GNC_TEST_ADD (suitename, "Account", Fixture, NULL, setup_account, test_account_kvp_properties, teardown);
+    GNC_TEST_ADD (suitename, "Transaction", Fixture, NULL, setup_trans, test_trans_kvp_properties, teardown);
 }

commit 8d9d51a7f776dc4c42d40c0b4368c6382203fd95
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 17:04:37 2013 -0700

    Add Account property "lot-next-id"
    
    Replaces direct kvp access.

diff --git a/src/engine/Account.c b/src/engine/Account.c
index b1b0a74..21333eb 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -85,6 +85,8 @@ enum
     PROP_PLACEHOLDER,
     PROP_FILTER,
     PROP_SORT_ORDER,
+
+    PROP_LOT_NEXT_ID,
 };
 
 #define GET_PRIVATE(o)  \
@@ -283,6 +285,8 @@ gnc_account_get_property (GObject         *object,
 {
     Account *account;
     AccountPrivate *priv;
+    const gchar *key;
+    GValue *temp;
 
     g_return_if_fail(GNC_IS_ACCOUNT(object));
 
@@ -378,6 +382,12 @@ gnc_account_get_property (GObject         *object,
     case PROP_SORT_ORDER:
         g_value_set_string(value, xaccAccountGetSortOrder(account));
         break;
+    case PROP_LOT_NEXT_ID:
+	key = "lot-mgmt/next-id";
+        /* Pre-set the value in case the frame is empty */
+	g_value_set_int64 (value, 0);
+	qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -392,6 +402,7 @@ gnc_account_set_property (GObject         *object,
 {
     Account *account;
     gnc_numeric *number;
+    gchar *key = NULL;
 
     g_return_if_fail(GNC_IS_ACCOUNT(object));
 
@@ -477,6 +488,10 @@ gnc_account_set_property (GObject         *object,
     case PROP_SORT_ORDER:
         xaccAccountSetSortOrder(account, g_value_get_string(value));
         break;
+    case PROP_LOT_NEXT_ID:
+	key = "lot-mgmt/next-id";
+	qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+	break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -834,6 +849,17 @@ gnc_account_class_init (AccountClass *klass)
                           "the sort order to be recalled.",
                           NULL,
                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+    (gobject_class,
+     PROP_LOT_NEXT_ID,
+     g_param_spec_int64 ("lot-next-id",
+                         "Lot Next ID",
+                         "Tracks the next id to use in gnc_lot_make_default.",
+                         (gint64)1,
+                         G_MAXINT64,
+                         (gint64)1,
+                         G_PARAM_READWRITE));
 }
 
 static void
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index 26100b0..d630b1d 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -675,19 +675,19 @@ GNCLot * gnc_lot_make_default (Account *acc)
 {
     GNCLot * lot;
     gint64 id;
-    char buff[200];
+    gchar *buff;
 
     lot = gnc_lot_new (qof_instance_get_book(acc));
 
     /* Provide a reasonable title for the new lot */
     xaccAccountBeginEdit (acc);
-    id = kvp_frame_get_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id");
-    snprintf (buff, 200, ("%s %" G_GINT64_FORMAT), _("Lot"), id);
-    kvp_frame_set_str (gnc_lot_get_slots (lot), "/title", buff);
+    qof_instance_get (QOF_INSTANCE (acc), "lot-next-id", &id, NULL);
+    buff = g_strdup_printf ("%s %" G_GINT64_FORMAT, _("Lot"), id);
+    gnc_lot_set_title (lot, buff);
     id ++;
-    kvp_frame_set_gint64 (xaccAccountGetSlots (acc), "/lot-mgmt/next-id", id);
-    qof_instance_set_dirty (QOF_INSTANCE(acc));
+    qof_instance_set (QOF_INSTANCE (acc), "lot-next-id", id, NULL);
     xaccAccountCommitEdit (acc);
+    g_free (buff);
     return lot;
 }
 
diff --git a/src/engine/test/Makefile.am b/src/engine/test/Makefile.am
index 8c6b613..5e216d1 100644
--- a/src/engine/test/Makefile.am
+++ b/src/engine/test/Makefile.am
@@ -113,8 +113,9 @@ noinst_PROGRAMS = ${TEST_PROGS} ${CHECK_PROGS}
 test_engine_SOURCES = \
 	test-engine.c \
 	utest-Account.c \
-    utest-Budget.c \
-	utest-Invoice.c
+	utest-Budget.c \
+	utest-Invoice.c \
+	test-engine-kvp-properties.c
 
 test_engine_LDADD = \
 	libutest-Split.la \
diff --git a/src/engine/test/test-engine-kvp-properties.c b/src/engine/test/test-engine-kvp-properties.c
new file mode 100644
index 0000000..9dda2f8
--- /dev/null
+++ b/src/engine/test/test-engine-kvp-properties.c
@@ -0,0 +1,107 @@
+/********************************************************************
+ * test-engine-kvp-properties.c: GLib g_test test suite for         *
+ * KVP-based properties in several engine classes.                  *
+ * Copyright 2013 John Ralls <jralls at ceridwen.us>		    *
+ *                                                                  *
+ * 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                   *
+\********************************************************************/
+
+/**
+ * Test Engine KVP Properties Acceptance testing for KVP Properties
+ * added to various engine classes to make private the internals of
+ * KVP storage used for a variety of parameters on several engine
+ * classes.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <qof.h>
+#include <unittest-support.h>
+#include "../Transaction.h"
+#include "../Split.h"
+#include "../Account.h"
+#include "../SchedXAction.h"
+#include "../gncCustomer.h"
+#include "../gncEmployee.h"
+#include "../gncJob.h"
+#include "../gncVendor.h"
+
+typedef struct
+{
+    union
+    {
+	Account      *acct;
+	Transaction  *trans;
+	GncCustomer  *cust;
+	GncEmployee  *emp;
+	GncJob       *job;
+	GncVendor    *vend;
+    };
+    GSList *split;
+} Fixture;
+
+/* Prototype to shut clang up */
+void test_suite_engine_kvp_properties (void);
+
+/* Private QofInstance function needed for testing */
+extern void qof_instance_mark_clean (QofInstance*);
+
+const gchar *suitename = "/engine/kvp-properties";
+
+static void
+setup_account (Fixture *fixture, gconstpointer pData)
+{
+    QofBook *book = qof_book_new ();
+    fixture->acct = xaccMallocAccount (book);
+}
+
+static void
+teardown (Fixture *fixture, gconstpointer pData)
+{
+/* It doesn't actually matter which union member we use here, they're
+ * all QofInstances, so this will work for any of them.
+ */
+    QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->acct));
+    test_destroy (fixture->acct);
+    test_destroy (book);
+}
+
+static void
+test_account_kvp_properties (Fixture *fixture, gconstpointer pData)
+{
+    gint64 next_id = 12345678909876;
+    gint64 next_id_r;
+
+    qof_instance_set (QOF_INSTANCE (fixture->acct),
+		      "lot-next-id", next_id,
+		      NULL);
+
+    g_assert (qof_instance_is_dirty (QOF_INSTANCE (fixture->acct)));
+    qof_instance_mark_clean (QOF_INSTANCE (fixture->acct));
+
+    qof_instance_get (QOF_INSTANCE (fixture->acct),
+		      "lot-next-id", &next_id_r,
+		      NULL);
+    g_assert_cmpint (next_id, ==, next_id_r);
+    g_assert (!qof_instance_is_dirty (QOF_INSTANCE (fixture->acct)));
+}
+
+void test_suite_engine_kvp_properties (void)
+{
+    GNC_TEST_ADD (suitename, "Account", Fixture, NULL, setup_account, test_account_kvp_properties, teardown);
+}
diff --git a/src/engine/test/test-engine.c b/src/engine/test/test-engine.c
index 508856e..19221b8 100644
--- a/src/engine/test/test-engine.c
+++ b/src/engine/test/test-engine.c
@@ -31,6 +31,7 @@ extern void test_suite_budget();
 extern void test_suite_gncInvoice();
 extern void test_suite_transaction();
 extern void test_suite_split();
+extern void test_suite_engine_kvp_properties (void);
 
 int
 main (int   argc,
@@ -49,6 +50,7 @@ main (int   argc,
     test_suite_gncInvoice();
     test_suite_transaction();
     test_suite_split();
+    test_suite_engine_kvp_properties ();
 
     return g_test_run( );
 }

commit 9ea9896620a03a74d316142c86e44dfec3cd5b7d
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 17:03:29 2013 -0700

    Remove convenience functions which return a pointer to kvm_data.

diff --git a/src/backend/dbi/test/test-dbi-stuff.c b/src/backend/dbi/test/test-dbi-stuff.c
index 4ac96ae..c0e1d1e 100644
--- a/src/backend/dbi/test/test-dbi-stuff.c
+++ b/src/backend/dbi/test/test-dbi-stuff.c
@@ -168,6 +168,9 @@ compare_sxs( QofBook* book_1, QofBook* book_2 )
                 compare_single_sx, "Scheduled transaction lists match" );
 }
 
+/* EFFECTIVE FRIEND FUNCTION */
+extern KvpFrame *qof_instance_get_slots (const QofInstance *);
+
 static void
 compare_single_lot( QofInstance* inst, gpointer user_data )
 {
@@ -181,8 +184,8 @@ compare_single_lot( QofInstance* inst, gpointer user_data )
                                 gnc_lot_get_account (lot_2), FALSE ));
     g_assert_cmpint (gnc_lot_is_closed (lot_1), ==, gnc_lot_is_closed (lot_2));
 
-    g_assert (kvp_frame_compare (gnc_lot_get_slots (lot_1),
-                                 gnc_lot_get_slots (lot_2)) == 0);
+    g_assert (kvp_frame_compare (qof_instance_get_slots (QOF_INSTANCE (lot_1)),
+                                 qof_instance_get_slots (QOF_INSTANCE (lot_2))) == 0);
     splits1 = gnc_lot_get_split_list (lot_1);
     splits2 = gnc_lot_get_split_list (lot_2);
     g_assert_cmpint (g_list_length (splits1), ==, g_list_length (splits2));
diff --git a/src/backend/xml/gnc-account-xml-v2.c b/src/backend/xml/gnc-account-xml-v2.c
index 8137147..85d475e 100644
--- a/src/backend/xml/gnc-account-xml-v2.c
+++ b/src/backend/xml/gnc-account-xml-v2.c
@@ -71,6 +71,9 @@ const gchar *account_version_string = "2.0.0";
 #define act_hidden_string "act:hidden"
 #define act_placeholder_string "act:placeholder"
 
+/* EFFECTIVE FRIEND FUNCTION */
+extern KvpFrame *qof_instance_get_slots (const QofInstance *);
+
 xmlNodePtr
 gnc_account_dom_tree_create(Account *act,
                             gboolean exporting,
@@ -134,7 +137,7 @@ gnc_account_dom_tree_create(Account *act,
         xmlAddChild(ret, text_to_dom_tree(act_description_string, str));
     }
 
-    kf = xaccAccountGetSlots(act);
+    kf = qof_instance_get_slots (QOF_INSTANCE (act));
     if (kf)
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(act_slots_string, kf);
@@ -370,7 +373,7 @@ account_slots_handler (xmlNodePtr node, gpointer act_pdata)
     struct account_pdata *pdata = act_pdata;
 
     return dom_tree_to_kvp_frame_given
-           (node, xaccAccountGetSlots (pdata->account));
+           (node, qof_instance_get_slots (QOF_INSTANCE (pdata->account)));
 }
 
 static gboolean
diff --git a/src/backend/xml/gnc-invoice-xml-v2.c b/src/backend/xml/gnc-invoice-xml-v2.c
index 2a9c769..901a733 100644
--- a/src/backend/xml/gnc-invoice-xml-v2.c
+++ b/src/backend/xml/gnc-invoice-xml-v2.c
@@ -72,6 +72,9 @@ const gchar *invoice_version_string = "2.0.0";
 #define invoice_tochargeamt_string "invoice:charge-amt"
 #define invoice_slots_string "invoice:slots"
 
+/* EFFECTIVE FRIEND FUNCTION */
+extern KvpFrame *qof_instance_get_slots (const QofInstance *);
+
 static void
 maybe_add_string (xmlNodePtr ptr, const char *tag, const char *str)
 {
@@ -410,7 +413,7 @@ invoice_slots_handler (xmlNodePtr node, gpointer invoice_pdata)
     struct invoice_pdata *pdata = invoice_pdata;
 
     return dom_tree_to_kvp_frame_given
-           (node, xaccAccountGetSlots (pdata->invoice));
+           (node, qof_instance_get_slots (QOF_INSTANCE (pdata->invoice)));
 }
 
 static struct dom_tree_handler invoice_handlers_v2[] =
diff --git a/src/backend/xml/gnc-lot-xml-v2.c b/src/backend/xml/gnc-lot-xml-v2.c
index f24001a..503e981 100644
--- a/src/backend/xml/gnc-lot-xml-v2.c
+++ b/src/backend/xml/gnc-lot-xml-v2.c
@@ -53,6 +53,8 @@ const gchar *lot_version_string = "2.0.0";
 #define gnc_lot_string "gnc:lot"
 #define lot_id_string "lot:id"
 #define lot_slots_string "lot:slots"
+/* EFFECTIVE FRIEND FUNCTION */
+extern KvpFrame *qof_instance_get_slots (const QofInstance *);
 
 xmlNodePtr
 gnc_lot_dom_tree_create(GNCLot *lot)
@@ -66,7 +68,7 @@ gnc_lot_dom_tree_create(GNCLot *lot)
 
     xmlAddChild(ret, guid_to_dom_tree(lot_id_string, gnc_lot_get_guid(lot)));
 
-    kf = gnc_lot_get_slots (lot);
+    kf = qof_instance_get_slots (QOF_INSTANCE (lot));
     if (kf)
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree(lot_slots_string, kf);
@@ -112,7 +114,7 @@ lot_slots_handler (xmlNodePtr node, gpointer p)
 
     ENTER("(lot=%p)", pdata->lot);
     success = dom_tree_to_kvp_frame_given
-              (node, gnc_lot_get_slots (pdata->lot));
+	(node, qof_instance_get_slots (QOF_INSTANCE (pdata->lot)));
 
     LEAVE("");
     g_return_val_if_fail(success, FALSE);
diff --git a/src/backend/xml/gnc-transaction-xml-v2.c b/src/backend/xml/gnc-transaction-xml-v2.c
index 9fdbaf5..6dc3736 100644
--- a/src/backend/xml/gnc-transaction-xml-v2.c
+++ b/src/backend/xml/gnc-transaction-xml-v2.c
@@ -49,6 +49,9 @@
 
 const gchar *transaction_version_string = "2.0.0";
 
+/* EFFECTIVE FRIEND FUNCTION */
+extern KvpFrame *qof_instance_get_slots (const QofInstance *);
+
 static void
 add_gnc_num(xmlNodePtr node, const gchar *tag, gnc_numeric num)
 {
@@ -124,7 +127,7 @@ split_to_dom_tree(const gchar *tag, Split *spl)
     }
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree("split:slots",
-                             xaccSplitGetSlots(spl));
+                             qof_instance_get_slots (QOF_INSTANCE (spl)));
         if (kvpnode)
         {
             xmlAddChild(ret, kvpnode);
@@ -181,7 +184,7 @@ gnc_transaction_dom_tree_create(Transaction *trn)
 
     {
         xmlNodePtr kvpnode = kvp_frame_to_dom_tree("trn:slots",
-                             xaccTransGetSlots(trn));
+                             qof_instance_get_slots (QOF_INSTANCE (trn)));
         if (kvpnode)
         {
             xmlAddChild(ret, kvpnode);
@@ -357,7 +360,7 @@ spl_slots_handler(xmlNodePtr node, gpointer data)
     gboolean successful;
 
     successful = dom_tree_to_kvp_frame_given(node,
-                 xaccSplitGetSlots (pdata->split));
+                 qof_instance_get_slots (QOF_INSTANCE (pdata->split)));
     g_return_val_if_fail(successful, FALSE);
 
     return TRUE;
@@ -516,7 +519,7 @@ trn_slots_handler(xmlNodePtr node, gpointer trans_pdata)
     Transaction *trn = pdata->trans;
     gboolean successful;
 
-    successful = dom_tree_to_kvp_frame_given(node, xaccTransGetSlots(trn));
+    successful = dom_tree_to_kvp_frame_given(node, qof_instance_get_slots (QOF_INSTANCE (trn)));
 
     g_return_val_if_fail(successful, FALSE);
 
diff --git a/src/backend/xml/test/test-xml-account.c b/src/backend/xml/test/test-xml-account.c
index 86dc90d..e9ac585 100644
--- a/src/backend/xml/test/test-xml-account.c
+++ b/src/backend/xml/test/test-xml-account.c
@@ -147,7 +147,7 @@ node_and_account_equal(xmlNodePtr node, Account *act)
         {
             /* xaccAccountDeleteOldData (act); */
 
-            if (!equals_node_val_vs_kvp_frame(mark, xaccAccountGetSlots(act)))
+            if (!equals_node_val_vs_kvp_frame(mark, qof_instance_get_slots(QOF_INSTANCE (act))))
             {
                 return g_strdup("slots differ");
             }
diff --git a/src/backend/xml/test/test-xml-transaction.c b/src/backend/xml/test/test-xml-transaction.c
index c194397..14edc79 100644
--- a/src/backend/xml/test/test-xml-transaction.c
+++ b/src/backend/xml/test/test-xml-transaction.c
@@ -306,7 +306,7 @@ node_and_transaction_equal(xmlNodePtr node, Transaction *trn)
         }
         else if (g_strcmp0((char*)mark->name, "trn:slots") == 0)
         {
-            if (!equals_node_val_vs_kvp_frame(mark, xaccTransGetSlots(trn)))
+            if (!equals_node_val_vs_kvp_frame(mark, qof_instance_get_slots (QOF_INSTANCE (trn))))
             {
                 return "slots differ";
             }
diff --git a/src/engine/Account.h b/src/engine/Account.h
index 34ee44f..b144637 100644
--- a/src/engine/Account.h
+++ b/src/engine/Account.h
@@ -874,8 +874,6 @@ gboolean xaccAccountGetReconcileChildrenStatus(const Account *account);
  */
 gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor);
 
-#define xaccAccountGetSlots(X) qof_instance_get_slots(QOF_INSTANCE(X))
-
 /** @} */
 
 /** @name Lookup Accounts and Subaccounts by name or code
diff --git a/src/engine/Scrub2.c b/src/engine/Scrub2.c
index 8c041f5..d938cae 100644
--- a/src/engine/Scrub2.c
+++ b/src/engine/Scrub2.c
@@ -157,7 +157,7 @@ xaccLotScrubDoubleBalance (GNCLot *lot)
 
     if (!lot) return;
 
-    ENTER ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
+    ENTER ("lot=%s", gnc_lot_get_title(lot));
 
     for (snode = gnc_lot_get_split_list(lot); snode; snode = snode->next)
     {
@@ -216,7 +216,7 @@ xaccLotScrubDoubleBalance (GNCLot *lot)
         }
     }
 
-    LEAVE ("lot=%s", kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
+    LEAVE ("lot=%s", gnc_lot_get_title(lot));
 }
 
 /* ================================================================= */
diff --git a/src/engine/Split.c b/src/engine/Split.c
index 09a2f01..e1fcbca 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -952,26 +952,6 @@ get_commodity_denom(const Split * s)
     }
 }
 
-/********************************************************************
- * xaccSplitGetSlots
- ********************************************************************/
-
-KvpFrame *
-xaccSplitGetSlots (const Split * s)
-{
-    return qof_instance_get_slots(QOF_INSTANCE(s));
-}
-/* Used for testing only: _get_random_split in test-engine-stuff.c */
-void
-xaccSplitSetSlots_nc(Split *s, KvpFrame *frm)
-{
-    if (!s || !frm) return;
-    xaccTransBeginEdit(s->parent);
-    qof_instance_set_slots(QOF_INSTANCE(s), frm);
-    xaccTransCommitEdit(s->parent);
-
-}
-
 /********************************************************************\
 \********************************************************************/
 
@@ -2112,7 +2092,7 @@ gboolean xaccSplitRegister (void)
         { SPLIT_ACCT_FULLNAME, SPLIT_ACCT_FULLNAME, no_op, NULL },
         { SPLIT_CORR_ACCT_NAME, SPLIT_CORR_ACCT_NAME, no_op, NULL },
         { SPLIT_CORR_ACCT_CODE, SPLIT_CORR_ACCT_CODE, no_op, NULL },
-        { SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)xaccSplitGetSlots, NULL },
+        { SPLIT_KVP, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)xaccSplitGetBook, NULL },
         {
             QOF_PARAM_GUID, QOF_TYPE_GUID,
diff --git a/src/engine/Split.h b/src/engine/Split.h
index d240bd8..cc512d1 100644
--- a/src/engine/Split.h
+++ b/src/engine/Split.h
@@ -144,20 +144,6 @@ GNCLot *      xaccSplitGetLot (const Split *split);
 /** Assigns the split to a specific Lot */
 void xaccSplitSetLot(Split* split, GNCLot* lot);
 
-
-/** Returns the KvpFrame slots of this split for direct editing.
- *
- * Split slots are used to store arbitrary strings, numbers, and
- * structures which aren't members of the transaction struct.  See
- * kvp_doc.txt for reserved slot names.
- */
-KvpFrame *xaccSplitGetSlots(const Split *split);
-
-/** Set the KvpFrame slots of this split to the given frm by directly
- * using the frm pointer (i.e. non-copying). */
-void xaccSplitSetSlots_nc(Split *s, KvpFrame *frm);
-
-
 /** The memo is an arbitrary string associated with a split.  It is
  * intended to hold a short (zero to forty character) string that is
  * displayed by the GUI along with this split.  Users typically type
diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h
index 51ba5e0..7fe4069 100644
--- a/src/engine/Transaction.h
+++ b/src/engine/Transaction.h
@@ -743,8 +743,6 @@ void xaccTransDump (const Transaction *trans, const char *tag);
 #define xaccTransGetGUID(X)      qof_entity_get_guid(QOF_INSTANCE(X))
 /** \deprecated */
 #define xaccTransReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_INSTANCE(X))) : *(guid_null()))
-/** \deprecated */
-#define xaccTransGetSlots(X)     qof_instance_get_slots (QOF_INSTANCE(X))
 
 #endif /* XACC_TRANSACTION_H */
 /** @} */
diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c
index 93daf6f..a313d53 100644
--- a/src/engine/cap-gains.c
+++ b/src/engine/cap-gains.c
@@ -553,8 +553,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
     currency = split->parent->common_currency;
 
     ENTER ("(split=%p gains=%p status=0x%x lot=%s)", split,
-           split->gains_split, split->gains,
-           kvp_frame_get_string (gnc_lot_get_slots (lot), "/title"));
+           split->gains_split, split->gains, gnc_lot_get_title(lot));
 
     /* Make sure the status flags and pointers are initialized */
     xaccSplitDetermineGainStatus(split);
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index b561ebc..26100b0 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -334,12 +334,6 @@ gnc_lot_set_closed_unknown(GNCLot* lot)
     }
 }
 
-KvpFrame *
-gnc_lot_get_slots (const GNCLot *lot)
-{
-    return qof_instance_get_slots(QOF_INSTANCE(lot));
-}
-
 SplitList *
 gnc_lot_get_split_list (const GNCLot *lot)
 {
@@ -364,14 +358,16 @@ const char *
 gnc_lot_get_title (const GNCLot *lot)
 {
     if (!lot) return NULL;
-    return kvp_frame_get_string (gnc_lot_get_slots(lot), "/title");
+    return kvp_frame_get_string (qof_instance_get_slots(QOF_INSTANCE (lot)),
+				 "/title");
 }
 
 const char *
 gnc_lot_get_notes (const GNCLot *lot)
 {
     if (!lot) return NULL;
-    return kvp_frame_get_string (gnc_lot_get_slots(lot), "/notes");
+    return kvp_frame_get_string (qof_instance_get_slots(QOF_INSTANCE (lot)),
+				 "/notes");
 }
 
 void
@@ -380,7 +376,8 @@ gnc_lot_set_title (GNCLot *lot, const char *str)
     if (!lot) return;
     qof_begin_edit(QOF_INSTANCE(lot));
     qof_instance_set_dirty(QOF_INSTANCE(lot));
-    kvp_frame_set_str (gnc_lot_get_slots(lot), "/title", str);
+    kvp_frame_set_str (qof_instance_get_slots(QOF_INSTANCE (lot)),
+		       "/title", str);
     gnc_lot_commit_edit(lot);
 }
 
@@ -390,7 +387,8 @@ gnc_lot_set_notes (GNCLot *lot, const char *str)
     if (!lot) return;
     gnc_lot_begin_edit(lot);
     qof_instance_set_dirty(QOF_INSTANCE(lot));
-    kvp_frame_set_str (gnc_lot_get_slots(lot), "/notes", str);
+    kvp_frame_set_str (qof_instance_get_slots (QOF_INSTANCE (lot)),
+		       "/notes", str);
     gnc_lot_commit_edit(lot);
 }
 
diff --git a/src/engine/gnc-lot.h b/src/engine/gnc-lot.h
index 1e477e1..64e1dfa 100644
--- a/src/engine/gnc-lot.h
+++ b/src/engine/gnc-lot.h
@@ -165,11 +165,6 @@ const char * gnc_lot_get_notes (const GNCLot *);
 void gnc_lot_set_title (GNCLot *, const char *);
 void gnc_lot_set_notes (GNCLot *, const char *);
 
-/** Every lot has a place to hang kvp data.  This routine returns that
- *     place.
- * */
-KvpFrame * gnc_lot_get_slots (const GNCLot *);
-
 /** XXX: Document? */
 GNCLot * gnc_lot_make_default (Account * acc);
 
diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index d77798f..c4ad44f 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -641,23 +641,6 @@ gboolean gncOwnerIsValid (const GncOwner *owner)
     return (owner->owner.undefined != NULL);
 }
 
-KvpFrame* gncOwnerGetSlots(GncOwner* owner)
-{
-    if (!owner) return NULL;
-
-    switch (gncOwnerGetType(owner))
-    {
-    case GNC_OWNER_CUSTOMER:
-    case GNC_OWNER_VENDOR:
-    case GNC_OWNER_EMPLOYEE:
-        return qof_instance_get_slots(QOF_INSTANCE(owner->owner.undefined));
-    case GNC_OWNER_JOB:
-        return gncOwnerGetSlots(gncJobGetOwner(gncOwnerGetJob(owner)));
-    default:
-        return NULL;
-    }
-}
-
 gboolean
 gncOwnerLotMatchOwnerFunc (GNCLot *lot, gpointer user_data)
 {
diff --git a/src/engine/gncOwner.h b/src/engine/gncOwner.h
index ac987bc..d94edd3 100644
--- a/src/engine/gncOwner.h
+++ b/src/engine/gncOwner.h
@@ -197,9 +197,6 @@ gboolean gncOwnerGetOwnerFromLot (GNCLot *lot, GncOwner *owner);
 
 gboolean gncOwnerGetOwnerFromTypeGuid (QofBook *book, GncOwner *owner, QofIdType type, GncGUID *guid);
 
-/** Get the kvp-frame from the underlying owner object */
-KvpFrame* gncOwnerGetSlots(GncOwner* owner);
-
 /**
  * Create a lot for a payment to the owner using the other
  * parameters passed in. If a transaction is set, this transaction will be
diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index 92b22f1..9a4f69a 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -1333,7 +1333,7 @@ get_random_split(QofBook *book, Account *acct, Transaction *trn)
     else
         g_assert(!gnc_numeric_positive_p(amt)); /* non-positive amt */
 
-    xaccSplitSetSlots_nc(ret, get_random_kvp_frame());
+    qof_instance_set_slots(QOF_INSTANCE (ret), get_random_kvp_frame());
     xaccTransCommitEdit(trn);
 
     return ret;
@@ -1360,7 +1360,7 @@ make_random_changes_to_split (Split *split)
     xaccSplitSetDateReconciledTS (split, ts);
     g_free(ts);
 
-    xaccSplitSetSlots_nc (split, get_random_kvp_frame());
+    qof_instance_set_slots (QOF_INSTANCE (split), get_random_kvp_frame());
 
     /* Don't change share values/prices here, since that would
      * throw transactions out of balance. Do that in the corresponding
@@ -2163,13 +2163,13 @@ make_trans_query (Transaction *trans, TestQueryTypes query_types)
     }
 
     if (query_types & SPLIT_KVP_QT)
-        add_kvp_query (q, xaccSplitGetSlots (s), GNC_ID_SPLIT);
+        add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (s)), GNC_ID_SPLIT);
 
     if (query_types & TRANS_KVP_QT)
-        add_kvp_query (q, xaccTransGetSlots (trans), GNC_ID_TRANS);
+        add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (trans)), GNC_ID_TRANS);
 
     if (query_types & ACCOUNT_KVP_QT)
-        add_kvp_query (q, xaccAccountGetSlots (a), GNC_ID_ACCOUNT);
+        add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (a)), GNC_ID_ACCOUNT);
 
     return q;
 }
diff --git a/src/import-export/log-replay/gnc-log-replay.c b/src/import-export/log-replay/gnc-log-replay.c
index d4ddaef..6fc69ab 100644
--- a/src/import-export/log-replay/gnc-log-replay.c
+++ b/src/import-export/log-replay/gnc-log-replay.c
@@ -45,6 +45,9 @@
 
 #define GNC_PREFS_GROUP "dialogs.log-replay"
 
+/* EFFECTIVE FRIEND FUNCTION */
+void qof_instance_set_guid (gpointer inst, const GncGUID *guid);
+
 /* NW: If you want a new log_module, just define
 a unique string either in gnc-engine.h or
 locally.*/
@@ -435,7 +438,8 @@ static void  process_trans_record(  FILE *log_file)
                             xaccTransBeginEdit(trans);
                         }
 
-                        xaccTransSetGUID (trans, &(record.trans_guid));
+                        qof_instance_set_guid (QOF_INSTANCE (trans),
+					       &(record.trans_guid));
                         /*Fill the transaction info*/
                         if (record.date_entered_present)
                         {

commit e58bcaac3441fb764d49f3684f0623d1a0085d5f
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 16:59:38 2013 -0700

    Move the capital gains account creation from cap-gains.c to Account.c
    
    Functions which change an object's state should be members of the objects class.

diff --git a/src/engine/Account.c b/src/engine/Account.c
index 8ca2c05..b1b0a74 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -4280,6 +4280,80 @@ xaccAccountSetLastNum (Account *acc, const char *num)
     xaccAccountCommitEdit (acc);
 }
 
+static Account *
+GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency)
+{
+    char * accname;
+    Account * acc;
+
+    g_return_val_if_fail (root, NULL);
+
+    /* build the account name */
+    if (!currency)
+    {
+        PERR ("No currency specified!");
+        return NULL;
+    }
+
+    accname = g_strconcat (_("Orphaned Gains"), "-",
+                           gnc_commodity_get_mnemonic (currency), NULL);
+
+    /* See if we've got one of these going already ... */
+    acc = gnc_account_lookup_by_name(root, accname);
+
+    if (acc == NULL)
+    {
+        /* Guess not. We'll have to build one. */
+        acc = xaccMallocAccount (gnc_account_get_book(root));
+        xaccAccountBeginEdit (acc);
+        xaccAccountSetName (acc, accname);
+        xaccAccountSetCommodity (acc, currency);
+        xaccAccountSetType (acc, ACCT_TYPE_INCOME);
+        xaccAccountSetDescription (acc, _("Realized Gain/Loss"));
+        xaccAccountSetNotes (acc,
+                             _("Realized Gains or Losses from "
+                               "Commodity or Trading Accounts "
+                               "that haven't been recorded elsewhere."));
+
+        /* Hang the account off the root. */
+        gnc_account_append_child (root, acc);
+        xaccAccountCommitEdit (acc);
+    }
+
+    g_free (accname);
+
+    return acc;
+}
+
+Account *
+xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
+{
+    KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    const gchar *curr_name = gnc_commodity_get_unique_name (curr);
+    GncGUID *guid;
+    Account *gains_account;
+
+    frame = kvp_frame_get_frame_slash (frame, "/lot-mgmt/gains-act/");
+    guid = kvp_frame_get_guid (frame, curr_name);
+    if (guid == NULL) /* No gains account for this currency */
+    {
+	gains_account = GetOrMakeOrphanAccount (gnc_account_get_root (acc),
+						curr);
+	guid = (GncGUID*)qof_instance_get_guid (QOF_INSTANCE (gains_account));
+	xaccAccountBeginEdit (acc);
+	{
+	    kvp_frame_set_guid (frame, curr_name, guid);
+	    qof_instance_set_dirty (QOF_INSTANCE (acc));
+	}
+	xaccAccountCommitEdit (acc);
+    }
+    else
+	gains_account = xaccAccountLookup (guid,
+					   qof_instance_get_book(acc));
+
+    return gains_account;
+}
+
 /********************************************************************\
 \********************************************************************/
 
diff --git a/src/engine/Account.h b/src/engine/Account.h
index e999a1e..34ee44f 100644
--- a/src/engine/Account.h
+++ b/src/engine/Account.h
@@ -417,6 +417,17 @@ void xaccAccountSortSplits (Account *acc, gboolean force);
  */
 gchar * gnc_account_get_full_name (const Account *account);
 
+/** Retrieve the gains account used by this account for the indicated
+ * currency, creating and recording a new one if necessary.
+ *
+ * FIXME: There is at present no interface to designate an existing
+ * account, and the new account name is hard coded to
+ * "Orphaned Gains -- CUR"
+ *
+ * FIXME: There is no provision for creating separate accounts for
+ * anything other than currency, e.g. holding period of a security.
+ */
+Account * xaccAccountGainsAccount (Account *acc, gnc_commodity *curr);
 /** Set a string that identifies the Finance::Quote backend that
  *  should be used to retrieve online prices.  See price-quotes.scm
  *  for more information
diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c
index 46b4cd2..93daf6f 100644
--- a/src/engine/cap-gains.c
+++ b/src/engine/cap-gains.c
@@ -216,99 +216,6 @@ xaccAccountFindLatestOpenLot (Account *acc, gnc_numeric sign,
 }
 
 /* ============================================================== */
-/* Similar to GetOrMakeAccount, but different in important ways */
-
-static Account *
-GetOrMakeLotOrphanAccount (Account *root, gnc_commodity * currency)
-{
-    char * accname;
-    Account * acc;
-
-    g_return_val_if_fail (root, NULL);
-
-    /* build the account name */
-    if (!currency)
-    {
-        PERR ("No currency specified!");
-        return NULL;
-    }
-
-    accname = g_strconcat (_("Orphaned Gains"), "-",
-                           gnc_commodity_get_mnemonic (currency), NULL);
-
-    /* See if we've got one of these going already ... */
-    acc = gnc_account_lookup_by_name(root, accname);
-
-    if (acc == NULL)
-    {
-        /* Guess not. We'll have to build one. */
-        acc = xaccMallocAccount (gnc_account_get_book(root));
-        xaccAccountBeginEdit (acc);
-        xaccAccountSetName (acc, accname);
-        xaccAccountSetCommodity (acc, currency);
-        xaccAccountSetType (acc, ACCT_TYPE_INCOME);
-        xaccAccountSetDescription (acc, _("Realized Gain/Loss"));
-        xaccAccountSetNotes (acc,
-                             _("Realized Gains or Losses from "
-                               "Commodity or Trading Accounts "
-                               "that haven't been recorded elsewhere."));
-
-        /* Hang the account off the root. */
-        gnc_account_append_child (root, acc);
-        xaccAccountCommitEdit (acc);
-    }
-
-    g_free (accname);
-
-    return acc;
-}
-
-/* ============================================================== */
-/* Functionally identical to the following:
- *   if (!xaccAccountGetDefaultGainAccount()) {
- *               xaccAccountSetDefaultGainAccount (); }
- * except that it saves a few cycles.
- */
-
-static Account *
-GetOrMakeGainAcct (Account *acc, gnc_commodity * currency)
-{
-    Account *gain_acct = NULL;
-    KvpFrame *cwd;
-    KvpValue *vvv;
-    GncGUID * gain_acct_guid;
-    const char * cur_name;
-
-    cwd = xaccAccountGetSlots (acc);
-    cwd = kvp_frame_get_frame_slash (cwd, "/lot-mgmt/gains-act/");
-
-    /* Accounts are indexed by thier unique currency name */
-    cur_name = gnc_commodity_get_unique_name (currency);
-    vvv = kvp_frame_get_slot (cwd, cur_name);
-    gain_acct_guid = kvp_value_get_guid (vvv);
-
-    gain_acct = xaccAccountLookup (gain_acct_guid, qof_instance_get_book(acc));
-
-    /* If there is no default place to put gains/losses
-     * for this account, then create such a place */
-    if (NULL == gain_acct)
-    {
-        Account *root;
-
-        xaccAccountBeginEdit (acc);
-        root = gnc_account_get_root(acc);
-        gain_acct = GetOrMakeLotOrphanAccount (root, currency);
-
-        vvv = kvp_value_new_guid (xaccAccountGetGUID (gain_acct));
-        kvp_frame_set_slot_nc (cwd, cur_name, vvv);
-        qof_instance_set_slots(QOF_INSTANCE(acc), acc->inst.kvp_data);
-        xaccAccountCommitEdit (acc);
-
-    }
-    return gain_acct;
-}
-
-/* ============================================================== */
 
 Split *
 xaccSplitAssignToLot (Split *split, GNCLot *lot)
@@ -890,7 +797,7 @@ xaccSplitComputeCapGains(Split *split, Account *gain_acc)
                     (FALSE == gnc_commodity_equiv (currency,
                                                    xaccAccountGetCommodity(gain_acc))))
             {
-                gain_acc = GetOrMakeGainAcct (lot_acc, currency);
+                gain_acc = xaccAccountGainsAccount (lot_acc, currency);
             }
 
             xaccAccountBeginEdit (gain_acc);

commit 9b51d42e7eeef928e81520c69cdb6d8f709a60dc
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 16:56:51 2013 -0700

    Remove unused functions.

diff --git a/src/engine/cap-gains.c b/src/engine/cap-gains.c
index 5401018..46b4cd2 100644
--- a/src/engine/cap-gains.c
+++ b/src/engine/cap-gains.c
@@ -264,57 +264,6 @@ GetOrMakeLotOrphanAccount (Account *root, gnc_commodity * currency)
 }
 
 /* ============================================================== */
-
-void
-xaccAccountSetDefaultGainAccount (Account *acc, const Account *gain_acct)
-{
-    KvpFrame *cwd;
-    KvpValue *vvv;
-    const char * cur_name;
-    gnc_commodity *acc_comm;
-
-    if (!acc || !gain_acct) return;
-
-    cwd = xaccAccountGetSlots (acc);
-    cwd = kvp_frame_get_frame_slash (cwd, "/lot-mgmt/gains-act/");
-
-    /* Accounts are indexed by thier unique currency name */
-    acc_comm = xaccAccountGetCommodity(acc);
-    cur_name = gnc_commodity_get_unique_name (acc_comm);
-
-    xaccAccountBeginEdit (acc);
-    vvv = kvp_value_new_guid (xaccAccountGetGUID (gain_acct));
-    kvp_frame_set_slot_nc (cwd, cur_name, vvv);
-    qof_instance_set_slots(QOF_INSTANCE(acc), acc->inst.kvp_data);
-    xaccAccountCommitEdit (acc);
-}
-
-/* ============================================================== */
-
-Account *
-xaccAccountGetDefaultGainAccount (const Account *acc, const gnc_commodity * currency)
-{
-    Account *gain_acct = NULL;
-    KvpFrame *cwd;
-    KvpValue *vvv;
-    GncGUID * gain_acct_guid;
-    const char * cur_name;
-
-    if (!acc || !currency) return NULL;
-
-    cwd = xaccAccountGetSlots (acc);
-    cwd = kvp_frame_get_frame_slash (cwd, "/lot-mgmt/gains-act/");
-
-    /* Accounts are indexed by thier unique currency name */
-    cur_name = gnc_commodity_get_unique_name (currency);
-    vvv = kvp_frame_get_slot (cwd, cur_name);
-    gain_acct_guid = kvp_value_get_guid (vvv);
-
-    gain_acct = xaccAccountLookup (gain_acct_guid, qof_instance_get_book(acc));
-    return gain_acct;
-}
-
-/* ============================================================== */
 /* Functionally identical to the following:
  *   if (!xaccAccountGetDefaultGainAccount()) {
  *               xaccAccountSetDefaultGainAccount (); }
diff --git a/src/engine/cap-gains.h b/src/engine/cap-gains.h
index 62c8f83..76792bd 100644
--- a/src/engine/cap-gains.h
+++ b/src/engine/cap-gains.h
@@ -124,25 +124,6 @@ GNCLot * xaccAccountFindLatestOpenLot (Account *acc,
                                        gnc_numeric sign,
                                        gnc_commodity *currency);
 
-/** The xaccAccountGetDefaultGainAccount() routine will return
- *   the account to which realized gains/losses may be posted.
- *   Because gains may be in different currencies, one must
- *   specify the currency type in which the gains will be posted.
- *   This routine does nothing more than return the value of
- *   the "/lot-mgmt/gains-act/XXX" key, where XXX is the unique
- *   currency name.  IOf there is no default account for this
- *   currency, NULL will be returned.
- */
-Account * xaccAccountGetDefaultGainAccount (const Account *acc, const gnc_commodity * currency);
-
-/** The xaccAccountSetDefaultGainAccount() routine can be used
- *   to set the account to which realized gains/losses will be
- *   posted by default. This routine does nothing more than set
- *   value of the "/lot-mgmt/gains-act/XXX" key, where XXX is the
- *   unique currency name of the currency of gains account.
- */
-void xaccAccountSetDefaultGainAccount (Account *acc, const Account *gains_acct);
-
 /** The xaccSplitGetCapGainsSplit() routine returns the split
  *  that records the cap gains for this split.  It returns NULL
  *  if not found.  This routine does nothing more than search for

commit d5a9cda70eeb61f6bb91b98865a530a146ba46ab
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 16:55:29 2013 -0700

    Wrap g_object_get/set with qof_instance_get/set
    
    qof_instance_set marks dirty and will eventually also begin and commit edits.

diff --git a/src/libqof/qof/qofinstance.c b/src/libqof/qof/qofinstance.c
index 5cfbecd..e0f5dfe 100644
--- a/src/libqof/qof/qofinstance.c
+++ b/src/libqof/qof/qofinstance.c
@@ -946,6 +946,31 @@ gboolean qof_instance_refers_to_object(const QofInstance* inst, const QofInstanc
     }
 }
 
+/* g_object_set/get wrappers */
+void
+qof_instance_get (const QofInstance *inst, const gchar *first_prop, ...)
+{
+    va_list ap;
+    g_return_if_fail (QOF_IS_INSTANCE (inst));
+
+    va_start (ap, first_prop);
+    g_object_get_valist (G_OBJECT (inst), first_prop, ap);
+    va_end (ap);
+}
+
+void
+qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
+{
+    va_list ap;
+    g_return_if_fail (QOF_IS_INSTANCE (inst));
+
+    qof_instance_set_dirty (inst);
+    va_start (ap, first_prop);
+    g_object_set_valist (G_OBJECT (inst), first_prop, ap);
+    va_end (ap);
+}
+
+
 /* =================================================================== */
 /* Entity edit and commit utilities */
 /* =================================================================== */
diff --git a/src/libqof/qof/qofinstance.h b/src/libqof/qof/qofinstance.h
index 89b7172..ca485c3 100644
--- a/src/libqof/qof/qofinstance.h
+++ b/src/libqof/qof/qofinstance.h
@@ -167,7 +167,16 @@ gboolean qof_instance_get_dirty (QofInstance *);
 
 gboolean qof_instance_get_infant(const QofInstance *inst);
 
+/**
+ * \brief Wrapper for g_object_get
+ */
+void qof_instance_get (const QofInstance *inst, const gchar *first_param, ...);
 
+/**
+ * \brief Wrapper for g_object_set
+ * Group setting multiple parameters in a single begin/commit/rollback
+ */
+void qof_instance_set (QofInstance *inst, const gchar *first_param, ...);
 
 /** get the instance tag number
     used for kvp management in sql backends. */

commit 1f3fbf4b52bdd64150f853f7682504bbe38586ec
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 16:53:48 2013 -0700

    Make most QofInstance functions private.
    
    Import qofinstance-p.h into QofInstance child classes.

diff --git a/src/engine/Account.c b/src/engine/Account.c
index 4b30953..8ca2c05 100644
--- a/src/engine/Account.c
+++ b/src/engine/Account.c
@@ -38,6 +38,7 @@
 #include "gnc-glib-utils.h"
 #include "gnc-lot.h"
 #include "gnc-pricedb.h"
+#include "qofinstance-p.h"
 
 static QofLogModule log_module = GNC_MOD_ACCOUNT;
 
diff --git a/src/engine/SX-book.c b/src/engine/SX-book.c
index 57ee618..62be033 100644
--- a/src/engine/SX-book.c
+++ b/src/engine/SX-book.c
@@ -150,6 +150,9 @@ sxtg_is_dirty(const QofCollection *col)
     return dirty;
 }
 
+/* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
+extern void qof_instance_mark_clean (QofInstance *);
+
 static void
 sxtg_mark_clean(QofCollection *col)
 {
diff --git a/src/engine/SchedXaction.c b/src/engine/SchedXaction.c
index 0943c2b..b342358 100644
--- a/src/engine/SchedXaction.c
+++ b/src/engine/SchedXaction.c
@@ -36,6 +36,7 @@
 #include "Transaction.h"
 #include "gnc-engine.h"
 #include "engine-helpers.h"
+#include "qofinstance-p.h"
 
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "gnc.engine.sx"
diff --git a/src/engine/Scrub.c b/src/engine/Scrub.c
index fe228da..d3a1a09 100644
--- a/src/engine/Scrub.c
+++ b/src/engine/Scrub.c
@@ -1206,6 +1206,9 @@ xaccAccountScrubCommodity (Account *account)
 
 /* ================================================================ */
 
+/* EFFECTIVE FRIEND FUNCTION declared in qofinstance-p.h */
+extern void qof_instance_set_dirty (QofInstance*);
+
 static void
 xaccAccountDeleteOldData (Account *account)
 {
diff --git a/src/engine/Split.c b/src/engine/Split.c
index ad74c13..09a2f01 100644
--- a/src/engine/Split.c
+++ b/src/engine/Split.c
@@ -51,6 +51,7 @@
 #include "gnc-engine.h"
 #include "gnc-lot.h"
 #include "gnc-event.h"
+#include "qofinstance-p.h"
 
 const char *void_former_amt_str = "void-former-amount";
 const char *void_former_val_str = "void-former-value";
diff --git a/src/engine/gnc-budget.c b/src/engine/gnc-budget.c
index ae1e2e3..47cbeab 100644
--- a/src/engine/gnc-budget.c
+++ b/src/engine/gnc-budget.c
@@ -22,19 +22,20 @@
  *                                                                  *
 \********************************************************************/
 
-#include "config.h"
+#include <config.h>
 #include <glib.h>
 #include <glib/gprintf.h>
 #include <glib/gi18n.h>
 #include <time.h>
-#include "qof.h"
-#include "qofbookslots.h"
+#include <qof.h>
+#include <qofbookslots.h>
+#include <gnc-gdate-utils.h>
+#include <qofinstance-p.h>
 
 #include "Account.h"
 
 #include "gnc-budget.h"
 #include "gnc-commodity.h"
-#include "gnc-gdate-utils.h"
 
 static QofLogModule log_module = GNC_MOD_ENGINE;
 
diff --git a/src/engine/gnc-commodity.c b/src/engine/gnc-commodity.c
index 5998cfa..f23235b 100644
--- a/src/engine/gnc-commodity.c
+++ b/src/engine/gnc-commodity.c
@@ -23,7 +23,7 @@
  *                                                                  *
  *******************************************************************/
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <regex.h>
+#include <qofinstance-p.h>
 
 #include "gnc-commodity.h"
 #include "gnc-prefs.h"
diff --git a/src/engine/gnc-lot.c b/src/engine/gnc-lot.c
index 08fdef6..b561ebc 100644
--- a/src/engine/gnc-lot.c
+++ b/src/engine/gnc-lot.c
@@ -39,10 +39,11 @@
  * Copyright (c) 2002,2003 Linas Vepstas <linas at linas.org>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
+#include <qofinstance-p.h>
 
 #include "Account.h"
 #include "AccountP.h"
diff --git a/src/engine/gncAddress.c b/src/engine/gncAddress.c
index 462cf07..437a76a 100644
--- a/src/engine/gncAddress.c
+++ b/src/engine/gncAddress.c
@@ -25,9 +25,10 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
+#include <qofinstance-p.h>
 
 #include "gncAddress.h"
 #include "gncAddressP.h"
diff --git a/src/engine/gncBillTerm.c b/src/engine/gncBillTerm.c
index 835f052..9c8e897 100644
--- a/src/engine/gncBillTerm.c
+++ b/src/engine/gncBillTerm.c
@@ -26,9 +26,10 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
+#include <qofinstance-p.h>
 
 #include "gnc-engine.h"
 #include "gncBillTermP.h"
diff --git a/src/engine/gncCustomer.c b/src/engine/gncCustomer.c
index 581e97a..2336cd6 100644
--- a/src/engine/gncCustomer.c
+++ b/src/engine/gncCustomer.c
@@ -30,6 +30,7 @@
 
 #include <glib.h>
 #include <string.h>
+#include <qofinstance-p.h>
 
 #include "gnc-commodity.h"
 
@@ -866,7 +867,6 @@ gboolean gncCustomerRegister (void)
             (QofSetterFunc)gncCustomerSetTaxTableOverride
         },
         { CUSTOMER_TERMS, GNC_ID_BILLTERM, (QofAccessFunc)gncCustomerGetTerms, (QofSetterFunc)gncCustomerSetTerms },
-        { CUSTOMER_SLOTS, QOF_TYPE_KVP, (QofAccessFunc)qof_instance_get_slots, NULL },
         { QOF_PARAM_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc)gncCustomerGetActive, (QofSetterFunc)gncCustomerSetActive },
         { QOF_PARAM_BOOK, QOF_ID_BOOK, (QofAccessFunc)qof_instance_get_book, NULL },
         { QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc)qof_instance_get_guid, NULL },
diff --git a/src/engine/gncEmployee.c b/src/engine/gncEmployee.c
index 94d7a72..46c3e40 100644
--- a/src/engine/gncEmployee.c
+++ b/src/engine/gncEmployee.c
@@ -26,10 +26,11 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <string.h>
+#include <qofinstance-p.h>
 
 #include "Account.h"
 #include "gnc-commodity.h"
diff --git a/src/engine/gncEntry.c b/src/engine/gncEntry.c
index 0661e2f..efdf802 100644
--- a/src/engine/gncEntry.c
+++ b/src/engine/gncEntry.c
@@ -25,9 +25,10 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
+#include <qofinstance-p.h>
 
 #include "gnc-commodity.h"
 
diff --git a/src/engine/gncInvoice.c b/src/engine/gncInvoice.c
index d4d670c..2f41025 100644
--- a/src/engine/gncInvoice.c
+++ b/src/engine/gncInvoice.c
@@ -27,10 +27,11 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
+#include <qofinstance-p.h>
 
 #include "Transaction.h"
 #include "Account.h"
diff --git a/src/engine/gncJob.c b/src/engine/gncJob.c
index 22a85cb..e65eca6 100644
--- a/src/engine/gncJob.c
+++ b/src/engine/gncJob.c
@@ -26,10 +26,11 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <string.h>
+#include <qofinstance-p.h>
 
 #include "gncInvoice.h"
 #include "gncJob.h"
diff --git a/src/engine/gncOrder.c b/src/engine/gncOrder.c
index dd613c4..1b073e1 100644
--- a/src/engine/gncOrder.c
+++ b/src/engine/gncOrder.c
@@ -25,10 +25,11 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
+#include <qofinstance-p.h>
 
 #include "gncEntry.h"
 #include "gncEntryP.h"
diff --git a/src/engine/gncOwner.c b/src/engine/gncOwner.c
index b9b66f2..d77798f 100644
--- a/src/engine/gncOwner.c
+++ b/src/engine/gncOwner.c
@@ -29,11 +29,12 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <string.h>		/* for memcpy() */
+#include <qofinstance-p.h>
 
 #include "gncCustomerP.h"
 #include "gncEmployeeP.h"
diff --git a/src/engine/gncTaxTable.c b/src/engine/gncTaxTable.c
index b6bb272..163243a 100644
--- a/src/engine/gncTaxTable.c
+++ b/src/engine/gncTaxTable.c
@@ -26,9 +26,10 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
+#include <qofinstance-p.h>
 
 #include "gncTaxTableP.h"
 
diff --git a/src/engine/gncVendor.c b/src/engine/gncVendor.c
index d416db4..a57124c 100644
--- a/src/engine/gncVendor.c
+++ b/src/engine/gncVendor.c
@@ -26,10 +26,11 @@
  * Author: Derek Atkins <warlord at MIT.EDU>
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <glib.h>
 #include <string.h>
+#include <qofinstance-p.h>
 
 #include "gnc-commodity.h"
 #include "gncAddressP.h"
diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c
index d9568cb..92b22f1 100644
--- a/src/engine/test-core/test-engine-stuff.c
+++ b/src/engine/test-core/test-engine-stuff.c
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <qofinstance-p.h>
 
 #include "Account.h"
 #include "AccountP.h"
diff --git a/src/engine/test/test-customer.c b/src/engine/test/test-customer.c
index 02f67df..fe8fb2f 100644
--- a/src/engine/test/test-customer.c
+++ b/src/engine/test/test-customer.c
@@ -24,9 +24,11 @@
  *
  *********************************************************************/
 
-#include "config.h"
+#include <config.h>
 #include <glib.h>
-#include "qof.h"
+#include <qof.h>
+#include <qofinstance-p.h>
+
 #include "cashobjects.h"
 #include "gncCustomerP.h"
 #include "gncInvoiceP.h"
diff --git a/src/engine/test/test-employee.c b/src/engine/test/test-employee.c
index 03bb066..1835bbf 100644
--- a/src/engine/test/test-employee.c
+++ b/src/engine/test/test-employee.c
@@ -24,9 +24,11 @@
  *
  *********************************************************************/
 
-#include "config.h"
+#include <config.h>
 #include <glib.h>
-#include "qof.h"
+#include <qof.h>
+#include <qofinstance-p.h>
+
 #include "gncEmployeeP.h"
 #include "gncCustomerP.h"
 #include "gncJobP.h"
diff --git a/src/engine/test/test-job.c b/src/engine/test/test-job.c
index b90950a..9791b4f 100644
--- a/src/engine/test/test-job.c
+++ b/src/engine/test/test-job.c
@@ -24,9 +24,11 @@
  *
  *********************************************************************/
 
-#include "config.h"
+#include <config.h>
 #include <glib.h>
-#include "qof.h"
+#include <qof.h>
+#include <qofinstance-p.h>
+
 #include "gncJobP.h"
 #include "gncInvoiceP.h"
 #include "gncCustomerP.h"
diff --git a/src/engine/test/test-vendor.c b/src/engine/test/test-vendor.c
index 65adf3e..c36ff72 100644
--- a/src/engine/test/test-vendor.c
+++ b/src/engine/test/test-vendor.c
@@ -24,8 +24,10 @@
  *
  *********************************************************************/
 
-#include "config.h"
+#include <config.h>
 #include <glib.h>
+#include <qofinstance-p.h>
+
 #include "gncInvoiceP.h"
 #include "gncCustomerP.h"
 #include "gncJobP.h"
diff --git a/src/engine/test/utest-Account.c b/src/engine/test/utest-Account.c
index 2a8fe33..07c47c7 100644
--- a/src/engine/test/utest-Account.c
+++ b/src/engine/test/utest-Account.c
@@ -25,6 +25,7 @@
 #include <unittest-support.h>
 #include <gnc-event.h>
 #include <gnc-gdate-utils.h>
+#include <qofinstance-p.h>
 /* Add specific headers for this class */
 #include "../Account.h"
 #include "../AccountP.h"
diff --git a/src/engine/test/utest-Split.c b/src/engine/test/utest-Split.c
index b1da99b..4bff6cc 100644
--- a/src/engine/test/utest-Split.c
+++ b/src/engine/test/utest-Split.c
@@ -34,6 +34,7 @@
 #include <gnc-lot.h>
 #include <gnc-event.h>
 #include <qofbookslots.h>
+#include <qofinstance-p.h>
 
 #ifdef HAVE_GLIB_2_38
 #define _Q "'"
diff --git a/src/libqof/qof/qof.h b/src/libqof/qof/qof.h
index 1137a21..73518e3 100644
--- a/src/libqof/qof/qof.h
+++ b/src/libqof/qof/qof.h
@@ -84,7 +84,6 @@
 #include "kvp-util-p.h"
 #include "qofbackend.h"
 #include "qofid-p.h"
-#include "qofinstance-p.h"
 #include "qofbook.h"
 #include "qofclass.h"
 #include "qofevent.h"
diff --git a/src/libqof/qof/qofid.c b/src/libqof/qof/qofid.c
index 116082b..7f7f472 100644
--- a/src/libqof/qof/qofid.c
+++ b/src/libqof/qof/qofid.c
@@ -29,6 +29,7 @@
 
 #include "qof.h"
 #include "qofid-p.h"
+#include "qofinstance-p.h"
 
 static QofLogModule log_module = QOF_MOD_ENGINE;
 static gboolean qof_alt_dirty_mode = FALSE;
diff --git a/src/libqof/qof/qofinstance-p.h b/src/libqof/qof/qofinstance-p.h
index 38015f7..0306b9e 100644
--- a/src/libqof/qof/qofinstance-p.h
+++ b/src/libqof/qof/qofinstance-p.h
@@ -49,9 +49,59 @@ void qof_instance_set_last_update (QofInstance *inst, Timespec ts);
  *  collection flag at all. */
 void qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag);
 
+/** Set the GncGUID of this instance */
+void qof_instance_set_guid (gpointer inst, const GncGUID *guid);
+
+/** Copy the GncGUID from one instance to another.  This routine should
+ *  be used with extreme caution, since GncGUID values are everywhere
+ *  assumed to be unique. */
+void qof_instance_copy_guid (gpointer to, gconstpointer from);
+
+//QofIdType qof_instance_get_e_type (const QofInstance *inst);
+//void qof_instance_set_e_type (QofInstance *ent, QofIdType e_type);
+
+/** Return the pointer to the kvp_data */
+/*@ dependent @*/
+KvpFrame* qof_instance_get_slots (const QofInstance *);
+void qof_instance_set_editlevel(gpointer inst, gint level);
+void qof_instance_increase_editlevel (gpointer ptr);
+void qof_instance_decrease_editlevel (gpointer ptr);
+void qof_instance_reset_editlevel (gpointer ptr);
+/** Set the flag that indicates whether or not this object is about to
+ *  be destroyed.
+ *
+ *  @param ptr The object whose flag should be set.
+ *
+ *  @param value The new value to be set for this object. */
+void qof_instance_set_destroying (gpointer ptr, gboolean value);
+
+/** \brief Set the dirty flag
+Sets this instance AND the collection as dirty.
+*/
+void qof_instance_set_dirty(QofInstance* inst);
+
+/* reset the dirty flag */
+void qof_instance_mark_clean (QofInstance *);
+/** Get the version number on this instance.  The version number is
+ *  used to manage multi-user updates. */
+gint32 qof_instance_get_version (gconstpointer inst);
+
+/** Set the version number on this instance.  The version number is
+ *  used to manage multi-user updates. */
+void qof_instance_set_version (gpointer inst, gint32 value);
+/** Copy the version number on this instance.  The version number is
+ *  used to manage multi-user updates. */
+void qof_instance_copy_version (gpointer to, gconstpointer from);
+
+/** Get the instance version_check number */
+guint32 qof_instance_get_version_check (gconstpointer inst);
+/** Set the instance version_check number */
+void qof_instance_set_version_check (gpointer inst, guint32 value);
+/** copy the instance version_check number */
+void qof_instance_copy_version_check (gpointer to, gconstpointer from);
+void qof_instance_set_idata(gpointer inst, guint32 idata);
 /* Convenience functions to save some typing in property handlers */
 void qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value);
 void qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value);
 
-
 #endif /* QOF_INSTANCE_P_H */
diff --git a/src/libqof/qof/qofinstance.h b/src/libqof/qof/qofinstance.h
index a296099..89b7172 100644
--- a/src/libqof/qof/qofinstance.h
+++ b/src/libqof/qof/qofinstance.h
@@ -121,30 +121,12 @@ const GncGUID * qof_entity_get_guid (gconstpointer);
 /*@ dependent @*/
 QofCollection* qof_instance_get_collection (gconstpointer inst);
 
-/** Set the GncGUID of this instance */
-void qof_instance_set_guid (gpointer inst, const GncGUID *guid);
-
-/** Copy the GncGUID from one instance to another.  This routine should
- *  be used with extreme caution, since GncGUID values are everywhere
- *  assumed to be unique. */
-void qof_instance_copy_guid (gpointer to, gconstpointer from);
-
 /** Compare the GncGUID values of two instances.  This routine returns 0
  *  if the two values are equal, <0 if the first is smaller than the
  *  second, or >0 if the second is smaller tan the first. */
 gint qof_instance_guid_compare(const gconstpointer ptr1, const gconstpointer ptr2);
 
-//QofIdType qof_instance_get_e_type (const QofInstance *inst);
-//void qof_instance_set_e_type (QofInstance *ent, QofIdType e_type);
-
-/** Return the pointer to the kvp_data */
-/*@ dependent @*/
-KvpFrame* qof_instance_get_slots (const QofInstance *);
-void qof_instance_set_editlevel(gpointer inst, gint level);
 gint qof_instance_get_editlevel (gconstpointer ptr);
-void qof_instance_increase_editlevel (gpointer ptr);
-void qof_instance_decrease_editlevel (gpointer ptr);
-void qof_instance_reset_editlevel (gpointer ptr);
 
 /** Compare two instances, based on thier last update times.
  *  Returns a negative, zero or positive value, respectively,
@@ -164,14 +146,6 @@ int qof_instance_version_cmp (const QofInstance *left, const QofInstance *right)
  *  is passed to the function. */
 gboolean qof_instance_get_destroying (gconstpointer ptr);
 
-/** Set the flag that indicates whether or not this object is about to
- *  be destroyed.
- *
- *  @param ptr The object whose flag should be set.
- *
- *  @param value The new value to be set for this object. */
-void qof_instance_set_destroying (gpointer ptr, gboolean value);
-
 /** Retrieve the flag that indicates whether or not this object has
  *  been modified.  This is specifically the flag on the object. It
  *  does not perform any other checking which might normally be
@@ -191,39 +165,13 @@ void qof_instance_print_dirty (const QofInstance *entity, gpointer dummy);
 #define qof_instance_is_dirty qof_instance_get_dirty
 gboolean qof_instance_get_dirty (QofInstance *);
 
-/** \brief Set the dirty flag
-
-Sets this instance AND the collection as dirty.
-*/
-void qof_instance_set_dirty(QofInstance* inst);
-
-/* reset the dirty flag */
-void qof_instance_mark_clean (QofInstance *);
-
 gboolean qof_instance_get_infant(const QofInstance *inst);
 
-/** Get the version number on this instance.  The version number is
- *  used to manage multi-user updates. */
-gint32 qof_instance_get_version (gconstpointer inst);
-
-/** Set the version number on this instance.  The version number is
- *  used to manage multi-user updates. */
-void qof_instance_set_version (gpointer inst, gint32 value);
-/** Copy the version number on this instance.  The version number is
- *  used to manage multi-user updates. */
-void qof_instance_copy_version (gpointer to, gconstpointer from);
 
-/** Get the instance version_check number */
-guint32 qof_instance_get_version_check (gconstpointer inst);
-/** Set the instance version_check number */
-void qof_instance_set_version_check (gpointer inst, guint32 value);
-/** copy the instance version_check number */
-void qof_instance_copy_version_check (gpointer to, gconstpointer from);
 
 /** get the instance tag number
     used for kvp management in sql backends. */
 guint32 qof_instance_get_idata (gconstpointer inst);
-void qof_instance_set_idata(gpointer inst, guint32 idata);
 
 /**
  * Returns a displayable name for this object.  The returned string must be freed by the caller.

commit 4a4b18059e61b3ec9217e694a9df53afd013ac5f
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Oct 15 16:47:49 2013 -0700

    Provide for easily moving GValues to and from KVP
    
    So that all interaction with KVP is easily handled with properties.
    Includes convenience functions for simplifying set/get property
    functions.

diff --git a/src/libqof/qof/kvp_frame.c b/src/libqof/qof/kvp_frame.c
index 7597ea0..48f1e73 100644
--- a/src/libqof/qof/kvp_frame.c
+++ b/src/libqof/qof/kvp_frame.c
@@ -1645,4 +1645,192 @@ kvp_frame_get_hash(const KvpFrame *frame)
     return frame->hash;
 }
 
+static GValue *gvalue_from_kvp_value (KvpValue*);
+static KvpValue *kvp_value_from_gvalue (const GValue*);
+
+static void
+gvalue_list_from_kvp_value (KvpValue *kval, gpointer pList)
+{
+    GList **gvlist = NULL;
+    GValue *gval = gvalue_from_kvp_value (kval);
+    gvlist =  (GList**)pList;
+    if (G_VALUE_TYPE (gval))
+	*gvlist = g_list_prepend (*gvlist, gval);
+}
+
+static void
+kvp_value_list_from_gvalue (GValue *gval, gpointer pList)
+{
+    GList **kvplist = (GList**)pList;
+    KvpValue *kvp;
+    if (!(gval && G_VALUE_TYPE (gval)))
+	return;
+    kvp = kvp_value_from_gvalue (gval);
+    *kvplist = g_list_prepend (*kvplist, kvp);
+}
+
+static GValue*
+gvalue_from_kvp_value (KvpValue *kval)
+{
+    GValue *val;
+    gnc_numeric num;
+    Timespec tm;
+    GDate gdate;
+
+    if (kval == NULL) return NULL;
+    val = g_slice_new0 (GValue);
+
+    switch (kval->type)
+    {
+	case KVP_TYPE_GINT64:
+	    g_value_init (val, G_TYPE_INT64);
+	    g_value_set_int64 (val, kvp_value_get_gint64 (kval));
+	    break;
+	case KVP_TYPE_DOUBLE:
+	    g_value_init (val, G_TYPE_DOUBLE);
+	    g_value_set_double (val, kvp_value_get_double (kval));
+	    break;
+	case KVP_TYPE_NUMERIC:
+	    g_value_init (val, GNC_TYPE_NUMERIC);
+	    num = kvp_value_get_numeric (kval);
+	    g_value_set_boxed (val, &num);
+	    break;
+	case KVP_TYPE_STRING:
+	    g_value_init (val, G_TYPE_STRING);
+	    g_value_set_string (val, kvp_value_get_string (kval));
+	    break;
+	case KVP_TYPE_GUID:
+	    g_value_init (val, GNC_TYPE_GUID);
+	    g_value_set_boxed (val, kvp_value_get_guid (kval));
+	    break;
+	case KVP_TYPE_TIMESPEC:
+	    g_value_init (val, GNC_TYPE_TIMESPEC);
+	    tm = kvp_value_get_timespec (kval);
+	    g_value_set_boxed (val, &tm);
+	    break;
+	case KVP_TYPE_BINARY:
+	    PWARN ("Error! Don't use Kvp Binary!");
+	    g_slice_free (GValue, val);
+	    val = NULL;
+	    break;
+	case KVP_TYPE_GDATE:
+	    g_value_init (val, G_TYPE_DATE);
+	    gdate = kvp_value_get_gdate (kval);
+	    g_value_set_boxed (val, &gdate);
+	    break;
+	case KVP_TYPE_GLIST:
+	{
+	    GList *gvalue_list = NULL;
+	    GList *kvp_list = kvp_value_get_glist (kval);
+	    g_list_foreach (kvp_list, (GFunc)gvalue_list_from_kvp_value, &gvalue_list);
+	    g_value_init (val, GNC_TYPE_VALUE_LIST);
+	    gvalue_list = g_list_reverse (gvalue_list);
+	    g_value_set_boxed (val, gvalue_list);
+	    break;
+	}
+/* No transfer of KVP frames outside of QofInstance-derived classes! */
+	case KVP_TYPE_FRAME:
+	    PWARN ("Error! Attempt to transfer KvpFrame!");
+	default:
+	    PWARN ("Error! Invalid KVP Transfer Request!");
+	    g_slice_free (GValue, val);
+	    val = NULL;
+	    break;
+    }
+    return val;
+}
+
+KvpValue*
+kvp_value_from_gvalue (const GValue *gval)
+{
+    KvpValue *val = NULL;
+    GType type = G_VALUE_TYPE (gval);
+    g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);
+
+    if (type == G_TYPE_INT64)
+	val = kvp_value_new_gint64 (g_value_get_int64 (gval));
+    else if (type == G_TYPE_DOUBLE)
+	val = kvp_value_new_double (g_value_get_double (gval));
+    else if (type == GNC_TYPE_NUMERIC)
+	val = kvp_value_new_numeric (*(gnc_numeric*)g_value_get_boxed (gval));
+    else if (type == G_TYPE_STRING)
+	val = kvp_value_new_string (g_value_get_string (gval));
+    else if (type == GNC_TYPE_GUID)
+	val = kvp_value_new_guid ((GncGUID*)g_value_get_boxed (gval));
+    else if (type == GNC_TYPE_TIMESPEC)
+	val = kvp_value_new_timespec (*(Timespec*)g_value_get_boxed (gval));
+    else if (type == G_TYPE_DATE)
+	val = kvp_value_new_gdate (*(GDate*)g_value_get_boxed (gval));
+    else if (type == GNC_TYPE_VALUE_LIST)
+    {
+	GList *gvalue_list = (GList*)g_value_get_boxed (gval);
+	GList *kvp_list = NULL;
+	g_list_foreach (gvalue_list, (GFunc)kvp_value_list_from_gvalue, &kvp_list);
+	kvp_list = g_list_reverse (kvp_list);
+	val = kvp_value_new_glist_nc (kvp_list);
+//	g_list_free_full (gvalue_list, (GDestroyNotify)g_value_unset);
+//	gvalue_list = NULL;
+    }
+    else
+	PWARN ("Error! Don't know how to make a KvpValue from a %s",
+	       G_VALUE_TYPE_NAME (gval));
+
+    return val;
+}
+
+GValue*
+kvp_frame_get_gvalue (KvpFrame *frame, const gchar *key)
+{
+    KvpValue *kval = kvp_frame_get_value (frame, key);
+    GValue *value = gvalue_from_kvp_value (kval);
+    return value;
+}
+
+void
+kvp_frame_set_gvalue (KvpFrame *frame, const gchar *key, const GValue *value)
+{
+  kvp_frame_set_value_nc (frame, key, kvp_value_from_gvalue (value));
+}
+
+static GValue*
+gnc_gvalue_copy (GValue *src, gpointer uData)
+{
+    GValue *dest = g_value_init (g_slice_new0 (GValue), G_VALUE_TYPE (src));
+    g_value_copy (src, dest);
+    return dest;
+}
+
+void
+gnc_gvalue_free (GValue *val)
+{
+    if (val == NULL || ! G_IS_VALUE (val)) return;
+    g_value_unset (val);
+    g_slice_free (GValue, val);
+}
+
+static GList*
+gnc_value_list_copy (GList *list)
+{
+    return g_list_copy_deep (list, (GCopyFunc)gnc_gvalue_copy, NULL);
+}
+
+static void
+gnc_value_list_free (GList *list)
+{
+    g_list_free_full (list, (GDestroyNotify)gnc_gvalue_free);
+}
+
+GType
+gnc_value_list_get_type (void)
+{
+    static GType type = 0;
+    if (type == 0)
+    {
+	type = g_boxed_type_register_static ("gnc_value_list",
+					     (GBoxedCopyFunc)gnc_value_list_copy,
+					     (GBoxedFreeFunc)gnc_value_list_free);
+    }
+    return type;
+}
+
 /* ========================== END OF FILE ======================= */
diff --git a/src/libqof/qof/kvp_frame.h b/src/libqof/qof/kvp_frame.h
index 3b9aae6..104a479 100644
--- a/src/libqof/qof/kvp_frame.h
+++ b/src/libqof/qof/kvp_frame.h
@@ -588,5 +588,58 @@ gchar* kvp_frame_to_string(const KvpFrame *frame);
 gchar* binary_to_string(const void *data, guint32 size);
 GHashTable* kvp_frame_get_hash(const KvpFrame *frame);
 
+/** KvpItem: GValue Exchange
+ * \brief Transfer of KVP to and from GValue, with the key
+ *
+ * Used to parameterize KVP <-> GValue exchanges.
+ */
+typedef struct
+{
+    const gchar   *key;
+    GValue        *value;
+}KvpItem;
+
+/** Return a KvpItem containing the value of a KvpFrame
+ *
+ * Structure types (gnc_numeric, Timespec) are converted to pointers
+ * and must be extracted with g_value_get_boxed. A KVP_TYPE_GLIST will
+ * have all of its contents converted from KvpValues to GValues, so
+ * the return type will be a GValue containing a GList of GValue*, not
+ * GValue.  Use gnc_value_list_free() to free such a list if you take
+ * it out of the GValue.
+ *
+ * \param frame: (transfer-none) The KvpFrame retrieved with kvp_get_frame_foo()
+ * \param key: (transfer-none) A slash-delimited string with the path to
+ * the stored value. Must not be NULL or empty.
+ * \return (transfer-full) A KvpItem* which must be freed with kvp_item_free().
+ */
+GValue *kvp_frame_get_gvalue (KvpFrame *frame, const gchar *key);
+
+/** Replace or create a Kvp slot from a KvpItem
+ *
+ * Structure types (gnc_numeric, Timespec) should be stored as
+ * boxed-type pointers in the GValue with the appropriate type from
+ * qof.h. Lists should be stored as a GValue containing a GList of
+ * GValues of type convertable to KvpValues. Unsupported types will
+ * emit a warning message and will be skipped.
+ *
+ * \param frame: (transfer none) The KvpFrame into which the value
+ * will be added.
+ * \param key: (transfer none) The subkey of the frame at which to
+ * store the value
+ * \param value: GValue containing the paramter to store.
+ */
+void kvp_frame_set_gvalue (KvpFrame *frame, const gchar *key, const GValue *value);
+
+/**
+ * \brief Convenience function to release the value in a GValue
+ * acquired by kvp_frame_get_gvalue and to free the GValue.
+ * \param value: A GValue* created by kvp_frame_get_gvalue
+ */
+void gnc_gvalue_free (GValue *value);
+
+GType gnc_value_list_get_type (void);
+#define GNC_TYPE_VALUE_LIST (gnc_value_list_get_type ())
+
 /** @} */
 #endif
diff --git a/src/libqof/qof/qofinstance-p.h b/src/libqof/qof/qofinstance-p.h
index 1765733..38015f7 100644
--- a/src/libqof/qof/qofinstance-p.h
+++ b/src/libqof/qof/qofinstance-p.h
@@ -49,4 +49,9 @@ void qof_instance_set_last_update (QofInstance *inst, Timespec ts);
  *  collection flag at all. */
 void qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag);
 
+/* Convenience functions to save some typing in property handlers */
+void qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value);
+void qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value);
+
+
 #endif /* QOF_INSTANCE_P_H */
diff --git a/src/libqof/qof/qofinstance.c b/src/libqof/qof/qofinstance.c
index 0327596..5cfbecd 100644
--- a/src/libqof/qof/qofinstance.c
+++ b/src/libqof/qof/qofinstance.c
@@ -1050,5 +1050,25 @@ qof_commit_edit_part2(QofInstance *inst,
     return TRUE;
 }
 
+void
+qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value)
+{
+    KvpFrame *frame = qof_instance_get_slots (inst);
+    kvp_frame_set_gvalue (frame, key, value);
+}
+
+void
+qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value)
+{
+    KvpFrame *frame = qof_instance_get_slots (inst);
+    GValue *temp = kvp_frame_get_gvalue (frame, key);
+    if (temp)
+    {
+	g_value_copy (temp, value);
+	gnc_gvalue_free (temp);
+    }
+}
+
+
 /* ========================== END OF FILE ======================= */
 
diff --git a/src/libqof/qof/test/test-kvp_frame.c b/src/libqof/qof/test/test-kvp_frame.c
index c3009cf..aaf7c74 100644
--- a/src/libqof/qof/test/test-kvp_frame.c
+++ b/src/libqof/qof/test/test-kvp_frame.c
@@ -22,7 +22,7 @@
 #include "config.h"
 #include <string.h>
 #include <glib.h>
-#include "unittest-support.h"
+#include <unittest-support.h>
 #include "qof.h"
 
 static const gchar *suitename = "/qof/kvp_frame";
@@ -31,18 +31,22 @@ void test_suite_kvp_frame ( void );
 typedef struct
 {
     KvpFrame *frame;
+    GSList *hdlrs;
 } Fixture;
 
 static void
 setup( Fixture *fixture, gconstpointer pData )
 {
     fixture->frame = kvp_frame_new();
+    fixture->hdlrs = NULL;
 }
 
 static void
 teardown( Fixture *fixture, gconstpointer pData )
 {
     kvp_frame_delete( fixture->frame );
+    g_slist_free_full (fixture->hdlrs, test_free_log_handler);
+    test_clear_error_list ();
 }
 
 extern KvpFrame* ( *p_get_trailer_make )( KvpFrame *frame, const char *key_path, char **end_key );
@@ -57,6 +61,7 @@ static void
 setup_static( Fixture *fixture, gconstpointer pData )
 {
     fixture->frame = kvp_frame_new();
+    fixture->hdlrs = NULL;
     init_static_test_pointers();
     g_assert( p_get_trailer_make && p_kvp_value_glist_to_string &&
               p_get_or_make && p_kvp_frame_get_frame_or_null_slash_trash &&
@@ -67,6 +72,8 @@ static void
 teardown_static( Fixture *fixture, gconstpointer pData )
 {
     kvp_frame_delete( fixture->frame );
+    g_slist_free_full (fixture->hdlrs, test_free_log_handler);
+    test_clear_error_list ();
     p_get_trailer_make = NULL;
     p_kvp_value_glist_to_string = NULL;
     p_get_or_make = NULL;
@@ -74,21 +81,19 @@ teardown_static( Fixture *fixture, gconstpointer pData )
     p_get_trailer_or_null = NULL;
 }
 
-static void
-test_kvp_frame_new_delete( void )
+static GncGUID*
+populate_frame (KvpFrame *frame)
 {
-    KvpFrame *frame;
+    GList *list = NULL;
     Timespec ts;
     GncGUID *guid;
+    GDate gdate;
 
     ts.tv_sec = 1;
     ts.tv_nsec = 1;
-    guid = guid_malloc();
-    guid_new( guid );
-
-    frame = kvp_frame_new();
-    g_assert( frame );
-    g_assert( kvp_frame_is_empty( frame ) );
+    guid = guid_malloc ();
+    guid_new (guid);
+    g_date_set_dmy (&gdate, 26, 1, 1957);
 
     kvp_frame_set_gint64( frame, "gint64-type", 100 );
     kvp_frame_set_double( frame, "double-type", 3.14159 );
@@ -96,14 +101,37 @@ test_kvp_frame_new_delete( void )
     kvp_frame_set_timespec( frame, "timespec-type", ts );
     kvp_frame_set_string( frame, "string-type", "abcdefghijklmnop" );
     kvp_frame_set_guid( frame, "guid-type", guid );
+    kvp_frame_set_value_nc (frame, "gdate-type", kvp_value_new_gdate (gdate));
     kvp_frame_set_frame( frame, "frame-type", kvp_frame_new() );
 
+    list = g_list_prepend (list, kvp_value_new_guid (guid));
+    list = g_list_prepend (list, kvp_value_new_string ("qrstuvwxyz"));
+    list = g_list_prepend (list, kvp_value_new_timespec (ts));
+    list = g_list_prepend (list, kvp_value_new_numeric (gnc_numeric_create (256, 120)));
+    list = g_list_prepend (list, kvp_value_new_double (0.4342944819));
+    list = g_list_prepend (list, kvp_value_new_gint64 (0x1f2e3d4c5b6a79LL));
+    kvp_frame_set_value (frame, "list-type", kvp_value_new_glist_nc (list));
+
+    return guid;
+}
+
+static void
+test_kvp_frame_new_delete( void )
+{
+    KvpFrame *frame;
+    GncGUID *guid;
+
+    frame = kvp_frame_new();
+    g_assert( frame );
+    g_assert( kvp_frame_is_empty( frame ) );
+
+    guid = populate_frame (frame);
+
     g_assert( !kvp_frame_is_empty( frame ) );
 
     kvp_frame_delete( frame );
     g_assert( frame );
-
-    guid_free( guid );
+    guid_free (guid);
 }
 
 static void
@@ -1455,6 +1483,203 @@ test_get_trailer_or_null( Fixture *fixture, gconstpointer pData )
     g_assert_cmpstr( last_key, == , "test2" );
 }
 
+static void
+test_kvp_frame_get_gvalue (Fixture *fixture, gconstpointer pData)
+{
+    KvpFrame *frame = fixture->frame;
+    GValue *value;
+    Timespec ts = {1, 1};
+    GncGUID *guid = populate_frame (frame);
+    GDate date;
+    gchar *log_domain = "qof.kvp";
+    gint log_level = G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL;
+    gchar *msg1 = "[gvalue_from_kvp_value()] Error! Attempt to transfer KvpFrame!";
+    gchar *msg2 = "[gvalue_from_kvp_value()] Error! Invalid KVP Transfer Request!";
+#undef _func
+    TestErrorStruct *check1 = test_error_struct_new (log_domain, log_level,
+							msg1);
+    TestErrorStruct *check2 = test_error_struct_new (log_domain, log_level,
+							msg2);
+    fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check1,
+						 (GLogFunc)test_list_handler);
+    test_add_error (check1);
+    test_add_error (check2);
+
+    g_date_clear (&date, 1);
+    g_date_set_dmy (&date, 26, 1, 1957);
+
+    value = kvp_frame_get_gvalue (frame, "gint64-type");
+    g_assert (value != NULL);
+    g_assert (G_VALUE_HOLDS_INT64 (value));
+    g_assert_cmpint (g_value_get_int64 (value), ==, 100);
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "double-type");
+    g_assert (value != NULL);
+    g_assert (G_VALUE_HOLDS_DOUBLE (value));
+    g_assert_cmpfloat (g_value_get_double (value), ==, 3.14159);
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "numeric-type");
+    g_assert (value != NULL);
+    g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_NUMERIC);
+    g_assert (gnc_numeric_zero_p (*(gnc_numeric*)g_value_get_boxed (value)));
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "timespec-type");
+    g_assert (value != NULL);
+    g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_TIMESPEC);
+    g_assert (timespec_equal (&ts, (Timespec*)g_value_get_boxed (value)));
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "string-type");
+    g_assert (value != NULL);
+    g_assert (G_VALUE_HOLDS_STRING (value));
+    g_assert_cmpstr (g_value_get_string (value), ==, "abcdefghijklmnop");
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "guid-type");
+    g_assert (value != NULL);
+    g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_GUID);
+    g_assert (guid_equal (guid, (GncGUID*)g_value_get_boxed (value)));
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "gdate-type");
+    g_assert (value != NULL);
+    g_assert_cmpint (G_VALUE_TYPE (value), ==, G_TYPE_DATE);
+    g_assert_cmpint (g_date_compare (&date, (GDate*)g_value_get_boxed (value)), ==, 0);
+    gnc_gvalue_free (value);
+
+    value = kvp_frame_get_gvalue (frame, "frame-type");
+    g_assert (value == NULL);
+    g_assert_cmpint (check1->hits, ==, 1);
+    g_assert_cmpint (check2->hits, ==, 1);
+
+    value = kvp_frame_get_gvalue (frame, "list-type");
+    g_assert (value != NULL);
+    g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_VALUE_LIST);
+    {
+	GList *list = (GList*)g_value_get_boxed (value);
+	GValue *value = NULL;
+
+	value = (GValue*)(list->data);
+	g_assert (G_VALUE_HOLDS_INT64 (value));
+	g_assert (g_value_get_int64 (value) == 0x1f2e3d4c5b6a79LL);
+	list = g_list_next (list);
+
+	value = (GValue*)(list->data);
+	g_assert (G_VALUE_HOLDS_DOUBLE (value));
+	g_assert_cmpfloat (g_value_get_double (value), ==, 0.4342944819);
+	list = g_list_next (list);
+
+	value = (GValue*)(list->data);
+	g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_NUMERIC);
+	g_assert (gnc_numeric_eq (*(gnc_numeric*)g_value_get_boxed (value),
+				  gnc_numeric_create (256, 120)));
+	list = g_list_next (list);
+
+	value = (GValue*)(list->data);
+	g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_TIMESPEC);
+	g_assert (timespec_equal (&ts, (Timespec*)g_value_get_boxed (value)));
+	list = g_list_next (list);
+
+	value = (GValue*)(list->data);
+	g_assert (G_VALUE_HOLDS_STRING (value));
+	g_assert_cmpstr (g_value_get_string (value), ==, "qrstuvwxyz");
+	list = g_list_next (list);
+
+	value = (GValue*)(list->data);
+	g_assert_cmpint (G_VALUE_TYPE (value), ==, GNC_TYPE_GUID);
+	g_assert (guid_equal (guid, (GncGUID*)g_value_get_boxed (value)));
+	list = g_list_next (list);
+
+	g_assert (list == NULL);
+
+    }
+    gnc_gvalue_free (value);
+}
+
+static void
+test_kvp_frame_set_gvalue (Fixture *fixture, gconstpointer pData)
+{
+/* Bit of a shortcut: We'll use kvp_frame_get_item to make our KvpItem
+ * and feed it into a new frame; something of a round-trip test.
+ */
+    KvpFrame *o_frame = fixture->frame;
+    KvpFrame *n_frame = kvp_frame_new ();
+    GValue *value;
+    GList *o_list, *n_list;
+
+    populate_frame (o_frame);
+
+    value = kvp_frame_get_gvalue (o_frame, "gint64-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "gint64-type", value);
+    g_assert_cmpint (kvp_frame_get_gint64 (o_frame, "gint64-type"), ==,
+		     kvp_frame_get_gint64 (n_frame, "gint64-type"));
+
+    value = kvp_frame_get_gvalue (o_frame, "double-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "double-type", value);
+    g_assert_cmpint (kvp_frame_get_double (o_frame, "double-type"), ==,
+		     kvp_frame_get_double (n_frame, "double-type"));
+
+    value = kvp_frame_get_gvalue (o_frame, "numeric-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "numeric-type", value);
+    g_assert (gnc_numeric_equal (kvp_frame_get_numeric (o_frame, "numeric-type"),
+				 kvp_frame_get_numeric (n_frame, "numeric-type")));
+
+    value = kvp_frame_get_gvalue (o_frame, "timespec-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "timespec-type", value);
+    {
+	Timespec o_ts = kvp_frame_get_timespec (o_frame, "timespec-type");
+	Timespec n_ts = kvp_frame_get_timespec (n_frame, "timespec-type");
+	g_assert (timespec_equal (&o_ts, &n_ts));
+    }
+
+    value = kvp_frame_get_gvalue (o_frame, "string-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "string-type", value);
+    g_assert_cmpstr (kvp_frame_get_string (o_frame, "string-type"), ==,
+		     kvp_frame_get_string (n_frame, "string-type"));
+
+    value = kvp_frame_get_gvalue (o_frame, "gdate-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "gdate-type", value);
+    {
+	GDate o_date = kvp_value_get_gdate (kvp_frame_get_slot (o_frame,
+								"gdate-type"));
+	GDate n_date = kvp_value_get_gdate (kvp_frame_get_slot (n_frame,
+								"gdate-type"));
+	g_assert_cmpint (g_date_compare (&o_date, &n_date), ==, 0);
+    }
+
+    value = kvp_frame_get_gvalue (o_frame, "guid-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "guid-type", value);
+    g_assert (guid_equal (kvp_frame_get_guid (o_frame, "guid-type"),
+			  kvp_frame_get_guid (n_frame, "guid-type")));
+
+    value = kvp_frame_get_gvalue (o_frame, "list-type");
+    g_assert (value != NULL);
+    kvp_frame_set_gvalue (n_frame, "list-type", value);
+    o_list = kvp_value_get_glist (kvp_frame_get_slot (o_frame, "list_type"));
+    n_list = kvp_value_get_glist (kvp_frame_get_slot (n_frame, "list_type"));
+
+    g_assert_cmpint (g_list_length (o_list), ==, g_list_length (n_list));
+    while (o_list && n_list)
+    {
+	g_assert_cmpint (kvp_value_compare ((KvpValue*)o_list->data,
+					    (KvpValue*)n_list->data), ==, 0);
+	o_list = g_list_next (o_list);
+	n_list = g_list_next (n_list);
+    }
+    kvp_frame_delete (n_frame);
+}
+
+
 void
 test_suite_kvp_frame( void )
 {
@@ -1482,4 +1707,6 @@ test_suite_kvp_frame( void )
     GNC_TEST_ADD( suitename, "get or make", Fixture, NULL, setup_static, test_get_or_make, teardown_static );
     GNC_TEST_ADD( suitename, "kvp frame get frame or null slash trash", Fixture, NULL, setup_static, test_kvp_frame_get_frame_or_null_slash_trash, teardown_static );
     GNC_TEST_ADD( suitename, "get trailer or null", Fixture, NULL, setup_static, test_get_trailer_or_null, teardown_static );
+    GNC_TEST_ADD ( suitename, "kvp frame get gvalue", Fixture, NULL, setup, test_kvp_frame_get_gvalue, teardown);
+    GNC_TEST_ADD ( suitename, "kvp frame set gvalue", Fixture, NULL, setup, test_kvp_frame_set_gvalue, teardown);
 }



Summary of changes:
 po/POTFILES.in                                     |   1 -
 src/app-utils/business-helpers.c                   |   2 +-
 src/app-utils/gnc-accounting-period.c              |  12 +-
 src/app-utils/gnc-sx-instance-model.c              | 162 ++---
 src/app-utils/option-util.h                        |   2 +-
 src/app-utils/test/Makefile.am                     |  18 +-
 .../test/test-app-utils.c}                         |  48 +-
 src/app-utils/test/test-option-util.c              | 126 ++++
 src/backend/dbi/test/test-dbi-stuff.c              |   7 +-
 src/backend/sql/gnc-account-sql.c                  |   4 +
 src/backend/sql/gnc-address-sql.c                  |   2 +
 src/backend/sql/gnc-backend-sql.c                  |  43 +-
 src/backend/sql/gnc-bill-term-sql.c                |   2 +
 src/backend/sql/gnc-budget-sql.c                   |   2 +
 src/backend/sql/gnc-commodity-sql.c                |   2 +
 src/backend/sql/gnc-invoice-sql.c                  |   2 +
 src/backend/sql/gnc-lots-sql.c                     |   2 +
 src/backend/sql/gnc-order-sql.c                    |   2 +
 src/backend/sql/gnc-owner-sql.c                    |   2 +
 src/backend/sql/gnc-tax-table-sql.c                |   2 +
 src/backend/sql/gnc-transaction-sql.c              |   5 +
 src/backend/xml/gnc-account-xml-v2.c               |   7 +-
 src/backend/xml/gnc-address-xml-v2.c               |   5 +-
 src/backend/xml/gnc-book-xml-v2.c                  |  10 +-
 src/backend/xml/gnc-entry-xml-v2.c                 |   5 +-
 src/backend/xml/gnc-invoice-xml-v2.c               |   5 +-
 src/backend/xml/gnc-job-xml-v2.c                   |   5 +-
 src/backend/xml/gnc-lot-xml-v2.c                   |   6 +-
 src/backend/xml/gnc-order-xml-v2.c                 |   7 +-
 src/backend/xml/gnc-tax-table-xml-v2.c             |   5 +-
 src/backend/xml/gnc-transaction-xml-v2.c           |  11 +-
 src/backend/xml/io-gncxml-v2.c                     |   2 +-
 src/backend/xml/test/test-xml-account.c            |   2 +-
 src/backend/xml/test/test-xml-transaction.c        |   2 +-
 src/business/business-gnome/dialog-invoice.c       |  37 +-
 src/business/business-gnome/dialog-payment.c       |  33 +-
 src/core-utils/gnc-features.c                      |  68 +-
 src/engine/Account.c                               | 791 ++++++++++++++++++++-
 src/engine/Account.h                               |  13 +-
 src/engine/SX-book.c                               |   9 +-
 src/engine/SchedXaction.c                          |  73 +-
 src/engine/SchedXaction.h                          |   8 -
 src/engine/Scrub.c                                 |   3 +
 src/engine/Scrub2.c                                |   4 +-
 src/engine/Split.c                                 | 284 +++++++-
 src/engine/Split.h                                 |  14 -
 src/engine/SplitP.h                                |   3 +-
 src/engine/Transaction.c                           | 119 +++-
 src/engine/Transaction.h                           |  10 +-
 src/engine/TransactionP.h                          |   1 +
 src/engine/cap-gains.c                             | 202 +-----
 src/engine/cap-gains.h                             |  19 -
 src/engine/engine.i                                |  17 +-
 src/engine/gnc-budget.c                            |  47 +-
 src/engine/gnc-commodity.c                         |  24 +-
 src/engine/gnc-engine.h                            |  11 +
 src/engine/gnc-lot.c                               | 124 +++-
 src/engine/gnc-lot.h                               |   5 -
 src/engine/gnc-pricedb.c                           |  14 +-
 src/engine/gncAddress.c                            |   3 +-
 src/engine/gncBillTerm.c                           |   5 +-
 src/engine/gncBusiness.h                           |   6 +
 src/engine/gncCustomer.c                           |  71 +-
 src/engine/gncEmployee.c                           |  87 ++-
 src/engine/gncEntry.c                              |  32 +-
 src/engine/gncInvoice.c                            |  69 +-
 src/engine/gncInvoice.h                            |   2 +-
 src/engine/gncJob.c                                |  36 +-
 src/engine/gncOrder.c                              |  19 +-
 src/engine/gncOwner.c                              |  95 ++-
 src/engine/gncOwner.h                              |   4 +-
 src/engine/gncTaxTable.c                           |  12 +-
 src/engine/gncVendor.c                             |  88 ++-
 src/engine/test-core/test-engine-stuff.c           |  11 +-
 src/engine/test/Makefile.am                        |   1 +
 src/engine/test/test-account-object.c              |   3 +
 src/engine/test/test-customer.c                    |   6 +-
 src/engine/test/test-employee.c                    |   6 +-
 src/engine/test/test-engine-kvp-properties.c       | 458 ++++++++++++
 src/engine/test/test-engine.c                      |   2 +
 src/engine/test/test-job.c                         |   6 +-
 src/engine/test/test-vendor.c                      |   4 +-
 src/engine/test/utest-Account.c                    |  21 +-
 src/engine/test/utest-Split.cpp                    |  59 +-
 src/engine/test/utest-Transaction.c                |  62 +-
 src/gnome-utils/dialog-preferences.c               |  16 +-
 src/gnome-utils/gnc-main-window.c                  |  11 +-
 src/gnome-utils/gnc-tree-util-split-reg.c          |  51 +-
 src/gnome-utils/gnc-tree-view-account.c            |  41 +-
 src/gnome-utils/gnc-tree-view-account.h            |  13 +-
 src/gnome-utils/gnc-tree-view-split-reg.c          |  79 +-
 src/gnome/assistant-hierarchy.c                    |  13 +-
 src/gnome/dialog-sx-editor.c                       | 129 ++--
 src/gnome/dialog-sx-editor2.c                      | 123 ++--
 src/gnome/gnc-plugin-page-register2.c              |  57 +-
 src/gnome/gnc-split-reg.c                          |  55 +-
 src/import-export/CMakeLists.txt                   |   2 -
 src/import-export/Makefile.am                      |   3 -
 src/import-export/aqb/gnc-ab-kvp.c                 | 109 ++-
 src/import-export/import-account-matcher.c         |   4 +-
 src/import-export/import-backend.c                 |  47 +-
 src/import-export/import-backend.h                 |   2 +-
 src/import-export/import-main-matcher.c            |   1 -
 src/import-export/import-match-map.h               |  84 ---
 src/import-export/import-utilities.c               |  53 +-
 src/import-export/log-replay/gnc-log-replay.c      |   6 +-
 src/import-export/ofx/gnc-ofx-kvp.c                |  29 +-
 src/libqof/qof/kvp_frame.cpp                       | 188 +++++
 src/libqof/qof/kvp_frame.h                         |  53 ++
 src/libqof/qof/qof.h                               |   1 -
 src/libqof/qof/qofbook.cpp                         | 329 +++++++--
 src/libqof/qof/qofbook.h                           |  35 +-
 src/libqof/qof/qofid.cpp                           |   1 +
 src/libqof/qof/qofinstance-p.h                     |  56 ++
 src/libqof/qof/qofinstance.cpp                     |  68 +-
 src/libqof/qof/qofinstance.h                       |  61 +-
 src/libqof/qof/qoflog.cpp                          |   2 +
 src/libqof/qof/test/test-kvp_frame.c               | 251 ++++++-
 src/libqof/qof/test/test-qofbook.c                 |  78 +-
 .../ledger-core/split-register-model-save.c        |  85 +--
 src/register/ledger-core/split-register-model.c    |  60 +-
 src/report/report-gnome/gnc-plugin-page-report.c   |  68 +-
 test-templates/Makefile.decl                       |   2 +-
 123 files changed, 4092 insertions(+), 1795 deletions(-)
 copy src/{engine/test/test-engine.c => app-utils/test/test-app-utils.c} (66%)
 create mode 100644 src/app-utils/test/test-option-util.c
 create mode 100644 src/engine/test/test-engine-kvp-properties.c
 delete mode 100644 src/import-export/import-match-map.h



More information about the gnucash-changes mailing list