[Gnucash-changes] Reference handling improvements

Neil Williams codehelp at cvs.gnucash.org
Mon Mar 21 09:56:34 EST 2005


Log Message:
-----------
Reference handling improvements

Tags:
----
gnucash-gnome2-dev

Modified Files:
--------------
    gnucash:
        ChangeLog
    gnucash/src/backend/qsf:
        qsf-backend.c
        qsf-xml.c
        qsf-xml.h
    gnucash/src/business/business-gnome:
        gnc-plugin-business.c
    gnucash/src/business/business-gnome/ui:
        gnc-plugin-business-ui.xml
    gnucash/src/engine:
        qofclass.c
        qofclass.h
        qofsession.c
        qofsession.h
    gnucash/src/gnome:
        dialog-chart-export.c
    gnucash/src/gnome/glade:
        chart-export.glade

Revision Data
-------------
Index: ChangeLog
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/ChangeLog,v
retrieving revision 1.1487.2.183
retrieving revision 1.1487.2.184
diff -LChangeLog -LChangeLog -u -r1.1487.2.183 -r1.1487.2.184
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,21 @@
+2005-03-21  Neil Williams <linux at codehelp.co.uk>
+	* src/backend/qsf/qsf-backend.c: 
+	* src/backend/qsf/qsf-xml.c:
+	* src/backend/qsf/qsf-xml.h: Reference handling improvements.		
+	* src/business/business-gnome/gnc-plugin-business.c:
+	* src/business/business-gnome/ui/gnc-plugin-business-ui.xml:
+	  Adding export routines for business objects.
+	* src/engine/qofclass.c:
+	* src/engine/qofclass.h:
+	Reference handling: qof_class_get_referenceList
+	* src/engine/qofsession.c:
+	* src/engine/qofsession.h: Reference handling improvements
+	and improved error handling. Also suspending engine events
+	during copy to improve speed.
+	* src/gnome/dialog-chart-export.c:
+	* src/gnome/glade/chart-export.glade: Removing unnecessary
+	file chooser dialog, using a standard box instead.	
+
 2005-03-13  Joshua Sled  <jsled at asynchronous.org>
 
 	* GNOME2_STATUS: Updates; removed some incorrectness, updated for
Index: gnc-plugin-business.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-gnome/Attic/gnc-plugin-business.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -Lsrc/business/business-gnome/gnc-plugin-business.c -Lsrc/business/business-gnome/gnc-plugin-business.c -u -r1.1.2.4 -r1.1.2.5
--- src/business/business-gnome/gnc-plugin-business.c
+++ src/business/business-gnome/gnc-plugin-business.c
@@ -95,6 +95,20 @@
 static void gnc_plugin_business_cmd_bills_due_reminder (EggAction *action,
 							GncMainWindowActionData *data);
 
+static void gnc_plugin_business_cmd_export_invoice  (EggAction *action,
+						     GncMainWindowActionData *data);
+
+static void gnc_plugin_business_cmd_export_customer (EggAction *action,
+						     GncMainWindowActionData *data);
+
+static void gnc_plugin_business_cmd_export_vendor   (EggAction *action,
+						     GncMainWindowActionData *data);
+
+static void gnc_plugin_business_cmd_export_employee (EggAction *action,
+						     GncMainWindowActionData *data);
+
+/*static void gnc_plugin_business_cmd_export_report   (EggAction *action,
+						      GncMainWindowActionData *data);*/
 
 #define PLUGIN_ACTIONS_NAME "gnc-plugin-business-actions"
 #define PLUGIN_UI_FILENAME  "gnc-plugin-business-ui.xml"
@@ -180,6 +194,19 @@
 	{ "BillsDueReminderOpenAction", N_("Bills Due Reminder"), NULL, NULL,
 	  N_("Open the Bills Due Reminder dialog"),
 	  G_CALLBACK (gnc_plugin_business_cmd_bills_due_reminder) },
+	{ "ExportMenuAction", N_("E_xport"), NULL, NULL, NULL, NULL },
+	{ "QSFInvoiceAction", N_("QSF _Invoice"), NULL, NULL,
+	  N_("Export one or more invoices to QSF"),
+	  G_CALLBACK (gnc_plugin_business_cmd_export_invoice) },
+	{ "QSFCustomerAction", N_("QSF _Customer"), NULL, NULL,
+	  N_("Export one or more customers to QSF"),
+	  G_CALLBACK (gnc_plugin_business_cmd_export_customer) },
+	{ "QSFVendorAction", N_("QSF _Vendor"), NULL, NULL,
+	  N_("Export one or more vendors to QSF"),
+	  G_CALLBACK (gnc_plugin_business_cmd_export_vendor) },
+	{ "QSFEmployeeAction", N_("QSF _Employee"), NULL, NULL,
+	  N_("Export one or more employees to QSF"),
+	  G_CALLBACK (gnc_plugin_business_cmd_export_employee) },
 };
 static guint gnc_plugin_n_actions = G_N_ELEMENTS (gnc_plugin_actions);
 
@@ -578,3 +605,147 @@
 	gnc_remind_bills_due gnc_ui_payment_new (priv->last_employee, gnc_get_current_book());
 #endif
 }
