[Gnucash-changes] r13306 - gnucash/trunk/lib/libqof - Improved reference handling for recursive copying of entities - relocate disparate functions to a single new file

Neil Williams codehelp at cvs.gnucash.org
Sun Feb 19 17:54:40 EST 2006


Author: codehelp
Date: 2006-02-19 17:54:39 -0500 (Sun, 19 Feb 2006)
New Revision: 13306
Trac: http://svn.gnucash.org/trac/changeset/13306

Added:
   gnucash/trunk/lib/libqof/qof/qofreference.c
   gnucash/trunk/lib/libqof/qof/qofreference.h
Modified:
   gnucash/trunk/lib/libqof/backend/file/qsf-backend.c
   gnucash/trunk/lib/libqof/qof/Makefile.am
   gnucash/trunk/lib/libqof/qof/qof.h
   gnucash/trunk/lib/libqof/qof/qofchoice.h
   gnucash/trunk/lib/libqof/qof/qoflog.h
   gnucash/trunk/lib/libqof/qof/qofsession.c
   gnucash/trunk/lib/libqof/qof/qofsession.h
Log:
Improved reference handling for recursive copying of entities - relocate disparate functions to a single new file

Modified: gnucash/trunk/lib/libqof/backend/file/qsf-backend.c
===================================================================
--- gnucash/trunk/lib/libqof/backend/file/qsf-backend.c	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/backend/file/qsf-backend.c	2006-02-19 22:54:39 UTC (rev 13306)
@@ -625,9 +625,9 @@
 	params = (qsf_param*)user_data;
 	if(!ent || !params) { return; }
 	qof_param = params->qof_param;
+	guid_to_string_buff(qof_entity_get_guid(ent), qsf_guid);
 	node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns,
 		BAD_CAST qof_param->param_type));
-	guid_to_string_buff(qof_entity_get_guid(ent), qsf_guid);
 	xmlNodeAddContent(node, BAD_CAST qsf_guid);
 	xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
 }
@@ -678,6 +678,7 @@
 	QofParam *ref_param;
 	QofEntityReference *reference, *starter;
 	qsf_param  *params;
+	const GUID *guid;
 	xmlNodePtr node, object_node;
 	xmlNsPtr ns;
 	GList *copy_list;
@@ -708,6 +709,18 @@
 		xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_name);
 		g_free(ref_name);
 	}
+	else {
+		ent = (QofEntity*)ref_param->param_getfcn(ent, ref_param);
+		if(!ent) { return; }
+		if((0 == safe_strcmp(ref_param->param_type, QOF_TYPE_COLLECT)) ||
+			(0 == safe_strcmp(ref_param->param_type, QOF_TYPE_CHOICE)))
+		{ return; }
+		node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST QOF_TYPE_GUID));
+		guid = qof_entity_get_guid(ent);
+		guid_to_string_buff(guid, qsf_guid);
+		xmlNodeAddContent(node, BAD_CAST qsf_guid);
+		xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ref_param->param_name);
+	}
 }
 
 /*=====================================
@@ -723,7 +736,6 @@
 	xmlNodePtr node, object_node;
 	xmlNsPtr   ns;
 	gchar      *string_buffer;
-	GString    *buffer;
 	QofParam   *qof_param;
 	QofEntity  *choice_ent;
 	KvpFrame   *qsf_kvp;
@@ -743,9 +755,9 @@
 	object_node = xmlNewChild(params->book_node, params->qsf_ns,
 		BAD_CAST QSF_OBJECT_TAG, NULL);
 	xmlNewProp(object_node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST ent->e_type);
-	buffer = g_string_new(" ");
-	g_string_printf(buffer, "%i", param_count);
-	xmlNewProp(object_node, BAD_CAST QSF_OBJECT_COUNT, BAD_CAST buffer->str);
+	string_buffer = g_strdup_printf("%i", param_count);
+	xmlNewProp(object_node, BAD_CAST QSF_OBJECT_COUNT, BAD_CAST string_buffer);
+	g_free(string_buffer);
 	param_list = g_slist_copy(params->qsf_sequence);
 	while(param_list != NULL) {
 		qof_param = (QofParam*)param_list->data;
@@ -760,6 +772,7 @@
 				string_buffer = g_strdup(cm_sa);
 				xmlNodeAddContent(node, BAD_CAST string_buffer);
 				xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE , BAD_CAST QOF_PARAM_GUID);
+				g_free(string_buffer);
 				own_guid = TRUE;
 			}
 			params->qsf_ent = ent;
@@ -775,7 +788,9 @@
 			if(qsf_coll) { 
 				params->qof_param = qof_param;
 				params->output_node = object_node;
-				qof_collection_foreach(qsf_coll, qsf_from_coll_cb, params);
+				if(qof_collection_count(qsf_coll) > 0) {
+					qof_collection_foreach(qsf_coll, qsf_from_coll_cb, params);
+				}
 			}
 			param_list = g_slist_next(param_list);
 			continue;
@@ -783,8 +798,6 @@
 		if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_CHOICE))
 		{
 			/** \todo use the reference list here. */
