eb65b63ad9ac2d19e59ad422f800932268f88cfe
[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       char *msg = strerror (errno);
88       g_warning ("Cannot open %s for writing: %s", conf->filename, msg);
89     }
90
91   g_free (kf);
92   conf->idle = 0;
93   return FALSE;
94 }
95
96 static void
97 conf_write (PsppireConf *conf)
98 {
99   if (conf->idle == 0)
100     conf->idle = g_idle_add_full (G_PRIORITY_LOW,
101                                   (GSourceFunc) flush_conf, conf, NULL);
102 }
103
104
105 static void
106 psppire_conf_dispose  (GObject *object)
107 {
108 }
109
110 static void
111 psppire_conf_finalize (GObject *object)
112 {
113   PsppireConf *conf = PSPPIRE_CONF (object);
114   g_key_file_free (conf->keyfile);
115   g_free (conf->filename);
116 }
117
118
119 static PsppireConf *the_instance = NULL;
120
121 static GObject*
122 psppire_conf_construct   (GType                  type,
123                                      guint                  n_construct_params,
124                                      GObjectConstructParam *construct_params)
125 {
126   GObject *object;
127
128   if (!the_instance)
129     {
130       object = G_OBJECT_CLASS (parent_class)->constructor (type,
131                                                            n_construct_params,
132                                                            construct_params);
133       the_instance = PSPPIRE_CONF (object);
134     }
135   else
136     object = g_object_ref (G_OBJECT (the_instance));
137
138   return object;
139 }
140
141 static void
142 psppire_conf_class_init (PsppireConfClass *class)
143 {
144   GObjectClass *object_class;
145
146   parent_class = g_type_class_peek_parent (class);
147   object_class = (GObjectClass*) class;
148
149   object_class->finalize = psppire_conf_finalize;
150   object_class->dispose = psppire_conf_dispose;
151   object_class->constructor = psppire_conf_construct;
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->idle = 0;
173 }
174
175
176 PsppireConf *
177 psppire_conf_new (void)
178 {
179   return g_object_new (psppire_conf_get_type (), NULL);
180 }
181
182
183
184 gboolean
185 psppire_conf_get_int (PsppireConf *conf, const gchar *base,
186                       const gchar *name, gint *value)
187 {
188   gboolean ok;
189   GError *err = NULL;
190   conf_read (conf);
191   *value = g_key_file_get_integer (conf->keyfile,
192                                    base,
193                                    name, &err);
194
195   ok = (err == NULL);
196   if (err != NULL)
197     g_error_free (err);
198
199   return ok;
200 }
201
202 gboolean
203 psppire_conf_get_boolean (PsppireConf *conf, const gchar *base,
204                           const gchar *name, gboolean *value)
205 {
206   gboolean ok;
207   gboolean b;
208   GError *err = NULL;
209   conf_read (conf);
210   b = g_key_file_get_boolean (conf->keyfile,
211                               base,
212                               name, &err);
213
214   ok = (err == NULL);
215   if (err != NULL)
216     g_error_free (err);
217
218   if (ok)
219     *value = b;
220
221   return ok;
222 }
223
224
225
226 gboolean
227 psppire_conf_get_string (PsppireConf *conf, const gchar *base,
228                          const gchar *name, gchar **value)
229 {
230   gboolean ok;
231   gchar *b;
232   GError *err = NULL;
233   conf_read (conf);
234   b = g_key_file_get_string (conf->keyfile,
235                              base,
236                              name, &err);
237
238   ok = (err == NULL);
239   if (err != NULL)
240     g_error_free (err);
241
242   if (ok)
243     *value = b;
244
245   return ok;
246 }
247
248
249
250
251 gboolean
252 psppire_conf_get_variant (PsppireConf *conf, const gchar *base,
253                           const gchar *name, GVariant **v)
254 {
255   gboolean ok;
256   gchar *b;
257   GError *err = NULL;
258   conf_read (conf);
259   b = g_key_file_get_string (conf->keyfile,
260                              base,
261                              name, &err);
262
263   ok = (err == NULL);
264   if (err != NULL)
265     g_error_free (err);
266
267   if (ok)
268     {
269       *v = g_variant_parse (NULL, b, NULL, NULL, NULL);
270       g_free (b);
271     }
272
273   return ok;
274 }
275
276 gboolean
277 psppire_conf_get_enum (PsppireConf *conf, const gchar *base,
278                        const gchar *name,
279                        GType t,
280                        int *v)
281 {
282   gboolean ok;
283   gchar *b;
284   GError *err = NULL;
285   conf_read (conf);
286   b = g_key_file_get_string (conf->keyfile,
287                              base,
288                              name, &err);
289
290   ok = (err == NULL);
291   if (err != NULL)
292     g_error_free (err);
293
294   if (ok)
295     {
296       GEnumClass *ec = g_type_class_ref (t);
297       GEnumValue *ev = g_enum_get_value_by_nick (ec, b);
298       *v = ev->value;
299       g_type_class_unref (ec);
300       g_free (b);
301     }
302
303   return ok;
304 }
305
306 void
307 psppire_conf_set_int (PsppireConf *conf,
308                       const gchar *base, const gchar *name,
309                       gint value)
310 {
311   g_key_file_set_integer (conf->keyfile, base, name, value);
312   conf_write (conf);
313 }
314
315 void
316 psppire_conf_set_boolean (PsppireConf *conf,
317                           const gchar *base, const gchar *name,
318                           gboolean value)
319 {
320   g_key_file_set_boolean (conf->keyfile, base, name, value);
321   conf_write (conf);
322 }
323
324
325 void
326 psppire_conf_set_string (PsppireConf *conf,
327                          const gchar *base, const gchar *name,
328                          const gchar *value)
329 {
330   g_key_file_set_string (conf->keyfile, base, name, value);
331   conf_write (conf);
332 }
333
334 void
335 psppire_conf_set_variant (PsppireConf *conf,
336                                const gchar *base, const gchar *name,
337                                GVariant *value)
338 {
339   gchar *v = g_variant_print (value, FALSE);
340   g_key_file_set_string (conf->keyfile, base, name, v);
341   conf_write (conf);
342   g_free (v);
343 }
344
345 void
346 psppire_conf_set_enum (PsppireConf *conf,
347                        const gchar *base, const gchar *name,
348                        GType enum_type,
349                        int value)
350 {
351   GEnumClass *ec = g_type_class_ref (enum_type);
352   GEnumValue *ev = g_enum_get_value (ec, value);
353
354   g_key_file_set_string (conf->keyfile, base, name,
355                          ev->value_nick);
356
357   g_type_class_unref (ec);
358
359   conf_write (conf);
360 }
361
362
363
364 /*
365   A convenience function to set the geometry of a
366   window from from a saved config
367 */
368 void
369 psppire_conf_set_window_geometry (PsppireConf *conf,
370                                   const gchar *base,
371                                   GtkWindow *window)
372 {
373   gint height, width;
374   gint x, y;
375   gboolean maximize;
376
377   if (psppire_conf_get_int (conf, base, "height", &height)
378       &&
379       psppire_conf_get_int (conf, base, "width", &width))
380     {
381       gtk_window_set_default_size (window, width, height);
382     }
383
384   if (psppire_conf_get_int (conf, base, "x", &x)
385        &&
386        psppire_conf_get_int (conf, base, "y", &y))
387     {
388       gtk_window_move (window, x, y);
389     }
390
391   if (psppire_conf_get_boolean (conf, base, "maximize", &maximize))
392     {
393       if (maximize)
394         gtk_window_maximize (window);
395       else
396         gtk_window_unmaximize (window);
397     }
398 }
399
400
401 /*
402    A convenience function to save the window geometry.
403    This should typically be called from a window's
404    "configure-event" and "window-state-event" signal handlers
405  */
406 void
407 psppire_conf_save_window_geometry (PsppireConf *conf,
408                                    const gchar *base,
409                                    GtkWindow *gtk_window)
410 {
411   gboolean maximized;
412   GdkWindow *w;
413
414   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
415   if (w == NULL)
416     return;
417
418   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
419   psppire_conf_set_boolean (conf, base, "maximize", maximized);
420
421   if (!maximized)
422     {
423       gint x, y;
424
425       gint width = gdk_window_get_width (w);
426       gint height= gdk_window_get_height (w);
427
428       gdk_window_get_position (w, &x, &y);
429
430       psppire_conf_set_int (conf, base, "height", height);
431       psppire_conf_set_int (conf, base, "width", width);
432       psppire_conf_set_int (conf, base, "x", x);
433       psppire_conf_set_int (conf, base, "y", y);
434     }
435 }