GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
assistant-xml-encoding.c
1 /**********************************************************************
2  * assistant-xml-encoding.c -- Coversion of old XML file
3  * Copyright (C) 2006 Andreas Koehler <[email protected]>
4  * Copyright (C) 2011 Robert Fewell
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA [email protected]
22  *
23  **********************************************************************/
24 
25 #include "config.h"
26 
27 #include <glib/gi18n.h>
28 #include <gmodule.h>
29 
30 #include "TransLog.h"
31 #include "assistant-xml-encoding.h"
32 #include "dialog-utils.h"
33 #include "assistant-utils.h"
34 #include "gnc-backend-xml.h"
35 #include "gnc-component-manager.h"
36 #include "gnc-uri-utils.h"
37 #include "gnc-module.h"
38 #include "gnc-ui.h"
39 #include "io-gncxml-v2.h"
40 
41 /* NOTE: This file uses the term "encoding" even in places where it is not
42  * accurate. Please ignore that. Encodings occur in different forms:
43  * - as descriptive string, as in the list of system encodings
44  * - as string used for g_iconv_open
45  * - as GQuark, representing above string
46  * - as pointer, containing above gquark, used in lists
47  */
48 
49 typedef struct
50 {
51  GtkWidget *assistant; /* assistant */
52  gboolean canceled; /* we are canceled */
53  GtkWidget *default_encoding_combo; /* top combo on conversion page */
54  GtkWidget *default_encoding_hbox; /* Encoding Hbox */
55  GtkWidget *summary_label; /* label on conversion page */
56  GtkWidget *impossible_label; /* impossible label on conversion page */
57  GtkWidget *string_box; /* vbox of combos on conversion page */
58  GtkWidget *string_box_container; /* container on conversion page */
59  GtkWidget *encodings_dialog; /* dialog for selection of encodings */
60  GtkWidget *custom_enc_entry; /* custom entry */
61  GtkTreeView *available_encs_view; /* list view of standard encodings */
62  GtkTreeView *selected_encs_view; /* list view of selected encodings */
63 
64  GList *encodings; /* list of GQuarks for encodings */
65  GQuark default_encoding; /* default GQuark, may be zero */
66 
67  /* hash table that maps byte sequences to conversions, i.e. in the current
68  encodings setting, there is only one possible conversion */
69  GHashTable *unique;
70 
71  /* hash table that maps byte sequences to a list of conversions, i.e. in the
72  current encodings setting, there exactly these conversions are possible */
73  GHashTable *ambiguous_ht;
74 
75  /* sorted list of ambiguous words, used for the construction of the combos */
76  GList *ambiguous_list;
77 
78  /* hash table that maps byte sequences to conversions. these reflect the
79  choices the user made, accumulated and updated in the whole conversion.
80  Note: this may contain conversions that are not available in the current
81  encodings setting, just imagine, user accidentally removed an important
82  encoding from the list */
83  GHashTable *choices;
84 
85  /* number of byte sequences that have multiple possible conversions, but not in
86  the default encoding. and the user has not decided yet, of course. */
87  gint n_unassigned;
88 
89  /* number of byte sequences without any reasonable interpretation */
90  gint n_impossible;
91 
92  /* hash table that maps byte sequences to other byte sequences to be replaced
93  by them. */
94  GHashTable *subst;
95 
96  gchar *filename;
97  QofSession *session;
99 
100 /* used for the string combos, see ambiguous_free */
101 typedef struct
102 {
103  gchar *byte_sequence;
104  GList *conv_list;
106 
107 enum
108 {
109  FILE_COL_NAME = 0,
110  FILE_COL_INFO,
111  FILE_NUM_COLS
112 };
113 
114 enum
115 {
116  WORD_COL_STRING = 0,
117  WORD_COL_ENCODING,
118  WORD_NUM_COLS
119 };
120 
121 enum
122 {
123  ENC_COL_STRING = 0,
124  ENC_COL_QUARK,
125  ENC_NUM_COLS
126 };
127 
128 
129 void gxi_prepare_cb (GtkAssistant *assistant, GtkWidget *page, GncXmlImportData *data);
130 void gxi_cancel_cb (GtkAssistant *gtkassistant, GncXmlImportData *data);
131 void gxi_finish_cb (GtkAssistant *gtkassistant, GncXmlImportData *data);
132 
133 void gxi_conversion_prepare (GtkAssistant *assistant, gpointer data );
134 void gxi_conversion_next (GtkAssistant *assistant, gpointer data);
135 
136 static void gxi_data_destroy (GncXmlImportData *data);
137 static void gxi_ambiguous_info_destroy (GncXmlImportData *data);
138 static void gxi_session_destroy (GncXmlImportData *data);
139 static void gxi_check_file (GncXmlImportData *data);
140 static void gxi_sort_ambiguous_list (GncXmlImportData *data);
141 static gboolean gxi_parse_file (GncXmlImportData *data);
142 static gboolean gxi_save_file (GncXmlImportData *data);
143 static void gxi_update_progress_bar (const gchar *message, double percentage);
144 static void gxi_update_default_enc_combo (GncXmlImportData *data);
145 static void gxi_update_summary_label (GncXmlImportData *data);
146 static void gxi_update_string_box (GncXmlImportData *data);
147 static void gxi_update_conversion_forward (GncXmlImportData *data);
148 
149 static void gxi_default_enc_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data);
150 static void gxi_string_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data);
151 void gxi_edit_encodings_clicked_cb (GtkButton *button, GncXmlImportData *data);
152 void gxi_available_enc_activated_cb (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, GncXmlImportData *data);
153 void gxi_add_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
154 void gxi_custom_enc_activate_cb (GtkEntry *entry, GncXmlImportData *data);
155 void gxi_add_custom_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
156 void gxi_selected_enc_activated_cb (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column, GncXmlImportData *data);
157 void gxi_remove_enc_clicked_cb (GtkButton *button, GncXmlImportData *data);
158 
159 static const gchar *encodings_doc_string = N_(
160  "\nThe file you are trying to load is from an older version of "
161  "GnuCash. The file format in the older versions was missing the "
162  "detailed specification of the character encoding being used. This "
163  "means the text in your data file could be read in multiple ambiguous "
164  "ways. This ambiguity cannot be resolved automatically, but the new "
165  "GnuCash 2.0.0 file format will include all necessary specifications so "
166  "that you do not have to go through this step again."
167  "\n\n"
168  "GnuCash will try to guess the correct character encoding for your data "
169  "file. On the next page GnuCash will show the resulting texts when "
170  "using this guess. You have to check whether the words look as "
171  "expected. Either everything looks fine and you can simply press "
172  "'Forward'. Or the words contain unexpected characters, in which "
173  "case you should select different character encodings to see "
174  "different results. You may have to edit the list of character "
175  "encodings by clicking on the respective button."
176  "\n\n"
177  "Press 'Forward' now to select the correct character encoding for "
178  "your data file.\n");
179 
180 static const gchar *encodings_doc_page_title = N_("Ambiguous character encoding");
181 
182 static const gchar *finish_convert_string = N_(
183  "The file has been loaded successfully. If you click 'Apply' it will be saved "
184  "and reloaded into the main application. That way you will have a working "
185  "file as backup in the same directory.\n\n"
186  "You can also go back and verify your selections by clicking on 'Back'.");
187 
188 /* The debugging module that this .o belongs to. */
189 static QofLogModule log_module = GNC_MOD_ASSISTANT;
190 
191 /* window containing a progress bar */
192 static GtkWidget *progress_window = NULL;
193 static GtkProgressBar *progress_bar = NULL;
194 
195 /* this is used for a static tree of system encodings. encoding may be NULL.
196  parent declares how often to go up in the path of the previous element and use
197  that as parent, e.g. 0 -> child of previous, 1 -> same level as previous */
198 typedef struct
199 {
200  gchar *text;
201  gchar *encoding;
202  gint parent;
204 static system_encoding_type system_encodings [] =
205 {
206  { N_("Unicode"), NULL, 2 },
207  { "UTF-8", "UTF-8", 0 },
208  { N_("European"), NULL, 2 },
209  { N_("ISO-8859-1 (West European)"), "ISO-8859-1", 0 },
210  { N_("ISO-8859-2 (East European)"), "ISO-8859-2", 1 },
211  { N_("ISO-8859-3 (South European)"), "ISO-8859-3", 1 },
212  { N_("ISO-8859-4 (North European)"), "ISO-8859-4", 1 },
213  { N_("ISO-8859-5 (Cyrillic)"), "ISO-8859-5", 1 },
214  { N_("ISO-8859-6 (Arabic)"), "ISO-8859-6", 1 },
215  { N_("ISO-8859-7 (Greek)"), "ISO-8859-7", 1 },
216  { N_("ISO-8859-8 (Hebrew)"), "ISO-8859-8", 1 },
217  { N_("ISO-8859-9 (Turkish)"), "ISO-8859-9", 1 },
218  { N_("ISO-8859-10 (Nordic)"), "ISO-8859-10", 1 },
219  { N_("ISO-8859-11 (Thai)"), "ISO-8859-11", 1 },
220  { N_("ISO-8859-13 (Baltic)"), "ISO-8859-13", 1 },
221  { N_("ISO-8859-14 (Celtic)"), "ISO-8859-14", 1 },
222  { N_("ISO-8859-15 (West European, Euro sign)"), "ISO-8859-15", 1 },
223  { N_("ISO-8859-16 (South-East European)"), "ISO-8859-16", 1 },
224  { N_("Cyrillic"), NULL, 2 },
225  { N_("KOI8-R (Russian)"), "KOI8-R", 0 },
226  { N_("KOI8-U (Ukrainian)"), "KOI8-U", 1 },
227 };
228 static guint n_system_encodings = G_N_ELEMENTS (system_encodings);
229 
230 
231 void gxi_prepare_cb (GtkAssistant *assistant, GtkWidget *page,
232  GncXmlImportData *data)
233 {
234  switch (gtk_assistant_get_current_page(assistant))
235  {
236  case 1:
237  /* Current page is the Conversion page */
238  gxi_conversion_prepare (assistant, data);
239  break;
240  case 2:
241  /* Current page is final page */
242  gxi_conversion_next (assistant, data);
243  break;
244  }
245 }
246 
247 void
248 gxi_finish_cb (GtkAssistant *assistant, GncXmlImportData *data)
249 {
250  gtk_main_quit();
251 }
252 
253 static void
254 gxi_update_conversion_forward (GncXmlImportData *data)
255 {
256  GtkAssistant *assistant = GTK_ASSISTANT(data->assistant);
257  gint num = gtk_assistant_get_current_page (assistant);
258  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
259 
260  if (data->n_unassigned || data->n_impossible)
261  gtk_assistant_set_page_complete (assistant, page, FALSE);
262  else
263  gtk_assistant_set_page_complete (assistant, page, TRUE);
264 }
265 
266 void
267 gxi_cancel_cb (GtkAssistant *gtkassistant, GncXmlImportData *data)
268 {
269  gnc_suspend_gui_refresh ();
270  data->canceled = TRUE;
271  gnc_resume_gui_refresh ();
272  gtk_main_quit();
273 }
274 
275 /***************************************************/
276 
277 gboolean
278 gnc_xml_convert_single_file (const gchar *filename)
279 {
280  GncXmlImportData *data;
281  GtkWidget *widget;
282  GtkBuilder *builder;
283  gboolean success;
284 
285  data = g_new0 (GncXmlImportData, 1);
286  data->filename = gnc_uri_get_path (filename);
287  data->canceled = FALSE;
288 
289  /* gather ambiguous info */
290  gxi_check_file (data);
291  if (data->n_impossible == -1)
292  return FALSE;
293 
294  if (!g_hash_table_size (data->ambiguous_ht))
295  {
296  /* no ambiguous strings */
297  success = gxi_parse_file (data) &&
298  gxi_save_file (data);
299 
300  gxi_data_destroy (data);
301  }
302  else
303  {
304  /* common assistant initialization */
305  builder = gtk_builder_new();
306  gnc_builder_add_from_file (builder , "assistant-xml-encoding.glade", "assistant_xml_encoding");
307  data->assistant = GTK_WIDGET(gtk_builder_get_object (builder, "assistant_xml_encoding"));
308 
309  gnc_assistant_set_colors (GTK_ASSISTANT (data->assistant));
310 
311  /* Enable buttons on all pages. */
312  gtk_assistant_set_page_complete (GTK_ASSISTANT (data->assistant),
313  GTK_WIDGET(gtk_builder_get_object(builder, "start_page")),
314  TRUE);
315  gtk_assistant_set_page_complete (GTK_ASSISTANT (data->assistant),
316  GTK_WIDGET(gtk_builder_get_object(builder, "conversion_page")),
317  TRUE);
318  gtk_assistant_set_page_complete (GTK_ASSISTANT (data->assistant),
319  GTK_WIDGET(gtk_builder_get_object(builder, "end_page")),
320  TRUE);
321 
322  /* start page, explanations */
323  gtk_assistant_set_page_title (GTK_ASSISTANT(data->assistant),
324  gtk_assistant_get_nth_page (GTK_ASSISTANT(data->assistant), 0),
325  gettext(encodings_doc_page_title));
326 
327  widget = GTK_WIDGET(gtk_builder_get_object (builder, "start_page"));
328  gtk_label_set_text (GTK_LABEL(widget), gettext (encodings_doc_string));
329 
330  /* conversion page */
331  data->default_encoding_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "default_enc_box"));
332  data->string_box_container = GTK_WIDGET(gtk_builder_get_object (builder, "string_box_container"));
333  data->impossible_label = GTK_WIDGET(gtk_builder_get_object (builder, "impossible_label"));
334 
335  /* finish page */
336  widget = GTK_WIDGET(gtk_builder_get_object(builder, "end_page"));
337  gtk_label_set_text (GTK_LABEL(widget), gettext (finish_convert_string));
338 
339  gtk_builder_connect_signals(builder, data);
340 
341  gtk_widget_show_all (data->assistant);
342 
343  gxi_update_default_enc_combo (data);
344  gxi_update_string_box (data);
345 
346  g_object_unref(G_OBJECT(builder));
347 
348  /* This won't return until the assistant is finished */
349  gtk_main();
350 
351  if (data->canceled)
352  success = FALSE;
353  else
354  success = gxi_save_file (data);
355  }
356 
357  /* destroy all the data variables */
358  gxi_data_destroy (data);
359  g_free (data);
360 
361  return success;
362 }
363 
364 static void
365 gxi_data_destroy (GncXmlImportData *data)
366 {
367  if (!data)
368  return;
369 
370  if (data->filename)
371  {
372  g_free (data->filename);
373  data->filename = NULL;
374  }
375 
376  gxi_session_destroy (data);
377  gxi_ambiguous_info_destroy (data);
378 
379  if (data->choices)
380  {
381  g_hash_table_destroy (data->choices);
382  data->choices = NULL;
383  }
384 
385  if (data->string_box)
386  {
387  gtk_widget_destroy (data->string_box);
388  data->string_box = NULL;
389  }
390 
391  if (data->assistant)
392  {
393  gtk_widget_destroy (data->assistant);
394  data->assistant = NULL;
395  }
396 }
397 
398 static void
399 conv_free (conv_type *conv)
400 {
401  if (conv)
402  {
403  g_free(conv->utf8_string);
404  g_free(conv);
405  }
406 }
407 
408 static conv_type *
409 conv_copy (const conv_type *conv)
410 {
411  conv_type *new_type = NULL;
412  if (conv)
413  {
414  new_type = g_new(conv_type, 1);
415  new_type->encoding = conv->encoding;
416  new_type->utf8_string = g_strdup (conv->utf8_string);
417  }
418  return new_type;
419 }
420 
421 static gint
422 conv_enc_cmp (const conv_type *conv, const GQuark *enc)
423 {
424  return conv->encoding - *enc;
425 }
426 
427 static const gchar *
428 get_decoded_string (const ambiguous_type *amb, const GQuark enc)
429 {
430  GList *found = g_list_find_custom (amb->conv_list, &enc,
431  (GCompareFunc) conv_enc_cmp);
432 
433  if (found)
434  {
435  return ((conv_type*) found->data)->utf8_string;
436  }
437  else
438  {
439  return NULL;
440  }
441 }
442 
443 static gint
444 ambiguous_cmp (const ambiguous_type *a, const ambiguous_type *b,
445  GncXmlImportData *data)
446 {
447  const gchar *string_a = get_decoded_string (a, data->default_encoding);
448  const gchar *string_b = get_decoded_string (b, data->default_encoding);
449 
450  if (string_a)
451  {
452  if (string_b)
453  {
454  /* both look good, usual compare */
455  return strcmp (string_a, string_b);
456  }
457  else
458  {
459  /* a look good, b not. put b to the top */
460  return 1;
461  }
462  }
463  else
464  {
465  if (string_b)
466  {
467  /* b looks good, a not. put a to the top */
468  return -1;
469  }
470  else
471  {
472  /* both look suboptimal, see whether one has a decision attached to it */
473  conv_type *conv_a = g_hash_table_lookup (data->choices, a->byte_sequence);
474  conv_type *conv_b = g_hash_table_lookup (data->choices, b->byte_sequence);
475  if (conv_a && !conv_b) return 1;
476  if (conv_b && !conv_a) return -1;
477  return strcmp (a->byte_sequence, b->byte_sequence);
478  }
479  }
480 }
481 
482 static void
483 ambiguous_list_insert (gchar *byte_sequence, GList *conv_list,
484  GncXmlImportData *data)
485 {
486  GList *iter;
487 
488  ambiguous_type *amb = g_new (ambiguous_type, 1);
489  amb->byte_sequence = g_strdup (byte_sequence);
490  amb->conv_list = NULL;
491  for (iter = g_list_last (conv_list); iter; iter = iter->prev)
492  amb->conv_list = g_list_prepend (amb->conv_list, conv_copy (iter->data));
493 
494  data->ambiguous_list = g_list_prepend (data->ambiguous_list, amb);
495 }
496 
497 static void
498 ambiguous_free (ambiguous_type *amb)
499 {
500  if (amb)
501  {
502  g_free (amb->byte_sequence);
503  g_list_foreach (amb->conv_list, (GFunc) conv_free, NULL);
504  g_list_free (amb->conv_list);
505  g_free (amb);
506  }
507 }
508 
509 static void
510 gxi_ambiguous_info_destroy (GncXmlImportData *data)
511 {
512  if (data->unique)
513  {
514  g_hash_table_destroy (data->unique);
515  data->unique = NULL;
516  }
517  if (data->ambiguous_ht)
518  {
519  g_hash_table_destroy (data->ambiguous_ht);
520  data->unique = NULL;
521  }
522  if (data->ambiguous_list)
523  {
524  g_list_foreach (data->ambiguous_list, (GFunc) ambiguous_free, NULL);
525  g_list_free (data->ambiguous_list);
526  data->ambiguous_list = NULL;
527  }
528 }
529 
530 static void
531 gxi_session_destroy (GncXmlImportData *data)
532 {
533  if (data->session)
534  {
535  xaccLogDisable ();
536  qof_session_destroy (data->session);
537  xaccLogEnable ();
538  data->session = NULL;
539  }
540 }
541 
542 static void
543 gxi_sort_ambiguous_list (GncXmlImportData *data)
544 {
545  data->ambiguous_list = g_list_sort_with_data (
546  data->ambiguous_list, (GCompareDataFunc) ambiguous_cmp, data);
547 
548 }
549 
550 static void
551 subst_insert_amb (gchar *byte_sequence, GList *conv_list, GncXmlImportData *data)
552 {
553  conv_type *choice;
554  GList *default_conv;
555  gchar *default_utf8;
556 
557  if (!data->subst)
558  return;
559  choice = g_hash_table_lookup (data->choices, byte_sequence);
560  if (choice)
561  {
562  /* user choice */
563  g_hash_table_insert (data->subst, g_strdup (byte_sequence),
564  g_strdup (choice->utf8_string));
565  }
566  else
567  {
568  default_conv = g_list_find_custom (conv_list, &data->default_encoding,
569  (GCompareFunc) conv_enc_cmp);
570  if (default_conv)
571  {
572  /* default conversion */
573  default_utf8 = ((conv_type*) default_conv->data)->utf8_string;
574  g_hash_table_insert (data->subst, g_strdup (byte_sequence),
575  g_strdup (default_utf8));
576  }
577  else
578  {
579  /* no conversion avaiable, stop filling of subst */
580  g_hash_table_destroy (data->subst);
581  data->subst = NULL;
582  }
583  }
584 }
585 
586 static void
587 subst_insert_unique (gchar *byte_sequence, conv_type *conv,
588  GncXmlImportData *data)
589 {
590  if (!data->subst)
591  return;
592  g_hash_table_insert (data->subst, g_strdup (byte_sequence),
593  g_strdup (conv->utf8_string));
594 }
595 
596 static void
597 gxi_update_progress_bar (const gchar *message, double percentage)
598 {
599  if (!progress_window)
600  {
601  progress_window = gtk_window_new (GTK_WINDOW_POPUP);
602  progress_bar = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
603  gtk_container_set_border_width (GTK_CONTAINER (progress_window), 12);
604  gtk_container_add (GTK_CONTAINER (progress_window),
605  GTK_WIDGET (progress_bar));
606  gtk_widget_show (GTK_WIDGET (progress_bar));
607  }
608 
609  if (percentage < 0)
610  {
611  gtk_progress_bar_set_text (progress_bar, NULL);
612  gtk_progress_bar_set_fraction (progress_bar, 0.0);
613  gtk_widget_hide (progress_window);
614  }
615  else
616  {
617  gtk_progress_bar_set_text (progress_bar, message);
618  if (percentage <= 100)
619  gtk_progress_bar_set_fraction (progress_bar, percentage / 100);
620  else
621  gtk_progress_bar_pulse (progress_bar);
622  gtk_widget_show (progress_window);
623  }
624 }
625 
626 static void
627 gxi_update_default_enc_combo (GncXmlImportData *data)
628 {
629  GtkComboBoxText *combo;
630  GList *enc_iter;
631 
632  /* add encodings list */
633  if (data->default_encoding_combo)
634  gtk_widget_destroy (data->default_encoding_combo);
635  data->default_encoding_combo = gtk_combo_box_text_new();
636  combo = GTK_COMBO_BOX_TEXT (data->default_encoding_combo);
637 
638  for (enc_iter = data->encodings; enc_iter; enc_iter = enc_iter->next)
639  {
640  gtk_combo_box_text_append_text (
641  combo, g_quark_to_string (GPOINTER_TO_UINT (enc_iter->data)));
642  }
643  gtk_combo_box_set_active (GTK_COMBO_BOX(combo),
644  g_list_index (data->encodings, GUINT_TO_POINTER (data->default_encoding)));
645 
646  /* show encodings */
647  g_signal_connect (G_OBJECT (combo), "changed",
648  G_CALLBACK (gxi_default_enc_combo_changed_cb), data);
649  gtk_container_add (GTK_CONTAINER (data->default_encoding_hbox), GTK_WIDGET (combo));
650  gtk_widget_show (GTK_WIDGET (combo));
651 }
652 
653 static void
654 gxi_update_summary_label (GncXmlImportData *data)
655 {
656  gchar *string = NULL;
657  gboolean show = FALSE;
658 
659  if (data->n_unassigned)
660  {
661  if (data->n_impossible)
662  {
663  string = g_strdup_printf (
664  _("There are %d unassigned and %d undecodable words. "
665  "Please add encodings."),
666  data->n_unassigned, data->n_impossible);
667  show = TRUE;
668  }
669  else
670  {
671  string = g_strdup_printf (
672  _("There are %d unassigned words. "
673  "Please decide on them or add encodings."),
674  data->n_unassigned);
675  show = TRUE;
676  }
677  }
678  else
679  {
680  if (data->n_impossible)
681  {
682  string = g_strdup_printf (
683  _("There are %d undecodable words. "
684  "Please add encodings."),
685  data->n_impossible);
686  show = TRUE;
687  }
688  else
689  {
690  show = FALSE;
691  }
692  }
693 
694  if (show)
695  {
696  gtk_label_set_text (GTK_LABEL (data->summary_label), string);
697  g_free (string);
698  gtk_widget_show (data->summary_label);
699  }
700  else
701  {
702  gtk_widget_hide (data->summary_label);
703  }
704 }
705 
706 static void
707 gxi_update_string_box (GncXmlImportData *data)
708 {
709  gchar *string;
710  const gchar *utf8;
711  GtkBox *vbox;
712  GtkComboBox *combo;
713  GtkListStore *store;
714  GList *word_iter, *conv_iter;
715  GtkCellRenderer *renderer;
716  GtkTreeIter iter;
717  GQuark chosen_encoding;
718  GtkTreeIter *chosen_iter, *default_iter;
719  ambiguous_type *amb;
720  conv_type *conv;
721 
722  if (data->string_box)
723  gtk_widget_destroy (data->string_box);
724 
725  data->string_box = gtk_vbox_new (FALSE, 6);
726  vbox = GTK_BOX (data->string_box);
727 
728  data->n_unassigned = 0;
729 
730  /* loop through words */
731  for (word_iter = data->ambiguous_list; word_iter; word_iter = word_iter->next)
732  {
733 
734  store = gtk_list_store_new (WORD_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
735  combo = GTK_COMBO_BOX (gtk_combo_box_new_with_model (
736  GTK_TREE_MODEL (store)));
737  g_object_unref (store);
738  renderer = gtk_cell_renderer_text_new ();
739  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
740  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
741  "text", WORD_COL_STRING, NULL);
742 
743  /* add default string, if possible */
744  amb = (ambiguous_type*) word_iter->data;
745  utf8 = get_decoded_string (amb, data->default_encoding);
746  default_iter = NULL;
747  if (utf8)
748  {
749  string = g_strdup_printf ("%s (default)", utf8);
750  gtk_list_store_append (store, &iter);
751  gtk_list_store_set (store, &iter, WORD_COL_STRING, string,
752  WORD_COL_ENCODING,
753  GUINT_TO_POINTER (data->default_encoding), -1);
754  g_free (string);
755  default_iter = gtk_tree_iter_copy (&iter);
756  }
757 
758  /* user has selected this previously */
759  conv = (conv_type*) g_hash_table_lookup (data->choices, amb->byte_sequence);
760  chosen_encoding = (conv) ? conv->encoding : 0;
761  chosen_iter = NULL;
762 
763  /* loop through conversions */
764  for (conv_iter = amb->conv_list; conv_iter; conv_iter = conv_iter->next)
765  {
766  conv = (conv_type*) conv_iter->data;
767  string = g_strdup_printf ("%s (%s)", conv->utf8_string,
768  g_quark_to_string (conv->encoding));
769  gtk_list_store_append (store, &iter);
770  gtk_list_store_set (store, &iter, WORD_COL_STRING, string,
771  WORD_COL_ENCODING,
772  GUINT_TO_POINTER (conv->encoding), -1);
773  g_free (string);
774 
775  if (chosen_encoding && conv->encoding == chosen_encoding)
776  {
777  chosen_iter = gtk_tree_iter_copy (&iter);
778  }
779  } /* next conversion */
780 
781  if (chosen_iter)
782  {
783  /* select previous selection again, are not we cute */
784  gtk_combo_box_set_active_iter (combo, chosen_iter);
785  gtk_tree_iter_free (chosen_iter);
786  }
787  else
788  {
789  if (default_iter)
790  {
791  /* select default entry */
792  gtk_combo_box_set_active_iter (combo, default_iter);
793  }
794  else
795  {
796  /* count it */
797  data->n_unassigned++;
798  }
799  }
800 
801  /* wire up combo */
802  g_object_set_data (G_OBJECT (combo), "ambiguous", amb);
803  g_signal_connect (G_OBJECT (combo), "changed",
804  G_CALLBACK (gxi_string_combo_changed_cb), data);
805  gtk_box_pack_start (vbox, GTK_WIDGET (combo), FALSE, FALSE, 0);
806  gtk_widget_show (GTK_WIDGET (combo));
807 
808  } /* next word */
809 
810  /* wire up whole string vbox */
811  gtk_container_add (GTK_CONTAINER (data->string_box_container), GTK_WIDGET (vbox));
812  gtk_widget_show (GTK_WIDGET (vbox));
813 
814  /* update label now, n_unassigned is calculated */
815  if (!data->summary_label)
816  data->summary_label = data->impossible_label;
817  gxi_update_summary_label (data);
818 }
819 
820 void
821 gxi_conversion_prepare (GtkAssistant *assistant, gpointer user_data )
822 {
823  GncXmlImportData *data = user_data;
824 
825  gxi_update_string_box (data);
826  gxi_update_conversion_forward (data);
827 }
828 
829 static void
830 gxi_default_enc_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data)
831 {
832  GtkTreeIter iter;
833  gchar *enc_string;
834  GQuark curr_enc;
835 
836  if (!gtk_combo_box_get_active_iter (combo, &iter))
837  return;
838 
839  gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
840  0, &enc_string, -1);
841  curr_enc = g_quark_from_string (enc_string);
842  g_free (enc_string);
843 
844  if (data->default_encoding == curr_enc)
845  return;
846  if (!g_list_find (data->encodings, GUINT_TO_POINTER (curr_enc)))
847  {
848  /* should not happen */
849  PERR("invalid encoding selection");
850  return;
851  }
852 
853  data->default_encoding = curr_enc;
854  gxi_sort_ambiguous_list (data);
855  gxi_update_string_box (data);
856  gxi_update_conversion_forward (data);
857 }
858 
859 static void
860 gxi_string_combo_changed_cb (GtkComboBox *combo, GncXmlImportData *data)
861 {
862  GtkTreeIter iter;
863  GList *found, *default_conv;
864  gboolean is_active;
865  ambiguous_type *amb;
866  conv_type *prev_conv, *curr_conv = NULL;
867  gpointer ptr;
868  GQuark prev_enc, curr_enc;
869 
870  amb = (ambiguous_type*) g_object_get_data (G_OBJECT (combo), "ambiguous");
871  prev_conv = (conv_type*) g_hash_table_lookup (data->choices,
872  amb->byte_sequence);
873  if (prev_conv)
874  prev_enc = prev_conv->encoding;
875 
876  default_conv = g_list_find_custom (amb->conv_list, &data->default_encoding,
877  (GCompareFunc) conv_enc_cmp);
878 
879  is_active = gtk_combo_box_get_active_iter (combo, &iter);
880  if (is_active)
881  {
882  gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
883  WORD_COL_ENCODING, &ptr, -1);
884  curr_enc = GPOINTER_TO_UINT (ptr);
885  found = g_list_find_custom (amb->conv_list, &curr_enc,
886  (GCompareFunc) conv_enc_cmp);
887  if (found)
888  {
889  curr_conv = (conv_type*) found->data;
890  }
891  else
892  {
893  /* should not happen */
894  PERR("invalid string selection");
895  is_active = FALSE;
896  }
897  }
898 
899  if (is_active)
900  {
901  if (prev_conv)
902  {
903  if (curr_enc == prev_enc)
904  return;
905 
906  /* remember new choice */
907  g_hash_table_replace (data->choices, g_strdup (amb->byte_sequence),
908  conv_copy (curr_conv));
909 
910  found = g_list_find_custom (amb->conv_list, &prev_enc,
911  (GCompareFunc) conv_enc_cmp);
912  if (!found && !default_conv)
913  {
914  /* user selected encoding for a byte sequence undecodable in the default
915  encoding, for the first time. previous selection is invalid now */
916  data->n_unassigned--;
917  gxi_update_summary_label (data);
918  gxi_update_conversion_forward (data);
919  }
920  }
921  else
922  {
923  /* first choice ever */
924  g_hash_table_insert (data->choices, g_strdup (amb->byte_sequence),
925  conv_copy (curr_conv));
926 
927  if (!default_conv)
928  {
929  /* user selected encoding for a byte sequence undecodable in the default
930  encoding, for the first time. no previous selection */
931  data->n_unassigned--;
932  gxi_update_summary_label (data);
933  gxi_update_conversion_forward (data);
934  }
935  }
936  }
937  else
938  {
939  if (prev_conv)
940  {
941  /* user decided not to decide... however he did that */
942  g_hash_table_remove (data->choices, amb->byte_sequence);
943 
944  if (!default_conv)
945  {
946  /* user deselected encoding for a byte sequence undecodable in the
947  default encoding */
948  data->n_unassigned++;
949  gxi_update_summary_label (data);
950  gxi_update_conversion_forward (data);
951  }
952  }
953  /* the missing else clause means pure ignorance of this dialog ;-) */
954  }
955 }
956 
957 void
958 gxi_conversion_next (GtkAssistant *assistant, gpointer user_data)
959 {
960  GncXmlImportData *data = user_data;
961  gxi_parse_file (data);
962 }
963 
964 static void
965 gxi_check_file (GncXmlImportData *data)
966 {
967  if (!data->encodings)
968  {
969  gboolean is_utf8;
970  const gchar *locale_enc;
971  gchar *enc_string, **enc_array, **enc_cursor;
972  gpointer enc_ptr;
973  GIConv iconv;
974 
975  /* first locale encoding */
976  is_utf8 = g_get_charset (&locale_enc);
977  enc_string = g_ascii_strup (locale_enc, -1);
978  enc_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
979  g_free (enc_string);
980  data->encodings = g_list_append (NULL, enc_ptr);
981 
982  /* add utf-8 */
983  if (!is_utf8)
984  {
985  enc_ptr = GUINT_TO_POINTER (g_quark_from_string ("UTF-8"));
986  data->encodings = g_list_append (data->encodings, enc_ptr);
987  }
988 
989  /* Translators: Please insert encodings here that are typically used in your
990  * locale, separated by spaces. No need for ASCII or UTF-8, check `locale -m`
991  * for assistance with spelling. */
992  enc_array = g_strsplit (_("ISO-8859-1 KOI8-U"), " ", 0);
993 
994  /* loop through typical encodings */
995  for (enc_cursor = enc_array; *enc_cursor; enc_cursor++)
996  {
997  if (!**enc_cursor) continue;
998  enc_string = g_ascii_strup (*enc_cursor, -1);
999  enc_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
1000 
1001  if (!g_list_find (data->encodings, enc_ptr))
1002  {
1003  /* test whether we like this encoding */
1004  iconv = g_iconv_open ("UTF-8", enc_string);
1005  if (iconv != (GIConv) - 1)
1006  /* we like it */
1007  data->encodings = g_list_append (data->encodings, enc_ptr);
1008  g_iconv_close (iconv);
1009  }
1010  g_free (enc_string);
1011  }
1012  g_strfreev (enc_array);
1013  }
1014 
1015  if (!data->default_encoding)
1016  {
1017  /* choose top one */
1018  data->default_encoding = GPOINTER_TO_UINT (data->encodings->data);
1019  }
1020 
1021  if (!data->choices)
1022  {
1023  data->choices = g_hash_table_new_full (g_str_hash, g_str_equal,
1024  g_free, (GDestroyNotify) conv_free);
1025  }
1026 
1027  gxi_ambiguous_info_destroy (data);
1028 
1029  /* analyze file */
1030  data->n_impossible = gnc_xml2_find_ambiguous (
1031  data->filename, data->encodings, &data->unique, &data->ambiguous_ht, NULL);
1032 
1033  if (data->n_impossible != -1)
1034  {
1035  /* sort ambiguous words */
1036  g_hash_table_foreach (data->ambiguous_ht, (GHFunc)ambiguous_list_insert,
1037  data);
1038  gxi_sort_ambiguous_list (data);
1039  }
1040 }
1041 
1042 static gboolean
1043 gxi_parse_file (GncXmlImportData *data)
1044 {
1045  QofSession *session = NULL;
1046  QofBook *book;
1047  FileBackend *backend;
1048  QofBackendError io_err = ERR_BACKEND_NO_ERR;
1049  gchar *message = NULL;
1050  gboolean success = FALSE;
1051 
1052  if (data->n_unassigned || data->n_impossible)
1053  goto cleanup_parse_file;
1054 
1055  /* fill subst hash table with byte sequence substitutions */
1056  data->subst = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1057  g_hash_table_foreach (data->ambiguous_ht, (GHFunc) subst_insert_amb, data);
1058  g_hash_table_foreach (data->unique, (GHFunc) subst_insert_unique, data);
1059 
1060  if (!data->subst)
1061  goto cleanup_parse_file;
1062 
1063  /* create a temporary QofSession */
1064  gxi_session_destroy (data);
1065  session = qof_session_new ();
1066  data->session = session;
1067  qof_session_begin (session, data->filename, TRUE, FALSE, FALSE);
1068  io_err = qof_session_get_error (session);
1069  if (io_err != ERR_BACKEND_NO_ERR)
1070  {
1071  message = _("The file could not be reopened.");
1072  goto cleanup_parse_file;
1073  }
1074 
1075  xaccLogDisable ();
1076  gxi_update_progress_bar (_("Reading file..."), 0.0);
1077  qof_session_load (session, gxi_update_progress_bar);
1078  gxi_update_progress_bar (NULL, -1.0);
1079  xaccLogEnable ();
1080 
1081  io_err = qof_session_get_error (session);
1082  if (io_err == ERR_BACKEND_NO_ERR)
1083  {
1084  /* loaded sucessfully now. strange, but ok */
1085  success = TRUE;
1086  goto cleanup_parse_file;
1087  }
1088  else if (io_err != ERR_FILEIO_NO_ENCODING)
1089  {
1090  /* another error, cannot handle this here */
1091  message = _("The file could not be reopened.");
1092  goto cleanup_parse_file;
1093  }
1094 
1095  qof_session_pop_error (session);
1096  book = qof_session_get_book (session);
1097  backend = (FileBackend*) qof_book_get_backend (book);
1098 
1099  gxi_update_progress_bar (_("Parsing file..."), 0.0);
1100  success = gnc_xml2_parse_with_subst (backend, book, data->subst);
1101  gxi_update_progress_bar (NULL, -1.0);
1102 
1103  if (success)
1104  data->session = session;
1105  else
1106  message = _("There was an error parsing the file.");
1107 
1108 cleanup_parse_file:
1109 
1110  if (data->subst)
1111  {
1112  g_hash_table_destroy (data->subst);
1113  data->subst = NULL;
1114  }
1115  if (message)
1116  {
1117  gnc_error_dialog (data->assistant, "%s", message);
1118  }
1119  if (!success)
1120  gxi_session_destroy (data);
1121 
1122  return success;
1123 }
1124 
1125 static gboolean
1126 gxi_save_file (GncXmlImportData *data)
1127 {
1128  QofBackendError io_err;
1129  g_return_val_if_fail (data && data->session, FALSE);
1130 
1131  gxi_update_progress_bar (_("Writing file..."), 0.0);
1132  qof_session_save (data->session, gxi_update_progress_bar);
1133  gxi_update_progress_bar (NULL, -1.0);
1134 
1135  io_err = qof_session_get_error (data->session);
1136 
1137  if (io_err == ERR_BACKEND_NO_ERR)
1138  {
1139  return TRUE;
1140  }
1141  else
1142  {
1143  gxi_session_destroy (data);
1144  return FALSE;
1145  }
1146 }
1147 
1148 
1149 /***************************
1150  * *
1151  * Encodings dialog window *
1152  * *
1153  **************************/
1154 void
1155 gxi_edit_encodings_clicked_cb (GtkButton *button, GncXmlImportData *data)
1156 {
1157  GtkBuilder *builder;
1158  GtkWidget *dialog;
1159  GtkListStore *list_store;
1160  GtkTreeStore *tree_store;
1161  GtkTreeIter iter, parent, *parent_ptr;
1162  GList *encodings_bak, *enc_iter;
1163  const gchar *encoding;
1164  system_encoding_type *system_enc;
1165  gpointer enc_ptr;
1166  gint i, j;
1167 
1168  builder = gtk_builder_new();
1169  gnc_builder_add_from_file (builder, "assistant-xml-encoding.glade", "Encodings Dialog");
1170  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Encodings Dialog"));
1171  data->encodings_dialog = dialog;
1172 
1173  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, data);
1174 
1175  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (data->assistant));
1176 
1177  data->available_encs_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "available_encs_view"));
1178 
1179  data->custom_enc_entry = GTK_WIDGET(gtk_builder_get_object (builder, "custom_enc_entry"));
1180 
1181  /* set up selected encodings list */
1182  data->selected_encs_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "selected_encs_view"));
1183  list_store = gtk_list_store_new (ENC_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
1184  for (enc_iter = data->encodings; enc_iter; enc_iter = enc_iter->next)
1185  {
1186  encoding = g_quark_to_string (GPOINTER_TO_UINT (enc_iter->data));
1187  gtk_list_store_append (list_store, &iter);
1188  gtk_list_store_set (list_store, &iter, ENC_COL_STRING, encoding,
1189  ENC_COL_QUARK, enc_iter->data, -1);
1190  }
1191  gtk_tree_view_insert_column_with_attributes (
1192  data->selected_encs_view, -1, NULL,
1193  gtk_cell_renderer_text_new (), "text", ENC_COL_STRING, NULL);
1194  gtk_tree_view_set_model (data->selected_encs_view,
1195  GTK_TREE_MODEL (list_store));
1196  g_object_unref (list_store);
1197 
1198  /* set up system encodings list */
1199  data->available_encs_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "available_encs_view"));
1200  tree_store = gtk_tree_store_new (ENC_NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);
1201  for (i = 0, system_enc = system_encodings;
1202  i < n_system_encodings;
1203  i++, system_enc++)
1204  {
1205  if (i == 0)
1206  {
1207  /* first system encoding */
1208  parent_ptr = NULL;
1209  }
1210  else
1211  {
1212  parent_ptr = &iter;
1213  for (j = 0; j < system_enc->parent; j++)
1214  if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (tree_store),
1215  &parent, &iter))
1216  {
1217  /* go up one level */
1218  iter = parent;
1219  }
1220  else
1221  {
1222  /* no parent to toplevel element */
1223  parent_ptr = NULL;
1224  }
1225  }
1226  if (system_enc->encoding)
1227  enc_ptr = GUINT_TO_POINTER (g_quark_from_string (system_enc->encoding));
1228  else
1229  enc_ptr = NULL;
1230 
1231  gtk_tree_store_append (tree_store, &iter, parent_ptr);
1232  gtk_tree_store_set (tree_store, &iter, ENC_COL_STRING,
1233  gettext (system_enc->text), ENC_COL_QUARK, enc_ptr, -1);
1234  }
1235  gtk_tree_view_insert_column_with_attributes (
1236  data->available_encs_view, -1, NULL,
1237  gtk_cell_renderer_text_new (), "text", ENC_COL_STRING, NULL);
1238  gtk_tree_view_set_model (data->available_encs_view,
1239  GTK_TREE_MODEL (tree_store));
1240  g_object_unref (tree_store);
1241 
1242  /* run the dialog */
1243  encodings_bak = g_list_copy (data->encodings);
1244  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
1245  {
1246  g_list_free (encodings_bak);
1247  if (!g_list_find (data->encodings,
1248  GUINT_TO_POINTER (data->default_encoding)))
1249  {
1250  /* choose top level encoding then */
1251  data->default_encoding = GPOINTER_TO_UINT (data->encodings->data);
1252  }
1253 
1254  /* update whole page */
1255  gxi_check_file (data);
1256  gxi_update_default_enc_combo (data);
1257  gxi_update_string_box (data);
1258  gxi_update_conversion_forward (data);
1259  }
1260  else
1261  {
1262  g_list_free (data->encodings);
1263  data->encodings = encodings_bak;
1264  }
1265  g_object_unref(G_OBJECT(builder));
1266 
1267  gtk_widget_destroy (dialog);
1268  data->encodings_dialog = NULL;
1269 }
1270 
1271 static void
1272 gxi_add_encoding (GncXmlImportData *data, gpointer encoding_ptr)
1273 {
1274  GIConv iconv;
1275  const gchar *message;
1276  gchar *enc_string;
1277  GtkListStore *store;
1278  GtkTreeIter iter;
1279 
1280  enc_string = g_ascii_strup (
1281  g_quark_to_string (GPOINTER_TO_UINT (encoding_ptr)), -1);
1282  encoding_ptr = GUINT_TO_POINTER (g_quark_from_string (enc_string));
1283 
1284  if (g_list_find (data->encodings, encoding_ptr))
1285  {
1286  message = _("This encoding has been added to the list already.");
1287  gnc_error_dialog (data->encodings_dialog, "%s", message);
1288  return;
1289  }
1290 
1291  /* test whether we like this encoding */
1292  iconv = g_iconv_open ("UTF-8", enc_string);
1293  if (iconv == (GIConv) - 1)
1294  {
1295  g_iconv_close (iconv);
1296  g_free (enc_string);
1297  message = _("This is an invalid encoding.");
1298  gnc_error_dialog (data->encodings_dialog, "%s", message);
1299  return;
1300  }
1301  g_iconv_close (iconv);
1302 
1303  /* add to the list */
1304  data->encodings = g_list_append (data->encodings, encoding_ptr);
1305  store = GTK_LIST_STORE (gtk_tree_view_get_model (data->selected_encs_view));
1306  gtk_list_store_append (store, &iter);
1307  gtk_list_store_set (store, &iter, ENC_COL_STRING, enc_string,
1308  ENC_COL_QUARK, encoding_ptr, -1);
1309 
1310  g_free (enc_string);
1311 
1312  if (!data->encodings->next)
1313  gtk_dialog_set_response_sensitive (GTK_DIALOG (data->encodings_dialog),
1314  GTK_RESPONSE_OK, TRUE);
1315 }
1316 
1317 void
1318 gxi_add_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
1319 {
1320  GtkTreeSelection *selection;
1321  GtkTreeModel *model;
1322  GtkTreeIter iter;
1323  gpointer enc_ptr;
1324 
1325  selection = gtk_tree_view_get_selection (data->available_encs_view);
1326  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1327  return;
1328  gtk_tree_model_get (model, &iter, ENC_COL_QUARK, &enc_ptr, -1);
1329  if (!enc_ptr)
1330  return;
1331  gxi_add_encoding (data, enc_ptr);
1332 }
1333 
1334 static void
1335 gxi_remove_encoding (GncXmlImportData *data, GtkTreeModel *model,
1336  GtkTreeIter *iter)
1337 {
1338  gpointer enc_ptr;
1339 
1340  gtk_tree_model_get (model, iter, ENC_COL_QUARK, &enc_ptr, -1);
1341  data->encodings = g_list_remove (data->encodings, enc_ptr);
1342  gtk_list_store_remove (GTK_LIST_STORE (model), iter);
1343  if (!data->encodings)
1344  gtk_dialog_set_response_sensitive (GTK_DIALOG (data->encodings_dialog),
1345  GTK_RESPONSE_OK, FALSE);
1346 }
1347 
1348 void
1349 gxi_remove_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
1350 {
1351  GtkTreeSelection *selection;
1352  GtkTreeModel *model;
1353  GtkTreeIter iter;
1354 
1355  selection = gtk_tree_view_get_selection (data->selected_encs_view);
1356  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1357  return;
1358  gxi_remove_encoding (data, model, &iter);
1359 }
1360 
1361 void
1362 gxi_available_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
1363  GtkTreeViewColumn *column,
1364  GncXmlImportData *data)
1365 {
1366  GtkTreeModel *model;
1367  GtkTreeIter iter;
1368  gpointer enc_ptr;
1369 
1370  model = gtk_tree_view_get_model (data->available_encs_view);
1371  if (!gtk_tree_model_get_iter (model, &iter, path))
1372  return;
1373  gtk_tree_model_get (model, &iter, ENC_COL_QUARK, &enc_ptr, -1);
1374  if (!enc_ptr)
1375  return;
1376  gxi_add_encoding (data, enc_ptr);
1377 }
1378 
1379 void
1380 gxi_custom_enc_activate_cb (GtkEntry *entry, GncXmlImportData *data)
1381 {
1382  const gchar *enc_string;
1383 
1384  enc_string = gtk_entry_get_text (entry);
1385  if (!enc_string)
1386  return;
1387  gxi_add_encoding (data, GUINT_TO_POINTER (g_quark_from_string (enc_string)));
1388 }
1389 
1390 void
1391 gxi_add_custom_enc_clicked_cb (GtkButton *button, GncXmlImportData *data)
1392 {
1393  GtkWidget *entry = data->custom_enc_entry;
1394  gxi_custom_enc_activate_cb (GTK_ENTRY (entry), data);
1395 }
1396 
1397 void
1398 gxi_selected_enc_activated_cb (GtkTreeView *view, GtkTreePath *path,
1399  GtkTreeViewColumn *column, GncXmlImportData *data)
1400 {
1401  GtkTreeModel *model;
1402  GtkTreeIter iter;
1403 
1404  model = gtk_tree_view_get_model (data->selected_encs_view);
1405  if (!gtk_tree_model_get_iter (model, &iter, path))
1406  return;
1407  gxi_remove_encoding (data, model, &iter);
1408 }
1409 
void qof_session_save(QofSession *session, QofPercentageFunc percentage_func)
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:59
gboolean gnc_xml2_parse_with_subst(FileBackend *fbe, QofBook *book, GHashTable *subst)
void xaccLogDisable(void)
Definition: TransLog.c:93
gchar * gnc_uri_get_path(const gchar *uri)
#define PERR(format, args...)
Definition: qoflog.h:237
QofBook * qof_session_get_book(const QofSession *session)
api for GnuCash version 2 XML-based file format
QofBackendError qof_session_pop_error(QofSession *session)
QofBackendError qof_session_get_error(QofSession *session)
API for the transaction logger.
void qof_session_begin(QofSession *session, const char *book_id, gboolean ignore_lock, gboolean create, gboolean force)
gint gnc_xml2_find_ambiguous(const gchar *filename, GList *encodings, GHashTable **unique, GHashTable **ambiguous, GList **impossible)
Utility functions for convert uri in separate components and back.
load and save data to files
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
void xaccLogEnable(void)
Definition: TransLog.c:97
const gchar * QofLogModule
Definition: qofid.h:89