mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Remove QSF
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@19099 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
36a9a2e592
commit
70f08de64a
@ -550,11 +550,8 @@ if test x$QOF_XML_DIR = x; then
|
||||
QOF_LIBS='${top_builddir}/src/libqof/qof/libgnc-qof.la'
|
||||
QOF_VERSION="internal"
|
||||
QOF_PREFIX="internal"
|
||||
QOF_XML_DIR='${pkgdatadir}/xml/qsf'
|
||||
LIBQOF_LIBRARY_VERSION=1:4:0
|
||||
LIBQOF_BACKEND_QSF_LIBRARY_VERSION=0:3:0
|
||||
AC_SUBST(LIBQOF_LIBRARY_VERSION)
|
||||
AC_SUBST(LIBQOF_BACKEND_QSF_LIBRARY_VERSION)
|
||||
AC_DEFINE(HAVE_LIBQOF,,[We will use the internal QOF code])
|
||||
HAVE_LIBQOF="use_internal"
|
||||
fi
|
||||
@ -566,7 +563,6 @@ AC_SUBST(QOF_LIBS)
|
||||
AS_SCRUB_INCLUDE(QOF_PREFIX)
|
||||
AC_SUBST(QOF_PREFIX)
|
||||
AC_SUBST(QOF_LIB_DIR)
|
||||
AC_SUBST(QOF_XML_DIR)
|
||||
|
||||
AC_DEFINE(QOF_DISABLE_DEPRECATED,1, [Don't use deprecated qof functions])
|
||||
|
||||
@ -1449,12 +1445,9 @@ AC_CONFIG_FILES(po/Makefile.in
|
||||
src/import-export/hbci/test/Makefile
|
||||
src/libqof/Makefile
|
||||
src/libqof/qof/Makefile
|
||||
src/libqof/backend/Makefile
|
||||
src/libqof/backend/file/Makefile
|
||||
src/optional/Makefile
|
||||
src/optional/python-bindings/Makefile
|
||||
src/optional/python-bindings/tests/Makefile
|
||||
src/optional/xsl/Makefile
|
||||
src/pixmaps/Makefile
|
||||
src/quotes/Makefile
|
||||
src/register/Makefile
|
||||
|
@ -56,7 +56,6 @@ AM_CFLAGS = \
|
||||
-I${top_srcdir}/src/test-core \
|
||||
-I${top_srcdir}/src/engine \
|
||||
-I${top_srcdir}/src/engine/test-core \
|
||||
-I${top_srcdir}/src/backend/qsf \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
-DTEST_MYSQL_URL=\"${TEST_MYSQL_URL}\" \
|
||||
-DTEST_PGSQL_URL=\"${TEST_PGSQL_URL}\" \
|
||||
|
@ -92,9 +92,6 @@ typedef enum
|
||||
GNC_BOOK_XML1_FILE,
|
||||
GNC_BOOK_XML2_FILE,
|
||||
GNC_BOOK_XML2_FILE_NO_ENCODING,
|
||||
QSF_GNC_OBJECT,
|
||||
QSF_OBJECT,
|
||||
QSF_MAP,
|
||||
} QofBookFileType;
|
||||
|
||||
/* ================================================================= */
|
||||
|
@ -237,7 +237,6 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/engine \
|
||||
-I${top_srcdir}/src/engine/test-core \
|
||||
-I${top_srcdir}/src/backend/xml \
|
||||
-I${top_srcdir}/src/backend/qsf \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${LIBXML2_CFLAGS} \
|
||||
${GLIB_CFLAGS} \
|
||||
|
@ -14,7 +14,7 @@ GNC_TEST_DEPS = \
|
||||
--library-dir ${top_builddir}/src/core-utils \
|
||||
--library-dir ${top_builddir}/src/gnc-module \
|
||||
--library-dir ${top_builddir}/src/engine \
|
||||
--library-dir ${top_builddir}/src/backend\sql
|
||||
--library-dir ${top_builddir}/src/backend/sql
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
GNC_ACCOUNT_PATH=${top_srcdir}/accounts/C \
|
||||
|
@ -6,6 +6,7 @@ AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/src/engine \
|
||||
-I${top_srcdir}/src/business/business-core \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
-I${top_srcdir}/src/backend/xml \
|
||||
${GUILE_INCS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
||||
@ -15,6 +16,7 @@ LDADD = \
|
||||
${top_builddir}/src/engine/libgncmod-engine.la \
|
||||
../libgncmod-business-core.la \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${top_builddir}/src/backend/xml/libgncmod-backend-xml.la \
|
||||
${GLIB_LIBS}
|
||||
|
||||
TESTS = \
|
||||
@ -36,7 +38,8 @@ GNC_TEST_DEPS = \
|
||||
--library-dir ${top_builddir}/src/core-utils \
|
||||
--library-dir ${top_builddir}/src/gnc-module \
|
||||
--library-dir ${top_builddir}/src/engine \
|
||||
--library-dir ${top_builddir}/src/business/business-core
|
||||
--library-dir ${top_builddir}/src/business/business-core \
|
||||
--library-dir ${top_builddir}/src/backend/xml
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
$(shell ${top_srcdir}/src/gnc-test-env --no-exports ${GNC_TEST_DEPS})
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include "gncJobP.h"
|
||||
#include "test-stuff.h"
|
||||
|
||||
#include "gnc-backend-xml.h"
|
||||
|
||||
#define FILE_NAME "xml:///tmp/testbook.gnucash"
|
||||
#define GNC_LIB_NAME "gncmod-backend-xml"
|
||||
|
||||
static int count = 0;
|
||||
|
||||
static void
|
||||
@ -60,14 +65,14 @@ test_customer (void)
|
||||
|
||||
session = qof_session_new();
|
||||
be = NULL;
|
||||
qof_session_begin(session, QOF_STDOUT, FALSE, FALSE);
|
||||
qof_session_begin(session, FILE_NAME, FALSE, FALSE);
|
||||
book = qof_session_get_book(session);
|
||||
be = qof_book_get_backend(book);
|
||||
|
||||
/* The book *must* have a backend to pass the test of the 'dirty' flag
|
||||
so use a session to use the default QSF. However, until the SQL backend can be used,
|
||||
so use a session to use the default XML. However, until the SQL backend can be used,
|
||||
entities remain dirty until the session is saved or closed. */
|
||||
do_test (be != NULL, "qsf backend could not be set");
|
||||
do_test (be != NULL, "xml backend could not be set");
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -210,6 +215,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
qof_init();
|
||||
qof_load_backend_library ("../../../backend/xml/.libs/", GNC_LIB_NAME);
|
||||
do_test (cashobjects_register(), "Cannot register cash objects");
|
||||
do_test (gncInvoiceRegister(), "Cannot register GncInvoice");
|
||||
do_test (gncJobRegister (), "Cannot register GncJob");
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include "gncInvoiceP.h"
|
||||
#include "test-stuff.h"
|
||||
|
||||
#include "gnc-backend-xml.h"
|
||||
|
||||
#define FILE_NAME "xml:///tmp/testbook.gnucash"
|
||||
#define GNC_LIB_NAME "gncmod-backend-xml"
|
||||
|
||||
static int count = 0;
|
||||
|
||||
static void
|
||||
@ -66,12 +71,13 @@ test_employee (void)
|
||||
GncEmployee *employee;
|
||||
|
||||
session = qof_session_new();
|
||||
qof_session_begin(session, QOF_STDOUT, FALSE, FALSE);
|
||||
qof_session_begin(session, FILE_NAME, FALSE, FALSE);
|
||||
book = qof_session_get_book(session);
|
||||
be = qof_book_get_backend (book);
|
||||
|
||||
/* The book *must* have a backend to pass the test of the 'dirty' flag */
|
||||
/* See the README file for details */
|
||||
|
||||
be = qof_book_get_backend (book);
|
||||
do_test (be != NULL, "xml backend could not be set");
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -220,6 +226,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
qof_init();
|
||||
qof_load_backend_library ("../../../backend/xml/.libs/", GNC_LIB_NAME);
|
||||
do_test (gncInvoiceRegister(), "Cannot register GncInvoice");
|
||||
do_test (gncJobRegister (), "Cannot register GncJob");
|
||||
do_test (gncCustomerRegister(), "Cannot register GncCustomer");
|
||||
|
@ -33,6 +33,11 @@
|
||||
#include "gncOwner.h"
|
||||
#include "test-stuff.h"
|
||||
|
||||
#include "gnc-backend-xml.h"
|
||||
|
||||
#define FILE_NAME "xml:///tmp/testbook.gnucash"
|
||||
#define GNC_LIB_NAME "gncmod-backend-xml"
|
||||
|
||||
static int count = 0;
|
||||
|
||||
static void
|
||||
@ -69,13 +74,13 @@ test_job (void)
|
||||
|
||||
session = qof_session_new();
|
||||
be = NULL;
|
||||
qof_session_begin(session, QOF_STDOUT, FALSE, FALSE);
|
||||
qof_session_begin(session, FILE_NAME, FALSE, FALSE);
|
||||
book = qof_session_get_book (session);
|
||||
be = qof_book_get_backend(book);
|
||||
|
||||
/* The book *must* have a backend to pass the test of the 'dirty' flag */
|
||||
/* See the README file for details */
|
||||
do_test (be != NULL, "qsf backend could not be set");
|
||||
do_test (be != NULL, "xml backend could not be set");
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -241,6 +246,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
qof_init();
|
||||
qof_load_backend_library ("../../../backend/xml/.libs/", GNC_LIB_NAME);
|
||||
do_test (gncInvoiceRegister(), "Cannot register GncInvoice");
|
||||
do_test (gncJobRegister (), "Cannot register GncJob");
|
||||
do_test (gncCustomerRegister(), "Cannot register GncCustomer");
|
||||
|
@ -32,6 +32,11 @@
|
||||
#include "gncVendorP.h"
|
||||
#include "test-stuff.h"
|
||||
|
||||
#include "gnc-backend-xml.h"
|
||||
|
||||
#define FILE_NAME "xml:///tmp/testbook.gnucash"
|
||||
#define GNC_LIB_NAME "gncmod-backend-xml"
|
||||
|
||||
static int count = 0;
|
||||
|
||||
static void
|
||||
@ -68,13 +73,13 @@ test_vendor (void)
|
||||
|
||||
session = qof_session_new();
|
||||
be = NULL;
|
||||
qof_session_begin(session, QOF_STDOUT, FALSE, FALSE);
|
||||
qof_session_begin(session, FILE_NAME, FALSE, FALSE);
|
||||
book = qof_session_get_book (session);
|
||||
be = qof_book_get_backend(book);
|
||||
|
||||
/* The book *must* have a backend to pass the test of the 'dirty' flag */
|
||||
/* See the README file for details */
|
||||
do_test (be != NULL, "qsf backend could not be set");
|
||||
do_test (be != NULL, "xml backend could not be set");
|
||||
|
||||
/* Test creation/destruction */
|
||||
{
|
||||
@ -222,6 +227,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
qof_init();
|
||||
qof_load_backend_library ("../../../backend/xml/.libs/", GNC_LIB_NAME);
|
||||
do_test (gncInvoiceRegister(), "Cannot register GncInvoice");
|
||||
do_test (gncJobRegister (), "Cannot register GncJob");
|
||||
do_test (gncCustomerRegister(), "Cannot register GncCustomer");
|
||||
|
@ -101,18 +101,6 @@ static void gnc_plugin_business_cmd_billing_terms (GtkAction *action,
|
||||
static void gnc_plugin_business_cmd_bills_due_reminder (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
static void gnc_plugin_business_cmd_export_invoice (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
static void gnc_plugin_business_cmd_export_customer (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
static void gnc_plugin_business_cmd_export_vendor (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
static void gnc_plugin_business_cmd_export_employee (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
static void gnc_plugin_business_cmd_test_search (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
@ -128,8 +116,6 @@ static void gnc_plugin_business_cmd_test_reload_receivable_report (GtkAction *ac
|
||||
static void gnc_plugin_business_cmd_test_init_data (GtkAction *action,
|
||||
GncMainWindowActionData *data);
|
||||
|
||||
/*static void gnc_plugin_business_cmd_export_report (GtkAction *action,
|
||||
GncMainWindowActionData *data);*/
|
||||
|
||||
#define PLUGIN_ACTIONS_NAME "gnc-plugin-business-actions"
|
||||
#define PLUGIN_UI_FILENAME "gnc-plugin-business-ui.xml"
|
||||
@ -268,26 +254,6 @@ static GtkActionEntry gnc_plugin_actions [] =
|
||||
G_CALLBACK (gnc_plugin_business_cmd_bills_due_reminder)
|
||||
},
|
||||
{ "ExportMenuAction", NULL, N_("E_xport"), NULL, NULL, NULL },
|
||||
{
|
||||
"QSFInvoiceAction", NULL, N_("QSF _Invoice..."), NULL,
|
||||
N_("Export one or more invoices to QSF"),
|
||||
G_CALLBACK (gnc_plugin_business_cmd_export_invoice)
|
||||
},
|
||||
{
|
||||
"QSFCustomerAction", NULL, N_("QSF _Customer..."), NULL,
|
||||
N_("Export one or more customers to QSF"),
|
||||
G_CALLBACK (gnc_plugin_business_cmd_export_customer)
|
||||
},
|
||||
{
|
||||
"QSFVendorAction", NULL, N_("QSF _Vendor..."), NULL,
|
||||
N_("Export one or more vendors to QSF"),
|
||||
G_CALLBACK (gnc_plugin_business_cmd_export_vendor)
|
||||
},
|
||||
{
|
||||
"QSFEmployeeAction", NULL, N_("QSF _Employee..."), NULL,
|
||||
N_("Export one or more employees to QSF"),
|
||||
G_CALLBACK (gnc_plugin_business_cmd_export_employee)
|
||||
},
|
||||
|
||||
/* Extensions Menu */
|
||||
{ "BusinessTestAction", NULL, N_("_Business"), NULL, NULL, NULL },
|
||||
@ -768,149 +734,6 @@ gnc_plugin_business_cmd_bills_due_reminder (GtkAction *action,
|
||||
gnc_invoice_remind_bills_due();
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* QSF export routines
|
||||
**************************************************************/
|
||||
|
||||
static void
|
||||
gnc_plugin_business_cmd_export_invoice (GtkAction *action, GncMainWindowActionData *mw)
|
||||
{
|
||||
QofSession *current_session, *chart_session;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
gchar *filename;
|
||||
gboolean success;
|
||||
|
||||
current_session = gnc_get_current_session();
|
||||
book = qof_session_get_book(current_session);
|
||||
chart_session = qof_session_new();
|
||||
success = FALSE;
|
||||
filename = gnc_file_dialog(_("Export Invoices to XML"), NULL,
|
||||
NULL, GNC_FILE_DIALOG_EXPORT);
|
||||
if (filename)
|
||||
{
|
||||
gchar* url = g_strdup_printf( "qsf:%s", filename );
|
||||
qof_session_begin(chart_session, url, TRUE, TRUE);
|
||||
coll = qof_book_get_collection(book, GNC_ID_INVOICE);
|
||||
success = qof_instance_copy_coll_r(chart_session, coll);
|
||||
/* Need to get the GList of GncEntry's - KVP */
|
||||
coll = qof_book_get_collection(book, GNC_ID_CUSTOMER);
|
||||
success = qof_instance_copy_coll_r(chart_session, coll);
|
||||
if (success)
|
||||
{
|
||||
qof_session_save(chart_session, NULL);
|
||||
}
|
||||
g_free(url);
|
||||
}
|
||||
show_session_error(qof_session_get_error(chart_session), filename,
|
||||
GNC_FILE_DIALOG_EXPORT);
|
||||
g_free(filename);
|
||||
qof_session_end(chart_session);
|
||||
gnc_set_current_session(current_session);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_plugin_business_cmd_export_customer (GtkAction *action, GncMainWindowActionData *mw)
|
||||
{
|
||||
QofSession *current_session, *chart_session;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
gchar *filename;
|
||||
gboolean success;
|
||||
|
||||
current_session = gnc_get_current_session();
|
||||
book = qof_session_get_book(current_session);
|
||||
chart_session = qof_session_new();
|
||||
success = FALSE;
|
||||
filename = gnc_file_dialog(_("Export Customers to XML"), NULL,
|
||||
NULL, GNC_FILE_DIALOG_EXPORT);
|
||||
if (filename)
|
||||
{
|
||||
gchar* url = g_strdup_printf( "qsf:%s", filename );
|
||||
qof_session_begin(chart_session, url, TRUE, TRUE);
|
||||
coll = qof_book_get_collection(book, GNC_ID_CUSTOMER);
|
||||
success = qof_instance_copy_coll_r(chart_session, coll);
|
||||
if (success)
|
||||
{
|
||||
qof_session_save(chart_session, NULL);
|
||||
}
|
||||
g_free(url);
|
||||
}
|
||||
show_session_error(qof_session_get_error(chart_session), filename,
|
||||
GNC_FILE_DIALOG_EXPORT);
|
||||
qof_session_end(chart_session);
|
||||
g_free(filename);
|
||||
gnc_set_current_session(current_session);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_plugin_business_cmd_export_vendor (GtkAction *action, GncMainWindowActionData *mw)
|
||||
{
|
||||
QofSession *current_session, *chart_session;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
gchar *filename;
|
||||
gboolean success;
|
||||
|
||||
current_session = gnc_get_current_session();
|
||||
book = qof_session_get_book(current_session);
|
||||
chart_session = qof_session_new();
|
||||
success = FALSE;
|
||||
filename = gnc_file_dialog(_("Export Vendors to XML"), NULL,
|
||||
NULL, GNC_FILE_DIALOG_EXPORT);
|
||||
if (filename)
|
||||
{
|
||||
gchar* url = g_strdup_printf( "qsf:%s", filename );
|
||||
qof_session_begin(chart_session, url, TRUE, TRUE);
|
||||
coll = qof_book_get_collection(book, GNC_ID_VENDOR);
|
||||
success = qof_instance_copy_coll_r(chart_session, coll);
|
||||
if (success)
|
||||
{
|
||||
qof_session_save(chart_session, NULL);
|
||||
}
|
||||
g_free(url);
|
||||
}
|
||||
show_session_error(qof_session_get_error(chart_session), filename,
|
||||
GNC_FILE_DIALOG_EXPORT);
|
||||
qof_session_end(chart_session);
|
||||
g_free(filename);
|
||||
gnc_set_current_session(current_session);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_plugin_business_cmd_export_employee (GtkAction *action, GncMainWindowActionData *mw)
|
||||
{
|
||||
QofSession *current_session, *chart_session;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
gchar *filename;
|
||||
gboolean success;
|
||||
|
||||
current_session = gnc_get_current_session();
|
||||
book = qof_session_get_book(current_session);
|
||||
chart_session = qof_session_new();
|
||||
success = FALSE;
|
||||
filename = gnc_file_dialog(_("Export Employees to XML"), NULL,
|
||||
NULL, GNC_FILE_DIALOG_EXPORT);
|
||||
if (filename)
|
||||
{
|
||||
gchar* url = g_strdup_printf( "qsf:%s", filename );
|
||||
qof_session_begin(chart_session, url, TRUE, TRUE);
|
||||
coll = qof_book_get_collection(book, GNC_ID_EMPLOYEE);
|
||||
success = qof_instance_copy_coll_r(chart_session, coll);
|
||||
if (success)
|
||||
{
|
||||
qof_session_save(chart_session, NULL);
|
||||
}
|
||||
g_free(url);
|
||||
}
|
||||
show_session_error(qof_session_get_error(chart_session), filename,
|
||||
GNC_FILE_DIALOG_EXPORT);
|
||||
qof_session_end(chart_session);
|
||||
g_free(filename);
|
||||
gnc_set_current_session(current_session);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_plugin_business_cmd_test_search (GtkAction *action,
|
||||
GncMainWindowActionData *data)
|
||||
|
@ -47,8 +47,8 @@
|
||||
#define OBJ_RELATIVE "family"
|
||||
#define OBJ_LIST "descendents"
|
||||
|
||||
/* set to TRUE to get QSF XML output
|
||||
* requires QSF available (i.e. make install) */
|
||||
/* set to TRUE to get XML output on stdout
|
||||
* requires a stdout capable backend available (i.e. make install) */
|
||||
static gboolean debug = FALSE;
|
||||
|
||||
/* simple object structure */
|
||||
@ -1168,7 +1168,8 @@ test_recursion (QofSession *original, guint counter)
|
||||
copy = qof_session_new();
|
||||
if (debug)
|
||||
{
|
||||
qof_session_begin(copy, QOF_STDOUT, TRUE, FALSE);
|
||||
/* FIXME XML backend can't handle STDOUT
|
||||
* qof_session_begin(copy, QOF_STDOUT, TRUE, FALSE); */
|
||||
}
|
||||
/* TODO: implement QOF_TYPE_CHOICE testing. */
|
||||
qof_instance_copy_coll_r(copy, grand_coll);
|
||||
@ -1189,8 +1190,9 @@ test_recursion (QofSession *original, guint counter)
|
||||
do_test((f == c.collect), "Number of children in descendents does not match");
|
||||
if (counter == 4 && debug == TRUE)
|
||||
{
|
||||
qof_session_save(copy, NULL);
|
||||
qof_session_save(original, NULL);
|
||||
/* FIXME XML backend can't handle STDOUT
|
||||
* qof_session_save(copy, NULL);
|
||||
qof_session_save(original, NULL); */
|
||||
}
|
||||
qof_session_end(copy);
|
||||
copy = NULL;
|
||||
@ -1211,7 +1213,8 @@ main (int argc, const char *argv[])
|
||||
original = qof_session_new();
|
||||
if (debug)
|
||||
{
|
||||
qof_session_begin(original, QOF_STDOUT, TRUE, FALSE);
|
||||
/* FIXME XML backend can't handle STDOUT
|
||||
* qof_session_begin(original, QOF_STDOUT, TRUE, FALSE); */
|
||||
}
|
||||
create_data(original, (counter % 5));
|
||||
test_recursion(original, (counter % 5));
|
||||
|
@ -332,79 +332,6 @@ show_session_error (QofBackendError io_error,
|
||||
gnc_error_dialog (parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
/* QSF additions */
|
||||
case ERR_QSF_INVALID_OBJ:
|
||||
fmt = _("Invalid QSF Object file! The QSF object file %s failed to"
|
||||
" validate against the QSF object schema. The XML structure of"
|
||||
" the file is either not well-formed or contains illegal data.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_INVALID_MAP:
|
||||
fmt = _("Invalid QSF Map file! The QSF map file %s failed to validate"
|
||||
" against the QSF map schema. The XML structure of the file"
|
||||
" is either not well-formed or contains illegal data.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_BAD_QOF_VERSION:
|
||||
fmt = _("The QSF Map file %s was written for a different version of"
|
||||
" QOF. It may need to be modified to work with your current"
|
||||
" QOF installation.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_BAD_MAP:
|
||||
fmt = _("The selected QSF map %s contains unusable data. "
|
||||
"This is usually because not all the required parameters for "
|
||||
"the defined objects have calculations described in the map.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_BAD_OBJ_GUID:
|
||||
fmt = _("The selected QSF object file %s contains one or more invalid "
|
||||
"GUIDs. The file cannot be processed - please check the source "
|
||||
"of the file and try again.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_NO_MAP:
|
||||
fmt = _("The selected QSF Object file %s requires a map but it was "
|
||||
"not provided.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_WRONG_MAP:
|
||||
fmt = _("Wrong QSF map selected. The selected map %s validates but was "
|
||||
"written for different QOF objects. The list of objects defined "
|
||||
"in this map does not include all the objects described in "
|
||||
"the current QSF object file.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_MAP_NOT_OBJ:
|
||||
fmt = _("The selected file %s is a QSF map and cannot be "
|
||||
"opened as a QSF object.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_OVERFLOW:
|
||||
fmt = _("When converting XML strings into numbers, an overflow "
|
||||
"has been detected. The QSF object file %s contains invalid "
|
||||
"data in a field that is meant to hold a number.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_QSF_OPEN_NOT_MERGE:
|
||||
fmt = _("The QSF object file %s is valid and contains GnuCash "
|
||||
"objects. However, GnuCash cannot open the file directly because "
|
||||
"the data needs to be merged into an existing GnuCash data book. "
|
||||
"Please open a GnuCash file or create a new one, then import "
|
||||
"this QSF object file so that the data can be merged into the "
|
||||
"main data book.");
|
||||
gnc_error_dialog(parent, fmt, newfile);
|
||||
break;
|
||||
|
||||
case ERR_FILEIO_FILE_BAD_READ:
|
||||
fmt = _("There was an error reading the file. "
|
||||
"Do you want to continue?");
|
||||
@ -776,10 +703,6 @@ gnc_post_file_open (const char * filename)
|
||||
gnc_file_new ();
|
||||
}
|
||||
}
|
||||
if (ERR_QSF_OPEN_NOT_MERGE == io_err)
|
||||
{
|
||||
uh_oh = TRUE;
|
||||
}
|
||||
/* if the database doesn't exist, ask the user ... */
|
||||
else if ((ERR_BACKEND_NO_SUCH_DB == io_err) ||
|
||||
(ERR_SQL_DB_TOO_OLD == io_err))
|
||||
|
@ -24,7 +24,6 @@ libgnc_gnome_la_LIBADD = \
|
||||
|
||||
libgnc_gnome_la_SOURCES = \
|
||||
swig-gnome.c \
|
||||
dialog-chart-export.c \
|
||||
dialog-commodities.c \
|
||||
dialog-fincalc.c \
|
||||
dialog-find-transactions.c \
|
||||
@ -39,7 +38,6 @@ libgnc_gnome_la_SOURCES = \
|
||||
dialog-tax-info.c \
|
||||
druid-acct-period.c \
|
||||
druid-hierarchy.c \
|
||||
druid-merge.c \
|
||||
druid-loan.c \
|
||||
druid-stock-split.c \
|
||||
gnc-plugin-account-tree.c \
|
||||
@ -66,7 +64,6 @@ gnomeapp_DATA = $(gnomeapp_in_files:.desktop.in=.desktop)
|
||||
appicondir = $(datadir)/pixmaps
|
||||
|
||||
noinst_HEADERS = \
|
||||
dialog-chart-export.h \
|
||||
dialog-fincalc.h \
|
||||
dialog-find-transactions.h \
|
||||
dialog-new-user.h \
|
||||
@ -77,7 +74,6 @@ noinst_HEADERS = \
|
||||
dialog-sx-since-last-run.h \
|
||||
druid-acct-period.h \
|
||||
druid-hierarchy.h \
|
||||
druid-merge.h \
|
||||
druid-loan.h \
|
||||
druid-stock-split.h \
|
||||
gnc-plugin-account-tree.h \
|
||||
|
@ -1,300 +0,0 @@
|
||||
/***************************************************************************
|
||||
* dialog-chart-export.c
|
||||
*
|
||||
* Sun Feb 27 14:19:12 2005
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@codehelp.co.uk
|
||||
* Copyright (c) 2006 David Hampton <hampton@employees.org>
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* 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 Library 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 "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "qof.h"
|
||||
#include "AccountP.h"
|
||||
#include "Transaction.h"
|
||||
#include "dialog-chart-export.h"
|
||||
#include "gnc-ui-util.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-file.h"
|
||||
#include "gnc-ui.h"
|
||||
#include "gnc-session.h"
|
||||
|
||||
#define EQUITY_ACCOUNT_NAME _("Opening Balances")
|
||||
#define OPENING_BALANCE_DESC _("Opening Balance")
|
||||
|
||||
void chart_export_response_cb (GtkDialog *dialog, gint response, gpointer user_data);
|
||||
|
||||
typedef struct chart_data_s
|
||||
{
|
||||
GladeXML *xml;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *calendar;
|
||||
time_t chart_time_t;
|
||||
QofSession *chart_session;
|
||||
Account *equity_account;
|
||||
GList *param_ref_list;
|
||||
} chart_data;
|
||||
|
||||
static void
|
||||
chart_collection_cb(QofInstance *ent, gpointer user_data)
|
||||
{
|
||||
chart_data *data;
|
||||
Account *acc;
|
||||
gboolean success;
|
||||
const GncGUID *guid;
|
||||
QofCollection *copy_coll;
|
||||
QofBook *book;
|
||||
|
||||
g_return_if_fail(user_data != NULL);
|
||||
data = (chart_data*)user_data;
|
||||
acc = (Account*)ent;
|
||||
if (0 == safe_strcmp(EQUITY_ACCOUNT_NAME, xaccAccountGetName(acc))
|
||||
&& (xaccAccountGetType(acc) == ACCT_TYPE_EQUITY))
|
||||
{
|
||||
success = qof_instance_copy_to_session(data->chart_session, ent);
|
||||
if (!success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
guid = qof_entity_get_guid(ent);
|
||||
book = qof_session_get_book(data->chart_session);
|
||||
copy_coll = qof_book_get_collection(book, GNC_ID_ACCOUNT);
|
||||
data->equity_account = (Account*)qof_collection_lookup_entity(copy_coll, guid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chart_reference_cb(QofInstance *ent, gpointer user_data)
|
||||
{
|
||||
QofInstanceReference *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_instance_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(QofInstance *ent, gpointer user_data)
|
||||
{
|
||||
chart_data *data;
|
||||
Account *acc_ent, *equity_account;
|
||||
Transaction *trans;
|
||||
Split *split;
|
||||
gnc_numeric balance;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
const GncGUID *guid;
|
||||
time_t trans_time;
|
||||
GList *ref;
|
||||
QofInstanceReference *ent_ref;
|
||||
|
||||
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;
|
||||
ref = NULL;
|
||||
equity_account = data->equity_account;
|
||||
g_return_if_fail(equity_account != NULL);
|
||||
balance = xaccAccountGetBalanceAsOfDate(acc_ent, data->chart_time_t);
|
||||
qof_instance_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);
|
||||
if (xaccAccountGetCommodity(acc_ent) == NULL)
|
||||
{
|
||||
xaccAccountSetCommodity(acc_ent, gnc_default_currency());
|
||||
}
|
||||
/* can't use gnc_account_create_opening_balance directly - the partial
|
||||
QofBook doesn't have an AccountGroup that is used to locate the Equity Account. */
|
||||
xaccAccountBeginEdit (acc_ent);
|
||||
xaccAccountBeginEdit (equity_account);
|
||||
trans = xaccMallocTransaction (book);
|
||||
xaccTransBeginEdit (trans);
|
||||
xaccTransSetCurrency (trans, xaccAccountGetCommodity (acc_ent));
|
||||
xaccTransSetDateSecs (trans, trans_time);
|
||||
xaccTransSetDateEnteredSecs (trans, trans_time);
|
||||
xaccTransSetDescription (trans, OPENING_BALANCE_DESC);
|
||||
/* User account split */
|
||||
split = xaccMallocSplit (book);
|
||||
xaccTransAppendSplit (trans, split);
|
||||
xaccAccountInsertSplit (acc_ent, split);
|
||||
xaccSplitSetAmount (split, balance);
|
||||
xaccSplitSetValue (split, balance);
|
||||
ref = qof_class_get_referenceList(GNC_ID_SPLIT);
|
||||
while (ref != NULL)
|
||||
{
|
||||
ent_ref = qof_instance_get_reference_from(QOF_INSTANCE(split), ref->data);
|
||||
qof_session_update_reference_list(data->chart_session, ent_ref);
|
||||
ref = g_list_next(ref);
|
||||
}
|
||||
g_list_free(ref);
|
||||
balance = gnc_numeric_neg (balance);
|
||||
/* Equity account split */
|
||||
split = xaccMallocSplit (book);
|
||||
xaccTransAppendSplit (trans, split);
|
||||
xaccAccountInsertSplit (equity_account, split);
|
||||
xaccSplitSetAmount (split, balance);
|
||||
xaccSplitSetValue (split, balance);
|
||||
xaccTransCommitEdit (trans);
|
||||
xaccAccountCommitEdit (equity_account);
|
||||
xaccAccountCommitEdit (acc_ent);
|
||||
ref = qof_class_get_referenceList(GNC_ID_TRANS);
|
||||
while (ref != NULL)
|
||||
{
|
||||
ent_ref = qof_instance_get_reference_from(QOF_INSTANCE(trans), ref->data);
|
||||
qof_session_update_reference_list(data->chart_session, ent_ref);
|
||||
ref = g_list_next(ref);
|
||||
}
|
||||
g_list_free(ref);
|
||||
ref = qof_class_get_referenceList(GNC_ID_SPLIT);
|
||||
while (ref != NULL)
|
||||
{
|
||||
ent_ref = qof_instance_get_reference_from(QOF_INSTANCE(split), ref->data);
|
||||
qof_session_update_reference_list(data->chart_session, ent_ref);
|
||||
ref = g_list_next(ref);
|
||||
}
|
||||
g_list_free(ref);
|
||||
}
|
||||
|
||||
void
|
||||
gnc_main_window_chart_export(void)
|
||||
{
|
||||
GladeXML *xml;
|
||||
chart_data *data;
|
||||
|
||||
xml = gnc_glade_xml_new ("chart-export.glade", "chart-export");
|
||||
data = g_new0(chart_data, 1);
|
||||
data->xml = xml;
|
||||
data->dialog = glade_xml_get_widget(xml, "chart-export");
|
||||
data->calendar = glade_xml_get_widget(xml, "chart-calendar");
|
||||
glade_xml_signal_autoconnect_full(xml,
|
||||
gnc_glade_autoconnect_full_func,
|
||||
data);
|
||||
gtk_widget_show(data->dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
on_dateok_clicked (chart_data *data)
|
||||
{
|
||||
guint year, month, day;
|
||||
struct tm *chart_tm;
|
||||
gchar *filename;
|
||||
QofSession *current_session, *chart_session;
|
||||
QofBook *book;
|
||||
QofCollection *coll;
|
||||
|
||||
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_mday;
|
||||
gtk_calendar_get_date(GTK_CALENDAR(data->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;
|
||||
}
|
||||
if (day != chart_tm->tm_yday)
|
||||
{
|
||||
chart_tm->tm_mday = day;
|
||||
}
|
||||
data->chart_time_t = mktime(chart_tm);
|
||||
current_session = gnc_get_current_session();
|
||||
book = qof_session_get_book(current_session);
|
||||
chart_session = qof_session_new();
|
||||
filename = gnc_file_dialog(_("Export Chart of Accounts to QSF XML"),
|
||||
NULL, NULL, GNC_FILE_DIALOG_EXPORT);
|
||||
if (filename)
|
||||
{
|
||||
gnc_set_busy_cursor(NULL, TRUE);
|
||||
qof_event_suspend();
|
||||
qof_session_begin(chart_session, filename, TRUE, TRUE);
|
||||
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)
|
||||
{
|
||||
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, ACCT_TYPE_EQUITY);
|
||||
xaccAccountSetCommodity (data->equity_account, gnc_default_currency());
|
||||
}
|
||||
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);
|
||||
show_session_error(qof_session_get_error(chart_session),
|
||||
filename, GNC_FILE_DIALOG_EXPORT);
|
||||
qof_event_resume();
|
||||
gnc_unset_busy_cursor(NULL);
|
||||
}
|
||||
qof_session_end(chart_session);
|
||||
gnc_set_current_session(current_session);
|
||||
}
|
||||
|
||||
void
|
||||
chart_export_response_cb (GtkDialog *dialog, gint response, gpointer user_data)
|
||||
{
|
||||
chart_data *data;
|
||||
data = (chart_data*)user_data;
|
||||
switch (response)
|
||||
{
|
||||
case GTK_RESPONSE_OK:
|
||||
gtk_widget_hide(data->dialog);
|
||||
on_dateok_clicked(data);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_widget_destroy(data->dialog);
|
||||
g_object_unref(data->xml);
|
||||
g_free(data);
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/***************************************************************************
|
||||
* dialog-chart-export.h
|
||||
*
|
||||
* Sun Feb 27 14:19:21 2005
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@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 Library 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 _DIALOG_CHART_EXPORT_H
|
||||
#define _DIALOG_CHART_EXPORT_H
|
||||
|
||||
/** @addtogroup Import_Export
|
||||
@{
|
||||
*/
|
||||
/** @addtogroup ChartExport Export a chart of accounts.
|
||||
|
||||
Remember to use qof_instance_copy routines
|
||||
like ::qof_instance_copy_to_session so that the QofBook is marked
|
||||
as \a partial.
|
||||
|
||||
\par guidelines Guidelines for partial book export
|
||||
-# When exporting GnuCash accounts into QSF, remember that there is no
|
||||
AccountGroup in the partial book, not even a root. Some account functions
|
||||
that you have used in full books will \b not work within a partial book.
|
||||
-# Take special care with the book pointer. It is \b very easy to use a
|
||||
QofBook* pointer to a book in a different QofSession. Certain API functions
|
||||
also make assumptions about the current book - \b check carefully.
|
||||
-# Remember that just because the function does not use books or AccountGroup
|
||||
itself, it does \b not follow that other functions called by the routine
|
||||
are also suitable. You may have to reimplement the body of certain functions.
|
||||
-# Commodities are \b not supported. Most Account functions will use the
|
||||
commodity of the account, so be sure to set at least the ::gnc_default_currency().
|
||||
|
||||
@{
|
||||
*/
|
||||
/** @file dialog-chart-export.h
|
||||
@brief Chart Export - Routines to export Chart of Accounts to file
|
||||
@author Copyright (C) 2005 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
/** \brief Export the Chart of Accounts to QSF
|
||||
|
||||
Write out the Chart of Accounts \b with balances as of a
|
||||
specific date, as QSF.
|
||||
|
||||
The function iterates over each account in the current book and
|
||||
gets the balance as of the specified date. The account is copied to
|
||||
the export session, setting the export session book as partial.
|
||||
The function then looks up the new entity in the export session
|
||||
book and sets the opening balance of the copied account.
|
||||
*/
|
||||
void
|
||||
gnc_main_window_chart_export(void);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif /* _DIALOG_CHART_EXPORT_H */
|
@ -34,7 +34,6 @@
|
||||
#include "dialog-new-user.h"
|
||||
#include "dialog-utils.h"
|
||||
#include "druid-hierarchy.h"
|
||||
#include "druid-merge.h"
|
||||
#include "druid-utils.h"
|
||||
#include "gnc-amount-edit.h"
|
||||
#include "gnc-currency-edit.h"
|
||||
|
@ -1,400 +0,0 @@
|
||||
/********************************************************************\
|
||||
* druid-merge.c -- account hierarchy merge functionality *
|
||||
* Copyright (C) 2001 Gnumatic, Inc. *
|
||||
* Copyright (C) 2004 Neil Williams <linux@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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gnome.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dialog-utils.h"
|
||||
#include "druid-merge.h"
|
||||
#include "druid-utils.h"
|
||||
#include "gnc-component-manager.h"
|
||||
#include "gnc-gui-query.h"
|
||||
#include "qof.h"
|
||||
#include "druid-hierarchy.h"
|
||||
#include "gnc-ui-util.h"
|
||||
#include "Account.h"
|
||||
|
||||
GtkWidget *druid_hierarchy_window = NULL;
|
||||
static GtkWidget *qsf_import_merge_window = NULL;
|
||||
QofSession *previous_session = NULL;
|
||||
gint count = 0;
|
||||
QofBookMergeData *mergeData = NULL;
|
||||
QofSession *merge_session = NULL;
|
||||
QofBook *mergeBook = NULL;
|
||||
QofBook *targetBook = NULL;
|
||||
|
||||
static QofLogModule log_module = GNC_QSF_IMPORT;
|
||||
|
||||
void collision_rule_loop (QofBookMergeData*, QofBookMergeRule*, guint );
|
||||
|
||||
static GtkWidget*
|
||||
merge_get_widget (const char *name)
|
||||
{
|
||||
if (!qsf_import_merge_window) return NULL;
|
||||
|
||||
return gnc_glade_lookup_widget (qsf_import_merge_window, name);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_merge_window (void)
|
||||
{
|
||||
if (!qsf_import_merge_window) return;
|
||||
|
||||
gtk_widget_destroy (qsf_import_merge_window);
|
||||
qsf_import_merge_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qof_book_merge_destroy_cb (GtkObject *obj, gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_import_start_page_next(GnomeDruidPage *gnomedruidpage,
|
||||
gpointer arg1,
|
||||
gpointer user_data)
|
||||
{
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_MergeUpdate_clicked (GtkButton *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkLabel *output;
|
||||
|
||||
g_return_if_fail(mergeData != NULL);
|
||||
ENTER (" ");
|
||||
mergeData = qof_book_merge_update_result(mergeData, MERGE_UPDATE);
|
||||
count = 0;
|
||||
qof_book_merge_rule_foreach(mergeData, collision_rule_loop, MERGE_REPORT);
|
||||
if (count == 0)
|
||||
{
|
||||
output = GTK_LABEL(merge_get_widget("OutPut"));
|
||||
gtk_label_set_text(output, _("No conflicts to be resolved."));
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
on_MergeDuplicate_clicked (GtkButton *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
QofBookMergeRule *currentRule;
|
||||
GtkLabel *output;
|
||||
|
||||
g_return_if_fail(mergeData != NULL);
|
||||
ENTER (" ");
|
||||
currentRule = mergeData->currentRule;
|
||||
if (currentRule->mergeAbsolute == FALSE)
|
||||
{
|
||||
mergeData = qof_book_merge_update_result(mergeData, MERGE_DUPLICATE);
|
||||
count = 0;
|
||||
}
|
||||
if (currentRule->mergeAbsolute == TRUE)
|
||||
{
|
||||
mergeData = qof_book_merge_update_result(mergeData, MERGE_ABSOLUTE);
|
||||
count = 0;
|
||||
}
|
||||
qof_book_merge_rule_foreach(mergeData, collision_rule_loop, MERGE_REPORT);
|
||||
if (count == 0)
|
||||
{
|
||||
output = GTK_LABEL(merge_get_widget("OutPut"));
|
||||
gtk_label_set_text(output, _("No conflicts to be resolved."));
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
on_MergeNew_clicked (GtkButton *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
QofBookMergeRule *currentRule;
|
||||
GtkLabel *output;
|
||||
|
||||
g_return_if_fail(mergeData != NULL);
|
||||
currentRule = mergeData->currentRule;
|
||||
g_return_if_fail(currentRule != NULL);
|
||||
ENTER (" ");
|
||||
if (currentRule->mergeAbsolute == FALSE)
|
||||
{
|
||||
mergeData = qof_book_merge_update_result(mergeData, MERGE_NEW);
|
||||
}
|
||||
count = 0;
|
||||
qof_book_merge_rule_foreach(mergeData, collision_rule_loop, MERGE_REPORT);
|
||||
if (count == 0)
|
||||
{
|
||||
output = GTK_LABEL(merge_get_widget("OutPut"));
|
||||
gtk_label_set_text(output, _("No conflicts to be resolved."));
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_import_next (GnomeDruidPage *gnomedruidpage,
|
||||
gpointer arg1,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *top;
|
||||
gchar *message;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
message = g_strdup_printf(_("Error: Please resolve all %d "
|
||||
"conflicts before trying to commit the data."), count);
|
||||
top = gtk_widget_get_toplevel (GTK_WIDGET (gnomedruidpage));
|
||||
gnc_error_dialog(top, "%s", message);
|
||||
g_free(message);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_merge_cancel (GnomeDruid *gnomedruid, gpointer user_data)
|
||||
{
|
||||
g_return_if_fail(mergeBook != NULL);
|
||||
gnc_suspend_gui_refresh ();
|
||||
delete_merge_window();
|
||||
qof_book_destroy(mergeBook);
|
||||
qof_session_end(merge_session);
|
||||
gnc_resume_gui_refresh ();
|
||||
}
|
||||
|
||||
void currency_transfer_cb ( QofInstance* ent, gpointer user_data)
|
||||
{
|
||||
if (!ent) return;
|
||||
if (xaccAccountGetCommodity((Account*)ent) == NULL)
|
||||
{
|
||||
xaccAccountSetCommodity((Account*)ent, gnc_default_currency());
|
||||
}
|
||||
}
|
||||
|
||||
/* If the account has no parent, shove it into the top level under the root. */
|
||||
void reference_parent_cb ( QofInstance* ent, gpointer user_data)
|
||||
{
|
||||
Account *root;
|
||||
|
||||
if (!ent) return;
|
||||
if (gnc_account_get_parent((Account*)ent) == NULL)
|
||||
{
|
||||
root = gnc_book_get_root_account(targetBook);
|
||||
gnc_account_append_child(root, (Account*)ent);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_merge_finish (GnomeDruidPage *gnomedruidpage,
|
||||
gpointer arg1,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint result;
|
||||
GtkWidget *top;
|
||||
const char *message;
|
||||
|
||||
ENTER (" ");
|
||||
g_return_if_fail(mergeData != NULL);
|
||||
gnc_suspend_gui_refresh ();
|
||||
result = qof_book_merge_commit(mergeData);
|
||||
if (result != 0)
|
||||
{
|
||||
message = g_strdup_printf(_("Error: the Commit operation failed, error code %d."), result);
|
||||
top = gtk_widget_get_toplevel (GTK_WIDGET (gnomedruidpage));
|
||||
gnc_error_dialog(top, "%s", message);
|
||||
}
|
||||
g_return_if_fail(result == 0);
|
||||
delete_merge_window ();
|
||||
qof_object_foreach(GNC_ID_ACCOUNT, targetBook, currency_transfer_cb, NULL);
|
||||
qof_object_foreach(GNC_ID_ACCOUNT, targetBook, reference_parent_cb, NULL);
|
||||
qof_book_destroy(mergeBook);
|
||||
qof_session_end(merge_session);
|
||||
gnc_resume_gui_refresh ();
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
on_merge_prepare (GnomeDruidPage *gnomedruidpage,
|
||||
gpointer arg1,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkLabel *progress, *output;
|
||||
|
||||
gnc_suspend_gui_refresh ();
|
||||
ENTER (" ");
|
||||
progress = GTK_LABEL (merge_get_widget("ResultsBox"));
|
||||
/* blank out old data */
|
||||
gtk_label_set_text(progress, "");
|
||||
g_return_if_fail(mergeBook || targetBook);
|
||||
mergeData = qof_book_merge_init(mergeBook, targetBook);
|
||||
g_return_if_fail(mergeData != NULL);
|
||||
count = 0;
|
||||
qof_book_merge_rule_foreach(mergeData, collision_rule_loop, MERGE_REPORT);
|
||||
if (count == 0)
|
||||
{
|
||||
output = GTK_LABEL(merge_get_widget("OutPut"));
|
||||
gtk_label_set_text(output, _("No conflicts to be resolved."));
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
}
|
||||
gnc_resume_gui_refresh ();
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gnc_create_import_druid ( void )
|
||||
{
|
||||
GtkWidget *dialog, *druid, *start_page;
|
||||
GladeXML *xml;
|
||||
|
||||
xml = gnc_glade_xml_new ("merge.glade", "Merge Druid");
|
||||
|
||||
dialog = glade_xml_get_widget (xml, "Merge Druid");
|
||||
druid = glade_xml_get_widget (xml, "merge_druid");
|
||||
gnc_druid_set_colors (GNOME_DRUID (druid));
|
||||
start_page = glade_xml_get_widget (xml, "start_page");
|
||||
gtk_widget_show (start_page);
|
||||
gtk_widget_show (glade_xml_get_widget (xml, "MergeDruidFinishPage"));
|
||||
|
||||
glade_xml_signal_connect(xml, "on_start_page_next",
|
||||
G_CALLBACK (on_import_start_page_next));
|
||||
|
||||
glade_xml_signal_connect(xml, "on_qof_book_merge_prepare",
|
||||
G_CALLBACK (on_merge_prepare));
|
||||
|
||||
glade_xml_signal_connect(xml, "on_qof_book_merge_next",
|
||||
G_CALLBACK (on_import_next));
|
||||
|
||||
glade_xml_signal_connect (xml, "on_finish",
|
||||
G_CALLBACK (on_merge_finish));
|
||||
|
||||
glade_xml_signal_connect (xml, "on_cancel",
|
||||
G_CALLBACK (on_merge_cancel));
|
||||
|
||||
glade_xml_signal_connect (xml, "on_MergeUpdate_clicked",
|
||||
G_CALLBACK (on_MergeUpdate_clicked));
|
||||
|
||||
glade_xml_signal_connect (xml, "on_MergeDuplicate_clicked",
|
||||
G_CALLBACK (on_MergeDuplicate_clicked));
|
||||
|
||||
glade_xml_signal_connect (xml, "on_MergeNew_clicked",
|
||||
G_CALLBACK (on_MergeNew_clicked));
|
||||
|
||||
g_signal_connect (dialog, "destroy",
|
||||
G_CALLBACK(qof_book_merge_destroy_cb), NULL);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
void collision_rule_loop(QofBookMergeData *mergeData, QofBookMergeRule *rule,
|
||||
guint remainder)
|
||||
{
|
||||
GSList *user_reports;
|
||||
QofParam *one_param;
|
||||
gchar *importstring, *targetstring;
|
||||
GtkLabel *output;
|
||||
gchar *buffer, *buffer2, *buffer3;
|
||||
|
||||
g_return_if_fail(rule != NULL);
|
||||
buffer = "";
|
||||
/* there is a rule awaiting resolution, don't print any more */
|
||||
if (count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ENTER (" remainder=%d", remainder);
|
||||
gnc_suspend_gui_refresh ();
|
||||
user_reports = rule->mergeParam;
|
||||
mergeData->currentRule = rule;
|
||||
output = GTK_LABEL(merge_get_widget("OutPut"));
|
||||
gtk_label_set_text(output, buffer);
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
gnc_resume_gui_refresh ();
|
||||
count = 1; /* user display text counts from 1, not zero */
|
||||
importstring = targetstring = NULL;
|
||||
gnc_suspend_gui_refresh ();
|
||||
/* Translators: %i is the number of conflicts. This is a
|
||||
ngettext(3) message. */
|
||||
buffer2 = g_strdup_printf(ngettext("%i conflict needs to be resolved.",
|
||||
"%i conflicts need to be resolved.",
|
||||
remainder),
|
||||
remainder);
|
||||
/* Translators: %i is the number of values. This is a
|
||||
ngettext(3) message. */
|
||||
buffer3 = g_strdup_printf(ngettext("%i parameter value for this \"%s\" object.",
|
||||
"%i parameter values for this \"%s\" object.",
|
||||
g_slist_length(user_reports)),
|
||||
g_slist_length(user_reports), rule->targetEnt->e_type);
|
||||
buffer = g_strconcat("\n", buffer2, "\n", "\n", buffer3, "\n", NULL);
|
||||
g_free(buffer2);
|
||||
g_free(buffer3);
|
||||
while (user_reports != NULL)
|
||||
{
|
||||
one_param = user_reports->data;
|
||||
/* FIXME: each g_strdup_printf as well as g_strconcat
|
||||
will allocate a new string; all of these need to be
|
||||
freed later. Currently this causes a lot of memory
|
||||
leaks. */
|
||||
buffer = g_strconcat(buffer, g_strdup_printf(_("%i: Parameter name: %s "),
|
||||
count, one_param->param_name), NULL);
|
||||
importstring = qof_book_merge_param_as_string(one_param, rule->importEnt);
|
||||
buffer = g_strconcat(buffer,
|
||||
g_strdup_printf(_("Import data : %s "), importstring), NULL);
|
||||
targetstring = qof_book_merge_param_as_string(one_param, rule->targetEnt);
|
||||
buffer = g_strconcat(buffer,
|
||||
g_strdup_printf(_("Original data : %s\n"), targetstring), NULL);
|
||||
user_reports = g_slist_next(user_reports);
|
||||
count++;
|
||||
}
|
||||
gtk_label_set_text(output, buffer);
|
||||
gtk_widget_show(GTK_WIDGET(output));
|
||||
gnc_resume_gui_refresh ();
|
||||
g_free(buffer);
|
||||
g_free(importstring);
|
||||
g_free(targetstring);
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
void
|
||||
gnc_ui_qsf_import_merge_druid (QofSession *original, QofSession *import)
|
||||
{
|
||||
if (qsf_import_merge_window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
qof_event_suspend ();
|
||||
qsf_import_merge_window = gnc_create_import_druid();
|
||||
g_return_if_fail(qsf_import_merge_window != NULL);
|
||||
previous_session = original;
|
||||
targetBook = qof_session_get_book(previous_session);
|
||||
merge_session = import;
|
||||
mergeBook = qof_session_get_book(merge_session);
|
||||
gtk_widget_show(qsf_import_merge_window);
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/********************************************************************\
|
||||
* druid-merge.h -- account hierarchy merge functionality *
|
||||
* Copyright (C) 2001 Gnumatic, Inc. *
|
||||
* Copyright (C) 2004 Neil Williams <linux@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, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#ifndef DRUID_MERGE_H
|
||||
#define DRUID_MERGE_H
|
||||
#include "qof.h"
|
||||
|
||||
/** @addtogroup GUI
|
||||
@{ */
|
||||
/** @addtogroup NewHierarchy Merging a new account tree into an existing file
|
||||
|
||||
<b>Collision handling principles.</b>\n
|
||||
\n
|
||||
This druid builds a second ::QofBook in memory using ::QofSession and
|
||||
populates the book with accounts created using the usual New Account Tree
|
||||
code. The druid then uses ::qof_book_merge_init to begin the merge
|
||||
of the new book (created with QofSession) with the existing QofBook
|
||||
(loaded by the user), with user intervention and collision handling.
|
||||
|
||||
-# Always check for a ::GncGUID first and compare. qof_book_merge only accepts valid ::QofBook
|
||||
data and therefore ALL objects in the import book will include valid GncGUID's.
|
||||
-# If the original import data did not contain a GncGUID (e.g. an external non-GnuCash source)
|
||||
the GncGUID values will have been created by QofSession and will not match any existing
|
||||
GncGUID's in the target book so objects that do not have a GncGUID match cannot be assumed to
|
||||
be ::MERGE_NEW - parameter values must be checked.
|
||||
|
||||
- If a GncGUID match exists, set QofBookMergeRule::mergeAbsolute to \a TRUE.
|
||||
-# If ALL parameters in the import object match the target object with the same \a GncGUID,
|
||||
set ::QofBookMergeResult to \a MERGE_ABSOLUTE.
|
||||
-# If any parameters differ, set ::MERGE_UPDATE.
|
||||
- If the import object \a GncGUID does not match an existing object,
|
||||
mergeAbsolute is unchanged from the default \a FALSE
|
||||
The parameter values of the object are compared to other objects of the same
|
||||
type in the target book.
|
||||
-# If the same data exists in the target book with a different GncGUID, the object
|
||||
is tagged as DUPLICATE.
|
||||
-# If the data has changed, the object is tagged as REPORT.
|
||||
-# If the data does not match, the object is tagged as NEW
|
||||
|
||||
More information is at http://code.neil.williamsleesmill.me.uk/
|
||||
|
||||
Each foreach function uses g_return_if_fail checks to protect the target book. If
|
||||
any essential data is missing, the loop returns without changing the target book.
|
||||
Note that this will not set or return an error value. However, g_return is only
|
||||
used for critical errors that arise from programming errors, not for invalid import data
|
||||
which should be cleaned up before creating the import QofBook.
|
||||
|
||||
Only ::qof_book_merge_init, ::qof_book_merge_update_result and ::qof_book_merge_commit return
|
||||
any error values to the calling process.
|
||||
|
||||
@{ */
|
||||
/** @file druid-merge.h
|
||||
@brief API for merging two \c QofBook* structures with collision handling
|
||||
@author Copyright (c) 2004 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
void gnc_ui_qsf_import_merge_druid(QofSession *original, QofSession *import);
|
||||
|
||||
#define GNC_QSF_IMPORT "gnc-qsf-import-druid"
|
||||
|
||||
/** \brief gncCommodity is not QOF enabled, need to set a default commodity before the merge */
|
||||
void currency_transfer_cb ( QofInstance* ent, gpointer user_data);
|
||||
|
||||
/** \brief workaround for AccountGroup not being fully QOF enabled. Eh? */
|
||||
void reference_parent_cb ( QofInstance* ent, gpointer user_data);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif
|
@ -4,11 +4,9 @@ glade_DATA = \
|
||||
acctperiod.glade \
|
||||
autoclear.glade \
|
||||
budget.glade \
|
||||
chart-export.glade \
|
||||
commodities.glade \
|
||||
fincalc.glade \
|
||||
lots.glade \
|
||||
merge.glade \
|
||||
newuser.glade \
|
||||
price.glade \
|
||||
print.glade \
|
||||
|
@ -1,245 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkDialog" id="chart-export">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Export Chart of Accounts</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="has_separator">False</property>
|
||||
<signal name="response" handler="chart_export_response_cb" last_modification_time="Mon, 23 Jan 2006 04:43:46 GMT"/>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancelbutton1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-6</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="dateok">
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Click to choose the filename and location.</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-5</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkAlignment" id="alignment2">
|
||||
<property name="visible">True</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<property name="top_padding">0</property>
|
||||
<property name="bottom_padding">0</property>
|
||||
<property name="left_padding">0</property>
|
||||
<property name="right_padding">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">2</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkImage" id="image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="stock">gtk-convert</property>
|
||||
<property name="icon_size">4</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="label">_Export</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="chartlabel">
|
||||
<property name="width_request">304</property>
|
||||
<property name="height_request">56</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">You can export the Chart of Accounts to a QSF XML file that can be imported into another GnuCash file or used in other programs.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_FILL</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.519999980927</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="chartnote">
|
||||
<property name="width_request">304</property>
|
||||
<property name="height_request">56</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">The Chart of Accounts includes the balance for each account, on the date specified. Note that future dates are not supported.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_FILL</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="processlabel">
|
||||
<property name="width_request">296</property>
|
||||
<property name="height_request">48</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Select the date to use and click Export to choose the filename and location. Future dates are not supported.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_FILL</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCalendar" id="chart-calendar">
|
||||
<property name="width_request">215</property>
|
||||
<property name="height_request">180</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="display_options">GTK_CALENDAR_SHOW_HEADING|GTK_CALENDAR_SHOW_DAY_NAMES</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
@ -1,296 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
<requires lib="gnome"/>
|
||||
|
||||
<widget class="GtkWindow" id="Merge Druid">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">QSF Data Import Setup</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GnomeDruid" id="merge_druid">
|
||||
<property name="border_width">4</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="show_help">False</property>
|
||||
<signal name="cancel" handler="on_cancel"/>
|
||||
|
||||
<child>
|
||||
<widget class="GnomeDruidPageEdge" id="start_page">
|
||||
<property name="visible">True</property>
|
||||
<property name="position">GNOME_EDGE_START</property>
|
||||
<property name="title" translatable="yes">QSF Data Import Setup</property>
|
||||
<property name="text" translatable="yes">This assistant will merge your QSF data into the currently open GnuCash file.
|
||||
|
||||
You will be asked how to proceed if some QSF data clashes with the your existing GnuCash data file.
|
||||
|
||||
There is NO way to undo this operation! Please ensure you have a backup of your file BEFORE continuing! You will be given the option to cancel the merge at all stages until the final merge operation. Once you click Finish, the new QSF data will be committed to your current data file.
|
||||
|
||||
There is currently no currency or price support in the merge operation, the new data will inherit any default currency or you can change the currency after the merge is complete.
|
||||
|
||||
Your QSF data is ready to import
|
||||
|
||||
Click 'Cancel' if you do not wish to merge your QSF data now.</property>
|
||||
<property name="title_color">#ffffffffffff</property>
|
||||
<property name="text_color">#000000000000</property>
|
||||
<property name="background_color">#191919197070</property>
|
||||
<property name="logo_background_color">#ffffffffffff</property>
|
||||
<property name="textbox_color">#ffffffffffff</property>
|
||||
<signal name="next" handler="on_start_page_next"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GnomeDruidPageStandard" id="qof_book_merge">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">Please resolve any conflicts in the merge</property>
|
||||
<property name="title_foreground">#ffffffffffff</property>
|
||||
<property name="background">#191919197070</property>
|
||||
<property name="logo_background">#ffffffffffff</property>
|
||||
<signal name="prepare" handler="on_qof_book_merge_prepare"/>
|
||||
<signal name="next" handler="on_qof_book_merge_next"/>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="druid-vbox6">
|
||||
<property name="border_width">16</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox105">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox121">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="ResultsBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="label"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox106">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow27">
|
||||
<property name="visible">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkViewport" id="viewport1">
|
||||
<property name="border_width">5</property>
|
||||
<property name="height_request">51</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Shows how your QSF data conflicts with existing data in your file.</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="OutPut">
|
||||
<property name="height_request">50</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">MergeUpdate</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="Static">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">You have three choices for each collision:
|
||||
1. The import object can be allowed to overwrite the target - use this to update your existing book.
|
||||
2. The import object can be ignored - use this if the import is a duplicate of an object in the existing book.
|
||||
3. The import object can be created as a new object in the existing book.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_FILL</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="MergeUpdate">
|
||||
<property name="border_width">5</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">overwrite the original with the import data</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label" translatable="yes">1. Update your existing book with the import data</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_MergeUpdate_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="MergeDuplicate">
|
||||
<property name="border_width">5</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">ignore the import, leave the original untouched</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">2. Ignore the import data, leave original unchanged</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_MergeDuplicate_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="MergeNew">
|
||||
<property name="border_width">5</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="tooltip" translatable="yes">Add the import as a new object, leave original in place</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">3. Import the data as a NEW object</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_MergeNew_clicked"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GnomeDruidPageEdge" id="MergeDruidFinishPage">
|
||||
<property name="visible">True</property>
|
||||
<property name="position">GNOME_EDGE_FINISH</property>
|
||||
<property name="title" translatable="yes">Commit QSF Import Data to data file</property>
|
||||
<property name="text" translatable="yes">Press `Apply' to merge your QSF data into the current GnuCash file.
|
||||
|
||||
Press `Back' to review your selections.
|
||||
|
||||
Press `Cancel' to close this dialog without changing your current data file.
|
||||
|
||||
REMEMBER: There is no way to undo this final operation! Make sure you have a backup before clicking 'Apply'.</property>
|
||||
<property name="title_color">#ffffffffffff</property>
|
||||
<property name="text_color">#000000000000</property>
|
||||
<property name="background_color">#191919197070</property>
|
||||
<property name="logo_background_color">#ffffffffffff</property>
|
||||
<property name="textbox_color">#ffffffffffff</property>
|
||||
<signal name="finish" handler="on_finish"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
@ -40,7 +40,6 @@
|
||||
#include "gnc-ui-util.h"
|
||||
|
||||
#include "dialog-book-close.h"
|
||||
#include "dialog-chart-export.h"
|
||||
#include "dialog-file-access.h"
|
||||
#include "dialog-fincalc.h"
|
||||
#include "dialog-find-transactions.h"
|
||||
@ -48,7 +47,6 @@
|
||||
#include "dialog-totd.h"
|
||||
#include "druid-acct-period.h"
|
||||
#include "druid-loan.h"
|
||||
#include "druid-merge.h"
|
||||
#include "gnc-engine.h"
|
||||
#include "gnc-file.h"
|
||||
#include "gnc-gui-query.h"
|
||||
@ -72,9 +70,7 @@ static void gnc_main_window_cmd_file_new (GtkAction *action, GncMainWindowAction
|
||||
static void gnc_main_window_cmd_file_open (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_file_save (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_file_save_as (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_file_qsf_import (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_file_export_accounts (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_file_chart_export (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_edit_tax_options (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_actions_mortgage_loan (GtkAction *action, GncMainWindowActionData *data);
|
||||
static void gnc_main_window_cmd_actions_scheduled_transaction_editor (GtkAction *action, GncMainWindowActionData *data);
|
||||
@ -119,26 +115,12 @@ static GtkActionEntry gnc_plugin_actions [] =
|
||||
NULL,
|
||||
G_CALLBACK (gnc_main_window_cmd_file_save_as)
|
||||
},
|
||||
#ifdef QSF_IMPORT_WORKS
|
||||
{
|
||||
"FileImportQSFAction", GTK_STOCK_CONVERT,
|
||||
N_("_QSF Import"), NULL,
|
||||
N_("Import a QSF object file"),
|
||||
G_CALLBACK (gnc_main_window_cmd_file_qsf_import)
|
||||
},
|
||||
#endif // QSF_IMPORT_WORKS
|
||||
{
|
||||
"FileExportAccountsAction", GTK_STOCK_CONVERT,
|
||||
N_("Export _Accounts"), NULL,
|
||||
N_("Export the account hierarchy to a new GnuCash datafile"),
|
||||
G_CALLBACK (gnc_main_window_cmd_file_export_accounts)
|
||||
},
|
||||
{
|
||||
"FileExportChartAction", GTK_STOCK_CONVERT,
|
||||
N_("Export _Chart of Accounts to QSF"), NULL,
|
||||
N_("Export the chart of accounts for a date with balances as QSF"),
|
||||
G_CALLBACK (gnc_main_window_cmd_file_chart_export)
|
||||
},
|
||||
|
||||
/* Edit menu */
|
||||
|
||||
@ -439,62 +421,6 @@ gnc_main_window_cmd_file_save_as (GtkAction *action, GncMainWindowActionData *da
|
||||
/* FIXME GNOME 2 Port (update the title etc.) */
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_file_select_ok(GtkWidget *w, GtkFileSelection *fs )
|
||||
{
|
||||
QofSession *qsf_session, *first_session;
|
||||
const gchar *filename, *message, *error_message;
|
||||
QofBook *original;
|
||||
QofBackendError err;
|
||||
|
||||
ENTER (" ");
|
||||
qof_event_suspend();
|
||||
filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs));
|
||||
gtk_widget_destroy((GtkWidget*) fs);
|
||||
first_session = gnc_get_current_session();
|
||||
original = qof_session_get_book(first_session);
|
||||
qsf_session = qof_session_new();
|
||||
qof_session_begin(qsf_session, filename, TRUE, FALSE);
|
||||
qof_session_load(qsf_session, NULL);
|
||||
err = qof_session_get_error(qsf_session);
|
||||
if (err != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
error_message = qof_session_get_error_message(qsf_session);
|
||||
if (!error_message)
|
||||
error_message = "";
|
||||
/* Translators: %d is the error number; %s is the error message as
|
||||
text. */
|
||||
message = g_strdup_printf(_("Error: Loading failed, error code %d - %s."), err, error_message);
|
||||
PERR("%s", message);
|
||||
qof_session_destroy(qsf_session);
|
||||
qof_event_resume();
|
||||
gnc_error_dialog(gnc_ui_get_toplevel(), "%s", message);
|
||||
LEAVE (" ");
|
||||
return;
|
||||
}
|
||||
|
||||
qof_event_resume();
|
||||
gnc_ui_qsf_import_merge_druid(first_session, qsf_session);
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_main_window_cmd_file_qsf_import (GtkAction *action, GncMainWindowActionData *data)
|
||||
{
|
||||
GtkWidget *file_select;
|
||||
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
gnc_window_set_progressbar_window(GNC_WINDOW(data->window));
|
||||
file_select = gtk_file_selection_new(_("Select the QSF file to import into GnuCash"));
|
||||
g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (file_select)->ok_button),
|
||||
"clicked", G_CALLBACK (qsf_file_select_ok), (gpointer) file_select);
|
||||
g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (file_select)->cancel_button),
|
||||
"clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (file_select));
|
||||
gtk_widget_show (file_select);
|
||||
gnc_window_set_progressbar_window(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_main_window_cmd_file_export_accounts (GtkAction *action, GncMainWindowActionData *data)
|
||||
{
|
||||
@ -507,18 +433,6 @@ gnc_main_window_cmd_file_export_accounts (GtkAction *action, GncMainWindowAction
|
||||
/* gnc_refresh_main_window_info (); */
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_main_window_cmd_file_chart_export (GtkAction *action, GncMainWindowActionData *data)
|
||||
{
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
gnc_window_set_progressbar_window (GNC_WINDOW(data->window));
|
||||
gnc_main_window_chart_export();
|
||||
gnc_window_set_progressbar_window (NULL);
|
||||
/* FIXME GNOME 2 Port (update the title etc.) */
|
||||
/* gnc_refresh_main_window_info (); */
|
||||
}
|
||||
|
||||
static void
|
||||
gnc_main_window_cmd_edit_tax_options (GtkAction *action, GncMainWindowActionData *data)
|
||||
{
|
||||
|
@ -1,2 +1,2 @@
|
||||
SUBDIRS = . qof backend
|
||||
SUBDIRS = . qof
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
SUBDIRS = file
|
||||
|
@ -1,46 +0,0 @@
|
||||
SUBDIRS = .
|
||||
|
||||
pkglib_LTLIBRARIES = libgncqof-backend-qsf.la
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I.. -I../.. \
|
||||
-I$(top_srcdir)/lib/libc \
|
||||
-DLOCALE_DIR=\""$(datadir)/locale"\" \
|
||||
-I${top_srcdir}/src/libqof/qof \
|
||||
${LIBXML2_CFLAGS} \
|
||||
${GLIB_CFLAGS}
|
||||
|
||||
libgncqof_backend_qsf_la_SOURCES = \
|
||||
qsf-backend.c \
|
||||
qsf-xml-map.c \
|
||||
qsf-xml.c
|
||||
|
||||
libgncqof_backend_qsf_la_LDFLAGS = -module -avoid-version
|
||||
libgncqof_backend_qsf_la_LIBADD = \
|
||||
${top_builddir}/src/libqof/qof/libgnc-qof.la \
|
||||
${GLIB_LIBS} \
|
||||
${REGEX_LIBS} \
|
||||
${LIBXML2_LIBS} \
|
||||
$(top_builddir)/lib/libc/libc-missing.la
|
||||
|
||||
qsfschemadir = $(QOF_XML_DIR)
|
||||
qsfschema_DATA = \
|
||||
qsf-object.xsd.xml \
|
||||
qsf-map.xsd.xml \
|
||||
pilot-qsf-GnuCashInvoice.xml \
|
||||
pilot-qsf-gncCustomer.xml
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(qsfschema_DATA) \
|
||||
qsf-dir.h.in \
|
||||
qof-backend-qsf.h \
|
||||
qsf-xml.h
|
||||
|
||||
qsf-dir.h: qsf-dir.h.in Makefile
|
||||
rm -f $@.tmp
|
||||
sed < $< > $@.tmp \
|
||||
-e 's#@-QSF_SCHEMA_DIR-@#${QOF_XML_DIR}#g'
|
||||
mv $@.tmp $@
|
||||
|
||||
BUILT_SOURCES = qsf-dir.h
|
||||
CLEANFILES = qsf-dir.h
|
@ -1,122 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- this map does NOT post invoices automatically -->
|
||||
<!-- maps use the same sequence of parameter types as other QSF -->
|
||||
<!-- Trans:desc can be set by expenses or datebook -->
|
||||
<qsf-map
|
||||
xmlns="http://qof.sourceforge.net/">
|
||||
<definition qof_version="3">
|
||||
<define e_type="pilot_expenses"/>
|
||||
<define e_type="pilot_datebook"/>
|
||||
<define e_type="pilot_address"/>
|
||||
<define e_type="gncInvoice"/>
|
||||
<define e_type="Trans"/>
|
||||
<define e_type="gncEntry"/>
|
||||
<default name="mileage_rate" type="numeric" value="30/100"/>
|
||||
<default name="use_weekday_descriptor" type="boolean" value="true"/>
|
||||
<default name="use_discount" type="boolean" value="false"/>
|
||||
<default name="tax_included" type="boolean" value="false"/>
|
||||
<default name="post_account" type="string" value="Assets:Current Assets:CD account"/>
|
||||
<default name="expenses_account" type="string" value="Income:Other Income"/>
|
||||
<default name="datebook_account" type="string" value="Income:Locum Income"/>
|
||||
<default name="tax_included" type="enum" value="1">GNC_TAXINCLUDED_YES</default>
|
||||
<default name="tax_included" type="enum" value="2">GNC_TAXINCLUDED_NO</default>
|
||||
<default name="tax_included" type="enum" value="3">GNC_TAXINCLUDED_USEGLOBAL</default>
|
||||
<default name="amount_type" type="enum" value="1">GNC_AMT_TYPE_VALUE</default>
|
||||
<default name="amount_type" type="enum" value="2">GNC_AMT_TYPE_PERCENT</default>
|
||||
</definition>
|
||||
<object type="gncEntry">
|
||||
<calculate type="string" value="desc">
|
||||
<if boolean="use_weekday_descriptor">
|
||||
<set format="%A">expense_date</set>
|
||||
</if>
|
||||
<else type="pilot_expenses">
|
||||
<set>expense_vendor</set>
|
||||
</else>
|
||||
<else type="pilot_datebook">
|
||||
<set>description</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="string" value="action">
|
||||
<if type="pilot_expenses">
|
||||
<set>Material</set>
|
||||
</if>
|
||||
<else type="pilot_datebook">
|
||||
<set>Hours</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="string" value="notes">
|
||||
<if type="pilot-expenses">
|
||||
<set>expense_note</set>
|
||||
</if>
|
||||
<else type="pilot_datebook">
|
||||
<set>note</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="guid" value="bill-to"/>
|
||||
<calculate type="boolean" value="invoice-taxable"/>
|
||||
<calculate type="boolean" value="bill-taxable"/>
|
||||
<calculate type="boolean" value="billable?"/>
|
||||
<calculate type="boolean" value="bill-tax-included"/>
|
||||
<calculate type="boolean" value="invoice-tax-included">
|
||||
<set>tax_included</set>
|
||||
</calculate>
|
||||
<calculate type="numeric" value="iprice">
|
||||
<if type="string" value="expense_type">
|
||||
<equals type="string" value="Mileage">
|
||||
<set>mileage_rate</set>
|
||||
</equals>
|
||||
</if>
|
||||
</calculate>
|
||||
<calculate type="numeric" value="bprice"/>
|
||||
<calculate type="numeric" value="qty">
|
||||
<if type="pilot_datebook">
|
||||
<set>end_time-start_time</set>
|
||||
</if>
|
||||
<else type="pilot_expenses">
|
||||
<set>expense_amount</set>
|
||||
</else>
|
||||
</calculate>
|
||||
<calculate type="numeric" value="invoice-discount">
|
||||
<set>0/1</set>
|
||||
</calculate>
|
||||
<calculate type="date" value="date-entered">
|
||||
<set>qsf_time_now</set>
|
||||
</calculate>
|
||||
<calculate type="date" value="date">
|
||||
<set>qsf_enquiry_date</set>
|
||||
</calculate>
|
||||
<calculate type="gint32" value="discount-type">
|
||||
<set option="amount_type_enum">GNC_AMT_TYPE_PERCENT</set>
|
||||
</calculate>
|
||||
<calculate type="gint32" value="discount-method">
|
||||
<set>2</set>
|
||||
</calculate>
|
||||
<calculate type="gint32" value="bill-payment-type"/>
|
||||
</object>
|
||||
<object type="Trans">
|
||||
<calculate type="string" value="num"/>
|
||||
<calculate type="string" value="desc"/>
|
||||
<calculate type="date" value="date-entered"/>
|
||||
<calculate type="date" value="date-posted"/>
|
||||
<calculate type="date" value="date-due"/>
|
||||
<calculate type="string" value="notes"/>
|
||||
</object>
|
||||
<object type="gncInvoice">
|
||||
<calculate type="string" value="id"/>
|
||||
<calculate type="string" value="billing_id"/>
|
||||
<calculate type="string" value="notes"/>
|
||||
<calculate type="guid" value="invoice_owner"/>
|
||||
<calculate type="guid" value="account"/>
|
||||
<calculate type="guid" value="posted_txn"/>
|
||||
<calculate type="guid" value="posted_lot"/>
|
||||
<calculate type="guid" value="terms"/>
|
||||
<calculate type="guid" value="bill-to"/>
|
||||
<calculate type="boolean" value="active">
|
||||
<set>true</set>
|
||||
</calculate>
|
||||
<calculate type="date" value="date_opened">
|
||||
<set>qsf_enquiry_date</set>
|
||||
</calculate>
|
||||
<calculate type="date" value="date_posted"/>
|
||||
</object>
|
||||
</qsf-map>
|
@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<qsf-map xmlns="http://qof.sourceforge.net/">
|
||||
<definition qof_version="3">
|
||||
<define e_type="pilot_address"/>
|
||||
<define e_type="gncBillTerm"/>
|
||||
<define e_type="gncCustomer"/>
|
||||
<define e_type="gncAddress" foreach="true"/>
|
||||
</definition>
|
||||
<object type="gncCustomer">
|
||||
<calculate type="string" value="id"/>
|
||||
<calculate type="string" value="notes">
|
||||
<set>entryNote</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="name">
|
||||
<set>entryCompany</set>
|
||||
</calculate>
|
||||
<calculate type="guid" value="guid"/>
|
||||
<calculate type="guid" value="addr">
|
||||
<set>guid</set>
|
||||
</calculate>
|
||||
<calculate type="guid" value="customer_terms"/>
|
||||
<calculate type="guid" value="shipaddr"/>
|
||||
<calculate type="boolean" value="active">
|
||||
<set>true</set>
|
||||
</calculate>
|
||||
<calculate type="boolean" value="tax table override"/>
|
||||
<calculate type="numeric" value="amount of discount"/>
|
||||
<calculate type="numeric" value="amount of credit"/>
|
||||
</object>
|
||||
<object type="gncAddress">
|
||||
<calculate type="string" value="city">
|
||||
<set>entryZip</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="street">
|
||||
<set>entryAddress</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="fax">
|
||||
<set>entryPhone2</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="number"/>
|
||||
<calculate type="string" value="name">
|
||||
<set>entryFirstname</set>
|
||||
<set>entryLastname</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="email">
|
||||
<set>entryPhone5</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="locality">
|
||||
<set>entryState</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="phone">
|
||||
<set>entryPhone1</set>
|
||||
</calculate>
|
||||
<calculate type="guid" value="guid"/>
|
||||
<calculate type="guid" value="owner">
|
||||
<set>guid</set>
|
||||
</calculate>
|
||||
</object>
|
||||
<object type="gncBillTerm">
|
||||
<calculate type="string" value="description"/>
|
||||
<calculate type="string" value="name"/>
|
||||
<calculate type="string" value="bill type"/>
|
||||
<calculate type="guid" value="guid"/>
|
||||
<calculate type="numeric" value="amount of discount"/>
|
||||
<calculate type="gint32" value="cut off"/>
|
||||
<calculate type="gint32" value="number of days due"/>
|
||||
<calculate type="gint32" value="number of discounted days"/>
|
||||
</object>
|
||||
<object type="pilot_address">
|
||||
<calculate type="string" value="entryCity">
|
||||
<set object="gncAddress">city</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryCustom4"/>
|
||||
<calculate type="string" value="entryPhone1">
|
||||
<set object="gncAddress">phone</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryZip"/>
|
||||
<calculate type="string" value="entryLastname">
|
||||
<set object="gncAddress">name</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryPhone2"/>
|
||||
<calculate type="string" value="entryNote"/>
|
||||
<calculate type="string" value="category"/>
|
||||
<calculate type="string" value="entryFirstname"/>
|
||||
<calculate type="string" value="entryPhone3"/>
|
||||
<calculate type="string" value="entryTitle"/>
|
||||
<calculate type="string" value="entryPhone4"/>
|
||||
<calculate type="string" value="entryCompany">
|
||||
<set object="gncCustomer">name</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryPhone5"/>
|
||||
<calculate type="string" value="entryState">
|
||||
<set object="gncAddress">locality</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryCustom1"/>
|
||||
<calculate type="string" value="entryAddress">
|
||||
<set object="gncAddress">number</set>
|
||||
</calculate>
|
||||
<calculate type="string" value="entryCustom2"/>
|
||||
<calculate type="string" value="entryCountry"/>
|
||||
<calculate type="string" valuee="entryCustom3"/>
|
||||
</object>
|
||||
</qsf-map>
|
@ -1,204 +0,0 @@
|
||||
/***************************************************************************
|
||||
* qof-backend-qsf.h
|
||||
*
|
||||
* Sat Jun 11 19:34:36 2005
|
||||
* Copyright 2005 Neil Williams
|
||||
* linux@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 Library 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.
|
||||
*/
|
||||
|
||||
/** @addtogroup Backend
|
||||
@{ */
|
||||
/** @addtogroup QSF QOF Serialisation Format
|
||||
|
||||
This is the public interface of the qof-backend-qsf library.
|
||||
|
||||
QSF - QOF Serialization Format is an XML serialization format
|
||||
i.e. it lays out a QOF object in a series of XML tags. The format will
|
||||
consist of two component formats:
|
||||
|
||||
qof-qsf for the QSF object data and
|
||||
|
||||
qsf-map to map sets of QSF objects between QOF applications.
|
||||
|
||||
Maps exist to allow complex conversions between objects where object parameters
|
||||
need to be calculated, combined or processed using conditionals. Some QSF objects
|
||||
can be converted using XSL or other standard tools. For more information on maps,
|
||||
see http://code.neil.williamsleesmill.me.uk/map.html
|
||||
|
||||
QSF object files will contain user data and are to be exported from QOF applications
|
||||
under user control or they can be hand-edited. QSF maps contain application data and
|
||||
can be created by application developers from application source code. Tools may be
|
||||
created later to generate maps interactively but maps require application support as
|
||||
well as an understanding of QOF objects in the import and output applications and are
|
||||
intended to remain within the scope of application developers rather than users.
|
||||
|
||||
A QSF file written by one QOF application will need an appropriate QSF map before the
|
||||
data can be accessed by a different application using QOF. Any QSF objects that are
|
||||
not defined in the map will be ignored. QSF files written and accessed by the same
|
||||
application can use maps if necessary or can simply import the QSF data as a whole.
|
||||
|
||||
Unless specifically mentioned otherwise, all defined strings are case-sensitive.
|
||||
|
||||
Full documentation of this format is at:
|
||||
|
||||
http://code.neil.williamsleesmill.me.uk/qsf.html
|
||||
|
||||
QSF itself is now being built into the QOF library for use with pilot-link to allow
|
||||
Palm objects to be described in QOF, written to XML as QSF and imported directly into
|
||||
GnuCash and other QOF-compliant applications. As a generic format, it does not depend
|
||||
on any pre-defined objects. Instead, QSF is a simple container for all QOF objects.
|
||||
|
||||
QSF grew from the qof_book_merge code base and uses the qof_book_merge code that is now
|
||||
part of QOF. Any QofBook generated by QSF still needs to be merged into the existing
|
||||
application data using qof_book_merge. See ::BookMerge.
|
||||
|
||||
QSF can be used as an export or offline storage format for QOF applications (although
|
||||
long term storage may be best performed using separate (non-XML) methods, depending
|
||||
on the application).
|
||||
|
||||
QSF is designed to cope with partial QofBooks at the QofObject level. There is no
|
||||
requirement for specific objects to always be defined, as long as each QOF object
|
||||
specified is fully defined, no orphan or missing parameters are allowed. Part of the
|
||||
handling for partial books requires a storage mechanism for references to entities
|
||||
that are not within reach of the current book. This requires a little extra coding
|
||||
in the QSF QofBackend to contain the reference data so that when the book is
|
||||
written out, the reference can be included. When the file is imported back in, a
|
||||
little extra code then rebuilds those references during the merge.
|
||||
|
||||
Copying entites from an existing QofBook using the qof_instance_copy routines will
|
||||
automatically create the reference table. If your QOF objects use references to other
|
||||
entities, books that are created manually also need to create a reference table.
|
||||
|
||||
Work is continuing on supporting QSF in GnuCash and QOF. QSF is a very open format -
|
||||
the majority of the work will be in standardising object types and creating maps that
|
||||
convert between objects. Applications that read QSF should ignore any objects that do
|
||||
not match the available maps and warn the user about missing data.
|
||||
|
||||
Anyone is free to create their own QSF objects, subject to the GNU GPL. It is intended
|
||||
that QSF can be used as the flexible, open and free format for QOF data - providing
|
||||
all that is lacking from a typical CSV export with all the validation benefits of XML
|
||||
and the complex data handling of QOF. The QSF object and map formats remain under the
|
||||
GNU GPL licence and QSF is free software.
|
||||
|
||||
\todo
|
||||
- Adding more map support, some parts of the map are still not coded. equals,
|
||||
variables and the conditional logic may not be up to the task of the
|
||||
datebook repetition calculations.
|
||||
|
||||
QSF is in three sections:
|
||||
- QSF Backend : a QofBackend for file:/ QSF objects and maps.
|
||||
qsf-backend.c
|
||||
- QSF Object : Input, export and validation of QSF object files.
|
||||
qsf-xml.c
|
||||
- QSF Map : Validation, processing and conversion routines.
|
||||
qsf-xml-map.c
|
||||
|
||||
To work with QSF, your QOF objects must have:
|
||||
- a create: function in the QofObject definition
|
||||
- a foreach: function in the QofObject definition
|
||||
- QofParam params[] registered with QOF using
|
||||
qof_class_register and containing all necessary parameters
|
||||
to reconstruct this object without any further information.
|
||||
- Logical distinction between those parameters that should be
|
||||
set (have a QofAccessFunc and QofSetterFunc) and those that
|
||||
should only be calculated (only a QofAccessFunc).
|
||||
|
||||
If you begin your QSF session with ::QOF_STDOUT as the book_id,
|
||||
QSF will write to STDOUT - usually a terminal. This is used by QOF
|
||||
applications to provide data streaming. If you don't want terminal
|
||||
output, take care to check the path given to
|
||||
::qof_session_begin - don't try to change it later!
|
||||
|
||||
The XML is validated against the QSF object schema before being
|
||||
written (to file or stdout).
|
||||
|
||||
Check the QofBackendError - don't assume the file is OK.
|
||||
|
||||
@{ */
|
||||
/** @file qof-backend-qsf.h
|
||||
@brief QSF API - Backend, maps, objects and configuration.
|
||||
@author Copyright (C) 2004-2005 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
#ifndef _QOF_BACKEND_QSF_H
|
||||
#define _QOF_BACKEND_QSF_H
|
||||
|
||||
#include <gmodule.h>
|
||||
#include "qoflog.h"
|
||||
#include "qofbackend.h"
|
||||
|
||||
/** \brief Describe this backend to the application.
|
||||
|
||||
Sets QSF Backend Version 0.2, access method = file:
|
||||
|
||||
The version number only changes if:
|
||||
-# The map schema is modified, or
|
||||
-# The object schema is modified, or
|
||||
-# The QofBackendProvider struct is modified in QOF to
|
||||
support new members and QSF can support the new function, or
|
||||
-# The QofBackendOption settings are modified.
|
||||
|
||||
v0.2 introduces the QSF_MAP_FILES QofBackendOption.
|
||||
|
||||
Initialises the backend and provides access to the
|
||||
functions that will load and save the data. Initialises
|
||||
default values for the QofBackendOption KvpFrame.
|
||||
*/
|
||||
G_MODULE_EXPORT void
|
||||
qof_backend_module_init(void);
|
||||
|
||||
/** \name Supported backend configurations
|
||||
@{
|
||||
*/
|
||||
|
||||
/** \brief compression level
|
||||
|
||||
\b Type: gint (KVP_TYPE_GINT64)
|
||||
|
||||
Use GINT_TO_POINTER() to set a integer value between 0 and 9.
|
||||
*/
|
||||
#define QSF_COMPRESS "compression_level"
|
||||
|
||||
/** \brief selected QSF maps
|
||||
|
||||
\b Type: GList* (KVP_TYPE_GLIST) of const char* (QOF_TYPE_STRING) values.
|
||||
|
||||
Defaults to the pre-installed QSF map(s) but may be overridden
|
||||
by the application to pass full path(s) of user selected
|
||||
QSF map file(s).
|
||||
|
||||
If you override the list, it is advisable to only specify the single
|
||||
map file for this QSF object to reduce the amount of error checking
|
||||
required within the backend. Simply reset the QofBackendOption before
|
||||
another file is to be opened. It is up to the application to decide how
|
||||
to offer multiple map selections to the user.
|
||||
|
||||
*/
|
||||
#define QSF_MAP_FILES "selected_map_files"
|
||||
|
||||
/** \brief Encoding string.
|
||||
*
|
||||
* Defaults of UTF-8. */
|
||||
#define QSF_ENCODING "encoding_string"
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif /* _QOF_BACKEND_QSF_H */
|
File diff suppressed because it is too large
Load Diff
@ -1,27 +0,0 @@
|
||||
/***************************************************************************
|
||||
* qsf-xml.h.in
|
||||
*
|
||||
* Mon Dec 20 20:27:48 2004
|
||||
* Copyright 2004 Neil Williams
|
||||
* linux@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.
|
||||
*/
|
||||
|
||||
#define QSF_SCHEMA_DIR "@-QSF_SCHEMA_DIR-@"
|
||||
|
@ -1,117 +0,0 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://qof.sourceforge.net/"
|
||||
xmlns:qsf-map="http://qof.sourceforge.net/">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation xml:lang="en">
|
||||
Query Object Framework Serialization Format (QSF)
|
||||
Copyright 2004 Neil Williams linux@codehelp.co.uk
|
||||
QSF is part of QOF.
|
||||
QOF 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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:element name="qsf-map" qsf-map:type="map-type"/>
|
||||
<xsd:complexType name="map-type">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="definition" qsf-map:type="qsfdefinition"/>
|
||||
<xsd:element name="object" qsf-map:type="mapobject" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfdefinition">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="define" qsf-map:type="qsfdefine" minOccurs="2" maxOccurs="unbounded"/>
|
||||
<xsd:element name="default" qsf-map:type="qsfdefault" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="variable" qsf-map:type="qsfvariable" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="qof_version" type="xsd:positiveInteger"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfdefine">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="e_type" type="xsd:string"/>
|
||||
<xsd:attribute name="foreach" type="xsd:string" use="optional"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfdefault">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfvariable">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="mapobject">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="calculate" qsf-map:type="qsfcalculate" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfcalculate">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="set" qsf-map:type="qsf_set" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="if" qsf-map:type="qsf_if" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="equals" qsf-map:type="qsf_equal" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xsd:element name="else" qsf-map:type="qsf_else" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsf_set">
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="option" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="format" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="object" type="xsd:string" use="optional"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsf_if">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="set" qsf-map:type="qsf_set" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="equals" qsf-map:type="qsf_equal" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="boolean" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="type" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="value" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="string" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsf_else">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="set" qsf-map:type="qsf_set" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="equals" qsf-map:type="qsf_equal" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsf_equal">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="set" qsf-map:type="qsf_set" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="equals" qsf-map:type="qsf_equal" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
|
@ -1,154 +0,0 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://qof.sourceforge.net/"
|
||||
xmlns:qof-qsf="http://qof.sourceforge.net/"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified" xml:lang="en-GB">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation xml:lang="en">
|
||||
Query Object Framework Serialization Format (QSF)
|
||||
Copyright 2004-5 Neil Williams linux@codehelp.co.uk
|
||||
QSF is part of QOF.
|
||||
QOF 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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:element name="qof-qsf" type="qof-qsf:qsftype"/>
|
||||
<xsd:complexType name="qsftype">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="book" type="qof-qsf:qofbook" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qofbook">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="book-guid" type="xsd:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:element name="object" type="qof-qsf:qsfobject" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="count" type="xsd:positiveInteger" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="qsfobject">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="string" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="guid" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:hexBinary">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="boolean" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:boolean">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="numeric" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="date" minOccurs="0" maxOccurs="unbounded" >
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:dateTime">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="gint32" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:int">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="gint64" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:long">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="double" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:double">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="character" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="kvp" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:string">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="path" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="value" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="collection" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:hexBinary">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="choice" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:simpleContent>
|
||||
<xsd:extension base="xsd:hexBinary">
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="type" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="count" type="xsd:positiveInteger" use="optional"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
@ -1,901 +0,0 @@
|
||||
/***************************************************************************
|
||||
* qsf-xml-map.c
|
||||
*
|
||||
* Sat Jan 1 07:31:55 2005
|
||||
* Copyright 2005-2006 Neil Williams
|
||||
* linux@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 Library 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 "config.h"
|
||||
#include <glib.h>
|
||||
#include <libxml/xmlversion.h>
|
||||
#include <libxml/xmlmemory.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include "qof.h"
|
||||
#include "qof-backend-qsf.h"
|
||||
#include "qsf-xml.h"
|
||||
#include "qsf-dir.h"
|
||||
|
||||
#ifndef HAVE_STRPTIME
|
||||
#include "strptime.h"
|
||||
#endif
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QSF;
|
||||
|
||||
static void
|
||||
qsf_date_default_handler(const gchar *default_name, GHashTable *qsf_default_hash,
|
||||
xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
|
||||
{
|
||||
xmlNodePtr output_parent;
|
||||
time_t *qsf_time;
|
||||
gchar date_as_string[QSF_DATE_LENGTH];
|
||||
|
||||
output_parent = xmlAddChild(parent_tag, xmlNewNode(ns,
|
||||
xmlGetProp(import_node, BAD_CAST QSF_OBJECT_TYPE)));
|
||||
xmlNewProp(output_parent, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(import_node, BAD_CAST MAP_VALUE_ATTR));
|
||||
qsf_time = (time_t*)g_hash_table_lookup(qsf_default_hash, default_name);
|
||||
qof_strftime(date_as_string, QSF_DATE_LENGTH, QSF_XSD_TIME, gmtime(qsf_time));
|
||||
xmlNodeAddContent(output_parent, BAD_CAST date_as_string);
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_string_default_handler(const gchar *default_name, GHashTable *qsf_default_hash,
|
||||
xmlNodePtr parent_tag, xmlNodePtr import_node, xmlNsPtr ns)
|
||||
{
|
||||
xmlNodePtr node;
|
||||
xmlChar *output;
|
||||
|
||||
node = xmlAddChild(parent_tag,
|
||||
xmlNewNode(ns, xmlGetProp(import_node, BAD_CAST QSF_OBJECT_TYPE)));
|
||||
xmlNewProp(node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(import_node, BAD_CAST MAP_VALUE_ATTR));
|
||||
output = (xmlChar *)g_hash_table_lookup(qsf_default_hash, default_name);
|
||||
xmlNodeAddContent(node, output);
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_map_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
|
||||
{
|
||||
xmlChar *qof_version, *match;
|
||||
GString *buff;
|
||||
xmlNodePtr child_node;
|
||||
xmlChar *obj_type;
|
||||
|
||||
if (qsf_is_element(child, ns, MAP_DEFINITION_TAG))
|
||||
{
|
||||
qof_version = xmlGetProp(child, BAD_CAST MAP_QOF_VERSION);
|
||||
buff = g_string_new(" ");
|
||||
g_string_printf(buff, "%i", QSF_QOF_VERSION);
|
||||
if (xmlStrcmp(qof_version, BAD_CAST buff->str) != 0)
|
||||
{
|
||||
valid->error_state = ERR_QSF_BAD_QOF_VERSION;
|
||||
return;
|
||||
}
|
||||
for (child_node = child->children; child_node != NULL;
|
||||
child_node = child_node->next)
|
||||
{
|
||||
if (qsf_is_element(child_node, ns, MAP_DEFINE_TAG))
|
||||
{
|
||||
g_hash_table_insert(valid->validation_table,
|
||||
xmlGetProp(child_node, BAD_CAST MAP_E_TYPE),
|
||||
xmlNodeGetContent(child_node));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qsf_is_element(child, ns, MAP_OBJECT_TAG))
|
||||
{
|
||||
match = NULL;
|
||||
obj_type = xmlGetProp(child, BAD_CAST MAP_TYPE_ATTR);
|
||||
match = BAD_CAST g_hash_table_lookup( valid->validation_table, obj_type);
|
||||
if (match)
|
||||
{
|
||||
valid->map_calculated_count++;
|
||||
if (TRUE == qof_class_is_registered((QofIdTypeConst) obj_type))
|
||||
{
|
||||
valid->qof_registered_count++;
|
||||
PINFO (" %s is to be calculated", obj_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
PINFO (" %s to be mapped", obj_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean is_qsf_object_with_map_be(gchar *map_file, qsf_param *params)
|
||||
{
|
||||
xmlDocPtr doc, map_doc;
|
||||
gint valid_count, calc_count;
|
||||
struct qsf_node_iterate iter;
|
||||
xmlNodePtr map_root, object_root;
|
||||
xmlNsPtr map_ns;
|
||||
qsf_validator valid;
|
||||
gchar *path;
|
||||
gchar *map_path;
|
||||
|
||||
g_return_val_if_fail((params != NULL), FALSE);
|
||||
PINFO (" mapfile=%s", map_file);
|
||||
path = g_strdup(params->filepath);
|
||||
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
|
||||
if (path == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
|
||||
return FALSE;
|
||||
}
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
if (map_path == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
map_doc = xmlParseFile(map_path);
|
||||
if (map_doc == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, map_doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(map_doc);
|
||||
valid.map_calculated_count = 0;
|
||||
valid.valid_object_count = 0;
|
||||
valid.qof_registered_count = 0;
|
||||
valid.error_state = ERR_BACKEND_NO_ERR;
|
||||
map_ns = map_root->ns;
|
||||
iter.ns = object_root->ns;
|
||||
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
|
||||
iter.ns = map_ns;
|
||||
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
|
||||
if (valid.error_state != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
qof_backend_set_error(params->be, valid.error_state);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return FALSE;
|
||||
}
|
||||
/* check all counted objects are valid */
|
||||
/* Should be:
|
||||
the same number of valid object calculations as there are defined in the map.
|
||||
And the number of calculations must match the number of unregistered
|
||||
objects plus the number of registered objects defined. */
|
||||
valid_count = g_hash_table_size(valid.validation_table) - valid.map_calculated_count;
|
||||
calc_count = valid.map_calculated_count -
|
||||
(valid.valid_object_count + valid.qof_registered_count);
|
||||
if (valid_count == 0 && calc_count == 0)
|
||||
{
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
qof_backend_get_error(params->be);
|
||||
return TRUE;
|
||||
}
|
||||
qof_backend_set_error(params->be, ERR_QSF_WRONG_MAP);
|
||||
/* the object is OK, only the map is wrong. */
|
||||
PINFO (" Map is wrong. map:%d object:%d reg:%d size:%d result:%d",
|
||||
valid.map_calculated_count, valid.valid_object_count,
|
||||
valid.qof_registered_count,
|
||||
g_hash_table_size(valid.validation_table), valid_count);
|
||||
if (valid_count != 0)
|
||||
{
|
||||
PINFO (" size - map != 0. actual: %d.", valid_count);
|
||||
}
|
||||
if (calc_count != 0)
|
||||
{
|
||||
PINFO (" map - (object + registered) != 0. Actual: %d.", calc_count);
|
||||
}
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file)
|
||||
{
|
||||
xmlDocPtr doc, map_doc;
|
||||
gint valid_count;
|
||||
struct qsf_node_iterate iter;
|
||||
xmlNodePtr map_root, object_root;
|
||||
xmlNsPtr map_ns;
|
||||
qsf_validator valid;
|
||||
gchar *map_path;
|
||||
|
||||
map_path = g_strdup_printf("%s/%s", QSF_SCHEMA_DIR, map_file);
|
||||
if (path == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
if (map_path == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
map_doc = xmlParseFile(map_path);
|
||||
if (map_doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, map_doc))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(map_doc);
|
||||
valid.map_calculated_count = 0;
|
||||
valid.valid_object_count = 0;
|
||||
valid.error_state = ERR_BACKEND_NO_ERR;
|
||||
map_ns = map_root->ns;
|
||||
iter.ns = map_ns;
|
||||
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
|
||||
iter.ns = object_root->ns;
|
||||
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
|
||||
if (valid.error_state != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return FALSE;
|
||||
}
|
||||
valid_count = 0 - g_hash_table_size(valid.validation_table);
|
||||
valid_count += valid.map_calculated_count;
|
||||
valid_count += valid.valid_object_count;
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
if (valid_count == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean is_qsf_map_be(qsf_param *params)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
struct qsf_node_iterate iter;
|
||||
qsf_validator valid;
|
||||
xmlNodePtr map_root;
|
||||
xmlNsPtr map_ns;
|
||||
gchar *path;
|
||||
|
||||
g_return_val_if_fail((params != NULL), FALSE);
|
||||
qof_backend_get_error(params->be);
|
||||
path = g_strdup(params->filepath);
|
||||
if (path == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(doc);
|
||||
map_ns = map_root->ns;
|
||||
iter.ns = map_ns;
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
valid.error_state = ERR_BACKEND_NO_ERR;
|
||||
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
|
||||
if (valid.error_state != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
qof_backend_set_error(params->be, valid.error_state);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return FALSE;
|
||||
}
|
||||
qof_backend_get_error(params->be);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean is_qsf_map(const gchar *path)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
struct qsf_node_iterate iter;
|
||||
qsf_validator valid;
|
||||
xmlNodePtr map_root;
|
||||
xmlNsPtr map_ns;
|
||||
|
||||
g_return_val_if_fail((path != NULL), FALSE);
|
||||
if (path == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_MAP_SCHEMA, doc))
|
||||
{
|
||||
xmlFreeDoc(doc);
|
||||
return FALSE;
|
||||
}
|
||||
map_root = xmlDocGetRootElement(doc);
|
||||
map_ns = map_root->ns;
|
||||
iter.ns = map_ns;
|
||||
valid.error_state = ERR_BACKEND_NO_ERR;
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
qsf_valid_foreach(map_root, qsf_map_validation_handler, &iter, &valid);
|
||||
if (valid.error_state != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return FALSE;
|
||||
}
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qsf_map_default_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params )
|
||||
{
|
||||
xmlChar *qsf_enum;
|
||||
gchar* iterate;
|
||||
|
||||
g_return_if_fail(params->qsf_define_hash != NULL);
|
||||
iterate = NULL;
|
||||
if (qsf_is_element(child, ns, MAP_DEFINE_TAG))
|
||||
{
|
||||
iterate = (gchar*)xmlGetProp(child, BAD_CAST MAP_ITERATE_ATTR);
|
||||
if (qof_util_bool_to_int(iterate) == 1)
|
||||
{
|
||||
params->qof_foreach = (QofIdType)xmlGetProp(child, BAD_CAST MAP_E_TYPE);
|
||||
}
|
||||
if (NULL == g_hash_table_lookup(params->qsf_define_hash,
|
||||
xmlGetProp(child, BAD_CAST MAP_E_TYPE)))
|
||||
{
|
||||
g_hash_table_insert(params->qsf_define_hash,
|
||||
xmlGetProp(child, BAD_CAST MAP_E_TYPE), params->child_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
PERR (" ERR_QSF_BAD_MAP set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (qsf_is_element(child, ns, MAP_DEFAULT_TAG))
|
||||
{
|
||||
if (qsf_strings_equal(xmlGetProp(child, BAD_CAST MAP_TYPE_ATTR), MAP_ENUM_TYPE))
|
||||
{
|
||||
qsf_enum = xmlNodeGetContent(child);
|
||||
/** Use content to discriminate enums in QOF */
|
||||
PERR (" enum todo incomplete");
|
||||
/** \todo FIXME: the default enum value is not used
|
||||
implemented properly or fully handled.
|
||||
*/
|
||||
if (NULL == g_hash_table_lookup(params->qsf_default_hash,
|
||||
xmlNodeGetContent(child)))
|
||||
{
|
||||
g_hash_table_insert(params->qsf_default_hash,
|
||||
xmlNodeGetContent(child), child);
|
||||
}
|
||||
else
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
PERR (" ERR_QSF_BAD_MAP set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
/** Non-enum defaults */
|
||||
else
|
||||
{
|
||||
if (NULL == g_hash_table_lookup(params->qsf_default_hash,
|
||||
xmlGetProp(child, BAD_CAST MAP_NAME_ATTR)))
|
||||
{
|
||||
g_hash_table_insert(params->qsf_default_hash,
|
||||
xmlGetProp(child, BAD_CAST MAP_NAME_ATTR), child);
|
||||
}
|
||||
else
|
||||
/* if(0 != xmlHashAddEntry(params->default_map,
|
||||
xmlGetProp(child_node, MAP_NAME_ATTR), child_node))*/
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_MAP);
|
||||
PERR (" ERR_QSF_BAD_MAP set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_map_top_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
xmlChar *qof_version;
|
||||
GString *buff;
|
||||
struct qsf_node_iterate iter;
|
||||
|
||||
if (!params->qsf_define_hash) return;
|
||||
if (!params->qsf_default_hash) return;
|
||||
ENTER (" child=%s", child->name);
|
||||
if (qsf_is_element(child, ns, MAP_DEFINITION_TAG))
|
||||
{
|
||||
qof_version = xmlGetProp(child, BAD_CAST MAP_QOF_VERSION);
|
||||
buff = g_string_new(" ");
|
||||
g_string_printf(buff, "%i", QSF_QOF_VERSION);
|
||||
if (xmlStrcmp(qof_version, BAD_CAST buff->str) != 0)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_BAD_QOF_VERSION);
|
||||
LEAVE (" ERR_QSF_BAD_QOF_VERSION set");
|
||||
return;
|
||||
}
|
||||
iter.ns = ns;
|
||||
qsf_node_foreach(child, qsf_map_default_handler, &iter, params);
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
static char*
|
||||
qsf_else_set_value(xmlNodePtr parent, GHashTable *default_hash,
|
||||
gchar *content, xmlNsPtr map_ns)
|
||||
{
|
||||
xmlNodePtr cur_node;
|
||||
|
||||
content = NULL;
|
||||
for (cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
if (qsf_is_element(cur_node, map_ns, QSF_CONDITIONAL_SET))
|
||||
{
|
||||
content = (gchar*)xmlNodeGetContent(cur_node);
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handles the set tag in the map.
|
||||
This function will be overhauled once inside QOF
|
||||
QOF hook required for "Lookup in the receiving application"
|
||||
*/
|
||||
static gchar*
|
||||
qsf_set_handler(xmlNodePtr parent, GHashTable *default_hash,
|
||||
gchar *content, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr cur_node, lookup_node;
|
||||
|
||||
ENTER (" lookup problem");
|
||||
content = NULL;
|
||||
for (cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
if (qsf_is_element(cur_node, params->map_ns, QSF_CONDITIONAL_SET))
|
||||
{
|
||||
content = (gchar*)xmlGetProp(cur_node, BAD_CAST QSF_OPTION);
|
||||
if (qsf_strings_equal(xmlGetProp(cur_node, BAD_CAST QSF_OPTION), "qsf_lookup_string"))
|
||||
{
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
xmlNodeGetContent(cur_node));
|
||||
content = (gchar*)xmlGetProp(lookup_node, BAD_CAST MAP_VALUE_ATTR);
|
||||
/** \todo FIXME: do the lookup. type is defined by output object. */
|
||||
/* Find by name, get GncGUID, return GncGUID as string. */
|
||||
g_message("Lookup %s in the receiving application\n", content );
|
||||
LEAVE (" todo");
|
||||
return content;
|
||||
}
|
||||
if (content)
|
||||
{
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(default_hash,
|
||||
xmlNodeGetContent(cur_node));
|
||||
content = (gchar*)xmlGetProp(lookup_node, BAD_CAST "value");
|
||||
return content;
|
||||
}
|
||||
content = (gchar*)xmlGetProp(parent, BAD_CAST "boolean");
|
||||
if (!content)
|
||||
{
|
||||
/** \todo Check qsf_parameter_hash arguments */
|
||||
lookup_node = (xmlNodePtr) g_hash_table_lookup(params->qsf_parameter_hash,
|
||||
xmlGetProp(parent->parent, BAD_CAST MAP_TYPE_ATTR));
|
||||
if (lookup_node)
|
||||
{
|
||||
return (gchar*)xmlNodeGetContent(lookup_node);
|
||||
}
|
||||
LEAVE (" check arguments");
|
||||
return (gchar*)xmlNodeGetContent(cur_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
LEAVE (" null");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_calculate_else(xmlNodePtr param_node, xmlNodePtr child, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr export_node;
|
||||
xmlChar *output_content, *object_data;
|
||||
|
||||
if (qsf_is_element(param_node, params->map_ns, QSF_CONDITIONAL_ELSE))
|
||||
{
|
||||
if (params->boolean_calculation_done == 0)
|
||||
{
|
||||
output_content = object_data = NULL;
|
||||
output_content = BAD_CAST qsf_set_handler(param_node,
|
||||
params->qsf_default_hash, (gchar*)output_content, params);
|
||||
if (output_content == NULL)
|
||||
{
|
||||
output_content = xmlGetProp(param_node, BAD_CAST MAP_TYPE_ATTR);
|
||||
object_data = BAD_CAST qsf_else_set_value(param_node, params->qsf_default_hash,
|
||||
(gchar*)output_content, params->map_ns);
|
||||
output_content = BAD_CAST xmlGetProp( (xmlNodePtr) g_hash_table_lookup(
|
||||
params->qsf_default_hash, object_data), BAD_CAST MAP_VALUE_ATTR);
|
||||
}
|
||||
if (object_data != NULL)
|
||||
{
|
||||
export_node = (xmlNodePtr) g_hash_table_lookup(
|
||||
params->qsf_parameter_hash,
|
||||
xmlGetProp(params->child_node, BAD_CAST QSF_OBJECT_TYPE));
|
||||
object_data = xmlNodeGetContent(export_node);
|
||||
}
|
||||
if (output_content != NULL)
|
||||
{
|
||||
object_data = output_content;
|
||||
}
|
||||
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
|
||||
xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE)));
|
||||
xmlNewProp(export_node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(child, BAD_CAST MAP_VALUE_ATTR));
|
||||
xmlNodeAddContent(export_node, object_data);
|
||||
params->boolean_calculation_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_set_format_value(xmlChar *format, gchar *qsf_time_now_as_string,
|
||||
xmlNodePtr cur_node, qsf_param *params)
|
||||
{
|
||||
gint result;
|
||||
xmlChar *content;
|
||||
time_t *output;
|
||||
struct tm *tmp;
|
||||
time_t tester;
|
||||
xmlNodePtr kl;
|
||||
regex_t reg;
|
||||
|
||||
/** Comments retained - this behaves a little strangely */
|
||||
|
||||
result = 0;
|
||||
if (format == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ENTER (" ");
|
||||
content = xmlNodeGetContent(cur_node);
|
||||
output = (time_t*) g_hash_table_lookup(params->qsf_default_hash, content);
|
||||
if (!output)
|
||||
{
|
||||
/** No default time set, use the object time */
|
||||
/** fill the time structs with temp data */
|
||||
tester = time(NULL);
|
||||
tmp = gmtime(&tester);
|
||||
/** Lookup the object value to read */
|
||||
/** \todo qsf_parameter_hash check correct arguments */
|
||||
kl = (xmlNodePtr) g_hash_table_lookup(params->qsf_parameter_hash, content);
|
||||
if (!kl)
|
||||
{
|
||||
LEAVE (" no suitable date set.");
|
||||
return;
|
||||
}
|
||||
/** Read the object value as a dateTime */
|
||||
strptime((char*)xmlNodeGetContent(kl), QSF_XSD_TIME, tmp);
|
||||
if (!tmp)
|
||||
{
|
||||
LEAVE (" empty date field in QSF object.\n");
|
||||
return;
|
||||
}
|
||||
tester = mktime(tmp);
|
||||
output = &tester;
|
||||
}
|
||||
result = regcomp(®, "%[a-zA-Z]", REG_EXTENDED | REG_NOSUB);
|
||||
result = regexec(®, (gchar*)format, (size_t)0, NULL, 0);
|
||||
if (result == REG_NOMATCH)
|
||||
{
|
||||
format = BAD_CAST "%F";
|
||||
}
|
||||
regfree(®);
|
||||
/** QSF_DATE_LENGTH preset for all internal and QSF_XSD_TIME string formats.
|
||||
*/
|
||||
qof_strftime(qsf_time_now_as_string, QSF_DATE_LENGTH, (char*)format, gmtime(output));
|
||||
LEAVE (" ok");
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_boolean_set_value(xmlNodePtr parent, qsf_param *params,
|
||||
gchar *content, xmlNsPtr map_ns)
|
||||
{
|
||||
xmlNodePtr cur_node;
|
||||
xmlChar *boolean_name;
|
||||
|
||||
boolean_name = NULL;
|
||||
for (cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
if (qsf_is_element(cur_node, map_ns, QSF_CONDITIONAL_SET))
|
||||
{
|
||||
boolean_name = xmlGetProp(cur_node, BAD_CAST QSF_FORMATTING_OPTION);
|
||||
qsf_set_format_value(boolean_name, content, cur_node, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_calculate_conditional(xmlNodePtr param_node, xmlNodePtr child, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr export_node;
|
||||
xmlChar *output_content;
|
||||
|
||||
output_content = NULL;
|
||||
if (qsf_is_element(param_node, params->map_ns, QSF_CONDITIONAL))
|
||||
{
|
||||
if (params->boolean_calculation_done == 0)
|
||||
{
|
||||
/* set handler */
|
||||
output_content = BAD_CAST qsf_set_handler(param_node, params->qsf_default_hash,
|
||||
(gchar*)output_content, params);
|
||||
/* If the 'if' contains a boolean that has a default value */
|
||||
if (output_content == NULL)
|
||||
{
|
||||
if (NULL != xmlGetProp(param_node, BAD_CAST QSF_BOOLEAN_DEFAULT))
|
||||
{
|
||||
output_content = xmlGetProp( (xmlNodePtr) g_hash_table_lookup(
|
||||
params->qsf_default_hash, xmlGetProp(param_node,
|
||||
BAD_CAST QSF_BOOLEAN_DEFAULT) ), BAD_CAST MAP_VALUE_ATTR);
|
||||
}
|
||||
/* Is the default set to true? */
|
||||
if ( 0 == qsf_compare_tag_strings(output_content, QSF_XML_BOOLEAN_TEST))
|
||||
{
|
||||
qsf_boolean_set_value(param_node, params, (gchar*)output_content, params->map_ns);
|
||||
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
|
||||
xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE)));
|
||||
xmlNewProp(export_node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(child, BAD_CAST MAP_VALUE_ATTR));
|
||||
xmlNodeAddContent(export_node, output_content);
|
||||
params->boolean_calculation_done = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_add_object_tag(qsf_param *params, gint count)
|
||||
{
|
||||
xmlNodePtr extra_node;
|
||||
GString *str;
|
||||
xmlChar *property;
|
||||
|
||||
str = g_string_new (" ");
|
||||
g_string_printf(str, "%i", count);
|
||||
extra_node = NULL;
|
||||
extra_node = xmlAddChild(params->output_node,
|
||||
xmlNewNode(params->qsf_ns, BAD_CAST QSF_OBJECT_TAG));
|
||||
xmlNewProp(extra_node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(params->convert_node, BAD_CAST QSF_OBJECT_TYPE));
|
||||
property = xmlCharStrdup(str->str);
|
||||
xmlNewProp(extra_node, BAD_CAST QSF_OBJECT_COUNT, property);
|
||||
params->lister = extra_node;
|
||||
}
|
||||
|
||||
static gint
|
||||
identify_source_func(gconstpointer qsf_object, gconstpointer map)
|
||||
{
|
||||
return safe_strcmp(((qsf_objects*)qsf_object)->object_type, (QofIdType)map);
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_map_calculate_output(xmlNodePtr param_node, xmlNodePtr child, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr export_node;
|
||||
xmlChar *output_content;
|
||||
xmlNodePtr node;
|
||||
GList *source;
|
||||
|
||||
DEBUG (" %s", xmlNodeGetContent(param_node));
|
||||
output_content = xmlNodeGetContent(param_node);
|
||||
/* source refers to the source object that provides the data */
|
||||
source = g_list_find_custom(params->qsf_object_list,
|
||||
BAD_CAST xmlGetProp(param_node, BAD_CAST MAP_OBJECT_ATTR),
|
||||
identify_source_func);
|
||||
if (!source) return;
|
||||
params->object_set = source->data;
|
||||
node = g_hash_table_lookup(params->object_set->parameters, output_content);
|
||||
export_node = xmlAddChild(params->lister, xmlNewNode(params->qsf_ns,
|
||||
xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE)));
|
||||
xmlNewProp(export_node, BAD_CAST QSF_OBJECT_TYPE,
|
||||
xmlGetProp(child, BAD_CAST MAP_VALUE_ATTR));
|
||||
if (node)
|
||||
{
|
||||
xmlNodeAddContent(export_node, xmlNodeGetContent(node));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_map_object_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr param_node;
|
||||
xmlNsPtr map_ns, qsf_ns;
|
||||
gint result;
|
||||
|
||||
map_ns = ns;
|
||||
qsf_ns = params->qsf_ns;
|
||||
param_node = NULL;
|
||||
result = 0;
|
||||
if (child == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ns == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
params->boolean_calculation_done = 0;
|
||||
|
||||
if (qsf_is_element(child, map_ns, MAP_CALCULATE_TAG))
|
||||
{
|
||||
params->boolean_calculation_done = 0;
|
||||
/* read the child nodes to prepare the calculation. */
|
||||
for (param_node = child->children; param_node != NULL;
|
||||
param_node = param_node->next)
|
||||
{
|
||||
if (qsf_is_element(param_node, map_ns, QSF_CONDITIONAL_SET))
|
||||
{
|
||||
/* Map the pre-defined defaults */
|
||||
if (0 == qsf_compare_tag_strings(
|
||||
xmlNodeGetContent(param_node), "qsf_enquiry_date"))
|
||||
{
|
||||
qsf_string_default_handler("qsf_enquiry_date",
|
||||
params->qsf_default_hash, params->lister, child, qsf_ns);
|
||||
}
|
||||
if (0 == qsf_compare_tag_strings(
|
||||
xmlNodeGetContent(param_node), "qsf_time_now"))
|
||||
{
|
||||
qsf_date_default_handler("qsf_time_now",
|
||||
params->qsf_default_hash, params->lister, child, qsf_ns);
|
||||
}
|
||||
if (0 == qsf_compare_tag_strings(
|
||||
xmlNodeGetContent(param_node), "qsf_time_string"))
|
||||
{
|
||||
qsf_string_default_handler("qsf_time_string",
|
||||
params->qsf_default_hash, params->lister, child, qsf_ns);
|
||||
}
|
||||
qsf_map_calculate_output(param_node, child, params);
|
||||
}
|
||||
qsf_calculate_conditional( param_node, child, params);
|
||||
qsf_calculate_else(param_node, child, params);
|
||||
}
|
||||
/* calculate_map currently not in use */
|
||||
/* ensure uniqueness of the key before re-instating */
|
||||
/* result = xmlHashAddEntry2(calculate_map,
|
||||
xmlGetProp(child_node, MAP_TYPE_ATTR),
|
||||
xmlGetProp(child_node, MAP_VALUE_ATTR), child_node);
|
||||
if(result != 0) {
|
||||
printf("add entry to calculate hash failed. %s\t%s\t%s.\n",
|
||||
xmlGetProp(child_node, MAP_TYPE_ATTR),
|
||||
xmlGetProp(child_node, MAP_VALUE_ATTR), child_node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
is_qsf_object_with_map(path, map_path);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iterator_cb(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
gchar *object_name;
|
||||
|
||||
/* count the number of iterators in the QSF file */
|
||||
if (qsf_is_element(child, ns, QSF_OBJECT_TAG))
|
||||
{
|
||||
object_name = (gchar *)xmlGetProp(child, BAD_CAST QSF_OBJECT_TYPE);
|
||||
if (0 == safe_strcmp(object_name, params->qof_foreach))
|
||||
{
|
||||
params->foreach_limit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlDocPtr
|
||||
qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params)
|
||||
{
|
||||
/* mapDoc : map document. qsf_root: incoming QSF root node. */
|
||||
struct qsf_node_iterate iter;
|
||||
xmlDocPtr output_doc;
|
||||
xmlNode *cur_node;
|
||||
xmlNode *map_root, *output_root;
|
||||
|
||||
g_return_val_if_fail((mapDoc && qsf_root && params), NULL);
|
||||
ENTER (" root=%s", qsf_root->name);
|
||||
/* prepare the intermediary document */
|
||||
iter.ns = params->qsf_ns;
|
||||
output_doc = xmlNewDoc(BAD_CAST QSF_XML_VERSION);
|
||||
output_root = xmlNewNode(NULL, BAD_CAST QSF_ROOT_TAG);
|
||||
xmlDocSetRootElement(output_doc, output_root);
|
||||
xmlSetNs(output_root, params->qsf_ns);
|
||||
params->output_node = xmlNewChild(output_root, params->qsf_ns,
|
||||
BAD_CAST QSF_BOOK_TAG, NULL);
|
||||
xmlNewProp(params->output_node, BAD_CAST QSF_BOOK_COUNT, BAD_CAST "1");
|
||||
/* parse the incoming QSF */
|
||||
qsf_book_node_handler(qsf_root->children->next, params->qsf_ns, params);
|
||||
/* parse the map and calculate the values */
|
||||
map_root = xmlDocGetRootElement(mapDoc);
|
||||
params->foreach_limit = 0;
|
||||
iter.ns = params->map_ns;
|
||||
qsf_node_foreach(map_root, qsf_map_top_node_handler, &iter, params);
|
||||
/* identify the entities of iterator type. */
|
||||
iter.ns = params->qsf_ns;
|
||||
qsf_node_foreach(qsf_root->children->next, iterator_cb, &iter, params);
|
||||
|
||||
params->count = 0;
|
||||
for (cur_node = map_root->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
params->convert_node = cur_node;
|
||||
if (qsf_is_element(cur_node, params->map_ns, MAP_OBJECT_TAG))
|
||||
{
|
||||
gint i;
|
||||
|
||||
params->lister = NULL;
|
||||
/* cur_node describes the target object */
|
||||
if (!qof_class_is_registered(
|
||||
(QofIdTypeConst)xmlGetProp(cur_node,
|
||||
BAD_CAST MAP_TYPE_ATTR)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
qsf_add_object_tag(params, params->count);
|
||||
params->count++;
|
||||
iter.ns = params->map_ns;
|
||||
for (i = 0; i < params->foreach_limit; i++)
|
||||
{
|
||||
qsf_node_foreach(cur_node, qsf_map_object_handler, &iter, params);
|
||||
params->qsf_object_list = g_list_next(params->qsf_object_list);
|
||||
qsf_add_object_tag(params, params->count);
|
||||
params->count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
params->file_type = OUR_QSF_OBJ;
|
||||
/* use for debugging */
|
||||
/* xmlSaveFormatFileEnc("-", output_doc, "UTF-8", 1);*/
|
||||
LEAVE (" ");
|
||||
return output_doc;
|
||||
}
|
@ -1,413 +0,0 @@
|
||||
/***************************************************************************
|
||||
* qsf-xml.c
|
||||
*
|
||||
* Fri Nov 26 19:29:47 2004
|
||||
* Copyright 2004,2005,2006 Neil Williams <linux@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 Library 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 "config.h"
|
||||
#include <glib.h>
|
||||
#include <libxml/xmlversion.h>
|
||||
#include <libxml/xmlmemory.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include "qof.h"
|
||||
#include "qof-backend-qsf.h"
|
||||
#include "qsf-dir.h"
|
||||
#include "qsf-xml.h"
|
||||
|
||||
static QofLogModule log_module = QOF_MOD_QSF;
|
||||
|
||||
gint
|
||||
qsf_compare_tag_strings(const xmlChar *node_name, gchar *tag_name)
|
||||
{
|
||||
return xmlStrcmp(node_name, (const xmlChar *)tag_name);
|
||||
}
|
||||
|
||||
gint
|
||||
qsf_strings_equal(const xmlChar *node_name, gchar *tag_name)
|
||||
{
|
||||
if (0 == qsf_compare_tag_strings(node_name, tag_name))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint
|
||||
qsf_is_element(xmlNodePtr a, xmlNsPtr ns, gchar *c)
|
||||
{
|
||||
g_return_val_if_fail(a != NULL, 0);
|
||||
g_return_val_if_fail(ns != NULL, 0);
|
||||
g_return_val_if_fail(c != NULL, 0);
|
||||
if ((a->ns == ns) && (a->type == XML_ELEMENT_NODE) &&
|
||||
qsf_strings_equal(a->name, c))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint
|
||||
qsf_check_tag(qsf_param *params, gchar *qof_type)
|
||||
{
|
||||
return qsf_is_element(params->child_node, params->qsf_ns, qof_type);
|
||||
}
|
||||
|
||||
gboolean
|
||||
qsf_is_valid(const gchar *schema_dir, const gchar* schema_filename, xmlDocPtr doc)
|
||||
{
|
||||
xmlSchemaParserCtxtPtr qsf_schema_file;
|
||||
xmlSchemaPtr qsf_schema;
|
||||
xmlSchemaValidCtxtPtr qsf_context;
|
||||
gchar *schema_path;
|
||||
gint result;
|
||||
|
||||
g_return_val_if_fail(doc || schema_filename, FALSE);
|
||||
schema_path = g_strdup_printf("%s/%s", schema_dir, schema_filename);
|
||||
qsf_schema_file = xmlSchemaNewParserCtxt(schema_path);
|
||||
qsf_schema = xmlSchemaParse(qsf_schema_file);
|
||||
qsf_context = xmlSchemaNewValidCtxt(qsf_schema);
|
||||
result = xmlSchemaValidateDoc(qsf_context, doc);
|
||||
xmlSchemaFreeParserCtxt(qsf_schema_file);
|
||||
xmlSchemaFreeValidCtxt(qsf_context);
|
||||
xmlSchemaFree(qsf_schema);
|
||||
g_free(schema_path);
|
||||
if (result == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
qsf_valid_foreach(xmlNodePtr parent, qsf_validCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_validator *valid)
|
||||
{
|
||||
xmlNodePtr cur_node;
|
||||
|
||||
iter->v_fcn = &cb;
|
||||
for (cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
cb(cur_node, iter->ns, valid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qsf_node_foreach(xmlNodePtr parent, qsf_nodeCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_param *params)
|
||||
{
|
||||
xmlNodePtr cur_node;
|
||||
|
||||
g_return_if_fail(iter->ns);
|
||||
iter->fcn = &cb;
|
||||
for (cur_node = parent->children; cur_node != NULL; cur_node = cur_node->next)
|
||||
{
|
||||
cb(cur_node, iter->ns, params);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid)
|
||||
{
|
||||
xmlNodePtr cur_node;
|
||||
xmlChar *object_declaration;
|
||||
guint count;
|
||||
|
||||
count = 0;
|
||||
for (cur_node = child->children; cur_node != NULL;
|
||||
cur_node = cur_node->next)
|
||||
{
|
||||
if (qsf_is_element(cur_node, ns, QSF_OBJECT_TAG))
|
||||
{
|
||||
object_declaration = xmlGetProp(cur_node, BAD_CAST QSF_OBJECT_TYPE);
|
||||
count = g_hash_table_size(valid->validation_table);
|
||||
g_hash_table_insert(valid->validation_table, object_declaration, xmlNodeGetContent(cur_node));
|
||||
if (g_hash_table_size(valid->validation_table) > count)
|
||||
{
|
||||
valid->valid_object_count++;
|
||||
if (TRUE == qof_class_is_registered((QofIdTypeConst) object_declaration))
|
||||
{
|
||||
valid->qof_registered_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gboolean is_our_qsf_object(const gchar *path)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
struct qsf_node_iterate iter;
|
||||
xmlNodePtr object_root;
|
||||
qsf_validator valid;
|
||||
gint table_count;
|
||||
|
||||
g_return_val_if_fail((path != NULL), FALSE);
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
PINFO (" validation failed %s %s %s", QSF_SCHEMA_DIR,
|
||||
QSF_OBJECT_SCHEMA, path);
|
||||
xmlFreeDoc(doc);
|
||||
return FALSE;
|
||||
}
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
/* check that all objects in the file are already registered in QOF */
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
valid.qof_registered_count = 0;
|
||||
valid.valid_object_count = 0;
|
||||
iter.ns = object_root->ns;
|
||||
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
|
||||
table_count = g_hash_table_size(valid.validation_table);
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
if (table_count == valid.qof_registered_count)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean is_qsf_object(const gchar *path)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
|
||||
g_return_val_if_fail((path != NULL), FALSE);
|
||||
if (path == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
xmlFreeDoc(doc);
|
||||
return FALSE;
|
||||
}
|
||||
xmlFreeDoc(doc);
|
||||
/* Note cannot test against a map here, so if the file is valid QSF,
|
||||
accept it and work out the details later. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean is_our_qsf_object_be(qsf_param *params)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
struct qsf_node_iterate iter;
|
||||
xmlNodePtr object_root;
|
||||
qsf_validator valid;
|
||||
gint table_count;
|
||||
gchar *path;
|
||||
|
||||
g_return_val_if_fail((params != NULL), FALSE);
|
||||
path = g_strdup(params->filepath);
|
||||
if (path == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
if (params->file_type != QSF_UNDEF)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
|
||||
return FALSE;
|
||||
}
|
||||
params->file_type = IS_QSF_OBJ;
|
||||
object_root = xmlDocGetRootElement(doc);
|
||||
valid.validation_table = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
valid.qof_registered_count = 0;
|
||||
iter.ns = object_root->ns;
|
||||
qsf_valid_foreach(object_root, qsf_object_validation_handler, &iter, &valid);
|
||||
table_count = g_hash_table_size(valid.validation_table);
|
||||
if (table_count == valid.qof_registered_count)
|
||||
{
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
qof_backend_set_error(params->be, ERR_BACKEND_NO_ERR);
|
||||
return TRUE;
|
||||
}
|
||||
g_hash_table_destroy(valid.validation_table);
|
||||
qof_backend_set_error(params->be, ERR_QSF_NO_MAP);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean is_qsf_object_be(qsf_param *params)
|
||||
{
|
||||
gboolean result;
|
||||
xmlDocPtr doc;
|
||||
GList *maps;
|
||||
gchar *path;
|
||||
|
||||
g_return_val_if_fail((params != NULL), FALSE);
|
||||
path = g_strdup(params->filepath);
|
||||
if (path == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_FILE_NOT_FOUND);
|
||||
return FALSE;
|
||||
}
|
||||
/* skip validation if is_our_qsf_object has already been called. */
|
||||
if (ERR_QSF_INVALID_OBJ == qof_backend_get_error(params->be))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (params->file_type == QSF_UNDEF)
|
||||
{
|
||||
doc = xmlParseFile(path);
|
||||
if (doc == NULL)
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_FILEIO_PARSE_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
if (TRUE != qsf_is_valid(QSF_SCHEMA_DIR, QSF_OBJECT_SCHEMA, doc))
|
||||
{
|
||||
qof_backend_set_error(params->be, ERR_QSF_INVALID_OBJ);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
result = FALSE;
|
||||
/* retrieve list of maps from config frame. */
|
||||
for (maps = params->map_files; maps; maps = maps->next)
|
||||
{
|
||||
QofBackendError err;
|
||||
result = is_qsf_object_with_map_be(maps->data, params);
|
||||
err = qof_backend_get_error(params->be);
|
||||
if ((err == ERR_BACKEND_NO_ERR) && result)
|
||||
{
|
||||
params->map_path = maps->data;
|
||||
PINFO ("map chosen = %s", params->map_path);
|
||||
break;
|
||||
}
|
||||
/* pop the error back on the stack. */
|
||||
else
|
||||
{
|
||||
qof_backend_set_error(params->be, err);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_supported_data_types(gpointer type, gpointer user_data)
|
||||
{
|
||||
qsf_param *params;
|
||||
|
||||
g_return_if_fail(user_data != NULL);
|
||||
g_return_if_fail(type != NULL);
|
||||
params = (qsf_param*) user_data;
|
||||
if (qsf_is_element(params->param_node, params->qsf_ns, (gchar*)type))
|
||||
{
|
||||
g_hash_table_insert(params->qsf_parameter_hash,
|
||||
xmlGetProp(params->param_node, BAD_CAST QSF_OBJECT_TYPE), params->param_node);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qsf_parameter_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
|
||||
{
|
||||
params->param_node = child;
|
||||
g_slist_foreach(params->supported_types, qsf_supported_data_types, params);
|
||||
}
|
||||
|
||||
void
|
||||
qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params)
|
||||
{
|
||||
struct qsf_node_iterate iter;
|
||||
qsf_objects *object_set;
|
||||
gchar *tail, *object_count_s;
|
||||
gint64 c;
|
||||
|
||||
g_return_if_fail(child != NULL);
|
||||
g_return_if_fail(qsf_ns != NULL);
|
||||
params->qsf_ns = qsf_ns;
|
||||
if (qsf_is_element(child, qsf_ns, QSF_OBJECT_TAG))
|
||||
{
|
||||
params->qsf_parameter_hash = NULL;
|
||||
c = 0;
|
||||
object_set = g_new(qsf_objects, 1);
|
||||
params->object_set = object_set;
|
||||
object_set->object_count = 0;
|
||||
object_set->parameters = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
object_set->object_type = g_strdup((gchar*)xmlGetProp(child,
|
||||
BAD_CAST QSF_OBJECT_TYPE));
|
||||
object_count_s = g_strdup((gchar*)xmlGetProp(child,
|
||||
BAD_CAST QSF_OBJECT_COUNT));
|
||||
c = (gint64)strtol(object_count_s, &tail, 0);
|
||||
object_set->object_count = (gint)c;
|
||||
g_free(object_count_s);
|
||||
params->qsf_object_list = g_list_prepend(params->qsf_object_list, object_set);
|
||||
iter.ns = qsf_ns;
|
||||
params->qsf_parameter_hash = object_set->parameters;
|
||||
qsf_node_foreach(child, qsf_parameter_handler, &iter, params);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qsf_book_node_handler(xmlNodePtr child, xmlNsPtr ns, qsf_param *params)
|
||||
{
|
||||
gchar *book_count_s, *tail;
|
||||
gint book_count;
|
||||
xmlNodePtr child_node;
|
||||
struct qsf_node_iterate iter;
|
||||
gchar *buffer;
|
||||
GncGUID book_guid;
|
||||
|
||||
g_return_if_fail(child);
|
||||
g_return_if_fail(params);
|
||||
ENTER (" child=%s", child->name);
|
||||
if (qsf_is_element(child, ns, QSF_BOOK_TAG))
|
||||
{
|
||||
book_count_s = (gchar*)xmlGetProp(child, BAD_CAST QSF_BOOK_COUNT);
|
||||
if (book_count_s)
|
||||
{
|
||||
book_count = (gint)strtol(book_count_s, &tail, 0);
|
||||
/* More than one book not currently supported. */
|
||||
g_return_if_fail(book_count == 1);
|
||||
}
|
||||
iter.ns = ns;
|
||||
child_node = child->children->next;
|
||||
if (qsf_is_element(child_node, ns, QSF_BOOK_GUID))
|
||||
{
|
||||
DEBUG (" trying to set book GncGUID");
|
||||
buffer = g_strdup((gchar*)xmlNodeGetContent(child_node));
|
||||
g_return_if_fail(TRUE == string_to_guid(buffer, &book_guid));
|
||||
qof_instance_set_guid(QOF_INSTANCE(params->book), &book_guid);
|
||||
xmlNewChild(params->output_node, params->qsf_ns,
|
||||
BAD_CAST QSF_BOOK_GUID, BAD_CAST buffer);
|
||||
g_free(buffer);
|
||||
}
|
||||
qsf_node_foreach(child, qsf_object_node_handler, &iter, params);
|
||||
}
|
||||
LEAVE (" ");
|
||||
}
|
@ -1,702 +0,0 @@
|
||||
/***************************************************************************
|
||||
* qsf-xml.h
|
||||
*
|
||||
* Fri Nov 26 19:29:47 2004
|
||||
* Copyright 2004,2005,2006 Neil Williams <linux@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 Library 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 QSF_XML_H
|
||||
#define QSF_XML_H
|
||||
|
||||
/** @file qsf-xml.h
|
||||
@brief Private QSF header - not for use by applications
|
||||
@author Copyright (C) 2004-2005 Neil Williams <linux@codehelp.co.uk>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <regex.h>
|
||||
#include <time.h>
|
||||
#include "qof.h"
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(String) dgettext (GETTEXT_PACKAGE, String)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
QSF_UNDEF = 0, /**< Initial undefined value. */
|
||||
IS_QSF_MAP, /**< A QSF map */
|
||||
IS_QSF_OBJ, /**< A QSF object without a map - it may or may not need one. */
|
||||
HAVE_QSF_MAP, /**< A QSF object with the map it needs. */
|
||||
OUR_QSF_OBJ, /**< A QSF object that can be loaded without a map. */
|
||||
} qsf_type;
|
||||
|
||||
/** \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
|
||||
many-to-many conversions where an invoice can receive data from an incoming
|
||||
expense AND datebook and use data from an incoming contacts object to lookup
|
||||
the customer for the invoice.
|
||||
*/
|
||||
typedef struct qsf_object_set
|
||||
{
|
||||
GHashTable *parameters;
|
||||
QofIdType object_type;
|
||||
gint object_count;
|
||||
} qsf_objects;
|
||||
|
||||
#define QSF_QOF_VERSION QOF_OBJECT_VERSION /**< QOF Version check.
|
||||
|
||||
Make sure the same version of QOF is in use in both applications.
|
||||
*/
|
||||
/** @name QSF Object XML
|
||||
|
||||
@{ */
|
||||
#define QSF_ROOT_TAG "qof-qsf" /**< The top level root tag */
|
||||
#define QSF_DEFAULT_NS "http://qof.sourceforge.net/" /**< Default namespace for QSF root tag
|
||||
|
||||
The map namespace is not included as maps are not currently written out by QOF.
|
||||
*/
|
||||
#define QSF_DATE_LENGTH MAX_DATE_LENGTH /**< Max length of QSF_XSD_TIME.
|
||||
|
||||
MAX_DATE_LENGTH itself is defined in gnc-date.h */
|
||||
#define QSF_BOOK_TAG "book" /**< First level child: book tag - the ::QofBook. */
|
||||
#define QSF_BOOK_GUID "book-guid" /**< QOF GncGUID tag for the QofBook
|
||||
described by this QSF object file */
|
||||
#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 */
|
||||
#define QSF_OBJECT_COUNT "count" /**< Sequential counter for each QSF object
|
||||
in this file */
|
||||
#define QSF_XML_VERSION "1.0" /**< The current XML version. */
|
||||
|
||||
/** @} */
|
||||
/** @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 GncGUID $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. */
|
||||
/** @} */
|
||||
/** @name QSF Map XML
|
||||
|
||||
@{ */
|
||||
#define MAP_ROOT_TAG "qsf-map" /**< Top level root tag for QSF Maps */
|
||||
#define MAP_DEFINITION_TAG "definition" /**< Second level container for defined objects
|
||||
|
||||
Attributes: qof_version - Taken from the QOF_OBJECT_VERSION macro in QOF,
|
||||
At the time of QSF development, QOF_OBJECT_VERSION is defined as 3. All
|
||||
QSF maps and QSF objects must use the same qof_version which in turn must
|
||||
match the QOF_OBJECT_VERSION for the QOF library in use by the calling process.
|
||||
|
||||
No text content allowed.
|
||||
*/
|
||||
#define MAP_DEFINE_TAG "define" /**< defines each object supported by this QSF map
|
||||
|
||||
Attributes: e_type Copied directly from the QofObject definition.
|
||||
Content: The full QofObject description for the defined QOF object.
|
||||
*/
|
||||
#define MAP_ITERATE_ATTR "foreach" /**< Dictate which object type is the basis
|
||||
for iteration in a hierarchical object set. */
|
||||
#define MAP_DEFAULT_TAG "default" /**< User editable defaults for data not
|
||||
available within the available QSF objects.
|
||||
|
||||
Some defaults will relate to how to format descriptive dates, whether discount
|
||||
should be considered, which account to use for certain QSF data from applications
|
||||
that do not use accounts.
|
||||
|
||||
Some defaults are pre-defined and cannot be over-written:
|
||||
- qsf_time_now
|
||||
- qsf_time_string
|
||||
|
||||
Attributes (All are mandatory):
|
||||
|
||||
\a name The text name for this default. Certain pre-defined defaults exist but
|
||||
user- or map-defined defaults can have any unique text name. Spaces are \b NOT allowed,
|
||||
use undersccores instead. The value of name must not duplicate any existing default,
|
||||
define, object or parameter unless the special type, enum, is used.
|
||||
|
||||
\a type QOF_TYPE - must be one of the recognised QOF data types for the
|
||||
qof_version in use or the special type, enum.
|
||||
|
||||
\a value Text representation of the required value. For numeric, use the format
|
||||
[0-9]?/[0-9]?
|
||||
|
||||
\attention Using boolean defaults
|
||||
|
||||
A boolean default is not output in the QSF directly, instead the value is
|
||||
used in the calculations to modify certain values. If the boolean default
|
||||
is set to true, the if statement containing the boolean name will be evaluated.
|
||||
If the boolean default is set to false, the corresponding else will be evaluted.
|
||||
Make sure your calculations contain an appropriate else statement so that the
|
||||
boolean value can be adjusted without invalidating the map!
|
||||
|
||||
QSF deals with partial QofBooks - each object is fully described but the
|
||||
book does not have to contain any specific object types or have any
|
||||
particular structure. To merge partial books into usual QofBook data
|
||||
sources, the map must deal with entities that need to be referenced in
|
||||
the target QofBook but which simply do not exist in the QofBook used to generate
|
||||
the QSF. e.g. pilot-link knows nothing of Accounts yet when QSF creates
|
||||
a gncInvoice from qof-datebook, gncInvoice needs to know the GncGUID of
|
||||
certain accounts in the target QofBook. This is handled in the map
|
||||
by specifying the name of the account as a default for that map. When imported,
|
||||
the QSF QofBackend looks up the object required using the name of
|
||||
the parameter to obtain the parameter type. This is the only situation
|
||||
where QSF converts between QOF data types. A string description of the
|
||||
required object is converted to the GncGUID for that specific entity. The
|
||||
map cannot contain the GncGUID as it is generic and used by multiple users.
|
||||
|
||||
\attention Using enumerators
|
||||
- enum types are the only defaults that are allowed to use the same name value
|
||||
more than once.
|
||||
- enum types are used to increase the readability of a QSF map.
|
||||
- The enum name acts to group the enum values together - in a similar fashion to
|
||||
radio buttons in HTML forms.
|
||||
- enum types are used only where the QOF object itself uses an enum type.
|
||||
|
||||
e.g. the tax_included enum type allows maps to use the full name of the enum
|
||||
value GNC_TAXINCLUDED_YES, instead of the cryptic digit value, 1.
|
||||
|
||||
*/
|
||||
#define MAP_OBJECT_TAG "object" /**< Contains all the calculations to make one
|
||||
object from others.
|
||||
|
||||
Note that creating an object for the import application can involve using data
|
||||
from more than one QSF object, as well as defaults and lookups in the import
|
||||
application itself. Conditionals, simple arithmetic and date/time formatting
|
||||
options are also available.
|
||||
*/
|
||||
#define MAP_CALCULATE_TAG "calculate" /**< One calculation for every parameter
|
||||
that needs to be set.
|
||||
|
||||
QSF follows the same rule as qof_book_merge. Only if a getter and a setter
|
||||
function are defined for a parameter is it available to QSF. If a ::QofAccessFunc
|
||||
and ::QofSetterFunc are both defined for any QofObject parameter, that parameter
|
||||
\b MUST be calculated in any map that defines that object.
|
||||
*/
|
||||
#define MAP_QOF_VERSION "qof_version" /**< This is the QOF_OBJECT_VERSION from QOF.
|
||||
|
||||
QSF maps may need to be updated if QOF itself is upgraded. This setting is coded
|
||||
into QOF and maps for one version cannot necessarily be used by other versions.
|
||||
At the first release of QSF, QOF_OBJECT_VERSION = 3.
|
||||
*/
|
||||
#define MAP_NAME_ATTR "name" /**< The name of the default setting.
|
||||
|
||||
Use this name to refer to the value of this default in the map calculations.
|
||||
|
||||
Make sure that the type of this default matches the type of the parameter being
|
||||
set by the parent calculation!
|
||||
*/
|
||||
#define MAP_TYPE_ATTR "type" /**< QSF will NOT convert between QOF types.
|
||||
|
||||
QSF will allow a conditional to use a parameter of one type to determine the
|
||||
value from a parameter of another type, but the final value assigned \b MUST be
|
||||
of the same type as the parent calculation.
|
||||
*/
|
||||
#define MAP_VALUE_ATTR "value" /**< The value of the tag, used in defaults and
|
||||
calculations.
|
||||
|
||||
The value of a default is a string representation of the value to be inserted into
|
||||
the calculation where the default is used.
|
||||
|
||||
The value of a calculation is the name of the parameter that will be set by that
|
||||
calculation.
|
||||
*/
|
||||
#define MAP_OBJECT_ATTR "object" /**< The object to use to provide the data
|
||||
being set using the map.*/
|
||||
#define MAP_E_TYPE "e_type" /**< Validates the objects defined in the map
|
||||
|
||||
The e_type will be used to match incoming QSF objects with the relevant QSF map.
|
||||
The value of the e_type must be the value of the e_type for that object in the
|
||||
originating QOF application. The define tag must contain the value of the description
|
||||
of the same object in the same originating QOF application.
|
||||
*/
|
||||
/** \todo enum is an attempt to make enumerator values descriptive in the maps
|
||||
and QSF (possibly). Not working yet. */
|
||||
#define MAP_ENUM_TYPE "enum"
|
||||
|
||||
/** \brief A specific boolean default for this map.
|
||||
*/
|
||||
#define QSF_BOOLEAN_DEFAULT "boolean"
|
||||
|
||||
#define QSF_CONDITIONAL "if" /**< child of calculate.
|
||||
|
||||
Conditionals can reference objects as if within the original application. In operation,
|
||||
the map is overlaid across both sets of defined objects, an import object in the source
|
||||
application and an output object for the destination object. The current import and output
|
||||
QSF objects are therefore always available to the map.
|
||||
Conditionals can reference parameter as well as object values.
|
||||
*/
|
||||
#define QSF_CONDITIONAL_SET "set" /**< Assignment statement
|
||||
|
||||
Map assignments can use the native values within the output object. The output object
|
||||
must support setting the relevant parameter using the value exactly as given in the map
|
||||
because the relevant set() function will be called using this value. This may reduce the
|
||||
readability of the map but the relevant application could also be modified to support
|
||||
a more readable set function.
|
||||
*/
|
||||
#define QSF_CONDITIONAL_ELSE "else" /**< Alternative
|
||||
|
||||
if(){} else{} is also supported. Nesting of conditionals causes problems for
|
||||
validating the final map against any sensible XML Schema and a map that does not
|
||||
validate will be rejected. When editing conditionals in a QSF map, ALWAYS
|
||||
validate the map using xmllint. If necessary, define a variable at the foot of
|
||||
the definitions block, using a similar syntax to a default, then use that
|
||||
variable in another conditional
|
||||
|
||||
\a variable \a name="my_rate" \a type="numeric" \a value="0/1"
|
||||
|
||||
The syntax for xmllint is:
|
||||
|
||||
\a xmllint \a --schema \a <schema file> \a <qsf-file>
|
||||
|
||||
Use the qsf-object.xsd.xml schema for objects and qsf-map.xsd.xml for map files.
|
||||
|
||||
e.g. xmllint --schema qsf-object.xsd.xml --noout qof-qsf.xml
|
||||
|
||||
*/
|
||||
#define QSF_OPTION "option" /**< enum operator
|
||||
|
||||
Not implemented yet - may need to change once work starts.
|
||||
Theoretically, option will specify when an enumerator value is in use -
|
||||
it is quite possible that it will be unnecessary.
|
||||
*/
|
||||
|
||||
#define QSF_FORMATTING_OPTION "format" /**< How to format dates/times
|
||||
|
||||
When the QSF map uses a date/time value as a \b string, the formatting
|
||||
can be adjusted to personal preference. \a format will only be evaluated
|
||||
if the calculated parameter is a QOF_TYPE_STRING - any format attributes
|
||||
on other data types will be ignored.
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
#define QSF_XSD_TIME QOF_UTC_DATE_FORMAT /**< xsd:dateTime format in coordinated
|
||||
universal time, UTC.
|
||||
|
||||
You can reproduce the string from the GNU/Linux command line using the date utility:
|
||||
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ
|
||||
|
||||
2004-12-12T23:39:11Z
|
||||
|
||||
The datestring must be timezone independent and include all specified fields.
|
||||
|
||||
Remember to use gmtime() NOT localtime()!. From the command line, use the
|
||||
-u switch with the date command: date -u
|
||||
|
||||
To generate a timestamp based on a real time, use the qsf_time_now and
|
||||
qsf_time_string defaults.
|
||||
|
||||
qsf_time_now : Format: QOF_TYPE_DATE. The current time taken from the moment
|
||||
the default is read into a QSF object at runtime.
|
||||
|
||||
qsf_time_string : Format: QOF_TYPE_STRING. The current timestamp taken from the
|
||||
moment the default is read into a QSF object at runtime. This form is used when
|
||||
the output parameter needs a formatted date string, not an actual date object.
|
||||
The format is determined by the optional format attribute of the set tag which
|
||||
takes the same operators as the GNU C Library for strftime() and output may therefore
|
||||
be dependent on the locale of the calling process - \b take \b care. Default value
|
||||
is %F, used when qsf_time_string is set without the format attribute.
|
||||
|
||||
Both defaults use UTC.
|
||||
|
||||
*/
|
||||
#define QSF_XML_BOOLEAN_TEST "true" /**< needs to be lowercase for XML validation */
|
||||
|
||||
#define QSF_OBJECT_SCHEMA "qsf-object.xsd.xml" /**< Name of the QSF Object Schema. */
|
||||
#define QSF_MAP_SCHEMA "qsf-map.xsd.xml" /**< Name of the QSF Map Schema. */
|
||||
/** \brief QSF Parameters
|
||||
|
||||
This struct is a catch-all for all parameters required
|
||||
for various stages of the process. There are lots of elements
|
||||
here that will finally be removed.
|
||||
*/
|
||||
typedef struct qsf_metadata
|
||||
{
|
||||
qsf_type file_type; /**< what type of file is being handled */
|
||||
qsf_objects *object_set; /**< current object set for qsf_object_list. */
|
||||
gint 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 */
|
||||
GList *referenceList; /**< Table of references, ::QofInstanceReference. */
|
||||
GHashTable *qsf_parameter_hash; /**< Hashtable of parameters for each object */
|
||||
GHashTable *qsf_calculate_hash, *qsf_default_hash, *qsf_define_hash;
|
||||
GSList *supported_types; /**< The list of QOF types currently supported, in QSF order. */
|
||||
xmlDocPtr input_doc; /**< Pointer to the input xml document(s). */
|
||||
xmlDocPtr output_doc; /**< Pointer to the output xml document(s). */
|
||||
xmlNodePtr child_node; /**< The current child_node. */
|
||||
xmlNodePtr convert_node; /**< Node in the converted object */
|
||||
xmlNodePtr param_node; /**< Node for parameter data. */
|
||||
xmlNodePtr output_node; /**< Node in the output document. */
|
||||
xmlNodePtr output_root; /**< Root node of the output document. */
|
||||
xmlNodePtr book_node; /**< Node for the book. */
|
||||
xmlNodePtr lister; /**< Comparison node for map defaults. */
|
||||
xmlNsPtr qsf_ns, map_ns; /**< Separate namespaces for QSF objects and QSF maps. */
|
||||
const gchar *qof_type; /**< Holds details of the QOF_TYPE */
|
||||
QofIdType qof_obj_type; /**< current QofObject type (e_type) for the parameters. */
|
||||
QofIdType qof_foreach; /**< How to iterate over hierarchical entities. */
|
||||
gint foreach_limit; /**< How many iterations are found in the QSF */
|
||||
QofInstance *qsf_ent; /**< Current entity in the book. */
|
||||
QofBackend *be; /**< the current QofBackend for this operation. */
|
||||
gboolean knowntype; /**< detect references by comparing with known QOF types. */
|
||||
QofParam *qof_param; /**< used by kvp to handle the frame hash table */
|
||||
QofBook *book; /**< the current QofBook.
|
||||
|
||||
Theoretically, QSF can handle multiple QofBooks - currently limited to 1.
|
||||
*/
|
||||
gint boolean_calculation_done; /**< simple trip once this boolean is complete. */
|
||||
gchar *filepath; /**< Path to the QSF file. */
|
||||
gchar *map_path; /**< Path to best match map, if any. */
|
||||
gchar* full_kvp_path; /**< Full path for each KvpValue written out. */
|
||||
gint64 use_gz_level; /**< Default compression level. */
|
||||
GList *map_files; /**< List of selected map files for this session.
|
||||
|
||||
Defaults to the pre-installed QSF maps, currently: pilot-qsf-GnuCashInvoice.xml
|
||||
*/
|
||||
const gchar *encoding; /**< Backend encoding option - defaults to UTF-8. */
|
||||
} qsf_param;
|
||||
|
||||
/** \brief Validation metadata
|
||||
|
||||
The validation is a separate parse with separate data.
|
||||
This is used to determine which backend should load the data.
|
||||
*/
|
||||
typedef struct qsf_validates
|
||||
{
|
||||
QofBackendError error_state;
|
||||
const gchar *object_path;
|
||||
const gchar *map_path;
|
||||
GHashTable *validation_table;
|
||||
gint valid_object_count;
|
||||
gint map_calculated_count;
|
||||
gint qof_registered_count;
|
||||
} qsf_validator;
|
||||
|
||||
/** \brief shorthand function
|
||||
|
||||
This may look repetitive but each one is used separately
|
||||
as well as in a block.
|
||||
*/
|
||||
gint
|
||||
qsf_compare_tag_strings(const xmlChar *node_name, gchar *tag_name);
|
||||
|
||||
/** \brief shorthand function
|
||||
|
||||
This may look repetitive but each one is used separately
|
||||
as well as in a block.
|
||||
*/
|
||||
gint
|
||||
qsf_strings_equal(const xmlChar *node_name, gchar *tag_name);
|
||||
|
||||
/** \brief shorthand function
|
||||
|
||||
This may look repetitive but each one is used separately
|
||||
as well as in a block.
|
||||
*/
|
||||
gint
|
||||
qsf_is_element(xmlNodePtr a, xmlNsPtr ns, gchar *c);
|
||||
|
||||
/** \brief shorthand function
|
||||
|
||||
This may look repetitive but each one is used separately
|
||||
as well as in a block.
|
||||
*/
|
||||
gint
|
||||
qsf_check_tag(qsf_param *params, gchar *qof_type);
|
||||
|
||||
/** \brief Checks all incoming objects for QOF registration.
|
||||
|
||||
Sums all existing objects in the QSF and counts the number of those
|
||||
objects that are also registered with QOF in the host application.
|
||||
*/
|
||||
void
|
||||
qsf_object_validation_handler(xmlNodePtr child, xmlNsPtr ns, qsf_validator *valid);
|
||||
|
||||
/** \brief Compares an xmlDoc in memory against the schema file.
|
||||
|
||||
@param schema_dir set at compile time to $prefix/share/qsf/
|
||||
@param schema_filename Either the QSF Object Schema or the QSF Map Schema.
|
||||
@param doc The xmlDoc read from the file using libxml2.
|
||||
|
||||
Ensure that you call the right schema_filename for the doc in question!
|
||||
|
||||
Incorrect validation will result in output to the terminal window.
|
||||
|
||||
@return TRUE if the doc validates against the assigned schema, otherwise FALSE.
|
||||
*/
|
||||
gboolean
|
||||
qsf_is_valid(const gchar *schema_dir, const gchar* schema_filename, xmlDocPtr doc);
|
||||
|
||||
/** \brief Prepare the default list of maps.
|
||||
|
||||
Prepend the default maps to the supplied GList.
|
||||
|
||||
The GList remains the property of the caller.
|
||||
*/
|
||||
GList** qsf_map_prepare_list(GList **maps);
|
||||
|
||||
/** \name Why two sets of functions and typedefs?
|
||||
|
||||
These functions are in pairs, one to use in an existing session and one to use
|
||||
when deciding which backend should be selected for a new session.
|
||||
- When there is an existing QofSession, the qsf_param
|
||||
context will be available, so set error codes in the backend.
|
||||
Use the *_be functions.
|
||||
- When just determining the type of file, qsf_param is
|
||||
not necessary and no backend is available (it has not been selected yet).
|
||||
Use the twin function. e.g. in ::qsf_file_type()
|
||||
|
||||
@{
|
||||
*/
|
||||
/** \brief map and qsf object callback
|
||||
|
||||
This callback cannot do both the map and the validation tasks
|
||||
because validation sometimes needs to be done without qsf_params.
|
||||
|
||||
e.g. when selecting which backend should be used for a particular
|
||||
data source where two or more backends share the same access_method.
|
||||
*/
|
||||
typedef void (* qsf_nodeCB)(xmlNodePtr, xmlNsPtr, qsf_param*);
|
||||
/** \brief validator callback
|
||||
|
||||
\todo The need for separate metadata means a separate callback typedef
|
||||
is needed for the validator, but this should be fixed to only need one.
|
||||
*/
|
||||
typedef void (* qsf_validCB)(xmlNodePtr, xmlNsPtr, qsf_validator*);
|
||||
/** \brief One iterator, two typedefs
|
||||
|
||||
\todo resolve the two callbacks in ::qsf_node_iterate into one.
|
||||
*/
|
||||
struct qsf_node_iterate
|
||||
{
|
||||
qsf_nodeCB *fcn;
|
||||
qsf_validCB *v_fcn;
|
||||
xmlNsPtr ns;
|
||||
};
|
||||
|
||||
/** \brief Validate a QSF file and identify a suitable QSF map
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
These functions are in pairs. When called from within a QofSession, the qsf_param
|
||||
context will be available. When just determining the type of file, qsf_param is
|
||||
not necessary. Use the *_be functions from within the QofBackend and the
|
||||
corresponding function in other code.
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if a suitable QSF
|
||||
map exists. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
@return TRUE if the file validates and a QSF map can be found,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_be(qsf_param *params);
|
||||
/** \brief Validate a QSF file and identify a suitable QSF map
|
||||
|
||||
@param path Absolute or relative path to the file to be validated.
|
||||
|
||||
These functions are in pairs. When called from within a QofSession, the qsf_param
|
||||
context will be available. When just determining the type of file, qsf_param is
|
||||
not necessary. Use the *_be functions from within the QofBackend and the
|
||||
corresponding function in other code.
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if a suitable QSF
|
||||
map exists. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
@return TRUE if the file validates and a QSF map can be found,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object(const gchar *path);
|
||||
/** \brief Validate a QSF file and determine type.
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to see if it is registered
|
||||
with QOF within the QOF environment of the calling process.
|
||||
|
||||
Files that pass the test can be imported into the QOF appliction without the need
|
||||
for a QSF map.
|
||||
|
||||
@return TRUE if the file validates and all objects pass,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_our_qsf_object_be(qsf_param *params);
|
||||
/** \brief Validate a QSF file.
|
||||
|
||||
@param path Absolute or relative path to the file to be validated
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to see if it is registered
|
||||
with QOF within the QOF environment of the calling process.
|
||||
|
||||
Files that pass the test can be imported into the QOF appliction without the need
|
||||
for a QSF map.
|
||||
|
||||
@return TRUE if the file validates and all objects pass,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_our_qsf_object(const gchar *path);
|
||||
/** \brief Validate a QSF map file.
|
||||
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated aginst the QSF map schema, qsf-map.xsd.xsml. This
|
||||
function is called by ::is_qsf_object. If called directly, the map file
|
||||
is validated and closed with a QofBackend error. QSF maps do not contain
|
||||
user data and are used to import QSF object files.
|
||||
|
||||
@return TRUE if the map validates, otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_map_be(qsf_param *params);
|
||||
/** \brief Validate a QSF map file.
|
||||
|
||||
@param path Absolute or relative path to the file to be validated
|
||||
|
||||
These functions are in pairs. When called from within a QofSession, the qsf_param
|
||||
context will be available. When just determining the type of file, qsf_param is
|
||||
not necessary. Use the *_be functions from within the QofBackend and the
|
||||
corresponding function in other code.
|
||||
|
||||
The file is validated aginst the QSF map schema, qsf-map.xsd.xsml. This
|
||||
function is called by ::is_qsf_object. If called directly, the map file
|
||||
is validated and closed, no data is retrieved. QSF maps do not contain
|
||||
user data but are used to import QSF object files from other applications.
|
||||
|
||||
@return TRUE if the map validates, otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_map(const gchar *path);
|
||||
/** \brief Validate a QSF file and a selected QSF map
|
||||
|
||||
@param map_path Absolute or relative path to the selected QSF map file
|
||||
@param params Pointer to qsf_param context
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if the supplied QSF
|
||||
map is suitable. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
This backend twin also sets QofBackendError codes.
|
||||
|
||||
@return TRUE if the file validates and the supplied QSF map is usable,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_with_map_be(gchar *map_path, qsf_param *params);
|
||||
/** \brief Validate a QSF file and a selected QSF map
|
||||
|
||||
@param path Absolute or relative path to the selected QSF map file
|
||||
@param map_file Name of the map file
|
||||
|
||||
The file is validated against the QSF object schema, qsf-object.xsd.xml and
|
||||
each object described in the file is checked to find out if the supplied QSF
|
||||
map is suitable. Map files are accepted if all objects described in the QSF object
|
||||
file are defined in the QSF map.
|
||||
|
||||
@return TRUE if the file validates and the supplied QSF map is usable,
|
||||
otherwise FALSE.
|
||||
*/
|
||||
gboolean is_qsf_object_with_map(const gchar *path, gchar *map_file);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** \brief Book and book-guid node handler.
|
||||
|
||||
Reads the book count="" attribute (currently only 1 QofBook is supported per QSF object file)
|
||||
Sets the book-guid as the GncGUID of the current QofBackend QofBook in qsf_param.
|
||||
Calls the next handler, qsf_object_node_handler, with the child of the book tag.
|
||||
*/
|
||||
void qsf_book_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params);
|
||||
|
||||
/** \brief Convert a string value into KvpValue
|
||||
|
||||
Partner to ::kvp_value_to_string. Given the type of KvpValue
|
||||
required, attempts to convert the string into that type of
|
||||
value.
|
||||
|
||||
@param content A string representation of the value, ideally as
|
||||
output by kvp_value_to_string.
|
||||
@param type KvpValueType of the intended KvpValue
|
||||
|
||||
@return KvpValue* or NULL on failure.
|
||||
*/
|
||||
KvpValue*
|
||||
string_to_kvp_value(const gchar *content, KvpValueType type);
|
||||
|
||||
/** Validate the children of the parent node.
|
||||
|
||||
\note Slightly different to qsf_node_foreach because
|
||||
the validation can be run without qsf_param being
|
||||
initialized.
|
||||
*/
|
||||
void
|
||||
qsf_valid_foreach(xmlNodePtr parent, qsf_validCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_validator *valid);
|
||||
|
||||
/** Iterate over the children of the parent node.
|
||||
|
||||
Only iterates over the immediate children of the parent -
|
||||
this function is \b not recursive.
|
||||
*/
|
||||
void
|
||||
qsf_node_foreach(xmlNodePtr parent, qsf_nodeCB cb,
|
||||
struct qsf_node_iterate *iter, qsf_param *params);
|
||||
|
||||
/** \brief Convert between QSF objects
|
||||
|
||||
This is the main workhorse of the conversion between QSF objects using
|
||||
maps.
|
||||
|
||||
@param mapDoc The map document, parsed by libxml2.
|
||||
@param qsf_root The top node of the QSF object to be converted using the map.
|
||||
@param params The QSF backend parameters.
|
||||
|
||||
Each calculation in the map is performed over the child nodes of the
|
||||
object tree. A new xmlDoc is created and this is made available to QOF to
|
||||
be loaded into the book.
|
||||
|
||||
*/
|
||||
xmlDocPtr
|
||||
qsf_object_convert(xmlDocPtr mapDoc, xmlNodePtr qsf_root, qsf_param *params);
|
||||
|
||||
/** Despite the name, this function handles the QSF object book tag
|
||||
AND the object tags.
|
||||
|
||||
Used to parse object and map files.
|
||||
*/
|
||||
void
|
||||
qsf_object_node_handler(xmlNodePtr child, xmlNsPtr qsf_ns, qsf_param *params);
|
||||
|
||||
/** @} */
|
||||
/** @} */
|
||||
|
||||
#endif /* QSF_XML_H */
|
@ -97,9 +97,4 @@
|
||||
#include "qofbookmerge.h"
|
||||
#include "qofreference.h"
|
||||
|
||||
/** allow easy logging of QSF debug messages */
|
||||
#define QOF_MOD_QSF "qof.backend.qsf"
|
||||
/** allow easy loading of the QSF backend */
|
||||
#define QSF_BACKEND_LIB "gncqof-backend-qsf"
|
||||
|
||||
#endif /* QOF_H_ */
|
||||
|
@ -75,37 +75,13 @@ typedef enum
|
||||
another user has deleted the object */
|
||||
ERR_BACKEND_MISC, /**< undetermined error */
|
||||
|
||||
/* QSF add-ons */
|
||||
ERR_QSF_INVALID_OBJ, /**< The QSF object failed to validate against the QSF object schema */
|
||||
ERR_QSF_INVALID_MAP, /**< The QSF map failed to validate against the QSF map schema */
|
||||
ERR_QSF_BAD_OBJ_GUID, /**< The QSF object contains one or more invalid GUIDs. */
|
||||
ERR_QSF_BAD_QOF_VERSION, /**< QSF map or object doesn't match the current QOF_OBJECT_VERSION. */
|
||||
ERR_QSF_BAD_MAP, /**< The selected map validates but is unusable.
|
||||
|
||||
This is usually because not all the required parameters for the defined objects
|
||||
have calculations described in the map.
|
||||
*/
|
||||
ERR_QSF_NO_MAP, /**< The QSF object file was loaded without a map
|
||||
|
||||
The QSF Object file requires a map but it was not provided.
|
||||
*/
|
||||
ERR_QSF_WRONG_MAP, /**< The selected map validates but is for different objects.
|
||||
|
||||
The list of objects defined in this map does not include all the objects described in
|
||||
the current QSF object file.
|
||||
*/
|
||||
ERR_QSF_MAP_NOT_OBJ, /**< Selected file is a QSF map and cannot be opened as a QSF object */
|
||||
ERR_QSF_OVERFLOW, /**< EOVERFLOW - generated by strtol or strtoll.
|
||||
ERR_QOF_OVERFLOW, /**< EOVERFLOW - generated by strtol or strtoll.
|
||||
|
||||
When converting XML strings into numbers, an overflow has been detected. The XML file
|
||||
contains invalid data in a field that is meant to hold a signed long integer or signed long long
|
||||
integer.
|
||||
*/
|
||||
ERR_QSF_OPEN_NOT_MERGE, /** QSF files cannot be opened alone. The data must be merged.
|
||||
|
||||
This error is more of a warning that can be ignored by any routine
|
||||
that uses qof_book_merge on the new session.
|
||||
*/
|
||||
/* fileio errors */
|
||||
ERR_FILEIO_FILE_BAD_READ = 1000, /**< read failed or file prematurely truncated */
|
||||
ERR_FILEIO_FILE_EMPTY, /**< file exists, is readable, but is empty */
|
||||
|
@ -54,8 +54,8 @@ really exist by itself:
|
||||
\verbatim
|
||||
QOF_TYPE_CHOICE<QOF_X, QOF_Y, QOF_Z>
|
||||
\endverbatim
|
||||
It holds a single entity of type X, Y, or Z for the purposes of QOF
|
||||
or ::QSF. For querying the object it queries as if it's an X, Y, or Z.
|
||||
It holds a single entity of type X, Y, or Z for the purposes of QOF.
|
||||
For querying the object it queries as if it's an X, Y, or Z.
|
||||
|
||||
Each choice type has it's own definition of the allowable objects -
|
||||
each of which need to be registered as normal. Objects can declare
|
||||
|
@ -1011,7 +1011,6 @@ Remember: Use the libdir from the current build environment
|
||||
and use JUST the module name without .so - .so is not portable! */
|
||||
struct backend_providers backend_list[] =
|
||||
{
|
||||
{ QOF_LIB_DIR, QSF_BACKEND_LIB },
|
||||
#ifdef HAVE_DWI
|
||||
{ QOF_LIB_DIR, "libqof_backend_dwi"},
|
||||
#endif
|
||||
|
@ -120,10 +120,9 @@ void qof_session_swap_data (QofSession *session_1, QofSession *session_2);
|
||||
/** The qof_session_begin () method begins a new session.
|
||||
* It takes as an argument the book id. The book id must be a string
|
||||
* in the form of a URI/URL. The access method specified depends
|
||||
* on the loaded backends. In the absence of a customised backend,
|
||||
* only QSF XML would be accepted). Paths may be relative or absolute.
|
||||
* If the path is relative; that is, if the argument is "file:somefile.xml"
|
||||
* then the current working directory is assumed. Customised backends can
|
||||
* on the loaded backends. Paths may be relative or absolute.
|
||||
* If the path is relative; that is, if the argument is "file://somefile.xml"
|
||||
* then the current working directory is assumed. Customized backends can
|
||||
* choose to search other, application-specific, directories as well.
|
||||
*
|
||||
* The 'ignore_lock' argument, if set to TRUE, will cause this routine
|
||||
|
@ -655,17 +655,6 @@ qof_sql_insertCB(const QofParam *param, const gchar *insert_string, QofSqlQuery
|
||||
LEAVE (" string to guid failed for %s", insert_string);
|
||||
return;
|
||||
}
|
||||
/* reference_type = xmlGetProp(node, QSF_OBJECT_TYPE);
|
||||
if(0 == safe_strcmp(QOF_PARAM_GUID, reference_type))
|
||||
{
|
||||
qof_instance_set_guid(qsf_ent, cm_guid);
|
||||
}
|
||||
else {
|
||||
reference = qof_instance_get_reference_from(qsf_ent, cm_param);
|
||||
if(reference) {
|
||||
params->referenceList = g_list_append(params->referenceList, reference);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_INT32) == 0)
|
||||
{
|
||||
@ -686,7 +675,7 @@ qof_sql_insertCB(const QofParam *param, const gchar *insert_string, QofSqlQuery
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QSF_OVERFLOW);
|
||||
qof_backend_set_error(backend, ERR_QOF_OVERFLOW);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_INT64) == 0)
|
||||
@ -708,7 +697,7 @@ qof_sql_insertCB(const QofParam *param, const gchar *insert_string, QofSqlQuery
|
||||
|
||||
book = qof_instance_get_book((QofInstance*)ent);
|
||||
backend = qof_book_get_backend(book);
|
||||
qof_backend_set_error(backend, ERR_QSF_OVERFLOW);
|
||||
qof_backend_set_error(backend, ERR_QOF_OVERFLOW);
|
||||
}
|
||||
}
|
||||
if (safe_strcmp(param->param_type, QOF_TYPE_DOUBLE) == 0)
|
||||
|
@ -413,7 +413,6 @@ qof_util_param_as_string(QofInstance *ent, QofParam *param)
|
||||
{
|
||||
boolean_getter = (gboolean (*)(QofInstance*, QofParam*)) param->param_getfcn;
|
||||
param_boolean = boolean_getter(ent, param);
|
||||
/* Boolean values need to be lowercase for QSF validation. */
|
||||
if (param_boolean == TRUE)
|
||||
{
|
||||
param_string = g_strdup("true");
|
||||
|
@ -1,2 +1,2 @@
|
||||
SUBDIRS = xsl ${PYTHON_DIR}
|
||||
DIST_SUBDIRS = xsl python-bindings
|
||||
SUBDIRS = ${PYTHON_DIR}
|
||||
DIST_SUBDIRS = python-bindings
|
||||
|
@ -1,13 +0,0 @@
|
||||
xsldir = ${datadir}/xml/gnucash/xsl
|
||||
|
||||
xsl_DATA = \
|
||||
README \
|
||||
date-time.xsl \
|
||||
gnucash-std.xsl \
|
||||
string.xsl \
|
||||
gnucash-gnccustomer-vcard2.xsl \
|
||||
vcard-gnccustomer.pl
|
||||
|
||||
EXTRA_DIST = \
|
||||
${xsl_DATA}
|
||||
|
@ -1,98 +0,0 @@
|
||||
GnuCash, XSL and QSF.
|
||||
====================
|
||||
|
||||
If you need to convert gnucash QSF data into other formats, take a look at the example
|
||||
stylesheets installed with gnucash. You are welcome to contribute new or amended
|
||||
stylesheets - just post them on the QOF-devel mailing list.
|
||||
|
||||
http://lists.sourceforge.net/lists/listinfo/qof-devel
|
||||
|
||||
Depending on your package manager, the XSL stylesheets should be installed in
|
||||
/usr/share/xml/gnucash/xsl/, or on Fink /sw/share/xml/gnucash/xsl/.
|
||||
|
||||
Current stylesheets are works in progress, but include:
|
||||
|
||||
· gnucash-gnccustomer-vcard2.xsl
|
||||
|
||||
This stylesheet converts QSF export gnucash customer data into a brief Vcard,
|
||||
suitable for upload to Kaddressbook. Each VCard is written into a separate .vcf
|
||||
file, named after the contact described in the pilot_address records. Spaces are
|
||||
replaced with underscores. Specify the '-o dir/' option to xsltproc to output all
|
||||
vcards into a directory.
|
||||
|
||||
· Others
|
||||
|
||||
Stylesheets for ICS, vcal and possibly LDAP are planned. Any plain text, XML or HTML
|
||||
format can be generated, theoretically. If you have a request for an XSL stylesheet
|
||||
or if you have a stylesheet you would like to make available to others, mention it
|
||||
on the QOF-devel mailing list.
|
||||
|
||||
Also included is a perl script:
|
||||
|
||||
· vcard-gnccustomer.pl
|
||||
|
||||
The script uses the Text::vCard::Addressbook CPAN module to parse VCard files,
|
||||
including those from other applications, into QSF XML that could be imported into
|
||||
gnucash and merged into your gnucash customer list. With a few tweaks, this could
|
||||
also be configured to create QSF XML suitable for gnucash vendor or employee records.
|
||||
|
||||
You are free to copy and modify these stylesheets to your own requirements, including
|
||||
translations and customised formats. Depending on your package manager, this is often
|
||||
best done by copying the installed file to a local directory before modifying it.
|
||||
GnuCash does not reference these stylesheets directly. If your modifications could be
|
||||
useful to others, please contribute them to gnucash via the QOF-devel mailing list or
|
||||
gnucash-devel mailing list. Submitted stylesheets should be licenced under the GNU GPL.
|
||||
|
||||
|
||||
LOCALISATION (l10N) OF STYLESHEET OUTPUT.
|
||||
========================================
|
||||
|
||||
Later HTML stylesheets will support providing translatable strings and user-specific
|
||||
encodings via external parameters. This can make the command line very long so is best
|
||||
performed using a script. Each descriptive word in the output is configured as a string
|
||||
parameter for the stylesheet and can be replaced with a translated version. HTML output
|
||||
supports setting the HTML language (as would be specified in the <html> lang attribute)
|
||||
and the encoding (as would be specified in the <meta> charset value in the content
|
||||
attribute). If you use these stylesheets via a scripting language - like bash, PHP or
|
||||
Perl - you could automate the translation by passing values obtained from a normal get-
|
||||
text PO file. Copy the translatable strings into your script file as normal variables
|
||||
then mark up those variables for translation by gettext. When the script is called, get-
|
||||
text will assign the translated values to the variables and your script can simply echo
|
||||
those values to the calls to the XSL parser routines.
|
||||
|
||||
It is important that the HTML language and the encoding match each other AND the
|
||||
expected content of the HTML output generated from the gnucash QSF data.
|
||||
|
||||
When providing translated strings, the same constraints apply as if you were using get-
|
||||
text and a normal PO file: the context and format of the translation should match the
|
||||
intention expressed in the default value of the parameter. If the default is plural, the
|
||||
translation should be plural. If the default is capitalised, the translation should be
|
||||
capitalised - subject to grammatical rules for that language - even if the parameter
|
||||
name itself is not capitalised.
|
||||
|
||||
Each stylesheet specifies the translatable strings in a block near the top of the file,
|
||||
marked as for the attention of translators. Common settings, like the HTML language
|
||||
parameter and the encoding support, are in the gnucash-std.xsl stylesheet and are
|
||||
available in all HTML stylesheets by using the string parameters html_lang and encoding.
|
||||
|
||||
For more information, please ask on the gnucash-devel mailing list, the QOF-devel mailing
|
||||
list or see the pilot-qof source: http://pilot-qof.sourceforge.net/
|
||||
|
||||
EXAMPLES
|
||||
========
|
||||
|
||||
Convert a QSF XML file containing gncCustomer records, into individual VCard .vcf files
|
||||
in the vcards/ directory - which must already exist. Files are named according to either
|
||||
the company or name of the gncAddress record.
|
||||
|
||||
$ xsltproc -o vcards/ gnucash-gnccustomer-vcard2.xsl addresses.xml
|
||||
|
||||
This example is based on an "in-progress" QSF invoice stylesheet for gnucash that is based
|
||||
on the existing pilot-qof HTML invoice stylesheet. It overrides the default mileage-rate
|
||||
(0.30 currency units per unit distance) and the default hourly-rate (20 currency units per
|
||||
hour) provided by the stylesheet with user specific values. The example is here just to
|
||||
indicate how --stringparam would be used.
|
||||
|
||||
$ xsltproc --stringparam mileage-rate 0.45 --stringparam hourly-rate 21 -o invoices/
|
||||
pilot-qof-invoice-xhtml.xsl invoice.xml
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,74 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:qof-qsf="http://qof.sourceforge.net/" xmlns:str="http://xsltsl.org/string" version="1.1">
|
||||
<xsl:import href="string.xsl"/>
|
||||
<!-- our own gnucash standard routines -->
|
||||
<xsl:import href="gnucash-std.xsl"/>
|
||||
<xsl:output method="text"/>
|
||||
<!-- Representing QSF gncAddress data in a 2.1 extended VCard
|
||||
|
||||
This stylesheet converts the GnuCash output from Export Customers
|
||||
into a simple Vcard, suitable for import into KAdddressbook. For other
|
||||
VCard support (e.g. for mobile phones), see other vcard XSL stylesheets in the
|
||||
gnucash collection.
|
||||
|
||||
Each VCard is written into a separate .vcf file, named after the
|
||||
contact described in the gncAddress records. Spaces are replaced with
|
||||
underscores. Specify the '-o dir/' option to xsltproc to output all vcards
|
||||
into a directory.
|
||||
-->
|
||||
<!-- Licence
|
||||
|
||||
This file 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.
|
||||
-->
|
||||
<xsl:template match="/*/qof-qsf:book/qof-qsf:object[@type='gncAddress']">
|
||||
<xsl:text>TEL;TYPE=WORK:</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='phone']"/>
|
||||
<xsl:text> TEL;TYPE=FAX:</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='fax']"/>
|
||||
<xsl:text> EMAIL:</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='email']"/>
|
||||
<xsl:text> ADR;TYPE=work:;;</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='number']"/>
|
||||
<xsl:text>;</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='street']"/>
|
||||
<xsl:text>;</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='locality']"/>
|
||||
<xsl:text>;</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='city']"/>
|
||||
<xsl:text> N:</xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='name']"/>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:template>
|
||||
<xsl:template match="/">
|
||||
<xsl:for-each select="/*/qof-qsf:book/qof-qsf:object[@type='gncCustomer']">
|
||||
<xsl:variable name="contactName">
|
||||
<xsl:value-of select="qof-qsf:string[@type='name']"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="card_title">
|
||||
<xsl:call-template name="get_chunk_name">
|
||||
<xsl:with-param name="entryName" select="$contactName"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<!-- chunking support -->
|
||||
<xsl:document href="{$card_title}.vcf" method="text">
|
||||
<xsl:text>BEGIN:VCARD VERSION:2.1 </xsl:text>
|
||||
<xsl:call-template name="locate_child">
|
||||
<xsl:with-param name="customer_object" select="."/>
|
||||
</xsl:call-template>
|
||||
<xsl:text>END:VCARD </xsl:text>
|
||||
</xsl:document>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
@ -1,140 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:qof-qsf="http://qof.sourceforge.net/" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:dt="http://xsltsl.org/date-time" xmlns:str="http://xsltsl.org/string" version="1.0" exclude-result-prefixes="qof-qsf html dt str">
|
||||
<xsl:import href="date-time.xsl"/>
|
||||
<xsl:import href="string.xsl"/>
|
||||
<!--This stylesheet contains standard templates for QOF QSF.-->
|
||||
<!--This is only a working prototype -->
|
||||
<!-- Licence
|
||||
|
||||
This file 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.
|
||||
-->
|
||||
<!-- Translation support via external parameters -->
|
||||
<xsl:param name="html_lang">en</xsl:param>
|
||||
<xsl:param name="encoding">iso-8859-15</xsl:param>
|
||||
<!-- Convert gnc_numeric notation to an XSL number -->
|
||||
<xsl:template name="numeric_to_double">
|
||||
<xsl:param name="numeric_string"/>
|
||||
<xsl:variable name="before" select="substring-before($numeric_string, '/')"/>
|
||||
<xsl:variable name="after" select="substring-after($numeric_string, '/')"/>
|
||||
<xsl:variable name="numeric" select="$before div $after"/>
|
||||
<xsl:value-of select="number($numeric)"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="get_chunk_name">
|
||||
<xsl:param name="entryName"/>
|
||||
<xsl:param name="entryCompany"/>
|
||||
<xsl:variable name="result">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$entryName = ''">
|
||||
<xsl:call-template name="str:subst">
|
||||
<xsl:with-param name="text" select="$entryCompany"/>
|
||||
<xsl:with-param name="replace">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:with-param>
|
||||
<xsl:with-param name="with">
|
||||
<xsl:text>_</xsl:text>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:variable name="temp">
|
||||
<xsl:call-template name="str:subst">
|
||||
<xsl:with-param name="text" select="$entryName"/>
|
||||
<xsl:with-param name="replace">
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:with-param>
|
||||
<xsl:with-param name="with">
|
||||
<xsl:text>_</xsl:text>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:call-template name="str:subst">
|
||||
<xsl:with-param name="text" select="$temp"/>
|
||||
<xsl:with-param name="replace">
|
||||
<xsl:text>;</xsl:text>
|
||||
</xsl:with-param>
|
||||
<xsl:with-param name="with">
|
||||
<xsl:text>_</xsl:text>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="$result"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="prepare_address_div">
|
||||
<xsl:param name="address_object" select="."/>
|
||||
<xsl:comment>this address panel can be located precisely using CSS</xsl:comment>
|
||||
<xsl:text> </xsl:text>
|
||||
<div class="address">
|
||||
<h2>Customer address</h2>
|
||||
<p class="address_para">
|
||||
<xsl:text> </xsl:text>
|
||||
<b>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryCompany']"/>
|
||||
</b>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryAddress']"/>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryCity']"/>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryState']"/>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryZip']"/>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryCountry']"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="qof-qsf:string[@type='entryPhone1']"/>
|
||||
</p>
|
||||
</div>
|
||||
</xsl:template>
|
||||
<xsl:template name="vcard_safe">
|
||||
<xsl:param name="address_string"/>
|
||||
<xsl:variable name="safe_string">
|
||||
<xsl:call-template name="str:subst">
|
||||
<xsl:with-param name="text" select="$entryCompany"/>
|
||||
<xsl:with-param name="replace">
|
||||
<xsl:text>,</xsl:text>
|
||||
</xsl:with-param>
|
||||
<xsl:with-param name="with">
|
||||
<xsl:text>\,</xsl:text>
|
||||
</xsl:with-param>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:value-of select="$safe_string"/>
|
||||
</xsl:template>
|
||||
<!-- hierarchy support -->
|
||||
<xsl:template name="locate_child">
|
||||
<xsl:param name="customer_object"/>
|
||||
<xsl:variable name="cust_addr_guid">
|
||||
<xsl:value-of select="qof-qsf:guid[@type='addr']"/>
|
||||
</xsl:variable>
|
||||
<xsl:for-each select="/*/qof-qsf:book/qof-qsf:object[@type='gncAddress']">
|
||||
<xsl:variable name="addr_guid">
|
||||
<xsl:value-of select="qof-qsf:guid[@type='guid']"/>
|
||||
</xsl:variable>
|
||||
<xsl:if test="$addr_guid = $cust_addr_guid">
|
||||
<xsl:variable name="set" select="."/>
|
||||
<xsl:apply-templates select="$set"/>
|
||||
</xsl:if>
|
||||
</xsl:for-each>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
File diff suppressed because one or more lines are too long
@ -1,103 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# 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.
|
||||
|
||||
use Text::vCard::Addressbook;
|
||||
use strict;
|
||||
use vars qw($address_book $hex_string $num $c $d $e $i $vcard $names $name $fullname $email $address $addresses $phones $phone $filename $usage $encoding);
|
||||
|
||||
############### USER CONFIGURATION ####################
|
||||
# Change to the encoding for you locale if your VCF data
|
||||
# contains accented characters etc.
|
||||
$encoding = 'UTF-8';
|
||||
############### END CONFIGURATION ####################
|
||||
|
||||
# About
|
||||
#
|
||||
# This is a very simple file and should be simple to customise.
|
||||
# A similar file is included in pilot-qof. Currently, the script
|
||||
# needs to be told where to find the VCF file to transform and
|
||||
# expects the user to redirect output to a file:
|
||||
# $ perl vcard-gnccustomer.pl contact.vcf > contact.xml
|
||||
|
||||
$usage = $#ARGV + 1;
|
||||
if($usage < 1)
|
||||
{
|
||||
print ("Error: please specify a .vcf file.\n\n");
|
||||
exit;
|
||||
}
|
||||
$filename = $ARGV[0];
|
||||
$address_book = Text::vCard::Addressbook->new({
|
||||
'source_file' => $filename, });
|
||||
# generate a temporary GUID to relate the address to the customer
|
||||
$hex_string = '';
|
||||
for($d = 1;$d < 5;$d++)
|
||||
{
|
||||
for($c = 1; $c < 8; $c++)
|
||||
{
|
||||
$num = (int(rand(99)) + 1) * 10**$c;
|
||||
}
|
||||
$hex_string .= sprintf("%x", $num);
|
||||
}
|
||||
print "<?xml version=\"1.0\" encoding=\"$encoding\"?>\n";
|
||||
print "<qof-qsf xmlns=\"http://qof.sourceforge.net/\">\n";
|
||||
print " <book count=\"1\">\n";
|
||||
print " <book-guid/>\n";
|
||||
print " <object type=\"gncAddress\" count=\"1\">\n";
|
||||
foreach $vcard ($address_book->vcards()) {
|
||||
$names = $vcard->get({ 'node_type' => 'name' });
|
||||
foreach $name (@{$names}){
|
||||
if($name->given()) {
|
||||
$fullname = $name->given() . " " . $name->family();
|
||||
}
|
||||
else {
|
||||
$fullname = $name->family();
|
||||
}
|
||||
&wrap_in_qsf($fullname, "name");
|
||||
}
|
||||
$phones = $vcard->get('tel');
|
||||
$i = 0;
|
||||
foreach $phone (@{$phones}){
|
||||
if($i == 0) {
|
||||
&wrap_in_qsf($phone->value(), "phone");
|
||||
}
|
||||
if($i == 1) {
|
||||
&wrap_in_qsf($phone->value(), "fax");
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$email = $vcard->get('email');
|
||||
foreach $e (@{$email}){ &wrap_in_qsf($e->value(), "email"); }
|
||||
$addresses = $vcard->get({ 'node_type' => 'addresses' });
|
||||
foreach $address (@{$addresses}) {
|
||||
&wrap_in_qsf($address->street(), "street");
|
||||
&wrap_in_qsf($address->city(), "city");
|
||||
&wrap_in_qsf($address->region(), "locality");
|
||||
}
|
||||
print " <guid type=\"guid\">$hex_string</guid>\n";
|
||||
}
|
||||
print " </object>\n";
|
||||
print " <object type=\"gncCustomer\" count=\"1\">\n";
|
||||
&wrap_in_qsf($fullname, "name");
|
||||
print " <boolean type=\"active\">true</boolean\n";
|
||||
print " <guid type=\"addr\">$hex_string</guid>\n";
|
||||
print " </book>\n";
|
||||
print "</qof-qsf>\n\n";
|
||||
|
||||
sub wrap_in_qsf()
|
||||
{
|
||||
if($_[0]) { print " <string type=\"$_[1]\">$_[0]</string>\n"; }
|
||||
else { print " <string type=\"$_[1]\"/>\n"; }
|
||||
};
|
Loading…
Reference in New Issue
Block a user