[Gnucash-changes] r13781 - gnucash/trunk - Initial support to
decode old, ambiguous data files,
missing an encoding declaration, with the help of the user.
Andreas Köhler
andi5 at cvs.gnucash.org
Fri Apr 14 13:39:01 EDT 2006
Author: andi5
Date: 2006-04-14 13:38:57 -0400 (Fri, 14 Apr 2006)
New Revision: 13781
Trac: http://svn.gnucash.org/trac/changeset/13781
Added:
gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c
gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.h
gnucash/trunk/src/gnome-utils/glade/druid-gnc-xml-import.glade
Modified:
gnucash/trunk/ChangeLog
gnucash/trunk/lib/libqof/qof/qofbackend.h
gnucash/trunk/lib/libqof/qof/qofsession.c
gnucash/trunk/src/backend/file/gnc-backend-file.c
gnucash/trunk/src/backend/file/gnc-backend-file.h
gnucash/trunk/src/backend/file/io-example-account.c
gnucash/trunk/src/backend/file/io-example-account.h
gnucash/trunk/src/backend/file/io-gncxml-v1.c
gnucash/trunk/src/backend/file/io-gncxml-v2.c
gnucash/trunk/src/backend/file/io-gncxml-v2.h
gnucash/trunk/src/backend/file/sixtp.c
gnucash/trunk/src/backend/file/sixtp.h
gnucash/trunk/src/backend/file/test/test-xml2-is-file.c
gnucash/trunk/src/gnome-utils/Makefile.am
gnucash/trunk/src/gnome-utils/glade/Makefile.am
gnucash/trunk/src/gnome-utils/gnc-file.c
Log:
Initial support to decode old, ambiguous data files, missing an encoding declaration, with the help of the user.
Modified: gnucash/trunk/ChangeLog
===================================================================
--- gnucash/trunk/ChangeLog 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/ChangeLog 2006-04-14 17:38:57 UTC (rev 13781)
@@ -1,3 +1,28 @@
+2006-04-14 Andreas Köhler <andi5.py at gmx.net>
+
+ * lib/libqof/qof/qofbackend.h:
+ * lib/libqof/qof/qofsession.c:
+ * src/backend/file/gnc-backend-file.[ch]:
+ * src/backend/file/io-example-account.[ch]:
+ * src/backend/file/io-gncxml-v1.c:
+ * src/backend/file/test/test-xml2-is-file.c: Add
+ ERR_FILEIO_NO_ENCODING and test whether xml data file declares
+ encoding.
+
+ * src/backend/file/sixtp.[ch]: Add parsing in push mode.
+
+ * src/backend/file/io-gncxml-v2.[ch]: Add analysis of data file to
+ find ambiguous words because of missing encoding, and parsing of
+ it with string substitutions.
+
+ * src/gnome-utils/druid-gnc-xml-import.[ch]:
+ * src/gnome-utils/glade/druid-gnc-xml-import.glade: Add Code and
+ GUI for a druid that enables the user to select from different
+ encodings for each ambiguous word.
+
+ * src/gnome-utils/gnc-file.c: Hook the druid into the file loading
+ process and reload the file if it was successful.
+
2006-04-14 Derek Atkins <derek at ihtfp.com>
* src/engine/Transaction.c:
Modified: gnucash/trunk/lib/libqof/qof/qofbackend.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofbackend.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/lib/libqof/qof/qofbackend.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -116,6 +116,7 @@
ERR_FILEIO_BACKUP_ERROR, /**< couldn't make a backup of the file */
ERR_FILEIO_WRITE_ERROR, /**< couldn't write to the file */
ERR_FILEIO_READ_ERROR, /**< Could not open the file for reading. */
+ ERR_FILEIO_NO_ENCODING, /**< file does not specify encoding */
/* network errors */
ERR_NETIO_SHORT_READ = 2000, /**< not enough bytes received */
Modified: gnucash/trunk/lib/libqof/qof/qofsession.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/qofsession.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/lib/libqof/qof/qofsession.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -1113,6 +1113,7 @@
err = qof_session_get_error(session);
if ((err != ERR_BACKEND_NO_ERR) &&
(err != ERR_FILEIO_FILE_TOO_OLD) &&
+ (err != ERR_FILEIO_NO_ENCODING) &&
(err != ERR_SQL_DB_TOO_OLD))
{
/* Something broke, put back the old stuff */
Modified: gnucash/trunk/src/backend/file/gnc-backend-file.c
===================================================================
--- gnucash/trunk/src/backend/file/gnc-backend-file.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/gnc-backend-file.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -408,8 +408,13 @@
static QofBookFileType
gnc_file_be_determine_file_type(const char *path)
{
- if (gnc_is_xml_data_file_v2(path)) {
- return GNC_BOOK_XML2_FILE;
+ gboolean with_encoding;
+ if (gnc_is_xml_data_file_v2(path, &with_encoding)) {
+ if (with_encoding) {
+ return GNC_BOOK_XML2_FILE;
+ } else {
+ return GNC_BOOK_XML2_FILE_NO_ENCODING;
+ }
} else if (gnc_is_xml_data_file(path)) {
return GNC_BOOK_XML1_FILE;
} else if (is_gzipped_file(path)) {
@@ -435,10 +440,10 @@
rc = stat(path, &sbuf);
if(rc < 0) { return FALSE; }
if (sbuf.st_size == 0) { PINFO (" empty file"); return TRUE; }
- if(gnc_is_xml_data_file_v2(path)) { return TRUE; }
- else if(gnc_is_xml_data_file(path)) { return TRUE; }
- else if(is_gzipped_file(path)) { return TRUE; }
- else if(gnc_is_bin_file(path)) { return TRUE; }
+ if(gnc_is_xml_data_file_v2(path, NULL)) { return TRUE; }
+ else if(gnc_is_xml_data_file(path)) { return TRUE; }
+ else if(is_gzipped_file(path)) { return TRUE; }
+ else if(gnc_is_bin_file(path)) { return TRUE; }
PINFO (" %s is not a gnc file", path);
return FALSE;
}
@@ -873,6 +878,9 @@
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
break;
+ case GNC_BOOK_XML2_FILE_NO_ENCODING:
+ error = ERR_FILEIO_NO_ENCODING;
+ break;
case GNC_BOOK_XML1_FILE:
rc = qof_session_load_from_xml_file (book, be->fullpath);
if (FALSE == rc) error = ERR_FILEIO_PARSE_ERROR;
Modified: gnucash/trunk/src/backend/file/gnc-backend-file.h
===================================================================
--- gnucash/trunk/src/backend/file/gnc-backend-file.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/gnc-backend-file.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -57,6 +57,7 @@
GNC_BOOK_BIN_FILE,
GNC_BOOK_XML1_FILE,
GNC_BOOK_XML2_FILE,
+ GNC_BOOK_XML2_FILE_NO_ENCODING,
QSF_GNC_OBJECT,
QSF_OBJECT,
QSF_MAP,
Modified: gnucash/trunk/src/backend/file/io-example-account.c
===================================================================
--- gnucash/trunk/src/backend/file/io-example-account.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/io-example-account.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -481,5 +481,5 @@
gboolean
gnc_is_example_account_xml(const gchar *name)
{
- return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING);
+ return gnc_is_our_xml_file(name, GNC_ACCOUNT_STRING, NULL);
}
Modified: gnucash/trunk/src/backend/file/io-example-account.h
===================================================================
--- gnucash/trunk/src/backend/file/io-example-account.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/io-example-account.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -51,8 +51,6 @@
const gchar *filename);
-gboolean gnc_is_xml_data_file_v2(const gchar *filename);
-
void gnc_free_example_account_list(GSList *list);
GSList* gnc_load_example_account_list(QofBook *book,
const char *dirname);
Modified: gnucash/trunk/src/backend/file/io-gncxml-v1.c
===================================================================
--- gnucash/trunk/src/backend/file/io-gncxml-v1.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/io-gncxml-v1.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -403,7 +403,7 @@
gboolean
gnc_is_xml_data_file(const gchar *filename)
{
- return gnc_is_our_xml_file(filename, "gnc");
+ return gnc_is_our_xml_file(filename, "gnc", NULL);
}
/* ================================================================== */
Modified: gnucash/trunk/src/backend/file/io-gncxml-v2.c
===================================================================
--- gnucash/trunk/src/backend/file/io-gncxml-v2.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/io-gncxml-v2.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
#include <zlib.h>
+#include <errno.h>
#include "gnc-engine.h"
#include "gnc-pricedb-p.h"
@@ -646,16 +647,19 @@
return gd;
}
-gboolean
-qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
+static gboolean
+qof_session_load_from_xml_file_v2_full(
+ FileBackend *fbe, QofBook *book,
+ sixtp_push_handler push_handler, gpointer push_user_data)
{
- AccountGroup *grp;
+ AccountGroup *grp;
QofBackend *be = &fbe->be;
sixtp_gdv2 *gd;
sixtp *top_parser;
sixtp *main_parser;
sixtp *book_parser;
struct file_backend be_data;
+ gboolean retval;
gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
@@ -717,9 +721,22 @@
xaccLogDisable ();
xaccDisableDataScrubbing();
- if(!gnc_xml_parse_file(top_parser, fbe->fullpath,
- generic_callback, gd, book))
- {
+ if (push_handler) {
+ gpointer parse_result = NULL;
+ gxpf_data gpdata;
+
+ gpdata.cb = generic_callback;
+ gpdata.parsedata = gd;
+ gpdata.bookdata = book;
+
+ retval = sixtp_parse_push(top_parser, push_handler, push_user_data,
+ NULL, &gpdata, &parse_result);
+ } else {
+ retval = gnc_xml_parse_file(top_parser, fbe->fullpath,
+ generic_callback, gd, book);
+ }
+
+ if (!retval) {
sixtp_destroy(top_parser);
xaccLogEnable ();
xaccEnableDataScrubbing();
@@ -766,6 +783,12 @@
return FALSE;
}
+gboolean
+qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
+{
+ return qof_session_load_from_xml_file_v2_full(fbe, book, NULL, NULL);
+}
+
/***********************************************************************/
static void
@@ -1359,7 +1382,391 @@
/***********************************************************************/
gboolean
-gnc_is_xml_data_file_v2(const gchar *name)
+gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding)
{
- return gnc_is_our_xml_file(name, GNC_V2_STRING);
+ return gnc_is_our_xml_file(name, GNC_V2_STRING, with_encoding);
}
+
+
+static void
+replace_character_references(gchar *string)
+{
+ gchar *cursor, *semicolon, *tail;
+ glong number;
+
+ for (cursor = strstr(string, "&#");
+ cursor && *cursor;
+ cursor = strstr(cursor, "&#")) {
+ semicolon = strchr(cursor, ';');
+ if (semicolon && *semicolon) {
+
+ /* parse number */
+ errno = 0;
+ if (*(cursor+2) == 'x') {
+ number = strtol(cursor+3, &tail, 16);
+ } else {
+ number = strtol(cursor+2, &tail, 10);
+ }
+ if (errno || tail != semicolon || number < 0 || number > 255) {
+ PWARN("Illegal character reference");
+ return;
+ }
+
+ /* overwrite '&' with the specified character */
+ *cursor = (gchar) number;
+ cursor++;
+ if (*(semicolon+1)) {
+ /* move text after semicolon the the left */
+ tail = g_strdup(semicolon+1);
+ strcpy(cursor, tail);
+ g_free(tail);
+ } else {
+ /* cut here */
+ *cursor = '\0';
+ }
+
+ } else {
+ PWARN("Unclosed character reference");
+ return;
+ }
+ }
+}
+
+static void
+conv_free(conv_type *conv) {
+ if (conv) {
+ g_free(conv->utf8_string);
+ g_free(conv);
+ }
+}
+
+static void
+conv_list_free(GList *conv_list) {
+ g_list_foreach(conv_list, (GFunc) conv_free, NULL);
+ g_list_free(conv_list);
+}
+
+typedef struct {
+ GQuark encoding;
+ GIConv iconv;
+} iconv_item_type;
+
+gint
+gnc_xml2_find_ambiguous(const gchar *filename, GList *encodings,
+ GHashTable **unique, GHashTable **ambiguous,
+ GList **impossible, GError **error)
+{
+ GIOChannel *channel=NULL;
+ GIOStatus status;
+ GList *iconv_list=NULL, *conv_list=NULL, *iter;
+ iconv_item_type *iconv_item=NULL, *ascii=NULL;
+ const gchar *enc;
+ GHashTable *processed=NULL;
+ gint n_impossible = 0;
+ gboolean clean_return = FALSE;
+
+ channel = g_io_channel_new_file(filename, "r", error);
+ if (*error) {
+ PWARN("Unable to open file %s", filename);
+ goto cleanup_find_ambs;
+ }
+
+ status = g_io_channel_set_encoding(channel, NULL, error);
+ if (status != G_IO_STATUS_NORMAL) {
+ PWARN("Error on unsetting encoding on IOChannel");
+ goto cleanup_find_ambs;
+ }
+
+ /* we need ascii */
+ ascii = g_new(iconv_item_type, 1);
+ ascii->encoding = g_quark_from_string("ASCII");
+ ascii->iconv = g_iconv_open("UTF-8", "ASCII");
+ if (ascii->iconv == (GIConv) -1) {
+ PWARN("Unable to open ASCII ICONV conversion descriptor");
+ goto cleanup_find_ambs;
+ }
+
+ /* call iconv_open on encodings */
+ for (iter = encodings; iter; iter = iter->next) {
+ iconv_item = g_new(iconv_item_type, 1);
+ iconv_item->encoding = GPOINTER_TO_UINT (iter->data);
+ if (iconv_item->encoding == ascii->encoding) {
+ continue;
+ }
+
+ enc = g_quark_to_string(iconv_item->encoding);
+ iconv_item->iconv = g_iconv_open("UTF-8", enc);
+ if (iconv_item->iconv == (GIConv) -1) {
+ PWARN("Unable to open IConv conversion descriptor for '%s'", enc);
+ goto cleanup_find_ambs;
+ } else {
+ iconv_list = g_list_prepend(iconv_list, iconv_item);
+ }
+ }
+
+ /* prepare data containers */
+ if (unique)
+ *unique = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) conv_free);
+ if (ambiguous)
+ *ambiguous = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify) conv_list_free);
+ if (impossible)
+ *impossible = NULL;
+ processed = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ /* loop through lines */
+ while (1) {
+ gchar *line, *word, *utf8;
+ gchar **word_array, **word_cursor;
+ conv_type *conv;
+
+ status = g_io_channel_read_line(channel, &line, NULL, NULL, error);
+ if (status == G_IO_STATUS_EOF) {
+ break;
+ }
+ if (status == G_IO_STATUS_AGAIN) {
+ continue;
+ }
+ if (status != G_IO_STATUS_NORMAL) {
+ goto cleanup_find_ambs;
+ }
+
+ g_strchomp(line);
+ replace_character_references(line);
+ word_array = g_strsplit_set(line, "> <", 0);
+ g_free(line);
+
+ /* loop through words */
+ for (word_cursor = word_array; *word_cursor; word_cursor++) {
+ word = *word_cursor;
+ if (!word)
+ continue;
+
+ utf8 = g_convert_with_iconv(word, -1, ascii->iconv,
+ NULL, NULL, error);
+ if (utf8) {
+ /* pure ascii */
+ g_free(utf8);
+ continue;
+ }
+ g_error_free(*error);
+ *error = NULL;
+
+ if (g_hash_table_lookup_extended(processed, word, NULL, NULL)) {
+ /* already processed */
+ continue;
+ }
+
+ /* loop through encodings */
+ conv_list = NULL;
+ for (iter = iconv_list; iter; iter = iter->next) {
+ iconv_item = iter->data;
+ utf8 = g_convert_with_iconv(word, -1, iconv_item->iconv,
+ NULL, NULL, error);
+ if (utf8) {
+ conv = g_new(conv_type, 1);
+ conv->encoding = iconv_item->encoding;
+ conv->utf8_string = utf8;
+ conv_list = g_list_prepend(conv_list, conv);
+ } else {
+ g_error_free(*error);
+ *error = NULL;
+ }
+ }
+
+ /* no successful conversion */
+ if (!conv_list) {
+ if (impossible)
+ *impossible = g_list_append(*impossible, g_strdup(word));
+ n_impossible++;
+ }
+
+ /* more than one successful conversion */
+ else if (conv_list->next) {
+ if (ambiguous) {
+ g_hash_table_insert(*ambiguous, g_strdup(word), conv_list);
+ } else {
+ conv_list_free(conv_list);
+ }
+ }
+
+ /* only one successful conversion */
+ else {
+ if (unique) {
+ g_hash_table_insert(*unique, g_strdup(word), conv);
+ } else {
+ conv_free(conv);
+ }
+ g_list_free(conv_list);
+ }
+
+ g_hash_table_insert(processed, g_strdup(word), NULL);
+ }
+ g_strfreev(word_array);
+ }
+
+ clean_return = TRUE;
+
+ cleanup_find_ambs:
+
+ if (iconv_list) {
+ for (iter = iconv_list; iter; iter = iter->next) {
+ if (iter->data) {
+ g_iconv_close(((iconv_item_type*) iter->data)->iconv);
+ g_free(iter->data);
+ }
+ }
+ g_list_free(iconv_list);
+ }
+ if (processed)
+ g_hash_table_destroy(processed);
+ if (ascii)
+ g_free(ascii);
+ if (channel)
+ g_io_channel_unref(channel);
+
+ return (clean_return) ? n_impossible : -1;
+}
+
+typedef struct {
+ gchar *filename;
+ GHashTable *subst;
+} push_data_type;
+
+static void
+parse_with_subst_push_handler (xmlParserCtxtPtr xml_context,
+ push_data_type *push_data)
+{
+ GIOChannel *channel=NULL;
+ GIOStatus status;
+ GIConv ascii=(GIConv)-1;
+ GString *output=NULL;
+ GError *error=NULL;
+
+ channel = g_io_channel_new_file(push_data->filename, "r", &error);
+ if (error) {
+ PWARN("Unable to open file %s", push_data->filename);
+ goto cleanup_push_handler;
+ }
+
+ status = g_io_channel_set_encoding(channel, NULL, &error);
+ if (status != G_IO_STATUS_NORMAL) {
+ PWARN("Error on unsetting encoding on IOChannel");
+ goto cleanup_push_handler;
+ }
+
+ ascii = g_iconv_open("UTF-8", "ASCII");
+ if (ascii == (GIConv) -1) {
+ PWARN("Unable to open ASCII ICONV conversion descriptor");
+ goto cleanup_push_handler;
+ }
+
+ /* loop through lines */
+ while (1) {
+ gchar *line, *word, *repl, *utf8;
+ gint pos, len;
+ gchar *start, *cursor;
+
+ status = g_io_channel_read_line(channel, &line, NULL, NULL, &error);
+ if (status == G_IO_STATUS_EOF) {
+ break;
+ }
+ if (status == G_IO_STATUS_AGAIN) {
+ continue;
+ }
+ if (status != G_IO_STATUS_NORMAL) {
+ goto cleanup_push_handler;
+ }
+
+ replace_character_references(line);
+ output = g_string_new(line);
+ g_free(line);
+
+ /* loop through words */
+ cursor = output->str;
+ pos = 0;
+ while (1) {
+ /* ignore delimiters */
+ while (*cursor=='>' || *cursor==' ' || *cursor=='<' ||
+ *cursor=='\n') {
+ cursor++;
+ pos += 1;
+ }
+
+ if (!*cursor)
+ /* welcome to EOL */
+ break;
+
+ /* search for a delimiter */
+ start = cursor;
+ len = 0;
+ while (*cursor && *cursor!='>' && *cursor!=' ' && *cursor!='<' &&
+ *cursor!='\n') {
+ cursor++;
+ len++;
+ }
+
+ utf8 = g_convert_with_iconv(start, len, ascii, NULL, NULL, &error);
+
+ if (utf8) {
+ /* pure ascii */
+ g_free(utf8);
+ pos += len;
+ } else {
+ g_error_free(error);
+ error = NULL;
+
+ word = g_strndup(start, len);
+ repl = g_hash_table_lookup(push_data->subst, word);
+ g_free(word);
+ if (repl) {
+ /* there is a replacement */
+ output = g_string_insert(g_string_erase(output, pos, len),
+ pos, repl);
+ pos += strlen(repl);
+ cursor = output->str + pos;
+ } else {
+ /* there is no replacement, return immediately */
+ goto cleanup_push_handler;
+ }
+ }
+ }
+
+ if (xmlParseChunk(xml_context, output->str, output->len, 0) != 0) {
+ goto cleanup_push_handler;
+ }
+ }
+
+ /* last chunk */
+ xmlParseChunk(xml_context, "", 0, 1);
+
+ cleanup_push_handler:
+
+ if (output)
+ g_string_free(output, TRUE);
+ if (ascii != (GIConv) -1)
+ g_iconv_close(ascii);
+ if (channel)
+ g_io_channel_unref(channel);
+}
+
+gboolean
+gnc_xml2_parse_with_subst (FileBackend *fbe, QofBook *book, GHashTable *subst)
+{
+ push_data_type *push_data;
+ gboolean success;
+
+ push_data = g_new(push_data_type, 1);
+ push_data->filename = fbe->fullpath;
+ push_data->subst = subst;
+
+ success = qof_session_load_from_xml_file_v2_full(
+ fbe, book, (sixtp_push_handler) parse_with_subst_push_handler,
+ push_data);
+
+ if (success)
+ qof_book_kvp_changed(book);
+
+ return success;
+}
Modified: gnucash/trunk/src/backend/file/io-gncxml-v2.h
===================================================================
--- gnucash/trunk/src/backend/file/io-gncxml-v2.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/io-gncxml-v2.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -142,11 +142,57 @@
/** The is_gncxml_file() routine checks to see if the first few
* chars of the file look like gnc-xml data.
*/
-gboolean gnc_is_xml_data_file_v2(const gchar *name);
+gboolean gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding);
/** Write a name-space declaration for the provided namespace data type
* within the GNC XML namespace at http://www.gnucash.org/XML.
*/
void gnc_xml2_write_namespace_decl (FILE *out, const char *namespace);
+
+typedef struct {
+ GQuark encoding;
+ gchar *utf8_string;
+} conv_type;
+
+/** Read a file as plain byte stream to find words that are not completely ASCII.
+ * On error, @unique, @ambiguous and @impossible will be filled up to that point,
+ * @error may contain an io channel error, -1 will be returned.
+ *
+ * @param filename Name of the file to read.
+ *
+ * @param encodings List of encodings to check words for, each begin one a GQuark
+ * in a pointer.
+ *
+ * @param unique Location used for a hash table for unique solutions, if not
+ * NULL. The byte sequence is the key, successful_conversion the value.
+ *
+ * @param ambiguous Location used for a hash table for ambiguous byte sequences,
+ * if not NULL. The byte sequences is the key, a list of successful_conversions
+ * the value.
+ *
+ * @param impossible Location used for a list for undecodable byte sequences,
+ * if not NULL.
+ *
+ * @param error Location to return an io channel error.
+ *
+ * @return Size of impossible, -1 on error.
+ */
+gint gnc_xml2_find_ambiguous(
+ const gchar *filename, GList *encodings, GHashTable **unique,
+ GHashTable **ambiguous, GList **impossible, GError **error);
+typedef gint (*find_ambiguous_handler)(
+ const gchar *filename, GList *encodings, GHashTable **unique,
+ GHashTable **ambiguous, GList **impossible, GError **error);
+
+/** Parse a file in push mode, but replace byte sequences in the file given a
+ * hash table of substitutions
+ *
+ * @param subst hash table with keys and values of type gchar*
+ */
+gboolean gnc_xml2_parse_with_subst (
+ FileBackend *fbe, QofBook *book, GHashTable *subst);
+typedef gboolean (*parse_with_subst_handler)(
+ FileBackend *fbe, QofBook *book, GHashTable *subst);
+
#endif /* __IO_GNCXML_V2_H__ */
Modified: gnucash/trunk/src/backend/file/sixtp.c
===================================================================
--- gnucash/trunk/src/backend/file/sixtp.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/sixtp.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -748,6 +748,52 @@
return ret;
}
+gboolean
+sixtp_parse_push (sixtp *sixtp,
+ sixtp_push_handler push_handler,
+ gpointer push_user_data,
+ gpointer data_for_top_level,
+ gpointer global_data,
+ gpointer *parse_result)
+{
+ sixtp_parser_context *ctxt;
+ xmlParserCtxtPtr xml_context;
+
+ if (!push_handler) {
+ PERR("No push handler specified");
+ return FALSE;
+ }
+
+ if (!(ctxt = sixtp_context_new(sixtp, global_data, data_for_top_level))) {
+ PERR("sixtp_context_new returned null");
+ return FALSE;
+ }
+
+ xml_context = xmlCreatePushParserCtxt(&ctxt->handler, &ctxt->data,
+ NULL, 0, NULL);
+ ctxt->data.saxParserCtxt = xml_context;
+ ctxt->data.bad_xml_parser = sixtp_dom_parser_new(gnc_bad_xml_end_handler,
+ NULL, NULL);
+
+ (*push_handler)(xml_context, push_user_data);
+
+ sixtp_context_run_end_handler(ctxt);
+
+ if (ctxt->data.parsing_ok) {
+ if (parse_result)
+ *parse_result = ctxt->top_frame->frame_data;
+ sixtp_context_destroy(ctxt);
+ return TRUE;
+ } else {
+ if (parse_result)
+ *parse_result = NULL;
+ if (g_slist_length(ctxt->data.stack) > 1)
+ sixtp_handle_catastrophe(&ctxt->data);
+ sixtp_context_destroy(ctxt);
+ return FALSE;
+ }
+}
+
/***********************************************************************/
static gboolean
eat_whitespace(unsigned char **cursor)
@@ -787,7 +833,8 @@
}
gboolean
-gnc_is_our_xml_file(const char *filename, const char *first_tag)
+gnc_is_our_xml_file(const char *filename, const char *first_tag,
+ gboolean *with_encoding)
{
FILE *f = NULL;
char first_chunk[256];
@@ -796,6 +843,10 @@
g_return_val_if_fail(filename, FALSE);
g_return_val_if_fail(first_tag, FALSE);
+
+ if (with_encoding) {
+ *with_encoding = FALSE;
+ }
f = fopen(filename, "r");
if (f == NULL) {
@@ -838,6 +889,18 @@
result = (strncmp(cursor, tag_compare, strlen(tag_compare)) == 0);
g_free (tag_compare);
+
+ if (result && with_encoding) {
+ *cursor = '\0';
+ cursor = first_chunk;
+ while (search_for('e', &cursor)) {
+ if (strncmp(cursor, "ncoding=", 8) == 0) {
+ *with_encoding = TRUE;
+ break;
+ }
+ }
+ }
+
return result;
}
else
Modified: gnucash/trunk/src/backend/file/sixtp.h
===================================================================
--- gnucash/trunk/src/backend/file/sixtp.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/sixtp.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -86,6 +86,9 @@
gpointer *result,
const gchar *tag);
+typedef void (*sixtp_push_handler)(xmlParserCtxtPtr xml_context,
+ gpointer user_data);
+
typedef struct sixtp
{
/* If you change this, don't forget to modify all the copy/etc. functions */
@@ -180,6 +183,9 @@
gboolean sixtp_parse_buffer(sixtp *sixtp, char *bufp, int bufsz,
gpointer data_for_top_level, gpointer global_data,
gpointer *parse_result);
+gboolean sixtp_parse_push(sixtp *sixtp, sixtp_push_handler push_handler,
+ gpointer push_user_data, gpointer data_for_top_level,
+ gpointer global_data, gpointer *parse_result);
void sixtp_set_start(sixtp *parser, sixtp_start_handler start_handler);
void sixtp_set_before_child(sixtp *parser, sixtp_before_child_handler handler);
@@ -198,7 +204,8 @@
gboolean sixtp_add_sub_parser(sixtp *parser, const gchar* tag,
sixtp *sub_parser);
-gboolean gnc_is_our_xml_file(const char *filename, const char *first_tag);
+gboolean gnc_is_our_xml_file(const char *filename, const char *first_tag,
+ gboolean *with_encoding);
#endif /* _SIXTP_H_ */
Modified: gnucash/trunk/src/backend/file/test/test-xml2-is-file.c
===================================================================
--- gnucash/trunk/src/backend/file/test/test-xml2-is-file.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/backend/file/test/test-xml2-is-file.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -22,7 +22,7 @@
filename = malloc(strlen(directory) + 1 + strlen(FILENAME) + 1);
sprintf(filename, "%s/%s", directory, FILENAME);
- do_test(gnc_is_xml_data_file_v2(filename), "gnc_is_xml_data_file_v2");
+ do_test(gnc_is_xml_data_file_v2(filename, NULL), "gnc_is_xml_data_file_v2");
print_test_results();
exit(get_rv());
Modified: gnucash/trunk/src/gnome-utils/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/Makefile.am 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/Makefile.am 2006-04-14 17:38:57 UTC (rev 13781)
@@ -48,6 +48,7 @@
dialog-utils.c \
druid-utils.c \
druid-gconf-setup.c \
+ druid-gnc-xml-import.c \
gnc-account-sel.c \
gnc-amount-edit.c \
gnc-commodity-edit.c \
@@ -116,6 +117,7 @@
dialog-utils.h \
druid-utils.h \
druid-gconf-setup.h \
+ druid-gnc-xml-import.h \
gnc-account-sel.h \
gnc-amount-edit.h \
gnc-commodity-edit.h \
Added: gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c
===================================================================
--- gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -0,0 +1,1518 @@
+/*
+ * druid-gnc-xml-import.c --
+ * Copyright (C) 2006 Andreas Koehler <andi5.py at gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation Voice: +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+ * Boston, MA 02110-1301, USA gnu at gnu.org
+ */
+
+#include "config.h"
+
+#include <gnome.h>
+#include <glib/gi18n.h>
+
+#include "TransLog.h"
+#include "druid-gnc-xml-import.h"
+#include "dialog-utils.h"
+#include "druid-utils.h"
+#include "gnc-backend-file.h"
+#include "gnc-filepath-utils.h"
+#include "gnc-module.h"
+#include "gnc-ui.h"
+#include "io-gncxml-v2.h"
+
+#define XML_GLADE_FILE "druid-gnc-xml-import.glade"
+
+/* NOTE: Merge stuff is not implemented, only the result of a file parse is
+ * merged into a given session.
+ */
+
+/* NOTE: This file uses the term "encoding" even in places where it is not
+ * accurate. Please ignore that. Encodings occur in different forms:
+ * - as descriptive string, as in the list of system encodings
+ * - as string used for g_iconv_open
+ * - as GQuark, representing above string
+ * - as pointer, containing above gquark, used in lists
+ */
+
+typedef enum {
+ XML_CONVERT_SINGLE_FILE,
+ XML_MERGE_FILES
+} GncXmlImportType;
+
+typedef struct {
+ GncXmlImportType import_type;
+
+ GtkWidget *dialog; /* global window */
+ GtkWidget *druid; /* druid */
+ GtkWidget *file_chooser; /* file chooser widget on load file page */
+ GtkWidget *default_encoding_combo; /* top combo on conversion page */
+ GtkWidget *summary_label; /* label on conversion page */
+ GtkWidget *string_box; /* vbox of combos on conversion page */
+ GtkWidget *encodings_dialog; /* dialog for selection of encodings */
+ GtkTreeView *available_encs_view; /* list view of standard encodings */
+ GtkTreeView *selected_encs_view; /* list view of selected encodings */
+ GtkListStore *file_list_store; /* list store for loaded files */
+ GtkTreeView *file_list_view; /* list view for loaded files */
+
+ GList *files; /* list of loaded files */
+
+ GList *encodings; /* list of GQuarks for encodings */
+ GQuark default_encoding; /* default GQuark, may be zero */
+
+ /* hash table that maps byte sequences to conversions, i.e. in the current
+ encodings setting, there is only one possible conversion */
+ GHashTable *unique;
+
+ /* hash table that maps byte sequences to a list of conversions, i.e. in the
+ current encodings setting, there exactly these conversions are possible */
+ GHashTable *ambiguous_ht;
+
+ /* sorted list of ambiguous words, used for the construction of the combos */
+ GList *ambiguous_list;
+
+ /* hash table that maps byte sequences to conversions. these reflect the
+ choices the user made, accumulated and updated in the whole conversion.
+ Note: this may contain conversions that are not available in the current
+ encodings setting, just imagine, user accidentally removed an important
+ encoding from the list */
+ GHashTable *choices;
+
+ /* number of byte sequences that have multiple possible conversions, but not in
+ the default encoding. and the user has not decided yet, of course. */
+ gint n_unassigned;
+
+ /* number of byte sequences without any reasonable interpretation */
+ gint n_impossible;
+
+ /* hash table that maps byte sequences to other byte sequences to be replaced
+ by them. */
+ GHashTable *subst;
+
+ gchar *filename;
+ QofSession *session;
+} GncXmlImportData;
+
+typedef struct {
+ gchar *filename;
+ GtkTreeIter *file_list_iter;
+} GncXmlImportFile;
+
+/* used for the string combos, see ambiguous_free */
+typedef struct {
+ gchar *byte_sequence;
+ GList *conv_list;
+} ambiguous_type;
+
+enum {
+ FILE_COL_NAME = 0,
+ FILE_COL_INFO,
+ FILE_NUM_COLS
+};
+
+enum {
+ WORD_COL_STRING = 0,
+ WORD_COL_ENCODING,
+ WORD_NUM_COLS
+};
+
+enum {
+ ENC_COL_STRING = 0,
+ ENC_COL_QUARK,
+ ENC_NUM_COLS
+};
+
+static void gxi_data_destroy (GncXmlImportData *data);
+static void gxi_ambiguous_info_destroy (GncXmlImportData *data);
+static void gxi_session_destroy (GncXmlImportData *data);
+static void gxi_check_file (GncXmlImportData *data);
+static gboolean gxi_parse_file (GncXmlImportData *data);
+static gboolean gxi_save_file (GncXmlImportData *data);
+static void gxi_update_progress_bar (const gchar *message, double percentage);
+static void gxi_update_default_enc_combo (GncXmlImportData *data);
+static void gxi_update_summary_label (GncXmlImportData *data);
+static void gxi_update_string_box (GncXmlImportData *data);
+static void gxi_update_conversion_forward (GncXmlImportData *data);
+static GnomeDruidPage *gxi_get_named_page (GncXmlImportData *data,
+ const gchar *name);
+void gxi_dialog_destroy_cb (GtkObject *object, GncXmlImportData *data);
+void gxi_cancel_cb (GnomeDruid *druid, GncXmlImportData *data);
+void gxi_chooser_file_activated_cb (GtkFileChooser *chooser,
+ GncXmlImportData *data);
+gboolean gxi_load_file_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+void gxi_conversion_prepare_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+static void gxi_default_enc_combo_changed_cb (GtkComboBox *combo,
+ GncXmlImportData *data);
+static void gxi_string_combo_changed_cb (GtkComboBox *combo,
+ GncXmlImportData *data);
+void gxi_edit_encodings_clicked_cb (GtkButton *button, GncXmlImportData *data);
+void gxi_available_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GncXmlImportData *data);
+void gxi_add_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
+void gxi_custom_enc_activate_cb (GtkEntry *entry, GncXmlImportData *data);
+void gxi_add_custom_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
+void gxi_selected_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GncXmlImportData *data);
+void gxi_remove_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
+gboolean gxi_conversion_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+void gxi_loaded_files_prepare_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+gboolean gxi_loaded_files_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+void gxi_unload_file_clicked_cb (GtkButton *button, GncXmlImportData *data);
+void gxi_load_file_clicked_cb (GtkButton *button, GncXmlImportData *data);
+void gxi_end_finish_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data);
+
+static const gchar *encodings_doc_string = N_(
+ "The file you tried to load does not specify an encoding, so GnuCash is "
+ "unable to unambiguously interpret it. This is typical for files created with "
+ "GnuCash prior to 2.0.\n\n"
+ "On the next page you will be asked to select the best looking decoded string "
+ "for every ambiguous word GnuCash found while trying to open your file. "
+ "Therefore GnuCash has guessed what encodings you might have used. So "
+ "probably everything will look just fine and you can simply click "
+ "'Forward'.\n\n"
+ "If it does not work for you, try to change the default encoding at the top. "
+ "Maybe you even have to edit the list of encodings by clicking on the button "
+ "in the top right corner.\n\n"
+ "The page is not overly complicated, just take the time until you feel "
+ "comfortable with it. You can always come back and read this message again.");
+
+static const gchar *encodings_doc_page_title = N_("Missing file encoding");
+
+/* The debugging module that this .o belongs to. */
+static QofLogModule log_module = GNC_MOD_GUI;
+
+/* window containing a progress bar */
+static GtkWidget *progress_window = NULL;
+static GtkProgressBar *progress_bar = NULL;
+
+/* this is used for a static tree of system encodings. encoding may be NULL.
+ parent declares how often to go up in the path of the previous element and use
+ that as parent, e.g. 0 -> child of previous, 1 -> same level as previous */
+typedef struct {
+ gchar *text;
+ gchar *encoding;
+ gint parent;
+} system_encoding_type;
+static system_encoding_type system_encodings [] =
+{
+ { N_("Unicode"), NULL, 2 },
+ { "UTF-8", "UTF-8", 0 },
+ { N_("European"), NULL, 2 },
+ { N_("ISO-8859-1 (West European)"), "ISO-8859-1", 0 },
+ { N_("ISO-8859-2 (East European)"), "ISO-8859-2", 1 },
+ { N_("ISO-8859-3 (South European)"), "ISO-8859-3", 1 },
+ { N_("ISO-8859-4 (North European)"), "ISO-8859-4", 1 },
+ { N_("ISO-8859-5 (Cyrillic)"), "ISO-8859-5", 1 },
+ { N_("ISO-8859-6 (Arabic)"), "ISO-8859-6", 1 },
+ { N_("ISO-8859-7 (Greek)"), "ISO-8859-7", 1 },
+ { N_("ISO-8859-8 (Hebrew)"), "ISO-8859-8", 1 },
+ { N_("ISO-8859-9 (Turkish)"), "ISO-8859-9", 1 },
+ { N_("ISO-8859-10 (Nordic)"), "ISO-8859-10", 1 },
+ { N_("ISO-8859-11 (Thai)"), "ISO-8859-11", 1 },
+ { N_("ISO-8859-13 (Baltic)"), "ISO-8859-13", 1 },
+ { N_("ISO-8859-14 (Celtic)"), "ISO-8859-14", 1 },
+ { N_("ISO-8859-15 (West European, Euro sign)"), "ISO-8859-15", 1 },
+ { N_("ISO-8859-16 (South-East European)"), "ISO-8859-16", 1 },
+ { N_("Cyrillic"), NULL, 2 },
+ { N_("KOI8-R (Russian)"), "KOI8-R", 0 },
+ { N_("KOI8-U (Ukrainian)"), "KOI8-U", 1 },
+};
+static guint n_system_encodings = G_N_ELEMENTS (system_encodings);
+
+static find_ambiguous_handler find_ambiguous = NULL;
+static parse_with_subst_handler parse_with_subst = NULL;
+static GModule *allsymbols = NULL;
+
+static gboolean
+gxi_find_backend_symbols ()
+{
+ if (!allsymbols)
+ allsymbols = g_module_open (NULL, 0);
+
+ if (!g_module_symbol (allsymbols, "gnc_xml2_find_ambiguous",
+ (gpointer*) &find_ambiguous) ||
+ !g_module_symbol (allsymbols, "gnc_xml2_parse_with_subst",
+ (gpointer*) &parse_with_subst))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean
+gnc_xml_convert_single_file (const gchar *filename)
+{
+ GncXmlImportData *data;
+ GtkWidget *dialog, *widget;
+ GladeXML *xml;
+ gboolean success;
+
+ g_return_val_if_fail (gxi_find_backend_symbols (), FALSE);
+
+ data = g_new0 (GncXmlImportData, 1);
+ data->import_type = XML_CONVERT_SINGLE_FILE;
+ data->filename = g_strdup (filename);
+
+ /* gather ambiguous info */
+ gxi_check_file (data);
+ if (data->n_impossible == -1)
+ return FALSE;
+
+ if (!g_hash_table_size (data->ambiguous_ht)) {
+
+ /* no ambiguous strings */
+ success =
+ gxi_parse_file (data) &&
+ gxi_save_file (data);
+
+ gxi_data_destroy (data);
+
+ } else {
+
+ /* common druid initialization */
+ xml = gnc_glade_xml_new (XML_GLADE_FILE, "GnuCash XML Import Dialog");
+
+ dialog = glade_xml_get_widget (xml, "GnuCash XML Import Dialog");
+ gtk_widget_hide ((GTK_DIALOG (dialog))->action_area);
+ data->dialog = dialog;
+ g_object_set_data_full (G_OBJECT (dialog), "xml", xml, g_object_unref);
+ glade_xml_signal_autoconnect_full (xml, gnc_glade_autoconnect_full_func,
+ data);
+
+ data->druid = glade_xml_get_widget (xml, "gnc_xml_import_druid");
+ gnc_druid_set_colors (GNOME_DRUID (data->druid));
+
+ /* start page, explanations */
+ widget = glade_xml_get_widget (xml, "start_page");
+ gnome_druid_page_edge_set_text (GNOME_DRUID_PAGE_EDGE (widget),
+ gettext (encodings_doc_string));
+ gnome_druid_page_edge_set_title (GNOME_DRUID_PAGE_EDGE (widget),
+ gettext (encodings_doc_page_title));
+ gtk_widget_show (widget);
+
+ gtk_widget_hide (glade_xml_get_widget (xml, "encodings_doc_page"));
+ gtk_widget_hide (glade_xml_get_widget (xml, "load_file_page"));
+ gtk_widget_hide (glade_xml_get_widget (xml, "loaded_files_page"));
+ gtk_widget_hide (glade_xml_get_widget (xml, "merge_page"));
+ gtk_widget_show (glade_xml_get_widget (xml, "end_page"));
+
+ gxi_update_default_enc_combo (data);
+ gxi_update_string_box (data);
+
+ success =
+ gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_APPLY &&
+ gxi_save_file (data);
+
+ gtk_widget_destroy (data->dialog);
+ }
+
+ return success;
+}
+
+/* this is NOT fully implemented */
+void
+gnc_xml_merge_files (void)
+{
+ GncXmlImportData *data;
+ GtkWidget *dialog, *widget, *box;
+ GladeXML *xml;
+
+ data = g_new0 (GncXmlImportData, 1);
+ data->import_type = XML_MERGE_FILES;
+
+ /* common druid initialization */
+ xml = gnc_glade_xml_new (XML_GLADE_FILE, "GnuCash XML Import Dialog");
+
+ dialog = glade_xml_get_widget (xml, "GnuCash XML Import Dialog");
+ gtk_widget_hide ((GTK_DIALOG (dialog))->action_area);
+ data->dialog = dialog;
+ g_object_set_data_full (G_OBJECT (dialog), "xml", xml, g_object_unref);
+ glade_xml_signal_autoconnect_full (xml, gnc_glade_autoconnect_full_func,
+ data);
+
+ data->druid = glade_xml_get_widget (xml, "gnc_xml_import_druid");
+ gnc_druid_set_colors (GNOME_DRUID (data->druid));
+
+ /* encodings explanations */
+ widget = glade_xml_get_widget (xml, "encodings_doc_label");
+ gtk_label_set_text (GTK_LABEL (widget), gettext (encodings_doc_string));
+ widget = glade_xml_get_widget (xml, "encodings_doc_page");
+ gnome_druid_page_standard_set_title (GNOME_DRUID_PAGE_STANDARD (widget),
+ gettext (encodings_doc_page_title));
+
+ gtk_widget_show (glade_xml_get_widget (xml, "start_page"));
+ gtk_widget_show (glade_xml_get_widget (xml, "end_page"));
+
+ /* file chooser */
+ data->file_chooser = gtk_file_chooser_widget_new (
+ GTK_FILE_CHOOSER_ACTION_OPEN);
+ box = glade_xml_get_widget (xml, "file_chooser_box");
+ gtk_box_pack_start (GTK_BOX (box), data->file_chooser, TRUE, TRUE, 0);
+ g_signal_connect (G_OBJECT (data->file_chooser), "file-activated",
+ G_CALLBACK (gxi_chooser_file_activated_cb), data);
+ gtk_widget_show (data->file_chooser);
+
+ /* selected file list */
+ data->file_list_store = gtk_list_store_new (FILE_NUM_COLS,
+ G_TYPE_STRING, G_TYPE_POINTER);
+ data->file_list_view = GTK_TREE_VIEW (glade_xml_get_widget (
+ xml, "selected_file_list"));
+ gtk_tree_view_insert_column_with_attributes (
+ data->file_list_view, -1, NULL,
+ gtk_cell_renderer_text_new (), "text", FILE_COL_NAME, NULL);
+ gtk_tree_view_set_model (data->file_list_view,
+ GTK_TREE_MODEL (data->file_list_store));
+ g_object_unref (data->file_list_store);
+
+ gtk_widget_show (dialog);
+}
+
+static void
+gxi_data_destroy (GncXmlImportData *data)
+{
+ if (!data)
+ return;
+
+ if (data->dialog)
+ gtk_widget_hide (data->dialog);
+
+ if (data->file_chooser) {
+ gtk_widget_destroy (data->file_chooser);
+ data->file_chooser = NULL;
+ }
+
+ if (data->filename) {
+ g_free (data->filename);
+ data->filename = NULL;
+ }
+
+ gxi_session_destroy (data);
+ gxi_ambiguous_info_destroy (data);
+
+ if (data->choices) {
+ g_hash_table_destroy (data->choices);
+ data->choices = NULL;
+ }
+
+ if (data->string_box) {
+ gtk_widget_destroy (data->string_box);
+ data->string_box = NULL;
+ }
+
+ if (data->dialog) {
+ gtk_widget_destroy (data->dialog);
+ data->dialog = NULL;
+ }
+
+ g_free (data);
+}
+
+static void
+conv_free (conv_type *conv) {
+ if (conv) {
+ g_free(conv->utf8_string);
+ g_free(conv);
+ }
+}
+
+static conv_type *
+conv_copy (const conv_type *conv) {
+ conv_type *new = NULL;
+ if (conv) {
+ new = g_new(conv_type, 1);
+ new->encoding = conv->encoding;
+ new->utf8_string = g_strdup (conv->utf8_string);
+ }
+ return new;
+}
+
+static gint
+conv_enc_cmp (const conv_type *conv, const GQuark *enc)
+{
+ return conv->encoding - *enc;
+}
+
+static const gchar *
+get_decoded_string (const ambiguous_type *amb, const GQuark enc)
+{
+ GList *found = g_list_find_custom (amb->conv_list, &enc,
+ (GCompareFunc) conv_enc_cmp);
+
+ if (found) {
+ return ((conv_type*) found->data)->utf8_string;
+ } else {
+ return NULL;
+ }
+}
+
+static gint
+ambiguous_cmp (const ambiguous_type *a, const ambiguous_type *b,
+ GncXmlImportData *data)
+{
+ const gchar *string_a = get_decoded_string (a, data->default_encoding);
+ const gchar *string_b = get_decoded_string (b, data->default_encoding);
+
+ if (string_a) {
+ if (string_b) {
+ /* both look good, usual compare */
+ return strcmp (string_a, string_b);
+ } else {
+ /* a look good, b not. put b to the top */
+ return 1;
+ }
+ } else {
+ if (string_b) {
+ /* b looks good, a not. pub a to the top */
+ return -1;
+ } else {
+ /* both look suboptimal, see whether one has a decision attached to it */
+ conv_type *conv_a = g_hash_table_lookup (data->choices, a->byte_sequence);
+ conv_type *conv_b = g_hash_table_lookup (data->choices, b->byte_sequence);
+ if (conv_a && !conv_b) return 1;
+ if (conv_b && !conv_a) return -1;
+ return strcmp (a->byte_sequence, b->byte_sequence);
+ }
+ }
+}
+
+static void
+ambiguous_list_insert (gchar *byte_sequence, GList *conv_list,
+ GncXmlImportData *data)
+{
+ GList *iter;
+
+ ambiguous_type *amb = g_new (ambiguous_type, 1);
+ amb->byte_sequence = g_strdup (byte_sequence);
+ amb->conv_list = NULL;
+ for (iter = g_list_last (conv_list); iter; iter = iter->prev)
+ amb->conv_list = g_list_prepend (amb->conv_list, conv_copy (iter->data));
+
+ data->ambiguous_list = g_list_insert_sorted_with_data (
+ data->ambiguous_list, amb, (GCompareDataFunc) ambiguous_cmp, data);
+}
+
+static void
+ambiguous_free (ambiguous_type *amb) {
+ if (amb) {
+ g_free (amb->byte_sequence);
+ g_list_foreach (amb->conv_list, (GFunc) conv_free, NULL);
+ g_list_free (amb->conv_list);
+ g_free (amb);
+ }
+}
+
+static void
+gxi_ambiguous_info_destroy (GncXmlImportData *data)
+{
+ if (data->unique) {
+ g_hash_table_destroy (data->unique);
+ data->unique = NULL;
+ }
+ if (data->ambiguous_ht) {
+ g_hash_table_destroy (data->ambiguous_ht);
+ data->unique = NULL;
+ }
+ if (data->ambiguous_list) {
+ g_list_foreach (data->ambiguous_list, (GFunc) ambiguous_free, NULL);
+ g_list_free (data->ambiguous_list);
+ data->ambiguous_list = NULL;
+ }
+}
+
+static void
+gxi_session_destroy (GncXmlImportData *data)
+{
+ if (data->session) {
+ xaccLogDisable ();
+ qof_session_destroy (data->session);
+ xaccLogEnable ();
+ data->session = NULL;
+ }
+}
+
+static void
+gxi_check_file (GncXmlImportData *data)
+{
+ GError *error=NULL;
+
+ if (!data->encodings) {
+ gboolean is_utf8;
+ const gchar *locale_enc;
+ gchar *enc_string, **enc_array, **enc_cursor;
+ gpointer enc_ptr;
+ GIConv iconv;
+
+ /* first locale encoding */
+ is_utf8 = g_get_charset (&locale_enc);
+ enc_string = g_ascii_strup (locale_enc, -1);
+ enc_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
+ g_free (enc_string);
+ data->encodings = g_list_append (NULL, enc_ptr);
+
+ /* add utf-8 */
+ if (!is_utf8) {
+ enc_ptr = GUINT_TO_POINTER (g_quark_from_string ("UTF-8"));
+ data->encodings = g_list_append (data->encodings, enc_ptr);
+ }
+
+ /* Translators: Please insert encodings here that are typically used in your
+ * locale, separated by spaces. No need for ASCII or UTF-8, check `locale -m`
+ * for assistance with spelling. */
+ enc_array = g_strsplit (_("ISO-8859-1 KOI8-U"), " ", 0);
+
+ /* loop through typical encodings */
+ for (enc_cursor = enc_array; *enc_cursor; enc_cursor++) {
+ if (!**enc_cursor) continue;
+ enc_string = g_ascii_strup (*enc_cursor, -1);
+ enc_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
+
+ if (!g_list_find (data->encodings, enc_ptr)) {
+ /* test whether we like this encoding */
+ iconv = g_iconv_open ("UTF-8", enc_string);
+ if (iconv != (GIConv) -1)
+ /* we like it */
+ data->encodings = g_list_append (data->encodings, enc_ptr);
+ g_iconv_close (iconv);
+ }
+ g_free (enc_string);
+ }
+ g_strfreev (enc_array);
+ }
+
+ if (!data->default_encoding) {
+ /* choose top one */
+ data->default_encoding = GPOINTER_TO_UINT (data->encodings->data);
+ }
+
+ if (!data->choices) {
+ data->choices = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) conv_free);
+ }
+
+ gxi_ambiguous_info_destroy (data);
+
+ /* analyze file */
+ data->n_impossible = (*find_ambiguous) (
+ data->filename, data->encodings, &data->unique, &data->ambiguous_ht,
+ NULL, &error);
+
+ if (data->n_impossible != -1) {
+ /* sort ambiguous words */
+ g_hash_table_foreach (data->ambiguous_ht, (GHFunc)ambiguous_list_insert,
+ data);
+ }
+}
+
+static void
+subst_insert_amb (gchar *byte_sequence, GList *conv_list, GncXmlImportData *data)
+{
+ conv_type *choice;
+ GList *default_conv;
+ gchar *default_utf8;
+
+ if (!data->subst)
+ return;
+ choice = g_hash_table_lookup (data->choices, byte_sequence);
+ if (choice) {
+ /* user choice */
+ g_hash_table_insert (data->subst, g_strdup (byte_sequence),
+ g_strdup (choice->utf8_string));
+ } else {
+ default_conv = g_list_find_custom (conv_list, &data->default_encoding,
+ (GCompareFunc) conv_enc_cmp);
+ if (default_conv) {
+ /* default conversion */
+ default_utf8 = ((conv_type*) default_conv->data)->utf8_string;
+ g_hash_table_insert (data->subst, g_strdup (byte_sequence),
+ g_strdup (default_utf8));
+ } else {
+ /* no conversion avaiable, stop filling of subst */
+ g_hash_table_destroy (data->subst);
+ data->subst = NULL;
+ }
+ }
+}
+
+static void
+subst_insert_unique (gchar *byte_sequence, conv_type *conv,
+ GncXmlImportData *data)
+{
+ if (!data->subst)
+ return;
+ g_hash_table_insert (data->subst, g_strdup (byte_sequence),
+ g_strdup (conv->utf8_string));
+}
+
+static gboolean
+gxi_parse_file (GncXmlImportData *data)
+{
+ QofSession *session=NULL;
+ QofBook *book;
+ FileBackend *backend;
+ QofBackendError io_err = ERR_BACKEND_NO_ERR;
+ gchar *logpath, *message=NULL;
+ gboolean success=FALSE;
+
+ if (data->n_unassigned || data->n_impossible)
+ goto cleanup_parse_file;
+
+ /* fill subst hash table with byte sequence substitutions */
+ data->subst = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ g_hash_table_foreach (data->ambiguous_ht, (GHFunc) subst_insert_amb, data);
+ g_hash_table_foreach (data->unique, (GHFunc) subst_insert_unique, data);
+
+ if (!data->subst)
+ goto cleanup_parse_file;
+
+ /* create a temporary QofSession */
+ gxi_session_destroy (data);
+ session = qof_session_new ();
+ data->session = session;
+ qof_session_begin (session, data->filename, TRUE, FALSE);
+ io_err = qof_session_get_error (session);
+ if (io_err != ERR_BACKEND_NO_ERR) {
+ message = _("The file could not be reopen.");
+ goto cleanup_parse_file;
+ }
+
+ logpath = xaccResolveFilePath (data->filename);
+ xaccLogSetBaseName (logpath);
+ xaccLogDisable ();
+ gxi_update_progress_bar (_("Reading file..."), 0.0);
+ qof_session_load (session, gxi_update_progress_bar);
+ gxi_update_progress_bar (NULL, -1.0);
+ xaccLogEnable ();
+
+ io_err = qof_session_get_error (session);
+ if (io_err == ERR_BACKEND_NO_ERR) {
+ /* loaded sucessfully now. strange, but ok */
+ success = TRUE;
+ goto cleanup_parse_file;
+ } else if (io_err != ERR_FILEIO_NO_ENCODING) {
+ /* another error, cannot handle this here */
+ message = _("The file could not be reopen.");
+ goto cleanup_parse_file;
+ }
+
+ qof_session_pop_error (session);
+ book = qof_session_get_book (session);
+ backend = (FileBackend*) qof_book_get_backend (book);
+
+ gxi_update_progress_bar (_("Parsing file..."), 0.0);
+ success = (*parse_with_subst) (backend, book, data->subst);
+ gxi_update_progress_bar (NULL, -1.0);
+
+ if (success)
+ data->session = session;
+ else
+ message = _("There was an error parsing the file.");
+
+ cleanup_parse_file:
+
+ if (data->subst) {
+ g_hash_table_destroy (data->subst);
+ data->subst = NULL;
+ }
+ if (message) {
+ gnc_error_dialog (data->dialog, message);
+ }
+ if (!success)
+ gxi_session_destroy (data);
+
+ return success;
+}
+
+static gboolean
+gxi_save_file (GncXmlImportData *data)
+{
+ QofBackendError io_err;
+ g_return_val_if_fail (data && data->session, FALSE);
+
+ gxi_update_progress_bar (_("Writing file..."), 0.0);
+ qof_session_save (data->session, gxi_update_progress_bar);
+ gxi_update_progress_bar (NULL, -1.0);
+
+ io_err = qof_session_get_error (data->session);
+
+ if (io_err == ERR_BACKEND_NO_ERR) {
+ return TRUE;
+ } else {
+ gxi_session_destroy (data);
+ return FALSE;
+ }
+}
+
+static void
+gxi_update_progress_bar (const gchar *message, double percentage)
+{
+ if (!progress_window) {
+ progress_window = gtk_window_new (GTK_WINDOW_POPUP);
+ progress_bar = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
+ gtk_container_set_border_width (GTK_CONTAINER (progress_window), 12);
+ gtk_container_add (GTK_CONTAINER (progress_window),
+ GTK_WIDGET (progress_bar));
+ gtk_widget_show (GTK_WIDGET (progress_bar));
+ }
+
+ if (percentage < 0) {
+ gtk_progress_bar_set_text (progress_bar, NULL);
+ gtk_progress_bar_set_fraction (progress_bar, 0.0);
+ gtk_widget_hide (progress_window);
+ } else {
+ gtk_progress_bar_set_text (progress_bar, message);
+ if (percentage <= 100)
+ gtk_progress_bar_set_fraction (progress_bar, percentage/100);
+ else
+ gtk_progress_bar_pulse (progress_bar);
+ gtk_widget_show (progress_window);
+ }
+}
+
+static void
+gxi_update_default_enc_combo (GncXmlImportData *data)
+{
+ GtkComboBox *combo;
+ GList *enc_iter;
+
+ /* add encodings list */
+ if (data->default_encoding_combo)
+ gtk_widget_destroy (data->default_encoding_combo);
+ data->default_encoding_combo = gtk_combo_box_new_text ();
+ combo = GTK_COMBO_BOX (data->default_encoding_combo);
+
+ for (enc_iter = data->encodings; enc_iter; enc_iter = enc_iter->next) {
+ gtk_combo_box_append_text (
+ combo, g_quark_to_string (GPOINTER_TO_UINT (enc_iter->data)));
+ }
+ gtk_combo_box_set_active (
+ combo,
+ g_list_index (data->encodings, GUINT_TO_POINTER (data->default_encoding)));
+
+ /* show encodings */
+ g_signal_connect (G_OBJECT (combo), "changed",
+ G_CALLBACK (gxi_default_enc_combo_changed_cb), data);
+ gtk_container_add (GTK_CONTAINER (gnc_glade_lookup_widget (
+ data->druid, "default_enc_box")),
+ GTK_WIDGET (combo));
+ gtk_widget_show (GTK_WIDGET (combo));
+}
+
+static void
+gxi_update_summary_label (GncXmlImportData *data)
+{
+ gchar *string;
+ gboolean show;
+
+ if (data->n_unassigned) {
+ if (data->n_impossible) {
+ string = g_strdup_printf (
+ _("There are %d unassigned and %d undecodable words. "
+ "Please add encodings."),
+ data->n_unassigned, data->n_impossible);
+ show = TRUE;
+ } else {
+ string = g_strdup_printf (
+ _("There are %d unassigned words. "
+ "Please decide on them or add encodings."),
+ data->n_unassigned);
+ show = TRUE;
+ }
+ } else {
+ if (data->n_impossible) {
+ string = g_strdup_printf (
+ _("There are %d undecodable words. "
+ "Please add encodings."),
+ data->n_impossible);
+ show = TRUE;
+ } else {
+ show = FALSE;
+ }
+ }
+
+ if (show) {
+ gtk_label_set_text (GTK_LABEL (data->summary_label), string);
+ g_free (string);
+ gtk_widget_show (data->summary_label);
+ } else {
+ gtk_widget_hide (data->summary_label);
+ }
+}
+
+static void
+gxi_update_string_box (GncXmlImportData *data)
+{
+ gchar *string;
+ const gchar *utf8;
+ GtkBox *vbox;
+ GtkComboBox *combo;
+ GtkListStore *store;
+ GList *word_iter, *conv_iter;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter;
+ GQuark chosen_encoding;
+ GtkTreeIter *chosen_iter, *default_iter;
+ ambiguous_type *amb;
+ conv_type *conv;
+
+ if (data->string_box)
+ gtk_widget_destroy (data->string_box);
+
+ data->string_box = gtk_vbox_new (FALSE, 6);
+ vbox = GTK_BOX (data->string_box);
+
+ data->n_unassigned = 0;
+
+ /* loop through words */
+ for (word_iter=data->ambiguous_list; word_iter; word_iter=word_iter->next) {
+
+ store = gtk_list_store_new (WORD_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+ combo = GTK_COMBO_BOX (gtk_combo_box_new_with_model (
+ GTK_TREE_MODEL (store)));
+ g_object_unref (store);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
+ "text", WORD_COL_STRING, NULL);
+
+ /* add default string, if possible */
+ amb = (ambiguous_type*) word_iter->data;
+ utf8 = get_decoded_string (amb, data->default_encoding);
+ default_iter = NULL;
+ if (utf8) {
+ string = g_strdup_printf ("%s (default)", utf8);
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, WORD_COL_STRING, string,
+ WORD_COL_ENCODING,
+ GUINT_TO_POINTER (data->default_encoding), -1);
+ g_free (string);
+ default_iter = gtk_tree_iter_copy (&iter);
+ }
+
+ /* user has selected this previously */
+ conv = (conv_type*) g_hash_table_lookup (data->choices, amb->byte_sequence);
+ chosen_encoding = (conv) ? conv->encoding : 0;
+ chosen_iter = NULL;
+
+ /* loop through conversions */
+ for (conv_iter = amb->conv_list; conv_iter; conv_iter = conv_iter->next) {
+ conv = (conv_type*) conv_iter->data;
+ string = g_strdup_printf ("%s (%s)", conv->utf8_string,
+ g_quark_to_string (conv->encoding));
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, WORD_COL_STRING, string,
+ WORD_COL_ENCODING,
+ GUINT_TO_POINTER (conv->encoding), -1);
+ g_free (string);
+
+ if (chosen_encoding && conv->encoding == chosen_encoding) {
+ chosen_iter = gtk_tree_iter_copy (&iter);
+ }
+ } /* next conversion */
+
+ if (chosen_iter) {
+ /* select previous selection again, are not we cute */
+ gtk_combo_box_set_active_iter (combo, chosen_iter);
+ gtk_tree_iter_free (chosen_iter);
+ } else {
+ if (default_iter) {
+ /* select default entry */
+ gtk_combo_box_set_active_iter (combo, default_iter);
+ } else {
+ /* count it */
+ data->n_unassigned++;
+ }
+ }
+
+ /* wire up combo */
+ g_object_set_data (G_OBJECT (combo), "ambiguous", amb);
+ g_signal_connect (G_OBJECT (combo), "changed",
+ G_CALLBACK (gxi_string_combo_changed_cb), data);
+ gtk_box_pack_start (vbox, GTK_WIDGET (combo), FALSE, FALSE, 0);
+ gtk_widget_show (GTK_WIDGET (combo));
+
+ } /* next word */
+
+ /* wire up whole string vbox */
+ gtk_container_add (GTK_CONTAINER (gnc_glade_lookup_widget (
+ data->druid, "string_box_container")),
+ GTK_WIDGET (vbox));
+ gtk_widget_show (GTK_WIDGET (vbox));
+
+ /* update label now, n_unassigned is calculated */
+ if (!data->summary_label)
+ data->summary_label = gnc_glade_lookup_widget (data->druid,
+ "impossible_label");
+ gxi_update_summary_label (data);
+}
+
+static void
+gxi_update_conversion_forward (GncXmlImportData *data)
+{
+ if (data->n_unassigned || data->n_impossible)
+ gnome_druid_set_buttons_sensitive (GNOME_DRUID (data->druid),
+ TRUE, FALSE, TRUE, TRUE);
+ else
+ gnome_druid_set_buttons_sensitive (GNOME_DRUID (data->druid),
+ TRUE, TRUE, TRUE, TRUE);
+}
+
+static GnomeDruidPage *
+gxi_get_named_page (GncXmlImportData *data, const gchar *name)
+{
+ return GNOME_DRUID_PAGE (gnc_glade_lookup_widget (data->dialog, name));
+}
+
+void
+gxi_dialog_destroy_cb (GtkObject *object, GncXmlImportData *data)
+{
+ data->dialog = NULL;
+ gxi_data_destroy (data);
+}
+
+void
+gxi_cancel_cb (GnomeDruid *druid, GncXmlImportData *data)
+{
+ if (data->import_type == XML_CONVERT_SINGLE_FILE) {
+ gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_CANCEL);
+ } else {
+ gtk_widget_destroy (data->dialog);
+ }
+}
+
+static gint
+file_filename_cmp (const GncXmlImportFile *file, const gchar *filename)
+{
+ return strcmp (file->filename, filename);
+}
+
+static void
+gxi_load_file (GncXmlImportData *data)
+{
+ GncXmlImportFile *file;
+ gchar *filename;
+ GtkTreeIter iter;
+
+ g_return_if_fail (data != NULL);
+
+ filename = gtk_file_chooser_get_filename (
+ GTK_FILE_CHOOSER (data->file_chooser));
+
+ if (filename == NULL) {
+ return;
+ }
+ if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+ g_free (filename);
+ return;
+ }
+
+ if (g_list_find_custom (data->files, filename,
+ (GCompareFunc) file_filename_cmp)) {
+ const gchar *message = _(
+ "That GnuCash XML file is already loaded. Please select another file.");
+ gnc_error_dialog (data->dialog, message);
+ g_free (filename);
+ return;
+ }
+
+ file = g_new0 (GncXmlImportFile, 1);
+ file->filename = filename;
+
+ data->files = g_list_append (data->files, file);
+
+ gtk_list_store_append (data->file_list_store, &iter);
+ gtk_list_store_set (data->file_list_store, &iter,
+ FILE_COL_NAME, filename,
+ FILE_COL_INFO, file,
+ -1);
+ file->file_list_iter = gtk_tree_iter_copy (&iter);
+
+ gnome_druid_set_page (
+ GNOME_DRUID (data->druid),
+/* gxi_get_named_page (data, "loaded_files_page")); */
+ gxi_get_named_page (data, "encodings_doc_page"));
+}
+
+static void
+gxi_unload_file (GncXmlImportData *data, GncXmlImportFile *file)
+{
+ g_return_if_fail (data != NULL && file != NULL);
+
+ data->files = g_list_remove (data->files, file);
+ gtk_list_store_remove (data->file_list_store, file->file_list_iter);
+ gtk_tree_iter_free (file->file_list_iter);
+
+ g_free (file->filename);
+}
+
+void
+gxi_chooser_file_activated_cb (GtkFileChooser *chooser, GncXmlImportData *data)
+{
+ gxi_load_file (data);
+}
+
+gboolean
+gxi_load_file_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->file_chooser);
+ gchar *filename = gtk_file_chooser_get_filename (chooser);
+
+ if (filename != NULL) {
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
+ gtk_file_chooser_set_current_folder (chooser, filename);
+ } else {
+ gxi_load_file (data);
+ }
+ g_free (filename);
+ }
+
+ return TRUE;
+}
+
+void
+gxi_conversion_prepare_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ gxi_update_conversion_forward (data);
+}
+
+static void
+gxi_default_enc_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data)
+{
+ GtkTreeIter iter;
+ gchar *enc_string;
+ GQuark curr_enc;
+
+ if (!gtk_combo_box_get_active_iter (combo, &iter))
+ return;
+
+ gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+ 0, &enc_string, -1);
+ curr_enc = g_quark_from_string (enc_string);
+
+ if (data->default_encoding == curr_enc)
+ return;
+ if (!g_list_find (data->encodings, GUINT_TO_POINTER (curr_enc))) {
+ /* should not happen */
+ PERR("invalid encoding selection");
+ return;
+ }
+
+ data->default_encoding = curr_enc;
+ gxi_check_file (data);
+ gxi_update_string_box (data);
+ gxi_update_conversion_forward (data);
+}
+
+static void
+gxi_string_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data)
+{
+ GtkTreeIter iter;
+ GList *found, *default_conv;
+ gboolean is_active;
+ ambiguous_type *amb;
+ conv_type *prev_conv, *curr_conv;
+ gpointer ptr;
+ GQuark prev_enc, curr_enc;
+
+ amb = (ambiguous_type*) g_object_get_data (G_OBJECT (combo), "ambiguous");
+ prev_conv = (conv_type*) g_hash_table_lookup (data->choices,
+ amb->byte_sequence);
+ if (prev_conv)
+ prev_enc = prev_conv->encoding;
+
+ default_conv = g_list_find_custom (amb->conv_list, &data->default_encoding,
+ (GCompareFunc) conv_enc_cmp);
+
+ is_active = gtk_combo_box_get_active_iter (combo, &iter);
+ if (is_active) {
+ gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+ WORD_COL_ENCODING, &ptr, -1);
+ curr_enc = GPOINTER_TO_UINT (ptr);
+ found = g_list_find_custom (amb->conv_list, &curr_enc,
+ (GCompareFunc) conv_enc_cmp);
+ if (found) {
+ curr_conv = (conv_type*) found->data;
+ } else {
+ /* should not happen */
+ PERR("invalid string selection");
+ is_active = FALSE;
+ }
+ }
+
+ if (is_active) {
+ if (prev_conv) {
+ if (curr_enc == prev_enc)
+ return;
+
+ /* remember new choice */
+ g_hash_table_replace (data->choices, g_strdup (amb->byte_sequence),
+ conv_copy (curr_conv));
+
+ found = g_list_find_custom (amb->conv_list, &prev_enc,
+ (GCompareFunc) conv_enc_cmp);
+ if (!found && !default_conv) {
+ /* user selected encoding for a byte sequence undecodable in the default
+ encoding, for the first time. previous selection is invalid now */
+ data->n_unassigned--;
+ gxi_update_summary_label (data);
+ }
+ }
+ else {
+ /* first choice ever */
+ g_hash_table_insert (data->choices, g_strdup (amb->byte_sequence),
+ conv_copy (curr_conv));
+
+ if (!default_conv) {
+ /* user selected encoding for a byte sequence undecodable in the default
+ encoding, for the first time. no previous selection */
+ data->n_unassigned--;
+ gxi_update_summary_label (data);
+ }
+ }
+ }
+ else {
+ if (prev_conv) {
+ /* user decided not to decide... however he did that */
+ g_hash_table_remove (data->choices, amb->byte_sequence);
+
+ if (!default_conv) {
+ /* user deselected encoding for a byte sequence undecodable in the
+ default encoding */
+ data->n_unassigned++;
+ gxi_update_summary_label (data);
+ }
+ }
+ /* the missing else clause means pure ignorance of this dialog ;-) */
+ }
+}
+
+void
+gxi_edit_encodings_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ GladeXML *xml;
+ GtkWidget *dialog;
+ GtkListStore *list_store;
+ GtkTreeStore *tree_store;
+ GtkTreeIter iter, parent, *parent_ptr;
+ GList *encodings_bak, *enc_iter;
+ const gchar *encoding;
+ gchar *string;
+ system_encoding_type *system_enc;
+ gpointer enc_ptr;
+ gint i, j;
+
+ xml = gnc_glade_xml_new (XML_GLADE_FILE, "Encodings Dialog");
+ dialog = glade_xml_get_widget (xml, "Encodings Dialog");
+ data->encodings_dialog = dialog;
+ g_object_set_data_full (G_OBJECT (dialog), "xml", xml, g_object_unref);
+ glade_xml_signal_autoconnect_full (xml, gnc_glade_autoconnect_full_func, data);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (data->dialog));
+
+ data->available_encs_view = GTK_TREE_VIEW (glade_xml_get_widget (
+ xml, "available_encs_view"));
+
+ /* set up selected encodings list */
+ data->selected_encs_view = GTK_TREE_VIEW (glade_xml_get_widget (
+ xml, "selected_encs_view"));
+ list_store = gtk_list_store_new (ENC_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+ for (enc_iter = data->encodings; enc_iter; enc_iter = enc_iter->next) {
+ encoding = g_quark_to_string (GPOINTER_TO_UINT (enc_iter->data));
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter, ENC_COL_STRING, encoding,
+ ENC_COL_QUARK, enc_iter->data, -1);
+ }
+ gtk_tree_view_insert_column_with_attributes (
+ data->selected_encs_view, -1, NULL,
+ gtk_cell_renderer_text_new (), "text", ENC_COL_STRING, NULL);
+ gtk_tree_view_set_model (data->selected_encs_view,
+ GTK_TREE_MODEL (list_store));
+ g_object_unref (list_store);
+
+ /* set up system encodings list */
+ data->available_encs_view = GTK_TREE_VIEW (glade_xml_get_widget (
+ xml, "available_encs_view"));
+ tree_store = gtk_tree_store_new (ENC_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
+ for (i = 0, system_enc = system_encodings;
+ i < n_system_encodings;
+ i++, system_enc++) {
+ if (i == 0) {
+ /* first system encoding */
+ parent_ptr = NULL;
+ } else {
+ parent_ptr = &iter;
+ for (j = 0; j < system_enc->parent; j++)
+ if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (tree_store),
+ &parent, &iter)) {
+ /* go up one level */
+ iter = parent;
+ } else {
+ /* no parent to toplevel element */
+ parent_ptr = NULL;
+ }
+ }
+ if (system_enc->encoding)
+ enc_ptr = GUINT_TO_POINTER (g_quark_from_string (system_enc->encoding));
+ else
+ enc_ptr = NULL;
+ string = gettext (system_enc->text);
+ gtk_tree_store_append (tree_store, &iter, parent_ptr);
+ gtk_tree_store_set (tree_store, &iter, ENC_COL_STRING,
+ gettext (system_enc->text), ENC_COL_QUARK, enc_ptr, -1);
+ }
+ gtk_tree_view_insert_column_with_attributes (
+ data->available_encs_view, -1, NULL,
+ gtk_cell_renderer_text_new (), "text", ENC_COL_STRING, NULL);
+ gtk_tree_view_set_model (data->available_encs_view,
+ GTK_TREE_MODEL (tree_store));
+ g_object_unref (tree_store);
+
+ /* run the dialog */
+ encodings_bak = g_list_copy (data->encodings);
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ g_list_free (encodings_bak);
+ if (!g_list_find (data->encodings,
+ GUINT_TO_POINTER (data->default_encoding))) {
+ /* choose top level encoding then */
+ data->default_encoding = GPOINTER_TO_UINT (data->encodings->data);
+ }
+
+ /* update whole page */
+ gxi_check_file (data);
+ gxi_update_default_enc_combo (data);
+ gxi_update_string_box (data);
+ gxi_update_conversion_forward (data);
+ }
+ else {
+ g_list_free (data->encodings);
+ data->encodings = encodings_bak;
+ }
+
+ gtk_widget_destroy (dialog);
+ data->encodings_dialog = NULL;
+}
+
+static void
+gxi_add_encoding (GncXmlImportData *data, gpointer encoding_ptr)
+{
+ GIConv iconv;
+ const gchar *message;
+ gchar *enc_string;
+ GtkListStore *store;
+ GtkTreeIter iter;
+
+ enc_string = g_ascii_strup (
+ g_quark_to_string (GPOINTER_TO_UINT (encoding_ptr)), -1);
+ encoding_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
+
+ if (g_list_find (data->encodings, encoding_ptr)) {
+ message = _("This encoding has been added to the list already.");
+ gnc_error_dialog (data->encodings_dialog, message);
+ return;
+ }
+
+ /* test whether we like this encoding */
+ iconv = g_iconv_open ("UTF-8", enc_string);
+ if (iconv == (GIConv) -1) {
+ g_iconv_close (iconv);
+ g_free (enc_string);
+ message = _("This is an invalid encoding.");
+ gnc_error_dialog (data->encodings_dialog, message);
+ return;
+ }
+ g_iconv_close (iconv);
+
+ /* add to the list */
+ data->encodings = g_list_append (data->encodings, encoding_ptr);
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (data->selected_encs_view));
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, ENC_COL_STRING, enc_string,
+ ENC_COL_QUARK, encoding_ptr, -1);
+
+ g_free (enc_string);
+
+ if (!data->encodings->next)
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (data->encodings_dialog),
+ GTK_RESPONSE_OK, TRUE);
+}
+
+void
+gxi_available_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GncXmlImportData *data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gpointer enc_ptr;
+
+ model = gtk_tree_view_get_model (data->available_encs_view);
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+ gtk_tree_model_get (model, &iter, ENC_COL_QUARK, &enc_ptr, -1);
+ if (!enc_ptr)
+ return;
+ gxi_add_encoding (data, enc_ptr);
+}
+
+void
+gxi_add_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gpointer enc_ptr;
+
+ selection = gtk_tree_view_get_selection (data->available_encs_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+ gtk_tree_model_get (model, &iter, ENC_COL_QUARK, &enc_ptr, -1);
+ if (!enc_ptr)
+ return;
+ gxi_add_encoding (data, enc_ptr);
+}
+
+void
+gxi_custom_enc_activate_cb (GtkEntry *entry, GncXmlImportData *data)
+{
+ const gchar *enc_string;
+
+ enc_string = gtk_entry_get_text (entry);
+ if (!enc_string)
+ return;
+ gxi_add_encoding (data, GUINT_TO_POINTER (g_quark_from_string (enc_string)));
+}
+
+void
+gxi_add_custom_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ GtkWidget *entry = gnc_glade_lookup_widget (data->encodings_dialog,
+ "custom_enc_entry");
+ gxi_custom_enc_activate_cb (GTK_ENTRY (entry), data);
+}
+
+static void
+gxi_remove_encoding (GncXmlImportData *data, GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ gpointer enc_ptr;
+
+ gtk_tree_model_get (model, iter, ENC_COL_QUARK, &enc_ptr, -1);
+ data->encodings = g_list_remove (data->encodings, enc_ptr);
+ gtk_list_store_remove (GTK_LIST_STORE (model), iter);
+ if (!data->encodings)
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (data->encodings_dialog),
+ GTK_RESPONSE_OK, FALSE);
+}
+
+void
+gxi_selected_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
+ GtkTreeViewColumn *column, GncXmlImportData *data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (data->selected_encs_view);
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+ gxi_remove_encoding (data, model, &iter);
+}
+
+void
+gxi_remove_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (data->selected_encs_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+ gxi_remove_encoding (data, model, &iter);
+}
+
+gboolean
+gxi_conversion_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ return !gxi_parse_file (data);
+}
+
+void
+gxi_loaded_files_prepare_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ gnome_druid_set_buttons_sensitive (GNOME_DRUID (data->druid),
+ FALSE, TRUE, TRUE, TRUE);
+}
+
+gboolean
+gxi_loaded_files_next_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ if (!g_list_first (data->files)) {
+ const gchar *message = _(
+ "No files to merge. Please add ones by clicking on 'Load another file'.");
+ gnc_error_dialog (data->dialog, message);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void
+gxi_unload_file_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GncXmlImportFile *file;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->file_list_view));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, FILE_COL_INFO, &file, -1);
+
+
+
+ gxi_unload_file (data, file);
+}
+
+void
+gxi_load_file_clicked_cb (GtkButton *button, GncXmlImportData *data)
+{
+ gnome_druid_set_page (GNOME_DRUID (data->druid),
+ gxi_get_named_page (data, "load_file_page"));
+}
+
+void
+gxi_end_finish_cb (GnomeDruidPage *page, GtkWidget *widget,
+ GncXmlImportData *data)
+{
+ if (data->import_type == XML_CONVERT_SINGLE_FILE) {
+ gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_APPLY);
+ } else {
+ gtk_widget_destroy (data->dialog);
+ }
+}
Added: gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.h
===================================================================
--- gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.h 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/druid-gnc-xml-import.h 2006-04-14 17:38:57 UTC (rev 13781)
@@ -0,0 +1,33 @@
+/*
+ * druid-gnc-xml-import.h --
+ * Copyright (C) 2006 Andreas Koehler <andi5.py at gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, contact:
+ *
+ * Free Software Foundation Voice: +1-617-542-5942
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
+ * Boston, MA 02110-1301, USA gnu at gnu.org
+ */
+
+#ifndef DRUID_GNC_XML_IMPORT_H
+#define DRUID_GNC_XML_IMPORT_H
+
+#include "qof.h"
+
+gboolean gnc_xml_convert_single_file (const gchar *filename);
+
+/* this is NOT fully implemented */
+void gnc_xml_merge_files (void);
+
+#endif /* DRUID_GNC_XML_IMPORT_H */
Modified: gnucash/trunk/src/gnome-utils/glade/Makefile.am
===================================================================
--- gnucash/trunk/src/gnome-utils/glade/Makefile.am 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/glade/Makefile.am 2006-04-14 17:38:57 UTC (rev 13781)
@@ -6,6 +6,7 @@
druid-provider-multifile.glade \
exchange-dialog.glade \
druid-gconf-setup.glade \
+ druid-gnc-xml-import.glade \
gnc-date-format.glade \
gnc-gui-query.glade \
preferences.glade \
Added: gnucash/trunk/src/gnome-utils/glade/druid-gnc-xml-import.glade
===================================================================
--- gnucash/trunk/src/gnome-utils/glade/druid-gnc-xml-import.glade 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/glade/druid-gnc-xml-import.glade 2006-04-14 17:38:57 UTC (rev 13781)
@@ -0,0 +1,1161 @@
+<?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="GtkDialog" id="GnuCash XML Import Dialog">
+ <property name="title" translatable="yes">GnuCash XML Import Druid</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="default_width">500</property>
+ <property name="default_height">500</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="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="hidden action area">
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ </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="GnomeDruid" id="gnc_xml_import_druid">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="show_help">False</property>
+ <signal name="cancel" handler="gxi_cancel_cb" last_modification_time="Thu, 30 Mar 2006 05:47:59 GMT"/>
+
+ <child>
+ <widget class="GnomeDruidPageEdge" id="start_page">
+ <property name="visible">True</property>
+ <property name="position">GNOME_EDGE_START</property>
+ <property name="title" translatable="yes">Title placeholder</property>
+ <property name="text">Introduction placeholder</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="load_file_page">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Choose a file to import</property>
+ <signal name="next" handler="gxi_load_file_next_cb" last_modification_time="Thu, 30 Mar 2006 05:52:54 GMT"/>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="file_chooser_box">
+ <property name="border_width">16</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="encodings_doc_page">
+ <property name="visible">True</property>
+ <property name="title">enc doc page placeholder</property>
+
+ <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">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="encodings_doc_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">placeholder</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</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>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="conversion_page">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Convert the file</property>
+ <signal name="prepare" handler="gxi_conversion_prepare_cb" after="yes" last_modification_time="Fri, 07 Apr 2006 18:12:18 GMT"/>
+ <signal name="next" handler="gxi_conversion_next_cb" last_modification_time="Sun, 09 Apr 2006 12:52:00 GMT"/>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="druid-vbox3">
+ <property name="border_width">16</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="edit_encs_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_edit_encodings_clicked_cb" last_modification_time="Fri, 07 Apr 2006 23:16:12 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment12">
+ <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="hbox12">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image15">
+ <property name="visible">True</property>
+ <property name="stock">gtk-select-font</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="label13">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit list of encodings</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>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="default_enc_box">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Default encoding:</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>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </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">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="impossible_label">
+ <property name="visible">True</property>
+ <property name="label">placeholder: #unassigned, #impossible</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>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment13">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0.75</property>
+ <property name="yscale">1</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="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</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="visible">True</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="string_box_container">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">12</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </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>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="loaded_files_page">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">GnuCash XML files you have loaded</property>
+ <signal name="prepare" handler="gxi_loaded_files_prepare_cb" last_modification_time="Thu, 30 Mar 2006 22:20:01 GMT"/>
+ <signal name="next" handler="gxi_loaded_files_next_cb" last_modification_time="Thu, 30 Mar 2006 23:20:21 GMT"/>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="druid-vbox5">
+ <property name="border_width">16</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="selected_file_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ </widget>
+ </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="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Click "Load another file" if you have more data to import at this time. Do this if you have saved your accounts to separate GnuCash files.
+
+Click "Forward" to finish loading files and move to the next step of the GnuCash XML import process.</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</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>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <property name="spacing">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="unload_file_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_unload_file_clicked_cb" last_modification_time="Thu, 30 Mar 2006 08:57:18 GMT"/>
+
+ <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-remove</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="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Unload selected file</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>
+ </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>
+
+ <child>
+ <widget class="GtkButton" id="load_file_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_load_file_clicked_cb" last_modification_time="Thu, 30 Mar 2006 09:01:19 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <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="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-add</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="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Load another file</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>
+ </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>
+
+ <child>
+ <widget class="GtkButton" id="no_merge_button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_cancel_cb" last_modification_time="Thu, 30 Mar 2006 22:07:55 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment4">
+ <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="hbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-cancel</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="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Do not merge</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>
+ </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">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageStandard" id="merge_page">
+ <property name="visible">True</property>
+ <property name="title">This one is a placeholder right now</property>
+
+ <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">6</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GnomeDruidPageEdge" id="end_page">
+ <property name="visible">True</property>
+ <property name="position">GNOME_EDGE_FINISH</property>
+ <property name="title" translatable="yes">Finish GnuCash XML Import</property>
+ <property name="text">FIXME: explain what we do or what we have done (+translatable)</property>
+ <signal name="finish" handler="gxi_end_finish_cb" last_modification_time="Thu, 30 Mar 2006 05:00:17 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="Encodings Dialog">
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes">Edit the list of encodings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_height">300</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="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</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_default">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="okbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</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">-5</property>
+ </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="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>S_ystem input encodings</b></property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">available_encs_view</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="available_encs_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <signal name="row_activated" handler="gxi_available_enc_activated_cb" last_modification_time="Sat, 08 Apr 2006 01:13:30 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</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="GtkButton" id="add_enc_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_add_enc_clicked_cb" last_modification_time="Sat, 08 Apr 2006 00:11:22 GMT"/>
+
+ <child>
+ <widget class="GtkImage" id="image11">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-forward</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>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </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="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>_Custom encoding</b></property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">custom_enc_entry</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkEntry" id="custom_enc_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ <signal name="activate" handler="gxi_custom_enc_activate_cb" last_modification_time="Sat, 08 Apr 2006 10:09:02 GMT"/>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="add_custom_enc_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_add_custom_enc_clicked_cb" last_modification_time="Sat, 08 Apr 2006 00:11:40 GMT"/>
+
+ <child>
+ <widget class="GtkImage" id="image10">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-forward</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>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </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">False</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="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>_Selected encodings</b></property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">selected_encs_view</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</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="GtkButton" id="remove_enc_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="gxi_remove_enc_clicked_cb" last_modification_time="Sat, 08 Apr 2006 00:12:54 GMT"/>
+
+ <child>
+ <widget class="GtkImage" id="image12">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-back</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>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="selected_encs_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <signal name="row_activated" handler="gxi_selected_enc_activated_cb" last_modification_time="Sat, 08 Apr 2006 01:12:38 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </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">False</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>
+
+</glade-interface>
Modified: gnucash/trunk/src/gnome-utils/gnc-file.c
===================================================================
--- gnucash/trunk/src/gnome-utils/gnc-file.c 2006-04-14 16:45:10 UTC (rev 13780)
+++ gnucash/trunk/src/gnome-utils/gnc-file.c 2006-04-14 17:38:57 UTC (rev 13781)
@@ -29,6 +29,7 @@
#include <g-wrap-wct.h>
#include "dialog-utils.h"
+#include "druid-gnc-xml-import.h"
#include "gnc-commodity.h"
#include "gnc-component-manager.h"
#include "gnc-engine.h"
@@ -740,6 +741,22 @@
/* check for i/o error, put up appropriate error dialog */
io_err = qof_session_get_error (new_session);
+
+ if (io_err == ERR_FILEIO_NO_ENCODING) {
+ qof_session_pop_error (new_session);
+ if (gnc_xml_convert_single_file (newfile)) {
+ /* try to load once again */
+ gnc_window_show_progress(_("Reading file..."), 0.0);
+ qof_session_load (new_session, gnc_window_show_progress);
+ gnc_window_show_progress(NULL, -1.0);
+ xaccLogEnable();
+ io_err = qof_session_get_error (new_session);
+ }
+ else {
+ io_err = ERR_FILEIO_PARSE_ERROR;
+ }
+ }
+
uh_oh = show_session_error (io_err, newfile, GNC_FILE_DIALOG_OPEN);
new_group = gnc_book_get_group (qof_session_get_book (new_session));
More information about the gnucash-changes
mailing list