+
+/**************************************************************
+ * QSF export routines
+ **************************************************************/
+
+static void
+gnc_plugin_business_cmd_export_invoice (EggAction *action, GncMainWindowActionData *mw)
+{
+	QofSession *current_session, *chart_session;
+	QofBook *book;
+	QofCollection *coll;
+	gchar *filename;
+	gboolean success;
+	GtkWidget *qsffilechooser;
+
+	current_session = qof_session_get_current_session();
+	book = qof_session_get_book(current_session);
+	chart_session = qof_session_new();
+	success = FALSE;
+	filename = g_strdup("/tmp/qsf-invoices.xml");
+	qsffilechooser = gtk_file_chooser_dialog_new("Export Invoices to XML", 
+		(GtkWindow*)mw->window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, 
+		GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_ACCEPT, NULL);
+	if (gtk_dialog_run (GTK_DIALOG (qsffilechooser)) == GTK_RESPONSE_ACCEPT)
+	{
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (qsffilechooser));
+		qof_session_begin(chart_session, filename, TRUE, TRUE);
+		coll = qof_book_get_collection(book, GNC_ID_INVOICE);
+		success = qof_entity_copy_coll(chart_session, coll);
+		if(success) 
+		{ 
+			qof_session_save(chart_session, NULL);
+		}
+	}
+	g_free(filename);
+	qof_session_end(chart_session);
+	gtk_widget_destroy(qsffilechooser);
+	qof_session_set_current_session(current_session);
+}
+
+static void
+gnc_plugin_business_cmd_export_customer (EggAction *action, GncMainWindowActionData *mw)
+{
+	QofSession *current_session, *chart_session;
+	QofBook *book;
+	QofCollection *coll;
+	gchar *filename;
+	gboolean success;
+	GtkWidget *qsffilechooser;
+
+	current_session = qof_session_get_current_session();
+	book = qof_session_get_book(current_session);
+	chart_session = qof_session_new();
+	success = FALSE;
+	filename = g_strdup("/tmp/qsf-customers.xml");
+	qsffilechooser = gtk_file_chooser_dialog_new("Export Customers to XML", 
+		(GtkWindow*)mw->window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, 
+		GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_ACCEPT, NULL);
+	if (gtk_dialog_run (GTK_DIALOG (qsffilechooser)) == GTK_RESPONSE_ACCEPT)
+	{
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (qsffilechooser));
+		qof_session_begin(chart_session, filename, TRUE, TRUE);
+		coll = qof_book_get_collection(book, GNC_ID_CUSTOMER);
+		success = qof_entity_copy_coll(chart_session, coll);
+		if(success) 
+		{ 
+			qof_session_save(chart_session, NULL);
+		}
+	}
+	qof_session_end(chart_session);
+	g_free(filename);
+	gtk_widget_destroy(qsffilechooser);
+	qof_session_set_current_session(current_session);
+}
+
+static void
+gnc_plugin_business_cmd_export_vendor (EggAction *action, GncMainWindowActionData *mw)
+{
+	QofSession *current_session, *chart_session;
+	QofBook *book;
+	QofCollection *coll;
+	gchar *filename;
+	gboolean success;
+	GtkWidget *qsffilechooser;
+
+	current_session = qof_session_get_current_session();
+	book = qof_session_get_book(current_session);
+	chart_session = qof_session_new();
+	success = FALSE;
+	filename = g_strdup("/tmp/qsf-vendors.xml");
+	qsffilechooser = gtk_file_chooser_dialog_new("Export Vendors to XML", 
+		(GtkWindow*)mw->window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, 
+		GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_ACCEPT, NULL);
+	if (gtk_dialog_run (GTK_DIALOG (qsffilechooser)) == GTK_RESPONSE_ACCEPT)
+	{
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (qsffilechooser));
+		qof_session_begin(chart_session, filename, TRUE, TRUE);
+		coll = qof_book_get_collection(book, GNC_ID_VENDOR);
+		success = qof_entity_copy_coll(chart_session, coll);
+		if(success) 
+		{ 
+			qof_session_save(chart_session, NULL);
+		}
+	}
+	qof_session_end(chart_session);
+	g_free(filename);
+	qof_session_set_current_session(current_session);
+	gtk_widget_destroy(qsffilechooser);
+}
+
+static void
+gnc_plugin_business_cmd_export_employee (EggAction *action, GncMainWindowActionData *mw)
+{
+	QofSession *current_session, *chart_session;
+	QofBook *book;
+	QofCollection *coll;
+	gchar *filename;
+	gboolean success;
+	GtkWidget *qsffilechooser;
+
+	current_session = qof_session_get_current_session();
+	book = qof_session_get_book(current_session);
+	chart_session = qof_session_new();
+	success = FALSE;
+	filename = g_strdup("/tmp/qsf-employee.xml");
+	qsffilechooser = gtk_file_chooser_dialog_new("Export Employees to XML", 
+		(GtkWindow*)mw->window, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, 
+		GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_ACCEPT, NULL);
+	if (gtk_dialog_run (GTK_DIALOG (qsffilechooser)) == GTK_RESPONSE_ACCEPT)
+	{
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (qsffilechooser));
+		qof_session_begin(chart_session, filename, TRUE, TRUE);
+		coll = qof_book_get_collection(book, GNC_ID_INVOICE);
+		success = qof_entity_copy_coll(chart_session, coll);
+		if(success) 
+		{ 
+			qof_session_save(chart_session, NULL);
+		}
+	}
+	qof_session_end(chart_session);
+	g_free(filename);
+	gtk_widget_destroy(qsffilechooser);
+	qof_session_set_current_session(current_session);
+}
Index: gnc-plugin-business-ui.xml
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/business/business-gnome/ui/Attic/gnc-plugin-business-ui.xml,v
retrieving revision 1.1.2.2
retrieving revision 1.1.2.3
diff -Lsrc/business/business-gnome/ui/gnc-plugin-business-ui.xml -Lsrc/business/business-gnome/ui/gnc-plugin-business-ui.xml -u -r1.1.2.2 -r1.1.2.3
--- src/business/business-gnome/ui/gnc-plugin-business-ui.xml
+++ src/business/business-gnome/ui/gnc-plugin-business-ui.xml
@@ -33,6 +33,13 @@
 	<menuitem name="TaxTablesOpen" action="TaxTablesOpenAction"/>
 	<menuitem name="BillingTermsOpen" action="BillingTermsOpenAction"/>
 	<menuitem name="BillsDueReminderOpen" action="BillsDueReminderOpenAction"/>
+
+	<menu name="ExportMenu" action="ExportMenuAction">
+	  <menuitem name="QSFInvoice" action="QSFInvoiceAction"/>
+	  <menuitem name="QSFCustomer" action="QSFCustomerAction"/>
+	  <menuitem name="QSFVendor" action="QSFVendorAction"/>
+	  <menuitem name="QSFEmployee" action="QSFEmployeeAction"/>
+	</menu>
       </menu>
     </placeholder>
   </menubar>
Index: qofsession.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.c,v
retrieving revision 1.2.4.12
retrieving revision 1.2.4.13
diff -Lsrc/engine/qofsession.c -Lsrc/engine/qofsession.c -u -r1.2.4.12 -r1.2.4.13
--- src/engine/qofsession.c
+++ src/engine/qofsession.c
@@ -54,11 +54,11 @@
 #include "gnc-engine-util.h"
 #include "gnc-event.h"
 #include "gnc-trace.h"
+#include "qofsession.h"
 #include "qofbackend-p.h"
 #include "qofbook.h"
 #include "qofbook-p.h"
 #include "qofobject.h"
-#include "qofsession.h"
 #include "qofsession-p.h"
 
 /* Some gnucash-specific code */
@@ -318,12 +318,40 @@
 typedef struct qof_entity_copy_data {
 	QofEntity *from;
 	QofEntity *to;
-	GHashTable *referenceTable;	
+	GList  *referenceList;
 	GSList *param_list;
 	QofSession *new_session;
 	gboolean error;
 }QofEntityCopyData;
 