-			/* repeats due to use of reference list for GUID and CHOICE */
-			/* fix to allow COLLECT too */
 			choice_ent = (QofEntity*)qof_param->param_getfcn(ent, qof_param);
 			if(!choice_ent) {
 				param_list = g_slist_next(param_list);
@@ -797,6 +810,7 @@
 			xmlNodeAddContent(node, BAD_CAST string_buffer);
 			xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
 			xmlNewProp(node, BAD_CAST "name", BAD_CAST choice_ent->e_type);
+			g_free(string_buffer);
 			param_list = g_slist_next(param_list);
 			continue;
 		}
@@ -818,8 +832,8 @@
 					node = xmlAddChild(object_node, xmlNewNode(ns, BAD_CAST qof_param->param_type));
 					string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param, ent));
 					xmlNodeAddContent(node, BAD_CAST string_buffer);
+					xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
 					g_free(string_buffer);
-					xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE, BAD_CAST qof_param->param_name);
 				}
 			}
 		}

Modified: gnucash/trunk/lib/libqof/qof/Makefile.am
===================================================================
--- gnucash/trunk/lib/libqof/qof/Makefile.am	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/Makefile.am	2006-02-19 22:54:39 UTC (rev 13306)
@@ -27,6 +27,7 @@
    qoflog.c          \
    qofobject.c       \
    qofquerycore.c    \
+   qofreference.c    \
    qofsession.c      \
    qof_book_merge.c
 
@@ -58,6 +59,7 @@
    qoflog.h          \
    qofobject.h       \
    qofquerycore.h    \
+   qofreference.h    \
    qofsession.h      \
    qofsql.h          \
    qof_book_merge.h

Modified: gnucash/trunk/lib/libqof/qof/qof.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qof.h	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qof.h	2006-02-19 22:54:39 UTC (rev 13306)
@@ -50,9 +50,6 @@
     @addtogroup Object Object: Dynamic Object Class Framework
     @ingroup QOF
 */
-/** @addtogroup Choice Choice and collect : One to many links.
-	@ingroup QOF
-*/
 /**
     @addtogroup Query Query: Querying for Objects
     @ingroup QOF
@@ -61,12 +58,18 @@
     @addtogroup Trace Trace: Error Reporting and Debugging
     @ingroup QOF
 */
-/** @addtogroup BookMerge Merging QofBook structures
+/** @addtogroup Event Event: QOF event handlers.
 	@ingroup QOF
 */
-/** @addtogroup Event Event: QOF event handlers.
+/** @addtogroup Choice Choice and collect : One to many links.
 	@ingroup QOF
 */
+/** @addtogroup BookMerge Merging QofBook structures
+	@ingroup QOF
+*/
+/** \addtogroup Reference Referring to entities outside a partial book.
+	\ingroup QOF
+*/
 /**
     @addtogroup Utilities Misc Utilities
     @ingroup QOF
@@ -96,6 +99,7 @@
 #include "qofchoice.h"
 #include "qof_book_merge.h"
 #include "qof-be-utils.h"
+#include "qofreference.h"
 #include "qofla-dir.h"
 #include "deprecated.h"
 

Modified: gnucash/trunk/lib/libqof/qof/qofchoice.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofchoice.h	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qofchoice.h	2006-02-19 22:54:39 UTC (rev 13306)
@@ -87,7 +87,7 @@
 */
 
 /** @file qofchoice.h
-	@brief Linking one entity to a single entity of many possible types.
+	@brief Linking one entity to other entities of many possible types.
 	@author Copyright (c) 2005 Neil Williams <linux at codehelp.co.uk>
 */
 #include "qofclass.h"
@@ -95,6 +95,10 @@
 
 #define QOF_MOD_CHOICE "qof-choice"
 
+/** \note Choice
+@{
+*/
+
 /** \brief Identify an object as containing a choice. */
 #define QOF_TYPE_CHOICE "choice"
 
@@ -147,7 +151,7 @@
 this parameter of this object. Otherwise, FALSE
 */
 gboolean qof_choice_check(char* choice_obj, char *param_name, char* choice);
+/** @} */
 
-
 /** @} */
 #endif /* _QOFCHOICE_H */

Modified: gnucash/trunk/lib/libqof/qof/qoflog.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qoflog.h	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qoflog.h	2006-02-19 22:54:39 UTC (rev 13306)
@@ -27,7 +27,7 @@
 /** @addtogroup Trace
     @{ */
 
-/** @file qof-log.h 
+/** @file qoflog.h 
  *  @brief QOF error logging and tracing facility 
 */
 
