GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-gsettings.c
1 /********************************************************************\
2  * gnc-gsettings.c -- utility functions for storing/retrieving *
3  * data in the GSettings database for GnuCash *
4  * Copyright (C) 2013 Geert Janssens <[email protected]> *
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 <stdio.h>
28 #include <string.h>
29 #include "gnc-gsettings.h"
30 #include "gnc-path.h"
31 #include "guile-mappings.h"
32 #include <libguile.h>
33 #include "libqof/qof/qof.h"
34 #include "gnc-prefs-p.h"
35 
36 #include <libxml/xmlmemory.h>
37 #include <libxml/debugXML.h>
38 #include <libxml/HTMLtree.h>
39 #include <libxml/xmlIO.h>
40 #include <libxml/xinclude.h>
41 #include <libxml/catalog.h>
42 #include <libxslt/xslt.h>
43 #include <libxslt/xsltInternals.h>
44 #include <libxslt/transform.h>
45 #include <libxslt/xsltutils.h>
46 
47 #define CLIENT_TAG "%s-%s-client"
48 #define NOTIFY_TAG "%s-%s-notify_id"
49 
50 #define GNC_PREF_MIGRATE_PREFS_DONE "migrate-prefs-done"
51 
52 static GHashTable *schema_hash = NULL;
53 static const gchar *gsettings_prefix;
54 static xmlExternalEntityLoader defaultEntityLoader = NULL;
55 
56 /* This static indicates the debugging module that this .o belongs to. */
57 static QofLogModule log_module = "gnc.app-utils.gsettings";
58 
59 /************************************************************/
60 /* Internal helper functions */
61 /************************************************************/
62 static gboolean gnc_gsettings_is_valid_key(GSettings *settings, const gchar *key)
63 {
64  gchar **keys = NULL;
65  gint i = 0;
66  gboolean found = FALSE;
67 
68  // Check if the key is valid key within settings
69  if (!G_IS_SETTINGS(settings))
70  return FALSE;
71 
72  // Get list of keys
73  keys = g_settings_list_keys(settings);
74 
75  while (keys && keys[i])
76  {
77  if (!g_strcmp0(key, keys[i]))
78  {
79  found = TRUE;
80  break;
81  }
82  i++;
83  }
84 
85  // Free keys
86  g_strfreev(keys);
87 
88  return found;
89 }
90 
91 static GSettings * gnc_gsettings_get_schema_ptr (const gchar *schema_str)
92 {
93  GSettings *gset = NULL;
94  gchar *full_name = gnc_gsettings_normalize_schema_name (schema_str);
95 
96  ENTER("");
97  if (!schema_hash)
98  schema_hash = g_hash_table_new (g_str_hash, g_str_equal);
99 
100  gset = g_hash_table_lookup (schema_hash, full_name);
101  DEBUG ("Looking for schema %s returned gsettings %p", full_name, gset);
102  if (!gset)
103  {
104  gset = g_settings_new (full_name);
105  DEBUG ("Created gsettings object %p for schema %s", gset, full_name);
106  if (G_IS_SETTINGS(gset))
107  g_hash_table_insert (schema_hash, full_name, gset);
108  else
109  PWARN ("Ignoring attempt to access unknown gsettings schema %s", full_name);
110  }
111 
112  LEAVE("");
113  return gset;
114 }
115 
116 
117 /************************************************************/
118 /* GSettings Utilities */
119 /************************************************************/
120 
121 void
122 gnc_gsettings_set_prefix (const gchar *prefix)
123 {
124  gsettings_prefix = prefix;
125 }
126 
127 const gchar *
129 {
130  if (!gsettings_prefix)
131  {
132  const char *prefix = g_getenv("GNC_GSETTINGS_PREFIX");
133  if (prefix)
134  gsettings_prefix = prefix;
135  else
136  gsettings_prefix = GSET_SCHEMA_PREFIX;
137  }
138  return gsettings_prefix;
139 }
140 
141 gchar *
143 {
144  if (name == NULL)
145  {
146  /* Need to return a newly allocated string */
147  return g_strdup(gnc_gsettings_get_prefix());
148  }
149  if (g_str_has_prefix (name, gnc_gsettings_get_prefix ()))
150  {
151  /* Need to return a newly allocated string */
152  return g_strdup(name);
153  }
154 
155  return g_strjoin(".", gnc_gsettings_get_prefix(), name, NULL);
156 }
157 
158 
159 /************************************************************/
160 /* Change notification */
161 /************************************************************/
162 
163 gulong
164 gnc_gsettings_register_cb (const gchar *schema,
165  const gchar *key,
166  gpointer func,
167  gpointer user_data)
168 {
169  gulong retval = 0;
170  gchar *signal = NULL;
171 
172  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
173 
174  ENTER("");
175  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), retval);
176  g_return_val_if_fail (func, retval);
177 
178  if ((!key) || (*key == '\0'))
179  signal = g_strdup ("changed");
180  else
181  {
182  if (gnc_gsettings_is_valid_key(schema_ptr, key))
183  signal = g_strconcat ("changed::", key, NULL);
184  }
185 
186  retval = g_signal_connect (schema_ptr, signal, G_CALLBACK (func), user_data);
187 
188  g_free (signal);
189 
190  LEAVE("");
191  return retval;
192 }
193 
194 
195 void
196 gnc_gsettings_remove_cb_by_func (const gchar *schema,
197  const gchar *key,
198  gpointer func,
199  gpointer user_data)
200 {
201  gint matched = 0;
202  GQuark quark = 0;
203 
204  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
205  g_return_if_fail (G_IS_SETTINGS (schema_ptr));
206  g_return_if_fail (func);
207 
208  ENTER ();
209 
210  if ((key) && (gnc_gsettings_is_valid_key(schema_ptr, key)))
211  quark = g_quark_from_string (key);
212 
213  matched = g_signal_handlers_disconnect_matched (
214  schema_ptr,
215  G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
216  g_signal_lookup ("changed", G_TYPE_SETTINGS), /* signal_id */
217  quark, /* signal_detail */
218  NULL, /* closure */
219  G_CALLBACK (func), /* callback function */
220  user_data);
221  LEAVE ("Schema: %s, key: %s - removed %d handlers for 'changed' signal", schema, key, matched);
222 }
223 
224 
225 void
226 gnc_gsettings_remove_cb_by_id (const gchar *schema,
227  guint handlerid)
228 {
229  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
230  g_return_if_fail (G_IS_SETTINGS (schema_ptr));
231 
232  g_signal_handler_disconnect (schema_ptr, handlerid);
233 }
234 
235 
236 guint
237 gnc_gsettings_register_any_cb (const gchar *schema,
238  gpointer func,
239  gpointer user_data)
240 {
241  return gnc_gsettings_register_cb (schema, NULL, func, user_data);
242 }
243 
244 
245 void
247  gpointer func,
248  gpointer user_data)
249 {
250  gnc_gsettings_remove_cb_by_func (schema, NULL, func, user_data);
251 }
252 
253 
254 void gnc_gsettings_bind (const gchar *schema,
255  /*@ null @*/ const gchar *key,
256  gpointer object,
257  const gchar *property)
258 {
259  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
260  g_return_if_fail (G_IS_SETTINGS (schema_ptr));
261 
262  if (gnc_gsettings_is_valid_key (schema_ptr, key))
263  g_settings_bind (schema_ptr, key, object, property, 0);
264  else
265  {
266  PERR ("Invalid key %s for schema %s", key, schema);
267  }
268 }
269 
270 /************************************************************/
271 /* Getters/Setters */
272 /************************************************************/
273 
274 gboolean
275 gnc_gsettings_get_bool (const gchar *schema,
276  const gchar *key)
277 {
278  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
279  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
280 
281  if (gnc_gsettings_is_valid_key (schema_ptr, key))
282  return g_settings_get_boolean (schema_ptr, key);
283  else
284  {
285  PERR ("Invalid key %s for schema %s", key, schema);
286  return FALSE;
287  }
288 }
289 
290 gboolean
291 gnc_gsettings_set_bool (const gchar *schema,
292  const gchar *key,
293  gboolean value)
294 {
295  gboolean result = FALSE;
296  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
297  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
298 
299  ENTER("schema: %s, key: %s", schema, key);
300  if (gnc_gsettings_is_valid_key (schema_ptr, key))
301  {
302  result = g_settings_set_boolean (schema_ptr, key, value);
303  if (!result)
304  PERR ("Unable to set value for key %s in schema %s", key, schema);
305  }
306  else
307  PERR ("Invalid key %s for schema %s", key, schema);
308 
309  LEAVE("result %i", result);
310  return result;
311 }
312 
313 gint
314 gnc_gsettings_get_int (const gchar *schema,
315  const gchar *key)
316 {
317  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
318  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), 0);
319 
320  if (gnc_gsettings_is_valid_key (schema_ptr, key))
321  return g_settings_get_int (schema_ptr, key);
322  else
323  {
324  PERR ("Invalid key %s for schema %s", key, schema);
325  return 0;
326  }
327 }
328 
329 gboolean
330 gnc_gsettings_set_int (const gchar *schema,
331  const gchar *key,
332  gint value)
333 {
334  gboolean result = FALSE;
335  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
336  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
337 
338  if (gnc_gsettings_is_valid_key (schema_ptr, key))
339  {
340  result = g_settings_set_int (schema_ptr, key, value);
341  if (!result)
342  PERR ("Unable to set value for key %s in schema %s", key, schema);
343  }
344  else
345  PERR ("Invalid key %s for schema %s", key, schema);
346 
347  return result;
348 }
349 
350 gdouble
351 gnc_gsettings_get_float (const gchar *schema,
352  const gchar *key)
353 {
354  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
355  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), 0);
356 
357  if (gnc_gsettings_is_valid_key (schema_ptr, key))
358  return g_settings_get_double (schema_ptr, key);
359  else
360  {
361  PERR ("Invalid key %s for schema %s", key, schema);
362  return 0;
363  }
364 }
365 
366 gboolean
367 gnc_gsettings_set_float (const gchar *schema,
368  const gchar *key,
369  gdouble value)
370 {
371  gboolean result = FALSE;
372  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
373  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
374 
375  if (gnc_gsettings_is_valid_key (schema_ptr, key))
376  {
377  result = g_settings_set_double (schema_ptr, key, value);
378  if (!result)
379  PERR ("Unable to set value for key %s in schema %s", key, schema);
380  }
381  else
382  PERR ("Invalid key %s for schema %s", key, schema);
383 
384  return result;
385 }
386 
387 gchar *
388 gnc_gsettings_get_string (const gchar *schema,
389  const gchar *key)
390 {
391  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
392  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), NULL);
393 
394  if (gnc_gsettings_is_valid_key (schema_ptr, key))
395  return g_settings_get_string (schema_ptr, key);
396  else
397  {
398  PERR ("Invalid key %s for schema %s", key, schema);
399  return NULL;
400  }
401 }
402 
403 gboolean
404 gnc_gsettings_set_string (const gchar *schema,
405  const gchar *key,
406  const gchar *value)
407 {
408  gboolean result = FALSE;
409  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
410  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
411 
412  ENTER("schema: %s, key: %s", schema, key);
413  if (gnc_gsettings_is_valid_key (schema_ptr, key))
414  {
415  result = g_settings_set_string (schema_ptr, key, value);
416  if (!result)
417  PERR ("Unable to set value for key %s in schema %s", key, schema);
418  }
419  else
420  PERR ("Invalid key %s for schema %s", key, schema);
421 
422  LEAVE("result %i", result);
423  return result;
424 }
425 
426 gint
427 gnc_gsettings_get_enum (const gchar *schema,
428  const gchar *key)
429 {
430  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
431  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), 0);
432 
433  if (gnc_gsettings_is_valid_key (schema_ptr, key))
434  return g_settings_get_enum (schema_ptr, key);
435  else
436  {
437  PERR ("Invalid key %s for schema %s", key, schema);
438  return 0;
439  }
440 }
441 
442 gboolean
443 gnc_gsettings_set_enum (const gchar *schema,
444  const gchar *key,
445  gint value)
446 {
447  gboolean result = FALSE;
448  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
449  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
450 
451  if (gnc_gsettings_is_valid_key (schema_ptr, key))
452  {
453  result = g_settings_set_enum (schema_ptr, key, value);
454  if (!result)
455  PERR ("Unable to set value for key %s in schema %s", key, schema);
456  }
457  else
458  PERR ("Invalid key %s for schema %s", key, schema);
459 
460  return result;
461 }
462 
463 GVariant *
464 gnc_gsettings_get_value (const gchar *schema,
465  const gchar *key)
466 {
467  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
468  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), NULL);
469 
470  if (gnc_gsettings_is_valid_key (schema_ptr, key))
471  return g_settings_get_value (schema_ptr, key);
472  else
473  {
474  PERR ("Invalid key %s for schema %s", key, schema);
475  return NULL;
476  }
477 }
478 
479 gboolean
480 gnc_gsettings_set_value (const gchar *schema,
481  const gchar *key,
482  GVariant *value)
483 {
484  gboolean result = FALSE;
485  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
486  g_return_val_if_fail (G_IS_SETTINGS (schema_ptr), FALSE);
487 
488  if (gnc_gsettings_is_valid_key (schema_ptr, key))
489  {
490  result = g_settings_set_value (schema_ptr, key, value);
491  if (!result)
492  PERR ("Unable to set value for key %s in schema %s", key, schema);
493  }
494  else
495  PERR ("Invalid key %s for schema %s", key, schema);
496 
497  return result;
498 }
499 
500 void
501 gnc_gsettings_reset (const gchar *schema,
502  const gchar *key)
503 {
504  GSettings *schema_ptr = gnc_gsettings_get_schema_ptr (schema);
505  g_return_if_fail (G_IS_SETTINGS (schema_ptr));
506 
507  if (gnc_gsettings_is_valid_key (schema_ptr, key))
508  g_settings_reset (schema_ptr, key);
509  else
510  PERR ("Invalid key %s for schema %s", key, schema);
511 }
512 
513 void
514 gnc_gsettings_reset_schema (const gchar *schema)
515 {
516  gchar **keys;
517  gint counter = 0;
518 
519  keys = g_settings_list_keys (gnc_gsettings_get_schema_ptr (schema));
520 
521  if (!keys)
522  return;
523 
524  while (keys[counter])
525  {
526  gnc_gsettings_reset (schema, keys[counter]);
527  counter++;
528  }
529 
530  g_strfreev (keys);
531 }
532 
534 {
535  ENTER("");
536 
537  /* The gsettings backend only works in an installed environment.
538  * When called from the source environment (for testing purposes)
539  * simply return.
540  */
541  if (g_strcmp0 (g_getenv ("GNC_UNINSTALLED"), "1") == 0)
542  return;
543 
544  if (!prefsbackend)
545  prefsbackend = g_new0 (PrefsBackend, 1);
546 
547  prefsbackend->register_cb = gnc_gsettings_register_cb;
548  prefsbackend->remove_cb_by_func = gnc_gsettings_remove_cb_by_func;
549  prefsbackend->remove_cb_by_id = gnc_gsettings_remove_cb_by_id;
550  prefsbackend->register_group_cb = gnc_gsettings_register_any_cb;
551  prefsbackend->remove_group_cb_by_func = gnc_gsettings_remove_any_cb_by_func;
552  prefsbackend->bind = gnc_gsettings_bind;
553  prefsbackend->get_bool = gnc_gsettings_get_bool;
554  prefsbackend->get_int = gnc_gsettings_get_int;
555  prefsbackend->get_float = gnc_gsettings_get_float;
556  prefsbackend->get_string = gnc_gsettings_get_string;
557  prefsbackend->get_enum = gnc_gsettings_get_enum;
558  prefsbackend->get_value = gnc_gsettings_get_value;
559  prefsbackend->set_bool = gnc_gsettings_set_bool;
560  prefsbackend->set_int = gnc_gsettings_set_int;
561  prefsbackend->set_float = gnc_gsettings_set_float;
562  prefsbackend->set_string = gnc_gsettings_set_string;
563  prefsbackend->set_enum = gnc_gsettings_set_enum;
564  prefsbackend->set_value = gnc_gsettings_set_value;
565  prefsbackend->reset = gnc_gsettings_reset;
566  prefsbackend->reset_group = gnc_gsettings_reset_schema;
567 
568  LEAVE("Prefsbackend bind = %p", prefsbackend->bind);
569 }
570 
571 /* Attempt to migrate preferences from gconf files
572  to gsettings if not already done so */
573 
574 /* This snippet is borrowed from the xsltproc source
575  * and adapted to help the xsl transform find our temporary
576  * files in $HOME/.gnc-migration-tmp/
577  */
578 static xmlParserInputPtr
579 xsltprocExternalEntityLoader(const char *URL, const char *ID,
580  xmlParserCtxtPtr ctxt)
581 {
582  xmlParserInputPtr ret;
583  warningSAXFunc warning = NULL;
584  xmlChar *newURL;
585  gchar *tmpdir = g_build_filename (g_get_home_dir (), ".gnc-migration-tmp", NULL);
586 
587  int i;
588  const char *lastsegment = URL;
589  const char *iter = URL;
590 
591  while (*iter != 0)
592  {
593  if (*iter == '/')
594  lastsegment = iter + 1;
595  iter++;
596  }
597 
598  if ((ctxt != NULL) && (ctxt->sax != NULL))
599  {
600  warning = ctxt->sax->warning;
601  ctxt->sax->warning = NULL;
602  }
603 
604  if (defaultEntityLoader != NULL)
605  {
606  ret = defaultEntityLoader(URL, ID, ctxt);
607  if (ret != NULL)
608  {
609  if (warning != NULL)
610  ctxt->sax->warning = warning;
611  return(ret);
612  }
613  }
614 
615  newURL = xmlStrdup((const xmlChar *) tmpdir);
616  newURL = xmlStrcat(newURL, (const xmlChar *) "/");
617  newURL = xmlStrcat(newURL, (const xmlChar *) lastsegment);
618  g_free (tmpdir);
619  if (newURL != NULL)
620  {
621  ret = defaultEntityLoader((const char *)newURL, ID, ctxt);
622  if (ret != NULL)
623  {
624  if (warning != NULL)
625  ctxt->sax->warning = warning;
626  xmlFree(newURL);
627  return(ret);
628  }
629  xmlFree(newURL);
630  }
631  if (warning != NULL)
632  {
633  ctxt->sax->warning = warning;
634  if (URL != NULL)
635  DEBUG ("External entity \"%s\" not loaded", URL);
636  else if (ID != NULL)
637  DEBUG ("External entity \"%s\" not loaded", ID);
638  }
639  return(NULL);
640 }
641 
642 /* Tool to migrate existing user settings from GConf to GSettings
643  *
644  * This tool will first run some sanity checks to see if migration
645  * is necessary/possible. The actual migration works directly from
646  * the GConf .xml files. Using an xsl transform it will convert them
647  * in a guile script to set most settings found.
648  *
649  * Notes:
650  * - due to some limitations in the xslt code, all the gconf xml files are
651  * first copied into a temporary directory. After the migration has finished,
652  * that temporary directory and its contents are removed.
653  * - not all settings can be migrated. All the important ones are though.
654  * The ones that are missing are mostly with respect to window position
655  * and size.
656  * - column widths/visibilities, sorting orders,... are no longer stored
657  * in gsettings, so these will obviously not be migrated either.
658  * - upon a successful run, a flag will be set to prevent the migration
659  * from running again. So in normal circumstances the migration will
660  * be executed only once.
661  */
662 void gnc_gsettings_migrate_from_gconf (void)
663 {
664  gchar *pkgdatadir, *stylesheet, *input, *output, *command;
665  gchar *gconf_root, *gconf_apps, *gconf_gnucash;
666  gchar *base_dir, *iter;
667  SCM migr_script, result;
668  xsltStylesheetPtr stylesheetptr = NULL;
669  xmlDocPtr inputxml, transformedxml;
670  FILE *outfile;
671  gboolean migration_ok = FALSE;
672 
673  ENTER ();
674 
675  /* Only attempt to migrate if no successful migration has been done before */
676  if (gnc_gsettings_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE))
677  {
678  LEAVE ("Preferences migration ran successfully before. Skipping.");
679  return;
680  }
681 
682  base_dir = g_strdup (g_get_home_dir ());
683  for (iter = base_dir; *iter != 0; iter++)
684  {
685  if ( *iter == '\\')
686  *iter = '/';
687  }
688 
689  /* Only attempt to migrate if there is something to migrate */
690  gconf_root = g_build_filename(base_dir, ".gconf", NULL);
691  gconf_apps = g_build_filename(gconf_root, "apps", NULL);
692  gconf_gnucash = g_build_filename(gconf_apps, "gnucash", NULL);
693  migration_ok = (g_file_test (gconf_root, G_FILE_TEST_IS_DIR) &&
694  g_file_test (gconf_apps, G_FILE_TEST_IS_DIR) &&
695  g_file_test (gconf_gnucash, G_FILE_TEST_IS_DIR));
696  g_free (gconf_root);
697  g_free (gconf_apps);
698  g_free (gconf_gnucash);
699  if (!migration_ok)
700  {
701  g_free (base_dir);
702  gnc_gsettings_set_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE, TRUE);
703  PINFO ("No pre-existing GConf gnucash section found.\n"
704  "Most likely this system never ran GnuCash before.\n"
705  "Assume migration is not needed.");
706  LEAVE ();
707  return;
708  }
709 
710  pkgdatadir = gnc_path_get_pkgdatadir();
711  stylesheet = g_build_filename(pkgdatadir, "make-prefs-migration-script.xsl", NULL);
712  input = g_build_filename(pkgdatadir, "migratable-prefs.xml", NULL);
713  g_free (pkgdatadir);
714 
715  migration_ok = (g_file_test (stylesheet, G_FILE_TEST_IS_REGULAR) &&
716  g_file_test (input, G_FILE_TEST_IS_REGULAR));
717  if (!migration_ok)
718  {
719  /* Critical files not found, abort migration */
720  g_free (base_dir);
721  g_free (stylesheet);
722  g_free (input);
723  PWARN ("Migration input file and stylesheet missing. Skip migration.");
724  return;
725  }
726 
727  command = g_strconcat ("(use-modules (migrate-prefs))(migration-prepare \"",
728  base_dir, "\")", NULL);
729  DEBUG ("command = %s", command);
730  migration_ok = scm_is_true (scm_c_eval_string (command));
731  g_free (command);
732  if (!migration_ok)
733  {
734  /* Preparation step failed */
735  g_free (base_dir);
736  g_free (stylesheet);
737  g_free (input);
738  PWARN ("Migration preparation step failed. Skip migration.");
739  LEAVE ();
740  return;
741  }
742 
743  output = g_build_filename(base_dir, ".gnc-migration-tmp", "migrate-prefs-user.scm", NULL);
744  xmlSubstituteEntitiesDefault(1);
745  xmlLoadExtDtdDefaultValue = 1;
746  defaultEntityLoader = xmlGetExternalEntityLoader();
747  xmlSetExternalEntityLoader(xsltprocExternalEntityLoader);
748  stylesheetptr = xsltParseStylesheetFile((const xmlChar *)stylesheet);
749  inputxml = xmlParseFile(input);
750  transformedxml = xsltApplyStylesheet(stylesheetptr, inputxml, NULL);
751 
752  outfile = fopen(output, "w");
753  xsltSaveResultToFile(outfile, transformedxml, stylesheetptr);
754  fclose(outfile);
755 
756  xsltFreeStylesheet(stylesheetptr);
757  xmlFreeDoc(inputxml);
758  xmlFreeDoc(transformedxml);
759 
760  xsltCleanupGlobals();
761  xmlCleanupParser();
762  g_free (stylesheet);
763  g_free (input);
764 
765  migr_script = scm_from_locale_string (output);
766  scm_primitive_load (migr_script);
767  g_free (output);
768 
769  migration_ok = scm_is_true (scm_c_eval_string ("(use-modules (migrate-prefs-user))(run-migration)"));
770  if (!migration_ok)
771  {
772  /* Actual migration step failed */
773  g_free (base_dir);
774  PWARN ("Actual migration step failed. Skip migration.");
775  LEAVE ();
776  return;
777  }
778 
779  /* If we got here, the preferences were migrated successfully
780  * Mark this success in gsettings, so we won't run the migration again.
781  */
782  gnc_gsettings_set_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_MIGRATE_PREFS_DONE, TRUE);
783 
784  /* All that is left now is to cleanup... */
785  command = g_strconcat ("(use-modules (migrate-prefs))(migration-cleanup \"",
786  base_dir, "\")", NULL);
787  DEBUG ("command = %s", command);
788  migration_ok = scm_is_true (scm_c_eval_string (command));
789  g_free (command);
790  if (!migration_ok) /* Cleanup step failed, not critical */
791  PWARN ("Cleanup step failed. You may need to delete %s/.gnc-migration-tmp manually.", base_dir);
792  else
793  PINFO ("Preferences migration completed successfully");
794 
795  LEAVE ("");
796  g_free (base_dir);
797 
798 }
gchar * gnc_gsettings_normalize_schema_name(const gchar *name)
gboolean gnc_gsettings_set_int(const gchar *schema, const gchar *key, gint value)
void gnc_gsettings_set_prefix(const gchar *prefix)
gboolean gnc_gsettings_set_float(const gchar *schema, const gchar *key, gdouble value)
#define PINFO(format, args...)
Definition: qoflog.h:249
gint gnc_gsettings_get_int(const gchar *schema, const gchar *key)
#define DEBUG(format, args...)
Definition: qoflog.h:255
void gnc_gsettings_bind(const gchar *schema, const gchar *key, gpointer object, const gchar *property)
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
void gnc_gsettings_remove_any_cb_by_func(const gchar *schema, gpointer func, gpointer user_data)
gboolean gnc_gsettings_set_enum(const gchar *schema, const gchar *key, gint value)
#define PWARN(format, args...)
Definition: qoflog.h:243
GVariant * gnc_gsettings_get_value(const gchar *schema, const gchar *key)
guint gnc_gsettings_register_any_cb(const gchar *schema, gpointer func, gpointer user_data)
void gnc_gsettings_reset_schema(const gchar *schema)
gdouble gnc_gsettings_get_float(const gchar *schema, const gchar *key)
void gnc_gsettings_reset(const gchar *schema, const gchar *key)
gchar * gnc_gsettings_get_string(const gchar *schema, const gchar *key)
gint gnc_gsettings_get_enum(const gchar *schema, const gchar *key)
gboolean gnc_gsettings_set_bool(const gchar *schema, const gchar *key, gboolean value)
void gnc_gsettings_load_backend(void)
#define LEAVE(format, args...)
Definition: qoflog.h:271
gboolean gnc_gsettings_get_bool(const gchar *schema, const gchar *key)
const gchar * gnc_gsettings_get_prefix(void)
void gnc_gsettings_remove_cb_by_id(const gchar *schema, guint handlerid)
gboolean gnc_gsettings_set_value(const gchar *schema, const gchar *key, GVariant *value)
gulong gnc_gsettings_register_cb(const char *schema, const gchar *key, gpointer func, gpointer user_data)
GSettings helper routines.
gboolean gnc_gsettings_set_string(const gchar *schema, const gchar *key, const gchar *value)
void gnc_gsettings_remove_cb_by_func(const gchar *schema, const gchar *key, gpointer func, gpointer user_data)
const gchar * QofLogModule
Definition: qofid.h:89