+static gboolean
+qsf_check_error(QofEntityCopyData *qecd)
+{
+	if(qecd->error == TRUE) {
+		qof_entity_release(qecd->to);
+		g_free(qecd->to);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+void
+qof_session_update_reference_list(QofSession *session, QofEntityReference *reference)
+{
+	QofBook  *book;
+	GList    *book_ref_list;
+	gboolean partial;
+
+	book = qof_session_get_book(session);
+	book_ref_list = (GList*)qof_book_get_data(book, ENTITYREFERENCE);
+	book_ref_list = g_list_append(book_ref_list, reference);
+	qof_book_set_data(book, ENTITYREFERENCE, book_ref_list);
+	partial = (gboolean)qof_book_get_data(book, PARTIAL_QOFBOOK);
+	if(!partial) {
+		qof_book_set_data(book, PARTIAL_QOFBOOK, (gboolean*)TRUE);
+	}
+}
+
 static void
 qof_entity_param_cb(QofParam *param, gpointer data)
 {
@@ -338,6 +366,32 @@
 	if(g_slist_length(qecd->param_list) == 0) { qecd->error = TRUE; }
 }
 
+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;
+
+	ref_ent = param->param_getfcn(ent, param);
+	if(ref_ent != NULL) {
+		reference = g_new0(QofEntityReference, 1);
+		reference->type = g_strdup(ent->e_type);
+		reference->ref_guid = g_new(GUID, 1);
+		reference->ent_guid = &ent->guid;
+		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)) {
+			return reference;
+		}
+	}
+	return NULL;
+}
+
 static void
 qof_entity_foreach_copy(gpointer data, gpointer user_data)
 {
@@ -349,9 +403,7 @@
 	QofParam     *cm_param;
 	gchar        *cm_string, *cm_char;
 	const GUID   *cm_guid;
-	GUID         *cm_src_guid;
 	KvpFrame     *cm_kvp;
-	char         cm_sa[GUID_ENCODING_LENGTH + 1];
 	/* 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*);
@@ -373,6 +425,9 @@
 	
 	g_return_if_fail(user_data != NULL);
 	context = (QofEntityCopyData*) user_data;
+	/* in case of any error, let the process know. */
+	if(context->error == TRUE) { return; }
+	context->error = TRUE;
 	importEnt = context->from;
 	targetEnt = context->to;
 	registered_type = FALSE;
@@ -384,6 +439,7 @@
 		string_setter = (void(*)(QofEntity*, const char*))cm_param->param_setfcn;
 		if(string_setter != NULL) { string_setter(targetEnt, cm_string); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_DATE) == 0) { 
 		date_getter = (Timespec (*)(QofEntity*, QofParam*))cm_param->param_getfcn;
@@ -391,6 +447,7 @@
 		date_setter = (void(*)(QofEntity*, Timespec))cm_param->param_setfcn;
 		if(date_setter != NULL) { date_setter(targetEnt, cm_date); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if((safe_strcmp(cm_param->param_type, QOF_TYPE_NUMERIC) == 0)  ||
 	(safe_strcmp(cm_param->param_type, QOF_TYPE_DEBCRED) == 0)) { 
@@ -399,12 +456,14 @@
 		numeric_setter = (void(*)(QofEntity*, gnc_numeric))cm_param->param_setfcn;
 		if(numeric_setter != NULL) { numeric_setter(targetEnt, cm_numeric); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_GUID) == 0) { 
 		cm_guid = cm_param->param_getfcn(importEnt, cm_param);
 		guid_setter = (void(*)(QofEntity*, const GUID*))cm_param->param_setfcn;
 		if(guid_setter != NULL) { guid_setter(targetEnt, cm_guid); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT32) == 0) { 
 		int32_getter = (gint32 (*)(QofEntity*, QofParam*)) cm_param->param_getfcn;
@@ -412,6 +471,7 @@
 		i32_setter = (void(*)(QofEntity*, gint32))cm_param->param_setfcn;
 		if(i32_setter != NULL) { i32_setter(targetEnt, cm_i32); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_INT64) == 0) { 
 		int64_getter = (gint64 (*)(QofEntity*, QofParam*)) cm_param->param_getfcn;
@@ -419,6 +479,7 @@
 		i64_setter = (void(*)(QofEntity*, gint64))cm_param->param_setfcn;
 		if(i64_setter != NULL) { i64_setter(targetEnt, cm_i64); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_DOUBLE) == 0) { 
 		double_getter = (double (*)(QofEntity*, QofParam*)) cm_param->param_getfcn;
@@ -426,6 +487,7 @@
 		double_setter = (void(*)(QofEntity*, double))cm_param->param_setfcn;
 		if(double_setter != NULL) { double_setter(targetEnt, cm_double); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_BOOLEAN) == 0){ 
 		boolean_getter = (gboolean (*)(QofEntity*, QofParam*)) cm_param->param_getfcn;
@@ -433,33 +495,30 @@
 		boolean_setter = (void(*)(QofEntity*, gboolean))cm_param->param_setfcn;
 		if(boolean_setter != NULL) { boolean_setter(targetEnt, cm_boolean); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_KVP) == 0) { 
 		cm_kvp = kvp_frame_copy(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); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(safe_strcmp(cm_param->param_type, QOF_TYPE_CHAR) == 0) { 
 		cm_char = cm_param->param_getfcn(importEnt,cm_param);
 		char_setter = (void(*)(QofEntity*, char*))cm_param->param_setfcn;
 		if(char_setter != NULL) { char_setter(targetEnt, cm_char); }
 		registered_type = TRUE;
+		context->error = FALSE;
 	}
 	if(registered_type == FALSE) {
-		referenceEnt = NULL;
+		PINFO (" cm_param type=%s", cm_param->param_type);
 		referenceEnt = cm_param->param_getfcn(importEnt, cm_param);
-		if(!referenceEnt) { return; }
-		reference = g_new(QofEntityReference, 1);
-		reference->type = g_strdup(referenceEnt->e_type);
-		reference->guid = g_new(GUID, 1);
-		cm_guid = qof_entity_get_guid(referenceEnt);
-		guid_to_string_buff(cm_guid, cm_sa);
-		cm_string = g_strdup(cm_sa);
-		if(TRUE == string_to_guid(cm_string, reference->guid)) {
-			cm_src_guid = &importEnt->guid;
-			g_hash_table_insert(context->referenceTable, cm_src_guid, reference);
+		reference = qof_entity_get_reference_from(importEnt, cm_param);
+		if(reference) {
+			qof_session_update_reference_list(context->new_session, reference);
 		}
+		context->error = FALSE;
 	}
 }
 
@@ -505,7 +564,9 @@
 	qof_entity_set_guid(qecd->to, g);
 	if(qecd->param_list != NULL) { g_slist_free(qecd->param_list); }
 	qof_class_param_foreach(original->e_type, qof_entity_param_cb, qecd);
+	if(qsf_check_error(qecd)) { return; }
 	g_slist_foreach(qecd->param_list, qof_entity_foreach_copy, qecd);
+	qsf_check_error(qecd);
 }
 
 static void
@@ -518,6 +579,7 @@
 	QofEntity *copy;
 	
 	g_return_if_fail(user_data != NULL);
+	copy = NULL;
 	qecd = (QofEntityCopyData*)user_data;
 	targetBook = qof_session_get_book(qecd->new_session);
 	g = qof_entity_get_guid(original);
@@ -542,9 +604,8 @@
 	qecd->from = original;
 	g = qof_entity_get_guid(original);
 	qof_entity_set_guid(qecd->to, g);
-	if(qecd->param_list != NULL) { g_slist_free(qecd->param_list); }
-	qof_class_param_foreach(original->e_type, qof_entity_param_cb, qecd);
 	g_slist_foreach(qecd->param_list, qof_entity_foreach_copy, qecd);
+	qsf_check_error(qecd);
 }
 
 gboolean qof_entity_copy_to_session(QofSession* new_session, QofEntity* original)
@@ -555,21 +616,22 @@
 	const GUID *g;
 
 	if(qof_entity_guid_match(new_session, original)) return FALSE;
+	gnc_engine_suspend_events();
 	qecd.param_list = NULL;
-	qecd.referenceTable = g_hash_table_new(NULL, NULL);
+	book = qof_session_get_book(new_session);
 	qecd.new_session = new_session;
 	qecd.error = FALSE;
-	book = qof_session_get_book(new_session);
 	inst = (QofInstance*)qof_object_new_instance(original->e_type, book);
 	qecd.to = &inst->entity;
 	qecd.from = original;
 	g = qof_entity_get_guid(original);
 	qof_entity_set_guid(qecd.to, g);
 	qof_class_param_foreach(original->e_type, qof_entity_param_cb, &qecd);
+	if(qsf_check_error(&qecd)) { return FALSE; }
 	g_slist_foreach(qecd.param_list, qof_entity_foreach_copy, &qecd);
+	if(qsf_check_error(&qecd)) { return FALSE; }
 	g_slist_free(qecd.param_list);
-	qof_book_set_data(book, ENTITYREFERENCE, qecd.referenceTable);
-	qof_book_set_data(book, PARTIAL_QOFBOOK, (gboolean*)TRUE);
+	gnc_engine_resume_events();
 	return TRUE;
 }
 
@@ -578,43 +640,38 @@
 	GList *e;
 	QofEntity *original;
 	QofEntityCopyData qecd;
-	QofBook *book;
 
+	gnc_engine_suspend_events();
 	qecd.param_list = NULL;
 	qecd.new_session = new_session;
-	qecd.referenceTable = g_hash_table_new(NULL, NULL);
 	qecd.error = FALSE;
 	for(e=entity_list; e; e=e->next)
 	{
 		original = (QofEntity*) e->data;
-		/* The GList can contain mixed entity types, it may 
-		appear slow, but we do need to check the type every time
-		because we can't re-use the QofCollection or QofIdType.	*/
+		/* The GList can contain mixed entity types, it may */
+		/* appear slow, but we do need to check the type every time */
+		/* because we can't re-use the QofCollection or QofIdType. */
 		if(qof_entity_guid_match(new_session, original)) return FALSE;
 	}
 	g_list_foreach(entity_list, qof_entity_list_foreach, &qecd);
