refactor
[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 G_DEFINE_TYPE (PsppireConf, psppire_conf, G_TYPE_OBJECT)
32
33 static void psppire_conf_finalize        (GObject   *object);
34 static void psppire_conf_dispose        (GObject   *object);
35
36 static GObjectClass *parent_class = NULL;
37
38 static void
39 conf_read (PsppireConf *conf)
40 {
41   g_key_file_load_from_file (conf->keyfile,
42                              conf->filename,
43                              G_KEY_FILE_KEEP_COMMENTS,
44                              NULL);
45 }
46
47 static gboolean
48 flush_conf (PsppireConf *conf)
49 {
50   gsize length = 0;
51
52   gchar *kf = g_key_file_to_data  (conf->keyfile, &length, NULL);
53   GError *err = NULL;
54
55   if (! g_file_set_contents (conf->filename, kf, length, &err))
56     {
57       g_warning ("Cannot open %s for writing: %s", conf->filename, err->message);
58       g_error_free (err);
59     }
60
61   g_free (kf);
62   conf->idle = 0;
63   return FALSE;
64 }
65
66 static void
67 conf_write (PsppireConf *conf)
68 {
69   if (conf->idle == 0)
70     conf->idle = g_idle_add_full (G_PRIORITY_LOW,
71                                   (GSourceFunc) flush_conf, conf, NULL);
72 }
73
74
75 static void
76 psppire_conf_dispose  (GObject *object)
77 {
78 }
79
80 static void
81 psppire_conf_finalize (GObject *object)
82 {
83   PsppireConf *conf = PSPPIRE_CONF (object);
84   g_key_file_free (conf->keyfile);
85   g_free (conf->filename);
86 }
87
88
89 static PsppireConf *the_instance = NULL;
90
91 static GObject*
92 psppire_conf_construct   (GType                  type,
93                                      guint                  n_construct_params,
94                                      GObjectConstructParam *construct_params)
95 {
96   GObject *object;
97
98   if (!the_instance)
99     {
100       object = G_OBJECT_CLASS (parent_class)->constructor (type,
101                                                            n_construct_params,
102                                                            construct_params);
103       the_instance = PSPPIRE_CONF (object);
104     }
105   else
106     object = g_object_ref (G_OBJECT (the_instance));
107
108   return object;
109 }
110
111 static void
112 psppire_conf_class_init (PsppireConfClass *class)
113 {
114   GObjectClass *object_class;
115
116   parent_class = g_type_class_peek_parent (class);
117   object_class = G_OBJECT_CLASS (class);
118
119   object_class->finalize = psppire_conf_finalize;
120   object_class->dispose = psppire_conf_dispose;
121   object_class->constructor = psppire_conf_construct;
122 }
123
124
125 static void
126 psppire_conf_init (PsppireConf *conf)
127 {
128   const gchar *dirname;
129   struct stat s;
130
131   /* Get the name of the directory for user configuration files, then, if it
132      doesn't already exist, create it, since we might be the first program
133      to want to put files there. */
134   dirname = g_get_user_config_dir ();
135   if (stat (dirname, &s) == -1 && errno == ENOENT)
136     mkdir (dirname, 0700);
137
138   conf->filename = g_strdup_printf ("%s/%s", dirname, "psppirerc");
139
140   conf->keyfile = g_key_file_new ();
141
142   conf->idle = 0;
143 }
144
145
146 PsppireConf *
147 psppire_conf_new (void)
148 {
149   return g_object_new (psppire_conf_get_type (), NULL);
150 }
151
152
153
154 gboolean
155 psppire_conf_get_int (PsppireConf *conf, const gchar *base,
156                       const gchar *name, gint *value)
157 {
158   gboolean ok;
159   GError *err = NULL;
160   conf_read (conf);
161   *value = g_key_file_get_integer (conf->keyfile,
162                                    base,
163                                    name, &err);
164
165   ok = (err == NULL);
166   if (err != NULL)
167     g_error_free (err);
168
169   return ok;
170 }
171
172 gboolean
173 psppire_conf_get_boolean (PsppireConf *conf, const gchar *base,
174                           const gchar *name, gboolean *value)
175 {
176   gboolean ok;
177   gboolean b;
178   GError *err = NULL;
179   conf_read (conf);
180   b = g_key_file_get_boolean (conf->keyfile,
181                               base,
182                               name, &err);
183
184   ok = (err == NULL);
185   if (err != NULL)
186     g_error_free (err);
187
188   if (ok)
189     *value = b;
190
191   return ok;
192 }
193
194
195
196 gboolean
197 psppire_conf_get_string (PsppireConf *conf, const gchar *base,
198                          const gchar *name, gchar **value)
199 {
200   gboolean ok;
201   gchar *b;
202   GError *err = NULL;
203   conf_read (conf);
204   b = g_key_file_get_string (conf->keyfile,
205                              base,
206                              name, &err);
207
208   ok = (err == NULL);
209   if (err != NULL)
210     g_error_free (err);
211
212   if (ok)
213     *value = b;
214
215   return ok;
216 }
217
218
219
220
221 gboolean
222 psppire_conf_get_variant (PsppireConf *conf, const gchar *base,
223                           const gchar *name, GVariant **v)
224 {
225   gboolean ok;
226   gchar *b;
227   GError *err = NULL;
228   conf_read (conf);
229   b = g_key_file_get_string (conf->keyfile,
230                              base,
231                              name, &err);
232
233   ok = (err == NULL);
234   if (err != NULL)
235     g_error_free (err);
236
237   if (ok)
238     {
239       *v = g_variant_parse (NULL, b, NULL, NULL, NULL);
240       g_free (b);
241     }
242
243   return ok;
244 }
245
246 gboolean
247 psppire_conf_get_enum (PsppireConf *conf, const gchar *base,
248                        const gchar *name,
249                        GType t,
250                        int *v)
251 {
252   gboolean ok;
253   gchar *b;
254   GError *err = NULL;
255   conf_read (conf);
256   b = g_key_file_get_string (conf->keyfile,
257                              base,
258                              name, &err);
259
260   ok = (err == NULL);
261   if (err != NULL)
262     g_error_free (err);
263
264   if (ok)
265     {
266       GEnumClass *ec = g_type_class_ref (t);
267       GEnumValue *ev = g_enum_get_value_by_nick (ec, b);
268       *v = ev->value;
269       g_type_class_unref (ec);
270       g_free (b);
271     }
272
273   return ok;
274 }
275
276 void
277 psppire_conf_set_int (PsppireConf *conf,
278                       const gchar *base, const gchar *name,
279                       gint value)
280 {
281   g_key_file_set_integer (conf->keyfile, base, name, value);
282   conf_write (conf);
283 }
284
285 void
286 psppire_conf_set_boolean (PsppireConf *conf,
287                           const gchar *base, const gchar *name,
288                           gboolean value)
289 {
290   g_key_file_set_boolean (conf->keyfile, base, name, value);
291   conf_write (conf);
292 }
293
294
295 void
296 psppire_conf_set_string (PsppireConf *conf,
297                          const gchar *base, const gchar *name,
298                          const gchar *value)
299 {
300   g_key_file_set_string (conf->keyfile, base, name, value);
301   conf_write (conf);
302 }
303
304 void
305 psppire_conf_set_variant (PsppireConf *conf,
306                                const gchar *base, const gchar *name,
307                                GVariant *value)
308 {
309   gchar *v = g_variant_print (value, FALSE);
310   g_key_file_set_string (conf->keyfile, base, name, v);
311   conf_write (conf);
312   g_free (v);
313 }
314
315 void
316 psppire_conf_set_enum (PsppireConf *conf,
317                        const gchar *base, const gchar *name,
318                        GType enum_type,
319                        int value)
320 {
321   GEnumClass *ec = g_type_class_ref (enum_type);
322   GEnumValue *ev = g_enum_get_value (ec, value);
323
324   g_key_file_set_string (conf->keyfile, base, name,
325                          ev->value_nick);
326
327   g_type_class_unref (ec);
328
329   conf_write (conf);
330 }
331
332
333
334 /*
335   A convenience function to set the geometry of a
336   window from from a saved config
337 */
338 void
339 psppire_conf_set_window_geometry (PsppireConf *conf,
340                                   const gchar *base,
341                                   GtkWindow *window)
342 {
343   gint height, width;
344   gint x, y;
345   gboolean maximize;
346
347   if (psppire_conf_get_int (conf, base, "height", &height)
348       &&
349       psppire_conf_get_int (conf, base, "width", &width))
350     {
351       gtk_window_set_default_size (window, width, height);
352     }
353
354   if (psppire_conf_get_int (conf, base, "x", &x)
355        &&
356        psppire_conf_get_int (conf, base, "y", &y))
357     {
358       gtk_window_move (window, x, y);
359     }
360
361   if (psppire_conf_get_boolean (conf, base, "maximize", &maximize))
362     {
363       if (maximize)
364         gtk_window_maximize (window);
365       else
366         gtk_window_unmaximize (window);
367     }
368 }
369
370
371 /*
372    A convenience function to save the window geometry.
373    This should typically be called from a window's
374    "configure-event" and "window-state-event" signal handlers
375  */
376 void
377 psppire_conf_save_window_geometry (PsppireConf *conf,
378                                    const gchar *base,
379                                    GtkWindow *gtk_window)
380 {
381   gboolean maximized;
382   GdkWindow *w;
383
384   w = gtk_widget_get_window (GTK_WIDGET (gtk_window));
385   if (w == NULL)
386     return;
387
388   maximized = (gdk_window_get_state (w) & GDK_WINDOW_STATE_MAXIMIZED) != 0;
389   psppire_conf_set_boolean (conf, base, "maximize", maximized);
390
391   if (!maximized)
392     {
393       gint x, y;
394
395       gint width = gdk_window_get_width (w);
396       gint height= gdk_window_get_height (w);
397
398       gdk_window_get_position (w, &x, &y);
399
400       psppire_conf_set_int (conf, base, "height", height);
401       psppire_conf_set_int (conf, base, "width", width);
402       psppire_conf_set_int (conf, base, "x", x);
403       psppire_conf_set_int (conf, base, "y", y);
404     }
405 }