Allow adding new variables in the var sheet
[pspp] / src / ui / gui / psppire-conf.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2009, 2010  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /*
18    This module provides an interface for simple user preference config
19    parameters.
20 */
21
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <sys/stat.h>
26
27 #include <glib.h>
28
29 #include "psppire-conf.h"
30
31 static void psppire_conf_init            (PsppireConf      *conf);
32 static void psppire_conf_class_init      (PsppireConfClass *class);
33
34 static void psppire_conf_finalize        (GObject   *object);
35 static void psppire_conf_dispose        (GObject   *object);
36
37 static GObjectClass *parent_class = NULL;
38
39
40 GType
41 psppire_conf_get_type (void)
42 {
43   static GType conf_type = 0;
44
45   if (!conf_type)
46     {
47       static const GTypeInfo conf_info =
48       {
49         sizeof (PsppireConfClass),
50         NULL,           /* base_init */
51         NULL,           /* base_finalize */
52         (GClassInitFunc) psppire_conf_class_init,
53         NULL,           /* class_finalize */
54         NULL,           /* class_data */
55         sizeof (PsppireConf),
56         0,
57         (GInstanceInitFunc) psppire_conf_init,
58       };
59
60       conf_type = g_type_register_static (G_TYPE_OBJECT,
61                                                 "PsppireConf",
62                                                 &conf_info, 0);
63     }
64
65   return conf_type;
66 }
67
68
69 static void
70 conf_read (PsppireConf *conf)
71 {
72   g_key_file_load_from_file (conf->keyfile,
73                              conf->filename,
74                              G_KEY_FILE_KEEP_COMMENTS,
75                              NULL);
76 }
77
78 static gboolean
79 flush_conf (PsppireConf *conf)
80 {
81   gsize length = 0;
82
83   gchar *kf = g_key_file_to_data  (conf->keyfile, &length, NULL);
84
85   if ( ! g_file_set_contents (conf->filename, kf, length, NULL) )
86     {
87       g_warning ("Cannot open %s for writing", conf->filename);
88     }
89
90   g_free (kf);
91   conf->idle = 0;
92   return FALSE;
93 }
94
95 static void
96 conf_write (PsppireConf *conf)
97 {
98   if ( conf->idle == 0)
99     conf->idle = g_idle_add_full (G_PRIORITY_LOW, 
100                                   (GSourceFunc) flush_conf, conf, NULL);
101 }
102
103
104 static void
105 psppire_conf_dispose  (GObject *object)
106 {
107 }
108
109 static void
110 psppire_conf_finalize (GObject *object)
111 {
112   PsppireConf *conf = PSPPIRE_CONF (object);
113   g_key_file_free (conf->keyfile);
114   g_free (conf->filename);
115 }
116
117
118 static PsppireConf *the_instance = NULL;
119
120 static GObject*
121 psppire_conf_construct   (GType                  type,
122                                      guint                  n_construct_params,
123                                      GObjectConstructParam *construct_params)
124 {
125   GObject *object;
126
127   if (!the_instance)
128     {
129       object = G_OBJECT_CLASS (parent_class)->constructor (type,
130                                                            n_construct_params,
131                                                            construct_params);
132       the_instance = PSPPIRE_CONF (object);
133     }
134   else
135     object = g_object_ref (G_OBJECT (the_instance));
136
137   return object;
138 }
139
140 static void
141 psppire_conf_class_init (PsppireConfClass *class)
142 {
143   GObjectClass *object_class;
144
145   parent_class = g_type_class_peek_parent (class);
146   object_class = (GObjectClass*) class;
147
148   object_class->finalize = psppire_conf_finalize;
149   object_class->dispose = psppire_conf_dispose;
150   object_class->constructor = psppire_conf_construct;
151
152 }
153
154
155 static void
156 psppire_conf_init (PsppireConf *conf)
157 {
158   const gchar *dirname;
159   struct stat s;
160
161   /* Get the name of the directory for user configuration files, then, if it
162      doesn't already exist, create it, since we might be the first program
163      to want to put files there. */
164   dirname = g_get_user_config_dir ();
165   if (stat (dirname, &s) == -1 && errno == ENOENT)
166     mkdir (dirname, 0700);
167
168   conf->filename = g_strdup_printf ("%s/%s", dirname, "psppirerc");
169
170   conf->keyfile = g_key_file_new ();
171
172   conf->dispose_has_run = FALSE;
173   conf->idle = 0;
174 }
175
176
177 PsppireConf *
178 psppire_conf_new (void)
179 {
180   return g_object_new (psppire_conf_get_type (), NULL);
181 }
182
183
184
185 gboolean
186 psppire_conf_get_int (PsppireConf *conf, const gchar *base,
187                       const gchar *name, gint *value)
188 {
189   gboolean ok;
190   GError *err = NULL;
191   conf_read (conf);
192   *value = g_key_file_get_integer (conf->keyfile,
193                                    base,
194                                    name, &err);
195
196   ok = (err == NULL);
197   if ( err != NULL )
198     g_error_free (err);
199
200   return ok;
201 }
202
203 gboolean
204 psppire_conf_get_boolean (PsppireConf *conf, const gchar *base,
205                           const gchar *name, gboolean *value)
206 {
207   gboolean ok;
208   gboolean b;
209   GError *err = NULL;
210   conf_read (conf);
211   b = g_key_file_get_boolean (conf->keyfile,
212                               base,
213                               name, &err);
214
215   ok = (err == NULL);
216   if ( err != NULL )
217     g_error_free (err);
218
219   if (ok)
220     *value = b;
221
222   return ok;
223 }
224
225
226
227 gboolean
228 psppire_conf_get_string (PsppireConf *conf, const gchar *base,
229                          const gchar *name, gchar **value)
230 {
231   gboolean ok;
232   gchar *b;
233   GError *err = NULL;
234   conf_read (conf);
235   b = g_key_file_get_string (conf->keyfile,
236                              base,
237                              name, &err);
238
239   ok = (err == NULL);
240   if ( err != NULL )
241     g_error_free (err);
242
243   if (ok)
244     *value = b;
245
246   return ok;
247 }
248
249
250
251
252 gboolean
253 psppire_conf_get_variant (PsppireConf *conf, const gchar *base,
254                           const gchar *name, GVariant **v)
255 {
256   gboolean ok;
257   gchar *b;
258   GError *err = NULL;
259   conf_read (conf);
260   b = g_key_file_get_string (conf->keyfile,
261                              base,
262                              name, &err);
263
264   ok = (err == NULL);
265   if ( err != NULL )
266     g_error_free (err);
267
268   if (ok)
269     {
270       *v = g_variant_parse (NULL, b, NULL, NULL, NULL);
271       g_free (b);
272     }
273
274   return ok;
275 }
276
277 gboolean
278 psppire_conf_get_enum (PsppireConf *conf, const gchar *base,
279                        const gchar *name,
280                        GType t,
281                        int *v)
282 {
283   gboolean ok;
284   gchar *b;
285   GError *err = NULL;
286   conf_read (conf);
287   b = g_key_file_get_string (conf->keyfile,
288                              base,
289                              name, &err);
290
291   ok = (err == NULL);
292   if ( err != NULL )
293     g_error_free (err);
294
295   if (ok)
296     {
297       GEnumClass *ec = g_type_class_ref (t);
298       GEnumValue *ev = g_enum_get_value_by_nick (ec, b);
299       *v = ev->value;
300       g_type_class_unref (ec);
301       g_free (b);
302     }
303
304   return ok;
305 }
306
307 void
308 psppire_conf_set_int (PsppireConf *conf,
309                       const gchar *base, const gchar *name,
310                       gint value)
311 {
312   g_key_file_set_integer (conf->keyfile, base, name, value);
313   conf_write (conf);
314 }
315
316 void
317 psppire_conf_set_boolean (PsppireConf *conf,
318                           const gchar *base, const gchar *name,
319                           gboolean value)
320 {
321   g_key_file_set_boolean (conf->keyfile, base, name, value);
322   conf_write (conf);
323 }
324
325
326 void
327 psppire_conf_set_string (PsppireConf *conf,
328                          const gchar *base, const gchar *name,
329                          const gchar *value)
330 {
331   g_key_file_set_string (conf->keyfile, base, name, value);
332   conf_write (conf);
333 }
334
335 void
336 psppire_conf_set_variant (PsppireConf *conf,
337                                const gchar *base, const gchar *name,
338                                GVariant *value)
339 {
340   gchar *v = g_variant_print (value, FALSE);
341   g_key_file_set_string (conf->keyfile, base, name, v);
342   conf_write (conf);
343   g_free (v);
344 }
345
346 void
347 psppire_conf_set_enum (PsppireConf *conf,
348                        const gchar *base, const gchar *name,
349                        GType enum_type,
350                        int value)
351 {
352   GEnumClass *ec = g_type_class_ref (enum_type);
353   GEnumValue *ev = g_enum_get_value (ec, value);
354   
355   g_key_file_set_string (conf->keyfile, base, name,
356                          ev->value_nick);
357
358   g_type_class_unref (ec);
359   
360   conf_write (conf);
361 }
362
363
364
365 /*
366   A convenience function to set the geometry of a
367   window from from a saved config
368 */
369 void
370 psppire_conf_set_window_geometry (PsppireConf *conf,
371                                   const gchar *base,
372                                   GtkWindow *window)
373 {
374   gint height, width;
375   gint x, y;
376   gboolean maximize;
377
378   if (psppire_conf_get_int (conf, base, "height", &height)
379       &&
380       psppire_conf_get_int (conf, base, "width", &width) )
381     {
382       gtk_window_set_default_size (window, width, height);
383     }
384
385   if ( psppire_conf_get_int (conf, base, "x", &x)
386        &&
387        psppire_conf_get_int (conf, base, "y", &y) )
388     {
389       gtk_window_move (window, x, y);
390     }
391
392   if ( psppire_conf_get_boolean (conf, base, "maximize", &maximize))
393     {
394       if (maximize)
395         gtk_window_maximize (window);
396       else
397         gtk_window_unmaximize (window);
398     }
399 }
400
401
402 /*
403    A convenience function to save the window geometry.
404    This should typically be called from a window's
405    "configure-event" and "window-state-event" signal handlers
406  */
407 void
408 psppire_conf_save_window_geometry (PsppireConf *conf,
409                                    const gchar *base,
410                                    GtkWindow *gtk_window)
411 {
412   gboolean maximized;
413   GdkWindow *w;
414
415   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
416   if (w == NULL)
417     return;
418
419   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
420   psppire_conf_set_boolean (conf, base, "maximize", maximized);
421
422   if (!maximized)
423     {
424       gint x, y;
425
426       gint width = gdk_window_get_width (w);
427       gint height= gdk_window_get_height (w);
428
429       gdk_window_get_position (w, &x, &y);
430
431       psppire_conf_set_int (conf, base, "height", height);
432       psppire_conf_set_int (conf, base, "width", width);
433       psppire_conf_set_int (conf, base, "x", x);
434       psppire_conf_set_int (conf, base, "y", y);
435     }
436 }