-	book = qof_session_get_book(qecd.new_session);
-	qof_book_set_data(book, ENTITYREFERENCE, qecd.referenceTable);
-	qof_book_set_data(book, PARTIAL_QOFBOOK, (gboolean*)TRUE);
+	gnc_engine_resume_events();
 	return TRUE;
 }
 
 gboolean qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_coll)
 {
 	QofEntityCopyData qecd;
-	QofBook *book;
 
+	gnc_engine_suspend_events();
 	qecd.param_list = NULL;
 	qecd.new_session = new_session;
-	qecd.referenceTable = g_hash_table_new(NULL, NULL);
 	qecd.error = FALSE;
 	qof_collection_foreach(entity_coll, qof_entity_coll_foreach, &qecd);
 	if(qecd.error == TRUE) return FALSE;
+	qof_class_param_foreach(qof_collection_get_type(entity_coll), qof_entity_param_cb, &qecd);
 	qof_collection_foreach(entity_coll, qof_entity_coll_copy, &qecd);
-	book = qof_session_get_book(qecd.new_session);
-	qof_book_set_data(book, ENTITYREFERENCE, qecd.referenceTable);
-	qof_book_set_data(book, PARTIAL_QOFBOOK, (gboolean*)TRUE);
 	if(qecd.param_list != NULL) { g_slist_free(qecd.param_list); }
+	gnc_engine_resume_events();
 	return TRUE;
 }
 
@@ -742,6 +799,7 @@
 	GList *node;
 	QofBackendProvider *prov;
 	QofBook *book;
+	char *msg;
 	
 	ENTER (" ");
 	/* If the provider list is null, try to register the 'well-known'
@@ -775,7 +833,7 @@
 		}
 		p = p->next;
 	}
-	msg = g_strdup_printf("failed to load '%s' backend", backend_name);
+	msg = g_strdup_printf("failed to load '%s' using access_method", access_method);
 	qof_session_push_error (session, ERR_BACKEND_NO_HANDLER, msg);
 	LEAVE (" ");
 }
Index: qofclass.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.h,v
retrieving revision 1.1.6.3
retrieving revision 1.1.6.4
diff -Lsrc/engine/qofclass.h -Lsrc/engine/qofclass.h -u -r1.1.6.3 -r1.1.6.4
--- src/engine/qofclass.h
+++ src/engine/qofclass.h
@@ -212,6 +212,13 @@
 void qof_class_param_foreach (QofIdTypeConst obj_name,
                               QofParamForeachCB, gpointer user_data);
 
+/** \brief List of the parameters that could be references.
+
+Simple check to return a GList of all parameters
+of this object type that are not known QOF data types.
+Used for partial QofBook support, see ::QofEntityReference
+*/
+GList* qof_class_get_referenceList(QofIdTypeConst type);
 
 #endif /* QOF_CLASS_H */
 /* @} */
Index: qofclass.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofclass.c,v
retrieving revision 1.1.6.2
retrieving revision 1.1.6.3
diff -Lsrc/engine/qofclass.c -Lsrc/engine/qofclass.c -u -r1.1.6.2 -r1.1.6.3
--- src/engine/qofclass.c
+++ src/engine/qofclass.c
@@ -250,4 +250,33 @@
   g_hash_table_foreach (param_ht, param_foreach_cb, &iter);
 }
 
+static void
+find_reference_param(QofParam *param, gpointer user_data)
+{
+	GList *ref_list;
+
+	ref_list = (GList*)user_data;
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_STRING))   { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_NUMERIC))  { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_DATE))     { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_CHAR))     { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_DEBCRED))  { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_GUID))     { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT32))    { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_INT64))    { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_DOUBLE))   { return; }
+	if(0 == safe_strcmp(param->param_type, QOF_TYPE_KVP))      { return; }
+	ref_list = g_list_append(ref_list, param);
+}
+
+GList*
+qof_class_get_referenceList(QofIdTypeConst type)
+{
+	GList *ref_list;
+
+	ref_list = NULL;
+	qof_class_param_foreach(type, find_reference_param, ref_list);
+	return ref_list;
+}
+
 /* ============================= END OF FILE ======================== */
Index: qofsession.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/engine/qofsession.h,v
retrieving revision 1.2.4.5
retrieving revision 1.2.4.6
diff -Lsrc/engine/qofsession.h -Lsrc/engine/qofsession.h -u -r1.2.4.5 -r1.2.4.6
--- src/engine/qofsession.h
+++ src/engine/qofsession.h
@@ -90,6 +90,8 @@
 
 #include "qofbackend.h"
 #include "qofbook.h"
+#include "qofclass.h"
+#include "qofobject.h"
 
 /* PROTOTYPES ******************************************************/
 
@@ -348,23 +350,64 @@
 
 /** \brief External references in a partial QofBook.
 
-This data is built into a hash table for use by any session that
-deals with partial QofBooks. It is used by the entity copy
-functions and by the QSF backend. The hashtable key is
-the GUID of the known entity and the value is a 
-QofEntityReference to the referenced entity. 
+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 type;
-	GUID      *guid;
+	QofIdType        type;       /**< The type of entity */
+	GUID             *ref_guid;  /**< The GUID of the REFERENCE entity */
+	const QofParam  *param;      /**< The parameter used to get/set this reference. */
+	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.
+ * of the original QofBook as well as the parameter data and the
+ * GUID of the original entity.
  * */
 #define ENTITYREFERENCE "QofEntityReference"
 
Index: dialog-chart-export.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/Attic/dialog-chart-export.c,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -Lsrc/gnome/dialog-chart-export.c -Lsrc/gnome/dialog-chart-export.c -u -r1.1.2.1 -r1.1.2.2
--- src/gnome/dialog-chart-export.c
+++ src/gnome/dialog-chart-export.c
@@ -32,22 +32,20 @@
 #include "dialog-utils.h"
 #include "gnc-engine-util.h"
 #include "global-options.h"
-#include "gnc-trace.h"
-static short int module = MOD_GUI;
+#include "gnc-event.h"
 
 #define EQUITY_ACCOUNT_NAME  _("Opening Balances")
 #define OPENING_BALANCE_DESC _("Opening Balance")
 
 static GtkWidget *chart_export;
-static GtkWidget *chart_filechooserdialog;
 void on_dateok_clicked (GtkButton *button, gpointer user_data);
-void on_exportok_clicked (GtkButton *button, gpointer user_data);
 
 typedef struct chart_data_s
 {
 	time_t chart_time_t;
 	QofSession *chart_session;
 	Account *equity_account;
+	GList      *param_ref_list;
 }chart_data;
 
 static void
@@ -77,6 +75,23 @@
 }
 
 static void