@@ -180,63 +180,63 @@
 /** Log a serious error */
 #define PERR(format, args...) do {                   \
   if (qof_log_check (log_module, GNC_LOG_ERROR)) {   \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,       \
-      "Error: %s(): " format, FUNK , ## args);       \
-  }                                                  \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,     \
+      "Error: %s(): " format, FUNK , ## args);     \
+  }                                                \
 } while (0)
 
 /** Log a warning */
 #define PWARN(format, args...) do {                    \
   if (qof_log_check (log_module, GNC_LOG_WARNING)) {   \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,          \
-      "Warning: %s(): " format, FUNK , ## args);       \
-  }                                                    \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,      \
+      "Warning: %s(): " format, FUNK , ## args);   \
+  }                                                \
 } while (0)
 
 /** Print an informational note */
 #define PINFO(format, args...) do {                 \
   if (qof_log_check (log_module, GNC_LOG_INFO)) {   \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,          \
-      "Info: %s(): " format,                        \
-      FUNK , ## args);                              \
-  }                                                 \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,         \
+      "Info: %s(): " format,                       \
+      FUNK , ## args);                             \
+  }                                                \
 } while (0)
 
 /** Print a debugging message */
 #define DEBUG(format, args...) do {                 \
   if (qof_log_check (log_module, GNC_LOG_DEBUG)) {  \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,         \
-      "Debug: %s(): " format,                       \
-      FUNK , ## args);                              \
-  }                                                 \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,        \
+      "Debug: %s(): " format,                      \
+      FUNK , ## args);                             \
+  }                                                \
 } while (0)
 
 /** Print a function entry debugging message */
 #define ENTER(format, args...) do {                 \
   if (qof_log_check (log_module, GNC_LOG_DEBUG)) {  \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,         \
-      "Enter in %s: %s()" format, __FILE__,         \
-      FUNK , ## args);                              \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,        \
+      "Enter in %s: %s()" format, __FILE__,        \
+      FUNK , ## args);                             \
     qof_log_add_indent();                           \
-  }                                                 \
+  }                                                \
 } while (0)
 
 /** Print a function exit debugging message */
 #define LEAVE(format, args...) do {                 \
   if (qof_log_check (log_module, GNC_LOG_DEBUG)) {  \
     qof_log_drop_indent();                          \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,         \
-      "Leave: %s()" format,                         \
-      FUNK , ## args);                              \
-  }                                                 \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,        \
+      "Leave: %s()" format,                        \
+      FUNK , ## args);                             \
+  }                                                \
 } while (0)
 
 /** Print a function trace debugging message */
 #define TRACE(format, args...) do {                 \
   if (qof_log_check (log_module, GNC_LOG_TRACE)) {  \
-    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,         \
-      "Trace: %s(): " format, FUNK , ## args);      \
-  }                                                 \
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,        \
+      "Trace: %s(): " format, FUNK , ## args);     \
+  }                                                \
 } while (0)
 
 #define DEBUGCMD(x) do {                            \
@@ -269,21 +269,21 @@
 #define START_CLOCK(clockno,format, args...) do {        \
   if (qof_log_check (log_module, GNC_LOG_INFO))          \
     qof_start_clock (clockno, log_module, GNC_LOG_INFO,  \
-             __FUNCTION__, format , ## args);            \
+             __FUNCTION__, format , ## args);               \
 } while (0)
 
 /** report elapsed time since last report on a particular timer */
 #define REPORT_CLOCK(clockno,format, args...) do {       \
   if (qof_log_check (log_module, GNC_LOG_INFO))          \
     qof_report_clock (clockno, log_module, GNC_LOG_INFO, \
-             __FUNCTION__, format , ## args);            \
+             __FUNCTION__, format , ## args);               \
 } while (0)
 
 /** report total elapsed time since timer started */
 #define REPORT_CLOCK_TOTAL(clockno,format, args...) do {       \
   if (qof_log_check (log_module, GNC_LOG_INFO))                \
     qof_report_clock_total (clockno, log_module, GNC_LOG_INFO, \
-             __FUNCTION__, format , ## args);                  \
+             __FUNCTION__, format , ## args);               \
 } while (0)
 
 

