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
conf_read(PsppireConf * conf)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
flush_conf(PsppireConf * conf)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
conf_write(PsppireConf * conf)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
psppire_conf_dispose(GObject * object)76 psppire_conf_dispose  (GObject *object)
77 {
78 }
79 
80 static void
psppire_conf_finalize(GObject * object)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*
psppire_conf_construct(GType type,guint n_construct_params,GObjectConstructParam * construct_params)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
psppire_conf_class_init(PsppireConfClass * class)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
psppire_conf_init(PsppireConf * conf)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 *
psppire_conf_new(void)147 psppire_conf_new (void)
148 {
149   return g_object_new (psppire_conf_get_type (), NULL);
150 }
151 
152 
153 
154 gboolean
psppire_conf_get_int(PsppireConf * conf,const gchar * base,const gchar * name,gint * value)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
psppire_conf_get_boolean(PsppireConf * conf,const gchar * base,const gchar * name,gboolean * value)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
psppire_conf_get_string(PsppireConf * conf,const gchar * base,const gchar * name,gchar ** value)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
psppire_conf_get_variant(PsppireConf * conf,const gchar * base,const gchar * name,GVariant ** v)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
psppire_conf_get_enum(PsppireConf * conf,const gchar * base,const gchar * name,GType t,int * v)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
psppire_conf_set_int(PsppireConf * conf,const gchar * base,const gchar * name,gint value)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
psppire_conf_set_boolean(PsppireConf * conf,const gchar * base,const gchar * name,gboolean value)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
psppire_conf_set_string(PsppireConf * conf,const gchar * base,const gchar * name,const gchar * value)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
psppire_conf_set_variant(PsppireConf * conf,const gchar * base,const gchar * name,GVariant * value)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
psppire_conf_set_enum(PsppireConf * conf,const gchar * base,const gchar * name,GType enum_type,int value)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
psppire_conf_set_window_geometry(PsppireConf * conf,const gchar * base,GtkWindow * window)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
psppire_conf_save_window_geometry(PsppireConf * conf,const gchar * base,GtkWindow * gtk_window)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 }
406