+chart_reference_cb(QofEntity *ent, gpointer user_data)
+{
+	QofEntityReference *reference;
+	QofParam     *ref_param;
+	chart_data   *data;
+
+	g_return_if_fail(user_data != NULL);
+	data = (chart_data*)user_data;
+	while(data->param_ref_list != NULL) {
+		ref_param = data->param_ref_list->data;
+		reference = qof_entity_get_reference_from(ent, ref_param);
+		qof_session_update_reference_list(data->chart_session, reference);
+		data->param_ref_list = data->param_ref_list->next;
+	}
+}
+
+static void
 chart_entity_cb(QofEntity *ent, gpointer user_data)
 {
 	chart_data *data;
@@ -87,21 +102,18 @@
 	QofBook *book;
 	QofCollection *coll;
 	const GUID *guid;
-	gboolean success;
+	time_t trans_time;
 	
-	success = FALSE;
 	g_return_if_fail(user_data != NULL);
 	data = (chart_data*)user_data;
+	trans_time = data->chart_time_t;
+	data->param_ref_list = NULL;
 	guid = qof_entity_get_guid(ent);
 	acc_ent = (Account*)ent;
 	equity_account = data->equity_account;
 	g_return_if_fail(equity_account != NULL);
-	ENTER (" Acc=%p\tEquity=%p ", acc_ent, equity_account);
 	balance = xaccAccountGetBalanceAsOfDate(acc_ent, data->chart_time_t);
-	success = qof_entity_copy_to_session(data->chart_session, ent);
-	if(!success) {
-		PWARN("%s - %s",  "ERR_BACKEND_MISC" , "entity already exists");
-	}
+	qof_entity_copy_to_session(data->chart_session, ent);
 	book = qof_session_get_book(data->chart_session);
 	coll = qof_book_get_collection(book, GNC_ID_ACCOUNT);
 	acc_ent = (Account*)qof_collection_lookup_entity(coll, guid);
@@ -116,7 +128,8 @@
 	trans = xaccMallocTransaction (book);
 	xaccTransBeginEdit (trans);
 	xaccTransSetCurrency (trans, xaccAccountGetCommodity (acc_ent));
-	xaccTransSetDateSecs (trans, data->chart_time_t);
+	xaccTransSetDateSecs (trans, trans_time);
+	xaccTransSetDateEnteredSecs (trans, trans_time);
 	xaccTransSetDescription (trans, OPENING_BALANCE_DESC);
 	split = xaccMallocSplit (book);
 	xaccTransAppendSplit (trans, split);
@@ -135,29 +148,16 @@
 }
 
 static GtkWidget *
-create_chartfilechooserdialog ( void )
-{
-	GtkWidget *dialog;
-	GladeXML *xml;
-	
-	xml = gnc_glade_xml_new ("chart-export.glade", "chartfilechooserdialog");
-	glade_xml_signal_connect(xml, "on_exportok_clicked",
-		GTK_SIGNAL_FUNC (on_exportok_clicked));
-	dialog = glade_xml_get_widget (xml, "chartfilechooserdialog");
-	return dialog;
-}
-
-
-static GtkWidget *
 create_chart_export ( void )
 {
   GtkWidget *dialog;
   GladeXML *xml;
+	chart_data *data;
 
 	xml = gnc_glade_xml_new ("chart-export.glade", "chart-export");
-
-	glade_xml_signal_connect(xml, "on_dateok_clicked",
-		GTK_SIGNAL_FUNC	(on_dateok_clicked));
+	data = g_new0(chart_data, 1);
+	glade_xml_signal_connect_data(xml, "on_dateok_clicked",
+		GTK_SIGNAL_FUNC (on_dateok_clicked), data);
 	dialog = glade_xml_get_widget (xml, "chart-export");
 	return dialog;	
 }
@@ -173,57 +173,74 @@
 on_dateok_clicked (GtkButton *button, gpointer user_data)
 {
 	guint year, month, day;
-	chart_data data;
+	chart_data  *data;
 	GtkCalendar *calendar;
 	struct tm *chart_tm;
+	GtkWidget   *qsffilechooser;
+	GtkWindow   *parent;
+	gchar *filename;
+	QofSession *current_session, *chart_session;
+	QofBook *book;
+	QofCollection *coll;
 
 	calendar = (GtkCalendar*)gnc_glade_lookup_widget(chart_export, "chart-calendar");
-	data.chart_time_t = time(NULL);
-	chart_tm = gmtime(&data.chart_time_t);
+	parent = (GtkWindow*)gtk_widget_get_parent ((GtkWidget*)chart_export);
+	data = (chart_data*)user_data;
+	data->chart_time_t = time(NULL);
+	chart_tm = gmtime(&data->chart_time_t);
 	/* set today - calendar will omit any zero/NULL values */
 	year = chart_tm->tm_year + 1900;
 	month = chart_tm->tm_mon + 1;
-	day = chart_tm->tm_yday + 1;
+	day = chart_tm->tm_mday;
 	gtk_calendar_get_date(calendar, &year, &month, &day);
+	if((year + 1900) != chart_tm->tm_year) { 
 	chart_tm->tm_year = year - 1900;
+	}
+	if(month != chart_tm->tm_mon) { 
 	chart_tm->tm_mon = month;
-	chart_tm->tm_yday = day - 1;
-	data.chart_time_t = mktime(chart_tm);
+	}
+	if(day != chart_tm->tm_yday) { 
+		chart_tm->tm_mday = day; 
+	}
+	data->chart_time_t = mktime(chart_tm);
 	gtk_widget_destroy(chart_export);
-	chart_filechooserdialog = create_chartfilechooserdialog ();
-	gtk_widget_show (chart_filechooserdialog);
-}
-
-void
-on_exportok_clicked (GtkButton *button, gpointer user_data)
-{
-	QofSession *current_session, *chart_session;
-	QofBook *book;
-	QofCollection *coll;
-	const char *filename;
-	chart_data data;
-
 	current_session = qof_session_get_current_session();
 	book = qof_session_get_book(current_session);
+	filename = g_strdup("/tmp/qsf-chartofaccounts.xml");
 	chart_session = qof_session_new();
-	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chart_filechooserdialog));
+	qsffilechooser = gtk_file_chooser_dialog_new("Export Chart of Accounts to QSF XML", 
+		parent, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, 
+		GTK_RESPONSE_CANCEL, GTK_STOCK_CONVERT, GTK_RESPONSE_ACCEPT, NULL);
+	if (gtk_dialog_run (GTK_DIALOG (qsffilechooser)) == GTK_RESPONSE_ACCEPT)
+	{
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (qsffilechooser));
+		gnc_engine_suspend_events();
 	qof_session_begin(chart_session, filename, TRUE, TRUE);
-	data.chart_session = chart_session;
-	data.equity_account = NULL;
-
+		data->chart_session = chart_session;
+		data->equity_account = NULL;
 	coll = qof_book_get_collection(book, GNC_ID_ACCOUNT);
-	qof_collection_foreach(coll, chart_collection_cb, &data);
-	if(data.equity_account == NULL)
+		qof_collection_foreach(coll, chart_collection_cb, data);
+		if(data->equity_account == NULL)
 	{
-		data.equity_account = xaccMallocAccount (qof_session_get_book(chart_session));
-		xaccAccountBeginEdit (data.equity_account);
-		xaccAccountSetName (data.equity_account, EQUITY_ACCOUNT_NAME);
-		xaccAccountSetType (data.equity_account, EQUITY);
-		xaccAccountSetCommodity (data.equity_account, gnc_default_currency());
+			data->equity_account = xaccMallocAccount (qof_session_get_book(chart_session));
+			xaccAccountBeginEdit (data->equity_account);
+			xaccAccountSetName (data->equity_account, EQUITY_ACCOUNT_NAME);
+			xaccAccountSetDescription(data->equity_account, EQUITY_ACCOUNT_NAME);
+			xaccAccountSetType (data->equity_account, EQUITY);
+			xaccAccountSetCommodity (data->equity_account, gnc_default_currency());
 	}
-	qof_object_foreach(GNC_ID_ACCOUNT, book, chart_entity_cb, &data);
+		qof_object_foreach(GNC_ID_ACCOUNT, book, chart_entity_cb, data);
+		data->param_ref_list = qof_class_get_referenceList(GNC_ID_TRANS);
+		qof_object_foreach(GNC_ID_TRANS, book, chart_reference_cb, data);
+		g_list_free(data->param_ref_list);
+		data->param_ref_list = qof_class_get_referenceList(GNC_ID_SPLIT);
+		qof_object_foreach(GNC_ID_SPLIT, book, chart_reference_cb, data);
+		g_list_free(data->param_ref_list);
 	qof_session_save(chart_session, NULL);
+		gnc_engine_resume_events();
+	}
 	qof_session_end(chart_session);