Added: gnucash/trunk/lib/libqof/qof/qofreference.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofreference.c	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qofreference.c	2006-02-19 22:54:39 UTC (rev 13306)
@@ -0,0 +1,162 @@
+/***************************************************************************
+ *            qofreference.c
+ *
+ *  Mon Feb 13 21:06:44 2006
+ *  Copyright  2006  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+/*
+ *  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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+ 
+#include "qofreference.h"
+
+static void
+entity_set_reference_cb(QofEntity *ent, gpointer user_data)
+{
+	void (*reference_setter) (QofEntity*, QofEntity*);
+	void (*choice_setter) (QofEntity*, QofEntity*);
+	void (*collect_setter)(QofEntity*, QofCollection*);
+	QofEntityReference *ref;
+	GList *book_ref_list;
+	QofCollection *coll;
+	QofIdType type;
+	QofEntity *reference;
+	QofBook *partial_book;
+	
+	partial_book = (QofBook*)user_data;
+	g_return_if_fail(partial_book || ent);
+	reference = NULL;
+	coll = NULL;
+	book_ref_list = qof_book_get_data(partial_book, ENTITYREFERENCE);
+	while(book_ref_list)
+	{
+		ref = (QofEntityReference*)book_ref_list->data;
+		if(0 == guid_compare(ref->ref_guid, qof_entity_get_guid(ent)))
+		{
+			/* avoid setting the entity's own guid as a reference. */
+			book_ref_list = g_list_next(book_ref_list);
+			continue;
+		}
+		if(qof_object_is_choice(ent->e_type)) { type = ref->choice_type; }
+		type = ref->param->param_type;
+		coll = qof_book_get_collection(partial_book, type);
+		reference = qof_collection_lookup_entity(coll, ref->ref_guid);
+		reference_setter = (void(*)(QofEntity*, QofEntity*))ref->param->param_setfcn;
+		if((reference) && (reference_setter))
+		{
+			qof_begin_edit((QofInstance*)ent);
+			qof_begin_edit((QofInstance*)reference);
+			reference_setter(ent, reference);
+			qof_commit_edit((QofInstance*)ent);
+			qof_commit_edit((QofInstance*)reference);
+		}
+		/* collect and choice handling */
+		collect_setter = (void(*)(QofEntity*, QofCollection*))ref->param->param_setfcn;
+		choice_setter = (void(*)(QofEntity*, QofEntity*))ref->param->param_setfcn;
+		if ((0 == safe_strcmp(ref->param->param_type, QOF_TYPE_COLLECT)) &&
+			(0 == guid_compare(qof_entity_get_guid(ent), ref->ent_guid)) &&
+			(0 == safe_strcmp(ref->type, ent->e_type)))
+		{
+			QofCollection *temp_col;
+			char cm_sa[GUID_ENCODING_LENGTH + 1];
+			
+			temp_col = ref->param->param_getfcn(ent, ref->param);
+			coll = qof_book_get_collection(partial_book, 
+				qof_collection_get_type(temp_col));
+			guid_to_string_buff(ref->ref_guid, cm_sa);
+			reference = qof_collection_lookup_entity(coll, ref->ref_guid);
+			if(reference) {
+				qof_collection_add_entity(temp_col, reference);
+				qof_begin_edit((QofInstance*)ent);
+				qof_begin_edit((QofInstance*)reference);
+				if(collect_setter) { collect_setter(ent, temp_col); }
+				qof_commit_edit((QofInstance*)ent);
+				qof_commit_edit((QofInstance*)reference);
+				qof_collection_destroy(temp_col);
+			}
+		}
+		if(0 == safe_strcmp(ref->param->param_type, QOF_TYPE_CHOICE))
+		{
+			coll = qof_book_get_collection(partial_book, ref->type);
+			reference = qof_collection_lookup_entity(coll, ref->ref_guid);
+			qof_begin_edit((QofInstance*)ent);
+			qof_begin_edit((QofInstance*)reference);
+			if(choice_setter) { choice_setter(ent, reference); }
+			qof_commit_edit((QofInstance*)ent);
+			qof_commit_edit((QofInstance*)reference);
+		}
+		book_ref_list = g_list_next(book_ref_list);
+	}
+}
+
+static void
+set_each_type(QofObject *obj, gpointer user_data)
+{
+	QofBook *book;
+
+	book = (QofBook*)user_data;
+	qof_object_foreach(obj->e_type, book, entity_set_reference_cb, book);
+}
+
+static QofEntityReference*
+create_reference(QofEntity *ent, const QofParam *param)
+{
+	QofEntityReference *reference;
+	QofEntity          *ref_ent;
+	const GUID         *cm_guid;
+	char                cm_sa[GUID_ENCODING_LENGTH + 1];
+	gchar              *cm_string;
+
+	ref_ent = (QofEntity*)param->param_getfcn(ent, param);
+	if(!ref_ent) { return NULL; }
+	reference = g_new0(QofEntityReference, 1);
+	reference->type = ent->e_type;
+	reference->ref_guid = g_new(GUID, 1);
+	reference->ent_guid = &ent->guid;
+	if(qof_object_is_choice(ent->e_type)) 
+	{ 
+		reference->choice_type = ref_ent->e_type; 
+	}
+	reference->param = param;
+	cm_guid = qof_entity_get_guid(ref_ent);
+	guid_to_string_buff(cm_guid, cm_sa);
+	cm_string = g_strdup(cm_sa);
+	if(TRUE == string_to_guid(cm_string, reference->ref_guid)) {
+		g_free(cm_string);
+		return reference;
+	}
+	g_free(cm_string);
+	return NULL;
+}
+
+QofEntityReference*
+qof_entity_get_reference_from(QofEntity *ent, const QofParam *param)
+{
+	g_return_val_if_fail(param, NULL);
+	param = qof_class_get_parameter(ent->e_type, param->param_name);
+	g_return_val_if_fail(0 != safe_strcmp(param->param_type, QOF_TYPE_COLLECT), NULL);
+	return create_reference(ent, param);
+}
+
+void qof_book_set_references(QofBook *book)
+{
+	gboolean partial;
+
+	partial =
+	  (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
+	g_return_if_fail(partial);
+	qof_object_foreach_type(set_each_type, book);
+}

Added: gnucash/trunk/lib/libqof/qof/qofreference.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofreference.h	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qofreference.h	2006-02-19 22:54:39 UTC (rev 13306)
@@ -0,0 +1,209 @@
+/***************************************************************************
+ *            qofreference.h
+ *
+ *  Mon Feb 13 21:07:06 2006
+ *  Copyright  2006  Neil Williams
+ *  linux at codehelp.co.uk
+ ****************************************************************************/
+/*
+ *  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, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+ 
+#ifndef _QOFREFERENCE_H
+#define _QOFREFERENCE_H
+
+/** \addtogroup Reference
+
+Partial book is a QofBook that lacks at least one of the key elements of a fully
+structured (complete) book:
+	- Self-contained: All relationships between entities are satisfied within
+		the book itself;
+	- Containing specific entities that provide an external structure to the
+		data within the book.
+
+Partial books are useful for query results, selective export and data mining
+but need to be merged back into standard books. It is not supported to construct
+a partial book and then convert the same book to a standard book.
+
+Different backends have different requirements for a complete book - some
+(like gnucash) are highly customised to that application - however all complete
+QofBooks must be self-contained, only a partial book uses QofEntityReference.
+
+To retain the relationships between entities, including between a partial and 
+a complete book, QofEntityReference data is stored in the QofBook. This data
+should be read by backends that support partial books so that the exported 
+data contains the GUID and QofIdType of the referenced entity. Even if that 
+entity does not then exist within the partial book, it can be located when
+the partial book is merged back into the original, complete, book. (Remember 
+that given the GUID and QofIdType of any QofEntity it is possible to uniquely
+identify that entity in another book.)
+
+Entities in partial books may need to refer to the entities that remain within
+the partial book. Once all the entities you want are in the partial book,
+call qof_book_set_references to restore as many references as possible. Each
+object type is checked in turn, each entity of that type and then each 
+parameter that can relate to another entity. Any references that cannot be
+found are left unset - depending on the object these may be undefined or NULL.
+(It is advisable to set all QOF parameters to either a default value or NULL 
+in the create: routine for the object but QOF has no way of guaranteeing this.)
+
+@{
+*/
+
+/** \file qofreference.h
+	\brief Dealing with relationships between entities in partial books.
+	\author Copyright (c) 2006 Neil Williams <linux at codehelp.co.uk>
+*/
+
+#include "qof.h"
+
+/** @name Using a partial QofBook.
+
+Part of the handling for partial books requires a storage mechanism for
+references to entities that are not within reach of the partial book.
+This requires a GList in the book data to contain the reference 
+QofIdType and GUID so that when the book is written out, the
+reference can be included. See ::qof_book_get_data. 
+
+When the file is imported back in, the list needs to be rebuilt.
+The QSF backend rebuilds the references by linking to real entities.
+Other backends can process the list in similar ways.
+
+The list stores the QofEntityReference to the referenced entity -
+a struct that contains the GUID and the QofIdType of the referenced
+entity as well as the parameter used to obtain the reference.
+
+Partial books need to be differentiated in the backend, the 
+flag in the book data is used by qof_session_save to prevent a partial
+book being saved using a backend that requires a full book. Forcing this
+flag would cause data loss so always merge a partial book with the complete
+book (even if that book is initially empty) before trying to save the data
+using a backend that does not support partial books.
+
+@{ */
+
+
+/** \brief External references in a partial QofBook.
+
+For use by any session that deals with partial QofBooks.
+It is used by the entity copy functions and by the QSF backend.
+Creates a GList stored in the Book hashtable to contain
+repeated references for a single entity.
+*/
+typedef struct qof_entity_reference {
+	QofIdType       choice_type;/**< Used when the reference is a QOF_TYPE_CHOICE type
+	- stores the actual type of the reference from the list of available choices. */
+	QofIdType       type;       /**< The type of the original entity -
+	use the param->param_type to obtain the type of the reference entity.
+	For a QOF_TYPE_COLLECT, obtain the collection and get the type from that. */
+	GUID            *ref_guid;  /**< The GUID of the REFERENCE entity */
+	const QofParam  *param;      /**< The parameter of the original entity to use 
+	to get or set the reference. */
+	const GUID      *ent_guid;   /**< The GUID of the original entity. */
+}QofEntityReference;
+
+/** \brief Adds a new reference to the partial book data hash.
+
+Retrieves any existing reference list and appends the new reference.
+
+If the book is not already marked as partial, it will be marked as
+partial.
+*/
+void
+qof_session_update_reference_list(QofSession *session, QofEntityReference *reference);
+
+/** Used as the key value for the QofBook data hash.
+ *
+ * Retrieved later by QSF (or any other suitable backend) to
+ * rebuild the references from the QofEntityReference struct
+ * that contains the QofIdType and GUID of the referenced entity
+ * of the original QofBook as well as the parameter data and the
+ * GUID of the original entity.
+ * */
+#define ENTITYREFERENCE "QofEntityReference"
+
+/** \brief Flag indicating a partial QofBook.
+
+When set in the book data with a gboolean value of TRUE,
+the flag denotes that only a backend that supports partial
+books can be used to save this session.
+*/
+
+#define PARTIAL_QOFBOOK "PartialQofBook"
+
+/** \brief Read QofEntityReference data for this book and set values.
+
+ at param book The partial book containing the referenceList
+
+The referenceList is a GList of QofEntityReference structures that contain
+the GUID of each end of a reference. e.g. where one entity refers to another.
+
+The referenceList is used in partial books to store relationships between
+entities when the entities themselves might not exist in the partial book.
+
+If the book is not marked as a partial book, an assertion error is generated.
+
+This routine tries to lookup each entity in the referenceList for the
+book and then tries to lookup the reference - to find the child entity that
+was originally linked to this parent. The child entity is then set in the
+parent so that it can be located as normal.
+
+If the child entity does not exist in this partial book, the parent entity
+is not updated. The referenceList is unchanged (in case the child is added
+later).
+
+*/
+void qof_book_set_references(QofBook *book);
+
+/** \brief Get a reference from this entity to another entity.
+
+\note Only to be used in situations where the QofParam has already
+been checked \b NOT to be QOF_TYPE_COLLECT or other known QOF types
+because this function expects to return a single reference and
+a collect parameter would need to return a list of references, other
+parameters would not return a viable QofEntity. (A string cannot be
+cast to an entity.)
+
+Used in the preparation of a partial QofBook when the known entity
+(the one currently being copied into the partial book) refers to
+any other entity, usually as a parent or child.
+The routine calls the param_getfcn of the supplied parameter,
+which must return an object (QofEntity*), not a known QOF data type, to
+retrieve the referenced entity and therefore the GUID. The GUID of
+both entities are stored in the reference which then needs to be added
+to the reference list which is added to the partial book data hash.
+The reference itself is used to preserve the relationship
+between entities within and outside the partial book.
+
+See also ::qof_class_get_referenceList to obtain the list of 
+parameters that provide references to the known entity whilst
+excluding parameters that return known QOF data types.
+
+Note that even if the referenced entity \b exists in the partial
+book (or will exist later), a reference must still be obtained and
+added to the reference list for the book itself. This maintains
+the integrity of the partial book during sequential copy operations.
+
+ at param ent   The known entity.
+ at param param  The parameter to use to get the referenced entity.
+
+ at return FALSE on error, otherwise a pointer to the QofEntityReference.
+*/
+QofEntityReference*
+qof_entity_get_reference_from(QofEntity *ent, const QofParam *param);
+
+/** @} */
+/** @} */
+#endif /* _QOFREFERENCE_H */

Modified: gnucash/trunk/lib/libqof/qof/qofsession.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofsession.c	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qofsession.c	2006-02-19 22:54:39 UTC (rev 13306)
@@ -49,6 +49,7 @@
 
 /** \deprecated should not be static */
 static QofSession * current_session = NULL;
+
 static GHookList * session_closed_hooks = NULL;
 static QofLogModule log_module = QOF_MOD_SESSION;
 static GSList *provider_list = NULL;
@@ -318,7 +319,7 @@
 	gboolean partial;
 
 	partial =
-	  (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
+         (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
 	if(!partial) {
 		qof_book_set_data(book, PARTIAL_QOFBOOK, GINT_TO_POINTER(TRUE));
 	}
@@ -351,39 +352,10 @@
 		return;
 	}
 	if((param->param_getfcn != NULL)&&(param->param_setfcn != NULL)) {
-		qecd->param_list = g_slist_prepend(qecd->param_list, param);
+			qecd->param_list = g_slist_prepend(qecd->param_list, param);
 	}
 }
 
-QofEntityReference*
-qof_entity_get_reference_from(QofEntity *ent, const QofParam *param)
-{
-	QofEntityReference *reference;
-	QofEntity    *ref_ent;
-	const GUID   *cm_guid;
-	char         cm_sa[GUID_ENCODING_LENGTH + 1];
-	gchar        *cm_string;
-
-	g_return_val_if_fail(param, NULL);
-	ref_ent = (QofEntity*)param->param_getfcn(ent, param);
-	if(ref_ent != NULL) {
-		reference = g_new0(QofEntityReference, 1);
-		reference->type = ent->e_type;
-		reference->ref_guid = g_new(GUID, 1);
-		reference->ent_guid = &ent->guid;
-		reference->param = qof_class_get_parameter(ent->e_type, param->param_name);
-		cm_guid = qof_entity_get_guid(ref_ent);
-		guid_to_string_buff(cm_guid, cm_sa);
-		cm_string = g_strdup(cm_sa);
-		if(TRUE == string_to_guid(cm_string, reference->ref_guid)) {
-			g_free(cm_string);
-			return reference;
-		}
-		g_free(cm_string);
-	}
-	return NULL;
-}
-
 static void
 col_ref_cb (QofEntity* ref_ent, gpointer user_data)
 {
@@ -415,33 +387,33 @@
 qof_entity_foreach_copy(gpointer data, gpointer user_data)
 {
 	QofEntity          *importEnt, *targetEnt/*, *referenceEnt*/;
-	QofEntityCopyData  *context;
-	QofEntityReference *reference;
-	gboolean           registered_type;
+	QofEntityCopyData 	*context;
+	QofEntityReference  *reference;
+	gboolean		registered_type;
 	/* cm_ prefix used for variables that hold the data to commit */
-	QofParam     *cm_param;
-	gchar        *cm_string, *cm_char;
-	const GUID   *cm_guid;
-	KvpFrame     *cm_kvp;
+	QofParam 		*cm_param;
+	gchar 			*cm_string, *cm_char;
+	const GUID 		*cm_guid;
+	KvpFrame 		*cm_kvp;
 	QofCollection *cm_col;
 	/* function pointers and variables for parameter getters that don't use pointers normally */
-	gnc_numeric cm_numeric, (*numeric_getter) (QofEntity*, QofParam*);
-	double      cm_double,  (*double_getter)  (QofEntity*, QofParam*);
-	gboolean    cm_boolean, (*boolean_getter) (QofEntity*, QofParam*);
-	gint32      cm_i32,     (*int32_getter)   (QofEntity*, QofParam*);
-	gint64      cm_i64,     (*int64_getter)   (QofEntity*, QofParam*);
-	Timespec    cm_date,    (*date_getter)    (QofEntity*, QofParam*);
+	gnc_numeric 	cm_numeric, (*numeric_getter)	(QofEntity*, QofParam*);
+	double 			cm_double, 	(*double_getter)	(QofEntity*, QofParam*);
+	gboolean 		cm_boolean, (*boolean_getter)	(QofEntity*, QofParam*);
+	gint32 			cm_i32, 	(*int32_getter)		(QofEntity*, QofParam*);
+	gint64 			cm_i64, 	(*int64_getter)		(QofEntity*, QofParam*);
+	Timespec 		cm_date, 	(*date_getter)		(QofEntity*, QofParam*);
 	/* function pointers to the parameter setters */
-	void (*string_setter)    (QofEntity*, const char*);
-	void (*date_setter)      (QofEntity*, Timespec);
-	void (*numeric_setter)   (QofEntity*, gnc_numeric);
-	void (*guid_setter)      (QofEntity*, const GUID*);
-	void (*double_setter)    (QofEntity*, double);
-	void (*boolean_setter)   (QofEntity*, gboolean);
-	void (*i32_setter)       (QofEntity*, gint32);
-	void (*i64_setter)       (QofEntity*, gint64);
-	void (*char_setter)      (QofEntity*, char*);
-	void (*kvp_frame_setter) (QofEntity*, KvpFrame*);
+	void	(*string_setter)	(QofEntity*, const char*);
+	void	(*date_setter)		(QofEntity*, Timespec);
+	void	(*numeric_setter)	(QofEntity*, gnc_numeric);
+	void	(*guid_setter)		(QofEntity*, const GUID*);
+	void	(*double_setter)	(QofEntity*, double);
+	void	(*boolean_setter)	(QofEntity*, gboolean);
+	void	(*i32_setter)		(QofEntity*, gint32);
+	void	(*i64_setter)		(QofEntity*, gint64);
+	void	(*char_setter)		(QofEntity*, char*);
+	void	(*kvp_frame_setter)	(QofEntity*, KvpFrame*);
 	
 	g_return_if_fail(user_data != NULL);
 	context = (QofEntityCopyData*) user_data;
@@ -456,8 +428,8 @@
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_STRING) == 0)  { 
 		cm_string = (gchar*)cm_param->param_getfcn(importEnt, cm_param);
 		if(cm_string) {
-			string_setter = (void(*)(QofEntity*, const char*))cm_param->param_setfcn;
-			if(string_setter != NULL) { string_setter(targetEnt, cm_string); }
+		string_setter = (void(*)(QofEntity*, const char*))cm_param->param_setfcn;
+		if(string_setter != NULL) {	string_setter(targetEnt, cm_string); }
 		}
 		registered_type = TRUE;
 	}
@@ -510,7 +482,7 @@
 		if(boolean_setter != NULL) { boolean_setter(targetEnt, cm_boolean); }
 		registered_type = TRUE;
 	}
