[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