-	gtk_widget_destroy(chart_filechooserdialog);
+	gtk_widget_destroy(qsffilechooser);
+	g_free(data);
 	qof_session_set_current_session(current_session);
 }
Index: qsf-xml.h
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/qsf/Attic/qsf-xml.h,v
retrieving revision 1.1.2.2
retrieving revision 1.1.2.3
diff -Lsrc/backend/qsf/qsf-xml.h -Lsrc/backend/qsf/qsf-xml.h -u -r1.1.2.2 -r1.1.2.3
--- src/backend/qsf/qsf-xml.h
+++ src/backend/qsf/qsf-xml.h
@@ -135,47 +135,6 @@
 #include "qofsession-p.h"
 #include "qofbook-p.h"
 
-/* KVP XML
- *
- * <kvp type="ACCOUNT_KVP", path="/book/accounting-period" value="string">week</kvp>
- * (ACCOUNT_KVP only for clarity here, actual is "kvp"
- *
- * <kvp type="kvp" path="/from-sched-xaction" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp>
- *
- * The relevance of kvp type won't be evident in GnuCash, they all use "kvp".
- *
- * need switch statement on kvp_value_get_type(val) val = kvp_value* val,
- * itself used by g_hash_table_foreach(kvp_frame_get_hash(frame), add_kvp_slot, ret);
- * xmlNodePtr ret;
- *
- * Then retrieve the kvp_frame as the parameter from the entity. Use that frame to
- * copy the key and value - become slots for this entity.
- *
- * kvp:key == path
- * kvp:value == content converted according to the type of value.
- * kvp:type == QofParam->name
- * 
- * Elsewhere:
- * string:type == QofParam->name
- * i.e. <string type="to_do_note"/> == a to_do_note type string
- * 
- *
- * Consider wholesale change from type="" to name="" for object parameters?
- * (but name has special meaning in the KVP documentation).
- * 
- *  
- * <kvp type="kvp" path="/from-sched-xaction" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp>
- * A kvp type KVP parameter located at $path containing a $value.
- *
- * A non-GnuCash example helps:
- * <kvp type="pilot_addr_kvp" path="/user/name" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp>
- * A pilot_addr_kvp type KVP parameter located at /user/name containing a guid value.
- *
- * 
- *
- * */
-
-
 typedef enum  {
 	QSF_UNDEF = 0, /**< Initial undefined value. */
 	IS_QSF_MAP,   /**< A QSF map */
@@ -184,7 +143,7 @@
 	OUR_QSF_OBJ,  /**< A QSF object that can be loaded without a map. */
 }qsf_type;
 	
-/** \internal Holds a description of the QofObject.
+/** \brief Holds a description of the QofObject.
 
 Used when converting QOF objects from another application. The incoming,
 \b unknown, objects need to be stored prior to conversion. This allows 
@@ -214,8 +173,23 @@
 #define QSF_BOOK_COUNT	"count" /**< Sequential counter of each book in this file */
 #define QSF_OBJECT_TAG	"object" /**< Second level child: object tag */
 #define QSF_OBJECT_TYPE	"type" /**< QSF parameter name for object type specifiers */
+
+/** @name Representing KVP as XML
+
+<kvp type="kvp" path="/from-sched-xaction" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp>
+A kvp type KVP parameter located at $path containing a GUID $value.
+
+The relevance of type="kvp" won't be evident in GnuCash, they all use "kvp".
+
+A non-GnuCash example helps:
+<kvp type="pilot_addr_kvp" path="/user/name" value="guid">c858b9a3235723b55bc1179f0e8c1322</kvp>
+A pilot_addr_kvp type KVP parameter located at /user/name containing a guid value.
+@{ */
+
 #define QSF_OBJECT_KVP  "path" /**< The path to this KVP value in the entity frame. */
 #define QSF_OBJECT_VALUE "value" /**< The KVP Value. */
+/** @} */
+
 #define QSF_OBJECT_COUNT	"count" /**< Sequential counter for each QSF object in this file */
 #define QSF_XML_VERSION	"1.0"  /**< The current XML version. */
 #define MAP_ROOT_TAG	"qsf-map" /**< Top level root tag for QSF Maps */
@@ -437,7 +411,7 @@
 	int count; /**< sequential counter for each object in the book */
 	GList *qsf_object_list; /**< list of qsf_objects */
 	GSList *qsf_sequence; /**< Parameter list sorted into QSF order */
-	GHashTable *referenceTable;  /**< Table of references, ::QofEntityReference. */
+	GList *referenceList;        /**< Table of references, ::QofEntityReference. */
 	GHashTable *qsf_parameter_hash; /**< Hashtable of parameters for each object */
 	GHashTable *qsf_calculate_hash, *qsf_default_hash, *qsf_define_hash;
 	GSList *supported_types; /**< The partial list of QOF types currently supported, in QSF order. */
Index: qsf-xml.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/qsf/Attic/qsf-xml.c,v
retrieving revision 1.1.2.3
retrieving revision 1.1.2.4
diff -Lsrc/backend/qsf/qsf-xml.c -Lsrc/backend/qsf/qsf-xml.c -u -r1.1.2.3 -r1.1.2.4
--- src/backend/qsf/qsf-xml.c
+++ src/backend/qsf/qsf-xml.c
@@ -34,8 +34,8 @@
 {
 	g_hash_table_destroy(params->qsf_calculate_hash);
 	g_hash_table_destroy(params->qsf_default_hash);
-	if(params->referenceTable) {
-		g_hash_table_destroy(params->referenceTable);
+	if(params->referenceList) {
+		g_list_free(params->referenceList);
 	}
 	g_slist_free(params->supported_types);
 	xmlFreeDoc(params->output_doc);
Index: qsf-backend.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/backend/qsf/Attic/qsf-backend.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -Lsrc/backend/qsf/qsf-backend.c -Lsrc/backend/qsf/qsf-backend.c -u -r1.1.2.4 -r1.1.2.5
--- src/backend/qsf/qsf-backend.c
+++ src/backend/qsf/qsf-backend.c
@@ -28,6 +28,10 @@
 #include "qsf-dir.h"
 #include <errno.h>
 
+#define QSF_TYPE_BINARY "binary"
+#define QSF_TYPE_GLIST "glist"
+#define QSF_TYPE_FRAME "frame"
+
 static short int module = MOD_BACKEND;
 
 struct QSFBackend_s 
@@ -64,7 +68,7 @@
 	params->qsf_default_hash = g_hash_table_new(g_str_hash, g_str_equal);
 	params->qsf_define_hash = g_hash_table_new(g_str_hash, g_str_equal);
 	params->qsf_calculate_hash = g_hash_table_new(g_str_hash, g_str_equal);
-	params->referenceTable = NULL;
+	params->referenceList = NULL;
 	params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_STRING);
 	params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_GUID);
 	params->supported_types = g_slist_append(params->supported_types, QOF_TYPE_BOOLEAN);
@@ -226,10 +230,7 @@
 	qsf_ns = qsf_root->ns;
 	iter.ns = qsf_ns;
 	book = params->book;
-	params->referenceTable = (GHashTable*)qof_book_get_data(book, ENTITYREFERENCE);
-	if(params->referenceTable == NULL) {
-		params->referenceTable = g_hash_table_new(NULL, NULL);
-	}
+	params->referenceList = (GList*)qof_book_get_data(book, ENTITYREFERENCE);
 	qsf_node_foreach(qsf_root, qsf_book_node_handler, &iter, params);
 	object_list = g_list_copy(params->qsf_object_list);
 	while(object_list != NULL)
@@ -242,7 +243,7 @@
 		g_hash_table_foreach(params->qsf_parameter_hash, qsf_object_commitCB, params);
 		object_list = g_list_next(object_list);
 	}