-	if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) {
+	if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) { 
 		cm_kvp = (KvpFrame*)cm_param->param_getfcn(importEnt,cm_param);
 		kvp_frame_setter = (void(*)(QofEntity*, KvpFrame*))cm_param->param_setfcn;
 		if(kvp_frame_setter != NULL) { kvp_frame_setter(targetEnt, cm_kvp); }
@@ -534,8 +506,10 @@
 		cm_col = (QofCollection*)cm_param->param_getfcn(importEnt, cm_param);
 		if(cm_col)
 		{
+			/* create one reference for each member of the collection. */
 			qof_collection_foreach(cm_col, col_ref_cb, context);
 		}
+		registered_type = TRUE;
 	}
 	if(registered_type == FALSE) {
 /*		referenceEnt = (QofEntity*)cm_param->param_getfcn(importEnt, cm_param);
@@ -566,7 +540,7 @@
 	coll = qof_book_get_collection(targetBook, type);
 	copy = qof_collection_lookup_entity(coll, g);
 	if(copy) { return TRUE; }
-	return FALSE;
+	return FALSE;	
 }
 
 static void
@@ -773,9 +747,10 @@
 		if(ref_param->param_name == NULL) { continue; }
 		if(0 == safe_strcmp(ref_param->param_type, QOF_TYPE_COLLECT)) {
 			QofCollection *col;
+
 			col = ref_param->param_getfcn(ent, ref_param);
 			if(col) {
-				qof_collection_foreach(col, recurse_collection_cb, store);
+			qof_collection_foreach(col, recurse_collection_cb, store);
 			}
 			continue;
 		}

Modified: gnucash/trunk/lib/libqof/qof/qofsession.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofsession.h	2006-02-19 22:53:08 UTC (rev 13305)
+++ gnucash/trunk/lib/libqof/qof/qofsession.h	2006-02-19 22:54:39 UTC (rev 13306)
@@ -209,7 +209,7 @@
  *    filepath is derived from the url by substituting commas for
  *    slashes).
  *
- *    The qof_session_get_url() routine returns the url that was opened.
+ * The qof_session_get_url() routine returns the url that was opened.
  *    URL's for local files take the form of 
  *    file:/some/where/some/file.gml
  */
@@ -223,7 +223,7 @@
  */
 gboolean qof_session_not_saved(QofSession *session);
 
-/** FIXME: This isn't as thorough as we might want it to be... */
+/** Allows the backend to warn the user if a dataset already exists. */
 gboolean qof_session_save_may_clobber_data (QofSession *session);
 
 /** The qof_session_save() method will commit all changes that have been
@@ -253,7 +253,7 @@
 
 The recommended backend for the new session is QSF or a future
 SQL backend. Using any of these entity copy functions sets a 
-flag in the backend that this is now a partial QofBook.
+flag in the backend that this is now a partial QofBook. See \ref Reference.
 When you save a session containing a partial QofBook,
 the session will check that the backend is able to handle the
 partial book. If not, the backend will be replaced by one that
@@ -384,106 +384,6 @@
 /** @} 
 */
 
-/** @name Using a partial QofBook.
-
-Part of the handling for partial books requires a storage mechanism for
-references to entities that are not within reach of the partial book.
-This requires a GList in the book data to contain the reference 
-QofIdType and GUID so that when the book is written out, the
-reference can be included. See ::qof_book_get_data. 
-
-When the file is imported back in, the list needs to be rebuilt.
-The QSF backend rebuilds the references by linking to real entities.
-Other backends can process the hash table in similar ways.
-
-The list stores the QofEntityReference to the referenced entity -
-a struct that contains the GUID and the QofIdType of the referenced
-entity as well as the parameter used to obtain the reference.
-
-Partial books need to be differentiated in the backend, the 
-flag in the book data is used by qof_session_save to prevent a partial
-book being saved using a backend that requires a full book.
-
- @{ */
-
-
-/** \brief External references in a partial QofBook.
-
-For use by any session that deals with partial QofBooks.
-It is used by the entity copy functions and by the QSF backend.
-Creates a GList stored in the Book hashtable to contain
-repeated references for a single entity.
-*/
-typedef struct qof_entity_reference {
-	QofIdType       choice_type;/**< When the reference is a different type.*/
-	QofIdType       type;       /**< The type of entity */
-	GUID            *ref_guid;  /**< The GUID of the REFERENCE entity */
-	const QofParam  *param;      /**< The parameter name and type. */
-	const GUID      *ent_guid;   /**< The GUID of the original entity. */
-}QofEntityReference;
-
-/** \brief Get a reference from this entity to another entity.
-
-Used in the preparation of a partial QofBook when the known entity
-(the one currently being copied into the partial book) refers to
-any other entity, usually as a parent or child.
-The routine calls the param_getfcn of the supplied parameter,
-which must return an object (QofEntity*), not a known QOF data type, to
-retrieve the referenced entity and therefore the GUID. The GUID of
-both entities are stored in the reference which then needs to be added
-to the reference list which is added to the partial book data hash.
-The reference itself is used by the backend to preserve the relationship
-between entities within and outside the partial book.
-
-See also ::qof_class_get_referenceList to obtain the list of 
-parameters that provide references to the known entity whilst
-excluding parameters that return known QOF data types.
-
-Note that even if the referenced entity \b exists in the partial
-book (or will exist later), a reference must still be obtained and
-added to the reference list for the book itself. This maintains
-the integrity of the partial book during sequential copy operations.
-
- at param ent   The known entity.
- at param param  The parameter to use to get the referenced entity.
-
- at return FALSE on error, otherwise a pointer to the QofEntityReference.
-*/
-QofEntityReference*
-qof_entity_get_reference_from(QofEntity *ent, const QofParam *param);
-
-/** \brief Adds a new reference to the partial book data hash.
-
-Retrieves any existing reference list and appends the new reference.
-
-If the book is not already marked as partial, it will be marked as
-partial.
-*/
-void
-qof_session_update_reference_list(QofSession *session, QofEntityReference *reference);
-
-/** Used as the key value for the QofBook data hash.
- *
- * Retrieved later by QSF (or any other suitable backend) to
- * rebuild the references from the QofEntityReference struct
- * that contains the QofIdType and GUID of the referenced entity
- * of the original QofBook as well as the parameter data and the
- * GUID of the original entity.
- * */
-#define ENTITYREFERENCE "QofEntityReference"
-
-/** \brief Flag indicating a partial QofBook.
-
-When set in the book data with a gboolean value of TRUE,
-the flag denotes that only a backend that supports partial
-books can be used to save this session.
-*/
-
-#define PARTIAL_QOFBOOK "PartialQofBook"
-
-/** @}
-*/
-
 /** \brief Allow session data to be printed to stdout
 
 book_id can't be NULL and we do need to have an access_method,



More information about the gnucash-changes mailing list