]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilechoosersettings.c
Add GtkSpinner::animation-duration style property
[~andy/gtk] / gtk / gtkfilechoosersettings.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilechoosersettings.c: Internal settings for the GtkFileChooser widget
3  * Copyright (C) 2006, Novell, Inc.
4  *
5  * Authors: Federico Mena-Quintero <federico@novell.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /* TODO:
24  *
25  * - Persist these:
26  *   - hpaned position
27  *   - browse_for_other_folders?
28  *
29  * - Do we want lockdown?
30  */
31
32 #include "config.h"
33 #include <errno.h>
34 #include <string.h>
35 #include <glib.h>
36 #include <glib/gi18n-lib.h>
37 #include "gtkfilechoosersettings.h"
38 #include "gtkalias.h"
39
40 #define SETTINGS_GROUP          "Filechooser Settings"
41 #define LOCATION_MODE_KEY       "LocationMode"
42 #define SHOW_HIDDEN_KEY         "ShowHidden"
43 #define EXPAND_FOLDERS_KEY      "ExpandFolders"
44 #define SHOW_SIZE_COLUMN_KEY    "ShowSizeColumn"
45 #define GEOMETRY_X_KEY          "GeometryX"
46 #define GEOMETRY_Y_KEY          "GeometryY"
47 #define GEOMETRY_WIDTH_KEY      "GeometryWidth"
48 #define GEOMETRY_HEIGHT_KEY     "GeometryHeight"
49 #define SORT_COLUMN_KEY         "SortColumn"
50 #define SORT_ORDER_KEY          "SortOrder"
51
52 #define COLUMN_NAME_STRING      "name"
53 #define COLUMN_MTIME_STRING     "modified"
54 #define COLUMN_SIZE_STRING      "size"
55 #define SORT_ASCENDING_STRING   "ascending"
56 #define SORT_DESCENDING_STRING  "descending"
57
58 #define MODE_PATH_BAR          "path-bar"
59 #define MODE_FILENAME_ENTRY    "filename-entry"
60
61 #define EQ(a, b) (g_ascii_strcasecmp ((a), (b)) == 0)
62
63 static char *
64 get_config_dirname (void)
65 {
66   return g_build_filename (g_get_user_config_dir (), "gtk-2.0", NULL);
67 }
68
69 static char *
70 get_config_filename (void)
71 {
72   return g_build_filename (g_get_user_config_dir (), "gtk-2.0", "gtkfilechooser.ini", NULL);
73 }
74
75 static void
76 warn_if_invalid_key_and_clear_error (const gchar  *key,
77                                      GError      **error)
78 {
79   if (error && *error)
80     {
81       if ((*error)->domain == G_KEY_FILE_ERROR &&
82           (*error)->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
83         g_warning ("Failed to read '%s' setting in filechooser settings: %s",
84                    key,
85                    (*error)->message);
86
87       g_clear_error (error);
88     }
89 }
90
91 static void
92 get_int_key (GKeyFile *key_file, const char *group, const char *key, int *out_value)
93 {
94   GError *error;
95   int val;
96
97   error = NULL;
98   val = g_key_file_get_integer (key_file, group, key, &error);
99
100   if (val == 0 && error != NULL)
101     {
102       *out_value = -1;
103       g_error_free (error);
104     }
105   else
106     *out_value = val;
107 }
108
109 static void
110 ensure_settings_read (GtkFileChooserSettings *settings)
111 {
112   GError *error;
113   GKeyFile *key_file;
114   gchar *location_mode_str, *filename;
115   gchar *sort_column, *sort_order;
116   gboolean value;
117
118   if (settings->settings_read)
119     return;
120
121   key_file = g_key_file_new ();
122
123   filename = get_config_filename ();
124
125   error = NULL;
126   if (!g_key_file_load_from_file (key_file, filename, 0, &error))
127     {
128       /* Don't warn on non-existent file */
129       if (error->domain != G_FILE_ERROR ||
130           error->code != G_FILE_ERROR_NOENT)
131         g_warning ("Failed to read filechooser settings from \"%s\": %s",
132                    filename, error->message);
133
134       g_error_free (error);
135       goto out;
136     }
137
138   if (!g_key_file_has_group (key_file, SETTINGS_GROUP))
139     goto out;
140
141   /* Location mode */
142
143   location_mode_str = g_key_file_get_string (key_file, SETTINGS_GROUP,
144                                              LOCATION_MODE_KEY, NULL);
145   if (location_mode_str)
146     {
147       if (EQ (location_mode_str, MODE_PATH_BAR))
148         settings->location_mode = LOCATION_MODE_PATH_BAR;
149       else if (EQ (location_mode_str, MODE_FILENAME_ENTRY))
150         settings->location_mode = LOCATION_MODE_FILENAME_ENTRY;
151       else
152         g_warning ("Unknown location mode '%s' encountered in filechooser settings",
153                    location_mode_str);
154
155       g_free (location_mode_str);
156     }
157
158   /* Show hidden */
159
160   value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
161                                   SHOW_HIDDEN_KEY, &error);
162   if (error)
163     warn_if_invalid_key_and_clear_error (SHOW_HIDDEN_KEY, &error);
164   else
165     settings->show_hidden = value != FALSE;
166
167   /* Expand folders */
168
169   value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
170                                   EXPAND_FOLDERS_KEY, &error);
171   if (error)
172     warn_if_invalid_key_and_clear_error (EXPAND_FOLDERS_KEY, &error);
173   else
174     settings->expand_folders = value != FALSE;
175
176   /* Show size column */
177
178   value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
179                                   SHOW_SIZE_COLUMN_KEY, &error);
180   if (error)
181     warn_if_invalid_key_and_clear_error (SHOW_SIZE_COLUMN_KEY, &error);
182   else
183     settings->show_size_column = value != FALSE;
184
185   /* Geometry */
186
187   get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_X_KEY, &settings->geometry_x);
188   get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_Y_KEY, &settings->geometry_y);
189   get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_WIDTH_KEY, &settings->geometry_width);
190   get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_HEIGHT_KEY, &settings->geometry_height);
191
192   /* Sort column */
193
194   sort_column = g_key_file_get_string (key_file, SETTINGS_GROUP,
195                                        SORT_COLUMN_KEY, NULL);
196   if (sort_column)
197     {
198       if (EQ (COLUMN_NAME_STRING, sort_column))
199         settings->sort_column = FILE_LIST_COL_NAME;
200       else if (EQ (COLUMN_MTIME_STRING, sort_column))
201         settings->sort_column = FILE_LIST_COL_MTIME;
202       else if (EQ (COLUMN_SIZE_STRING, sort_column))
203         settings->sort_column = FILE_LIST_COL_SIZE;
204       else
205         g_warning ("Unknown sort column name '%s' encountered in filechooser settings",
206                    sort_column);
207
208       g_free (sort_column);
209     }
210
211   /* Sort order */
212
213   sort_order = g_key_file_get_string (key_file, SETTINGS_GROUP,
214                                       SORT_ORDER_KEY, NULL);
215   if (sort_order)
216     {
217       if (EQ (SORT_ASCENDING_STRING, sort_order))
218         settings->sort_order = GTK_SORT_ASCENDING;
219       else if (EQ (SORT_DESCENDING_STRING, sort_order))
220         settings->sort_order = GTK_SORT_DESCENDING;
221       else
222         g_warning ("Unknown sort column order '%s' encountered in filechooser settings",
223                    sort_order);
224
225       g_free (sort_order);
226     }
227
228  out:
229
230   g_key_file_free (key_file);
231   g_free (filename);
232
233   settings->settings_read = TRUE;
234 }
235
236 G_DEFINE_TYPE (GtkFileChooserSettings, _gtk_file_chooser_settings, G_TYPE_OBJECT)
237
238 static void
239 _gtk_file_chooser_settings_class_init (GtkFileChooserSettingsClass *class)
240 {
241 }
242
243 static void
244 _gtk_file_chooser_settings_init (GtkFileChooserSettings *settings)
245 {
246   settings->location_mode = LOCATION_MODE_PATH_BAR;
247   settings->sort_order = GTK_SORT_ASCENDING;
248   settings->sort_column = FILE_LIST_COL_NAME;
249   settings->show_hidden = FALSE;
250   settings->expand_folders = FALSE;
251   settings->show_size_column = TRUE;
252   settings->geometry_x      = -1;
253   settings->geometry_y      = -1;
254   settings->geometry_width  = -1;
255   settings->geometry_height = -1;
256 }
257
258 GtkFileChooserSettings *
259 _gtk_file_chooser_settings_new (void)
260 {
261   return g_object_new (GTK_FILE_CHOOSER_SETTINGS_TYPE, NULL);
262 }
263
264 LocationMode
265 _gtk_file_chooser_settings_get_location_mode (GtkFileChooserSettings *settings)
266 {
267   ensure_settings_read (settings);
268   return settings->location_mode;
269 }
270
271 void
272 _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings,
273                                               LocationMode location_mode)
274 {
275   settings->location_mode = location_mode;
276 }
277
278 gboolean
279 _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings)
280 {
281   ensure_settings_read (settings);
282   return settings->show_hidden;
283 }
284
285 void
286 _gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings,
287                                             gboolean show_hidden)
288 {
289   settings->show_hidden = show_hidden != FALSE;
290 }
291
292 gboolean
293 _gtk_file_chooser_settings_get_expand_folders (GtkFileChooserSettings *settings)
294 {
295   ensure_settings_read (settings);
296   return settings->expand_folders;
297 }
298
299 void
300 _gtk_file_chooser_settings_set_show_size_column (GtkFileChooserSettings *settings,
301                                                  gboolean show_column)
302 {
303   settings->show_size_column = show_column != FALSE;
304 }
305
306 gboolean
307 _gtk_file_chooser_settings_get_show_size_column (GtkFileChooserSettings *settings)
308 {
309   ensure_settings_read (settings);
310   return settings->show_size_column;
311 }
312
313 void
314 _gtk_file_chooser_settings_set_expand_folders (GtkFileChooserSettings *settings,
315                                                gboolean expand_folders)
316 {
317   settings->expand_folders = expand_folders != FALSE;
318 }
319
320 void
321 _gtk_file_chooser_settings_get_geometry (GtkFileChooserSettings *settings,
322                                          int                    *out_x,
323                                          int                    *out_y,
324                                          int                    *out_width,
325                                          int                    *out_height)
326 {
327   ensure_settings_read (settings);
328
329   *out_x      = settings->geometry_x;
330   *out_y      = settings->geometry_y;
331   *out_width  = settings->geometry_width;
332   *out_height = settings->geometry_height;
333 }
334
335 void
336 _gtk_file_chooser_settings_set_geometry (GtkFileChooserSettings *settings,
337                                          int                     x,
338                                          int                     y,
339                                          int                     width,
340                                          int                     height)
341 {
342   settings->geometry_x      = x;
343   settings->geometry_y      = y;
344   settings->geometry_width  = width;
345   settings->geometry_height = height;
346 }
347
348 gint
349 _gtk_file_chooser_settings_get_sort_column (GtkFileChooserSettings *settings)
350 {
351   ensure_settings_read (settings);
352   return settings->sort_column;
353 }
354
355 void
356 _gtk_file_chooser_settings_set_sort_column (GtkFileChooserSettings *settings,
357                                             gint sort_column)
358 {
359   settings->sort_column = sort_column;
360 }
361
362 GtkSortType
363 _gtk_file_chooser_settings_get_sort_order (GtkFileChooserSettings *settings)
364 {
365   ensure_settings_read (settings);
366   return settings->sort_order;
367 }
368
369 void
370 _gtk_file_chooser_settings_set_sort_order (GtkFileChooserSettings *settings,
371                                            GtkSortType sort_order)
372 {
373   settings->sort_order = sort_order;
374 }
375
376 gboolean
377 _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings,
378                                  GError                **error)
379 {
380   const gchar *location_mode_str;
381   gchar *filename;
382   gchar *dirname;
383   gchar *contents;
384   gchar *sort_column;
385   gchar *sort_order;
386   gsize len;
387   gboolean retval;
388   GKeyFile *key_file;
389
390   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
391
392   filename = get_config_filename ();
393   dirname = NULL;
394
395   retval = FALSE;
396
397   if (settings->location_mode == LOCATION_MODE_PATH_BAR)
398     location_mode_str = MODE_PATH_BAR;
399   else if (settings->location_mode == LOCATION_MODE_FILENAME_ENTRY)
400     location_mode_str = MODE_FILENAME_ENTRY;
401   else
402     {
403       g_assert_not_reached ();
404       return FALSE;
405     }
406
407   switch (settings->sort_column)
408     {
409     case FILE_LIST_COL_NAME:
410       sort_column = COLUMN_NAME_STRING;
411       break;
412
413     case FILE_LIST_COL_MTIME:
414       sort_column = COLUMN_MTIME_STRING;
415       break;
416
417     case FILE_LIST_COL_SIZE:
418       sort_column = COLUMN_SIZE_STRING;
419       break;
420
421     default:
422       g_assert_not_reached ();
423       sort_column = NULL;
424     }
425
426   switch (settings->sort_order)
427     {
428     case GTK_SORT_ASCENDING:
429       sort_order = SORT_ASCENDING_STRING;
430       break;
431
432     case GTK_SORT_DESCENDING:
433       sort_order = SORT_DESCENDING_STRING;
434       break;
435
436     default:
437       g_assert_not_reached ();
438       sort_order = NULL;
439     }
440
441   key_file = g_key_file_new ();
442
443   /* Initialise with the on-disk keyfile, so we keep unknown options */
444   g_key_file_load_from_file (key_file, filename, 0, NULL);
445
446   g_key_file_set_string (key_file, SETTINGS_GROUP,
447                          LOCATION_MODE_KEY, location_mode_str);
448   g_key_file_set_boolean (key_file, SETTINGS_GROUP,
449                           SHOW_HIDDEN_KEY, settings->show_hidden);
450   g_key_file_set_boolean (key_file, SETTINGS_GROUP,
451                           EXPAND_FOLDERS_KEY, settings->expand_folders);
452   g_key_file_set_boolean (key_file, SETTINGS_GROUP,
453                           SHOW_SIZE_COLUMN_KEY, settings->show_size_column);
454   g_key_file_set_integer (key_file, SETTINGS_GROUP,
455                           GEOMETRY_X_KEY, settings->geometry_x);
456   g_key_file_set_integer (key_file, SETTINGS_GROUP,
457                           GEOMETRY_Y_KEY, settings->geometry_y);
458   g_key_file_set_integer (key_file, SETTINGS_GROUP,
459                           GEOMETRY_WIDTH_KEY, settings->geometry_width);
460   g_key_file_set_integer (key_file, SETTINGS_GROUP,
461                           GEOMETRY_HEIGHT_KEY, settings->geometry_height);
462   g_key_file_set_string (key_file, SETTINGS_GROUP,
463                          SORT_COLUMN_KEY, sort_column);
464   g_key_file_set_string (key_file, SETTINGS_GROUP,
465                          SORT_ORDER_KEY, sort_order);
466
467   contents = g_key_file_to_data (key_file, &len, error);
468   g_key_file_free (key_file);
469
470   if (!contents)
471     goto out;
472
473   if (!g_file_set_contents (filename, contents, len, NULL))
474     {
475       char *dirname;
476       int saved_errno;
477
478       /* Directory is not there? */
479
480       dirname = get_config_dirname ();
481       if (g_mkdir_with_parents (dirname, 0700) != 0) /* 0700 per the XDG basedir spec */
482         {
483           saved_errno = errno;
484           g_set_error (error,
485                        G_FILE_ERROR,
486                        g_file_error_from_errno (saved_errno),
487                        _("Error creating folder '%s': %s"),
488                        dirname, g_strerror (saved_errno));
489           goto out;
490         }
491
492       if (!g_file_set_contents (filename, contents, len, error))
493         goto out;
494     }
495
496   retval = TRUE;
497
498  out:
499
500   g_free (contents);
501   g_free (dirname);
502   g_free (filename);
503
504   return retval;
505 }