-	qof_book_set_data(book, ENTITYREFERENCE, params->referenceTable);
+	qof_book_set_data(book, ENTITYREFERENCE, params->referenceList);
 	return TRUE;
 }
 
@@ -250,15 +251,40 @@
 qsf_object_sequence(QofParam *qof_param, gpointer data)
 {
 	qsf_param *params;
+	GSList *checklist, *result;
 
 	g_return_if_fail(data != NULL);
 	params = (qsf_param*) data;
+	result = NULL;
+	checklist = NULL;
+	params->knowntype = FALSE;
+	checklist = g_slist_copy(params->supported_types);
+	for(result = checklist; result != NULL; result = result->next)
+	{
+		if(0 == safe_strcmp((QofIdType)result->data, qof_param->param_type))
+		{
+			params->knowntype = TRUE;
+		}
+	}
+	g_slist_free(checklist);
 	if(0 == safe_strcmp(qof_param->param_type, params->qof_type))
 	{
 		params->qsf_sequence = g_slist_append(params->qsf_sequence, qof_param);
+		params->knowntype = TRUE;
+	}
+	/* handle params->qof_type = QOF_TYPE_GUID and qof_param->param_type != known type */
+	if(0 == safe_strcmp(params->qof_type, QOF_TYPE_GUID)
+		&& (params->knowntype == FALSE))
+	{
+		params->qsf_sequence = g_slist_append(params->qsf_sequence, qof_param);
+		params->knowntype = TRUE;
 	}
 }	
 
+/* receives each entry from supported_types in sequence
+	type = qof data type from supported list
+	user_data = params. Holds object type
+*/
 static void
 qsf_supported_parameters(gpointer type, gpointer user_data)
 {
@@ -279,50 +305,78 @@
 	if(0 == safe_strcmp(QOF_TYPE_INT64, type_string)) { return KVP_TYPE_GINT64; }
 	if(0 == safe_strcmp(QOF_TYPE_DOUBLE, type_string)) { return KVP_TYPE_DOUBLE; }
 	if(0 == safe_strcmp(QOF_TYPE_NUMERIC, type_string)) { return KVP_TYPE_NUMERIC; }
+	if(0 == safe_strcmp(QSF_TYPE_BINARY, type_string))  { return KVP_TYPE_BINARY; }
+	if(0 == safe_strcmp(QSF_TYPE_GLIST, type_string))   { return KVP_TYPE_GLIST; }
+	if(0 == safe_strcmp(QSF_TYPE_FRAME, type_string))   { return KVP_TYPE_FRAME; }
 	return 0;
 }
 
 static void
-qsf_from_kvp_helper(gpointer key, gpointer value, gpointer data)
+qsf_from_kvp_helper(const char *path, KvpValue *content, gpointer data)
 {
 	qsf_param *params;
 	QofParam *qof_param;
 	xmlNodePtr node;
-	KvpValue *content;
-	gchar *path;
 
 	params = (qsf_param*)data;
-	qof_param = (QofParam*)params->qof_param;
-	node = params->output_node;
-	path = (gchar*)key;
-	content = (KvpValue*)value;
-	xmlNodeAddContent(node, kvp_value_to_bare_string(content));
-	xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
-	xmlNewProp(node, QSF_OBJECT_KVP, path);
+	qof_param = params->qof_param;
+	g_return_if_fail(params != NULL);
 	switch(kvp_value_get_type(content))
 	{
 		case KVP_TYPE_STRING:
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
 			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_STRING);
 			break;
 		case KVP_TYPE_GUID:
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
 			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_GUID);
 			break;
 		case KVP_TYPE_BINARY:
-//			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_STRING);
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
+			xmlNewProp(node, QSF_OBJECT_VALUE, QSF_TYPE_BINARY);
 			break;
 		case KVP_TYPE_GLIST:
-//			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_STRING);
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
+			xmlNewProp(node, QSF_OBJECT_VALUE, QSF_TYPE_GLIST);
 			break;
 		case KVP_TYPE_FRAME:
-//			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_STRING);
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
+			xmlNewProp(node, QSF_OBJECT_VALUE, QSF_TYPE_FRAME);
 			break;
 		case KVP_TYPE_GINT64:
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
 			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_INT64);
 			break;
 		case KVP_TYPE_DOUBLE:
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
 			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_DOUBLE);
 			break;
 		case KVP_TYPE_NUMERIC:
+			node = xmlAddChild(params->output_node, xmlNewNode(params->qsf_ns, qof_param->param_type));
+			xmlNodeAddContent(node, kvp_value_to_bare_string(content));
+			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+			xmlNewProp(node, QSF_OBJECT_KVP, path);
 			xmlNewProp(node, QSF_OBJECT_VALUE, QOF_TYPE_NUMERIC);
 			break;
 		default:
@@ -330,24 +384,64 @@
 	}
 }
 
+/******* reference handling ***********/
+
+static gint
+qof_reference_list_cb(gconstpointer a, gconstpointer b)
+{
+	const QofEntityReference *aa;
+	const QofEntityReference *bb;
+
+	aa = (QofEntityReference*)a;
+	bb = (QofEntityReference*) b;
+	g_return_val_if_fail((aa != NULL), 1);
+	g_return_val_if_fail((bb != NULL), 1);
+	g_return_val_if_fail((aa->type != NULL), 1);
+	if((0 == guid_compare(bb->ent_guid, aa->ent_guid))
+		&&(0 == safe_strcmp(bb->type, aa->type)))
+	{
+		return 0;
+	}
+	return 1;
+}
+
+static QofEntityReference*
+qof_reference_lookup(GList *referenceList, QofEntityReference *find)
+{
+	GList *single_ref;
+	QofEntityReference *ent_ref;
+
+	if(referenceList == NULL) { return NULL; }
+	g_return_val_if_fail(find != NULL, NULL);
+	single_ref = NULL;
+	ent_ref = NULL;
+	single_ref = g_list_find_custom(referenceList, find, qof_reference_list_cb);
+	if(single_ref == NULL) { return ent_ref; }
+	ent_ref = (QofEntityReference*)single_ref->data;
+	g_list_free(single_ref);
+	return ent_ref;
+}
+
 /*=====================================
 	Convert QofEntity to QSF XML node
+qof_param holds the parameter sequence.
 =======================================*/
 static void
 qsf_entity_foreach(QofEntity *ent, gpointer data)
 {
-	QofEntityReference *reference;
+	QofEntityReference *reference, *starter;
 	qsf_param  *params;
-	GSList     *param_list;
+	GSList     *param_list, *supported;
 	xmlNodePtr node, object_node;
 	xmlNsPtr   ns;
-	gchar      *string_buffer, qsf_guid[GUID_ENCODING_LENGTH + 1];
+	gchar      *string_buffer, qsf_guid[GUID_ENCODING_LENGTH + 1], *ref_name;
 	GString    *buffer;
 	QofParam   *qof_param;
 	KvpFrame   *qsf_kvp;
-	GHashTable *kvp_hash;
 	int        param_count;
 	gboolean   own_guid;
+	const GUID *cm_guid;
+	char       cm_sa[GUID_ENCODING_LENGTH + 1];
 
 	g_return_if_fail(data != NULL);
 	params = (qsf_param*)data;
@@ -365,46 +459,65 @@
 		g_return_if_fail(qof_param != NULL);
 		if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_GUID))
 		{
-			if(!own_guid) {
-				node = xmlAddChild(object_node, xmlNewNode(ns, qof_param->param_type));
-				string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param, ent));
+			if(!own_guid)
+			{
+				cm_guid = qof_entity_get_guid(ent);
+				node = xmlAddChild(object_node, xmlNewNode(ns, QOF_TYPE_GUID));
+				guid_to_string_buff(cm_guid, cm_sa);
+				string_buffer = g_strdup(cm_sa);
 				xmlNodeAddContent(node, string_buffer);
-				xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
+				xmlNewProp(node, QSF_OBJECT_TYPE , QOF_PARAM_GUID);
 				own_guid = TRUE;
 			}
-			reference = (QofEntityReference*)g_hash_table_lookup(params->referenceTable, 
-				qof_entity_get_guid(ent));
+			PINFO (" own_guid=%d ent->e_type=%s qof_param->param_name=%s",
+				own_guid, ent->e_type, qof_param->param_name);
+/*			if((qof_param->param_setfcn != NULL) && (qof_param->param_getfcn != NULL))
+			{*/
+				starter = g_new(QofEntityReference, 1);
+				starter->ent_guid = qof_entity_get_guid(ent);
+				/* Reading ent->e_type can seg fault if the above check on get() and set() is removed. */
+				/* Some entities seem to be invalid artefacts. Why? */
+				starter->type = g_strdup(ent->e_type);
+				starter->param = qof_param;
+				starter->ref_guid = NULL;
+				reference = qof_reference_lookup(params->referenceList, starter);
+				g_free(starter);
 			if(reference != NULL) {
-				if(0 == safe_strcmp(reference->type, qof_param->param_name))
-				{
-					node = xmlAddChild(object_node, xmlNewNode(ns, qof_param->param_type));
-					guid_to_string_buff(reference->guid, qsf_guid);
+					ref_name = g_strdup(reference->param->param_name);
+					node = xmlAddChild(object_node, xmlNewNode(ns, QOF_TYPE_GUID));
+					guid_to_string_buff(reference->ref_guid, qsf_guid);
+					PINFO ("reference found=%s %s %s", ref_name, qsf_guid, reference->type);
 					xmlNodeAddContent(node, qsf_guid);
-					xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
-				}
+					xmlNewProp(node, QSF_OBJECT_TYPE ,ref_name);
+					g_free(ref_name);
 			}
+				param_list = g_slist_next(param_list);
+				continue;
+/*			}*/
 		}
 		if(0 == safe_strcmp(qof_param->param_type, QOF_TYPE_KVP))
 		{
 			/** Special KVP handling - the book_merge function doesn't render KVP */
 			qsf_kvp = kvp_frame_copy(qof_param->param_getfcn(ent,qof_param));
-			kvp_hash = kvp_frame_get_hash(qsf_kvp);
 			params->qof_param = qof_param;
-			if(kvp_hash)
-			{
-				node = xmlAddChild(object_node, xmlNewNode(ns, qof_param->param_type));
-				params->output_node = node;
-				g_hash_table_foreach(kvp_hash, qsf_from_kvp_helper, params);
-			}
+			params->output_node = object_node;
+			kvp_frame_for_each_slot(qsf_kvp, qsf_from_kvp_helper, params);
 		}
 		if((qof_param->param_setfcn != NULL) && (qof_param->param_getfcn != NULL))
 		{
+			supported = g_slist_copy(params->supported_types);
+			for( supported = g_slist_copy(params->supported_types); 
+				supported != NULL; supported = g_slist_next(supported))
+			{
+				if(0 == safe_strcmp((const char*)supported->data, (const char*)qof_param->param_type))
+				{
 			node = xmlAddChild(object_node, xmlNewNode(ns, qof_param->param_type));
 			string_buffer = g_strdup(qof_book_merge_param_as_string(qof_param, ent));
 			xmlNodeAddContent(node, string_buffer);
 			xmlNewProp(node, QSF_OBJECT_TYPE ,qof_param->param_name);
 		}
-		
+			}
+		}
 		param_list = g_slist_next(param_list);
 	}
 }
@@ -448,10 +561,7 @@
 	params = g_new(qsf_param, 1);
 	qsf_param_init(params);
 	params->book = book;
-	params->referenceTable = (GHashTable*)qof_book_get_data(book, ENTITYREFERENCE);
-	if(params->referenceTable == NULL) {
-		params->referenceTable = g_hash_table_new(NULL, NULL);
-	}
+	params->referenceList = g_list_copy((GList*)qof_book_get_data(book, ENTITYREFERENCE));
 	doc = xmlNewDoc(QSF_XML_VERSION);
 	top_node = xmlNewNode(NULL, QSF_ROOT_TAG);
 	xmlDocSetRootElement(doc, top_node);
@@ -465,7 +575,6 @@
 	xmlNewChild(params->book_node, params->qsf_ns, QSF_BOOK_GUID, buffer);
 	params->output_doc = doc;
 	params->book_node = node;
-//	params->output_node = node;
 	qof_object_foreach_type(qsf_foreach_obj_type, params);
 	return params->output_doc;
 }
@@ -634,8 +743,6 @@
 	time_t             qsf_time_t;
 	char               *tail;
 	/* cm_ prefix used for variables that hold the data to commit */
-	char           cm_sa[GUID_ENCODING_LENGTH + 1];
-	gchar          *cm_string;
 	gnc_numeric    cm_numeric;
 	double         cm_double;
 	gboolean       cm_boolean;
@@ -644,7 +751,6 @@
 	Timespec       cm_date;
 	char           cm_char,    (*char_getter)  (xmlNodePtr);
 	GUID           *cm_guid;
-	const GUID     *cm_const_guid;
 	KvpFrame       *cm_kvp;
 	KvpValue       *cm_value;
 	KvpValueType   cm_type;
@@ -700,20 +806,14 @@
 			return;
 		}
 		reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
-		if(0 == safe_strcmp(qsf_ent->e_type, reference_type)) 
+		if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type)) 
 		{
 			qof_entity_set_guid(qsf_ent, cm_guid);
 		}
 		else {
-			reference = g_new(QofEntityReference, 1);
-			reference->type = g_strdup(qsf_ent->e_type);
-			reference->guid = g_new(GUID, 1);
-			cm_const_guid = qof_entity_get_guid(qsf_ent);
-			guid_to_string_buff(cm_const_guid, cm_sa);
-			cm_string = g_strdup(cm_sa);
-			if(TRUE == string_to_guid(cm_string, reference->guid)) {
-				cm_guid = &qsf_ent->guid;
-				g_hash_table_insert(params->referenceTable, cm_guid, reference);
+			reference = qof_entity_get_reference_from(qsf_ent, cm_param);
+			if(reference) {
+				params->referenceList = g_list_append(params->referenceList, reference);
 			}
 		}
 	}
@@ -763,7 +863,6 @@
 	if(safe_strcmp(qof_type, QOF_TYPE_CHAR) == 0) { 
 		char_getter = (char (*)(xmlNodePtr))xmlNodeGetContent;
 		cm_char = char_getter(node);
-		LEAVE (" cm_char=%c", cm_char);
 		char_setter = (void(*)(QofEntity*, char))cm_setter;
 		if(char_setter != NULL) { char_setter(qsf_ent, cm_char); }
 	}
Index: chart-export.glade
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/glade/Attic/chart-export.glade,v
retrieving revision 1.1.2.1
retrieving revision 1.1.2.2
diff -Lsrc/gnome/glade/chart-export.glade -Lsrc/gnome/glade/chart-export.glade -u -r1.1.2.1 -r1.1.2.2
--- src/gnome/glade/chart-export.glade
+++ src/gnome/glade/chart-export.glade
@@ -11,7 +11,6 @@
   <property name="modal">False</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
-  <property name="icon">gnucash-icon.png</property>
   <property name="decorated">True</property>
   <property name="skip_taskbar_hint">False</property>
   <property name="skip_pager_hint">False</property>
@@ -178,7 +177,6 @@
   <property name="modal">False</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
-  <property name="icon">gnucash-icon.png</property>
   <property name="decorated">True</property>
   <property name="skip_taskbar_hint">False</property>
   <property name="skip_pager_hint">False</property>


More information about the gnucash-changes mailing list