gtkfilechoosersettings.c 13.3 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * gtkfilechoosersettings.c: Internal settings for the GtkFileChooser widget
 * Copyright (C) 2006, Novell, Inc.
 *
 * Authors: Federico Mena-Quintero <federico@novell.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/* TODO:
 *
 * - Persist these:
 *   - hpaned position
 *   - browse_for_other_folders?
 *
 * - Do we want lockdown?
 */

32
#include "config.h"
33 34
#include <errno.h>
#include <string.h>
35
#include <glib.h>
36 37
#include <glib/gi18n-lib.h>
#include "gtkfilechoosersettings.h"
38
#include "gtkalias.h"
39

40 41 42 43
#define SETTINGS_GROUP		"Filechooser Settings"
#define LOCATION_MODE_KEY	"LocationMode"
#define SHOW_HIDDEN_KEY		"ShowHidden"
#define EXPAND_FOLDERS_KEY	"ExpandFolders"
44
#define SHOW_SIZE_COLUMN_KEY    "ShowSizeColumn"
45 46 47 48
#define GEOMETRY_X_KEY		"GeometryX"
#define GEOMETRY_Y_KEY		"GeometryY"
#define GEOMETRY_WIDTH_KEY	"GeometryWidth"
#define GEOMETRY_HEIGHT_KEY	"GeometryHeight"
49 50 51 52 53 54 55 56
#define SORT_COLUMN_KEY         "SortColumn"
#define SORT_ORDER_KEY          "SortOrder"

#define COLUMN_NAME_STRING      "name"
#define COLUMN_MTIME_STRING     "modified"
#define COLUMN_SIZE_STRING      "size"
#define SORT_ASCENDING_STRING   "ascending"
#define SORT_DESCENDING_STRING  "descending"
57 58 59

#define MODE_PATH_BAR          "path-bar"
#define MODE_FILENAME_ENTRY    "filename-entry"
60 61 62 63 64 65 66 67 68 69 70 71

#define EQ(a, b) (g_ascii_strcasecmp ((a), (b)) == 0)

static char *
get_config_dirname (void)
{
  return g_build_filename (g_get_user_config_dir (), "gtk-2.0", NULL);
}

static char *
get_config_filename (void)
{
72
  return g_build_filename (g_get_user_config_dir (), "gtk-2.0", "gtkfilechooser.ini", NULL);
73 74
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void
warn_if_invalid_key_and_clear_error (const gchar  *key,
                                     GError      **error)
{
  if (error && *error)
    {
      if ((*error)->domain == G_KEY_FILE_ERROR &&
          (*error)->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
        g_warning ("Failed to read '%s' setting in filechooser settings: %s",
                   key,
                   (*error)->message);

      g_clear_error (error);
    }
}

91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
static void
get_int_key (GKeyFile *key_file, const char *group, const char *key, int *out_value)
{
  GError *error;
  int val;

  error = NULL;
  val = g_key_file_get_integer (key_file, group, key, &error);

  if (val == 0 && error != NULL)
    {
      *out_value = -1;
      g_error_free (error);
    }
  else
    *out_value = val;
}

109
static void
110
ensure_settings_read (GtkFileChooserSettings *settings)
111
{
112 113 114
  GError *error;
  GKeyFile *key_file;
  gchar *location_mode_str, *filename;
115
  gchar *sort_column, *sort_order;
116
  gboolean value;
117

118 119
  if (settings->settings_read)
    return;
120

121
  key_file = g_key_file_new ();
122

123
  filename = get_config_filename ();
124

125 126 127 128 129 130 131 132 133 134 135
  error = NULL;
  if (!g_key_file_load_from_file (key_file, filename, 0, &error))
    {
      /* Don't warn on non-existent file */
      if (error->domain != G_FILE_ERROR ||
	  error->code != G_FILE_ERROR_NOENT)
        g_warning ("Failed to read filechooser settings from \"%s\": %s",
                   filename, error->message);

      g_error_free (error);
      goto out;
136 137
    }

138 139
  if (!g_key_file_has_group (key_file, SETTINGS_GROUP))
    goto out;
140

141 142
  /* Location mode */

143 144 145
  location_mode_str = g_key_file_get_string (key_file, SETTINGS_GROUP,
					     LOCATION_MODE_KEY, NULL);
  if (location_mode_str)
146
    {
147 148 149 150
      if (EQ (location_mode_str, MODE_PATH_BAR))
        settings->location_mode = LOCATION_MODE_PATH_BAR;
      else if (EQ (location_mode_str, MODE_FILENAME_ENTRY))
        settings->location_mode = LOCATION_MODE_FILENAME_ENTRY;
151
      else
152 153
        g_warning ("Unknown location mode '%s' encountered in filechooser settings",
		   location_mode_str);
154

155
      g_free (location_mode_str);
156 157
    }

158 159
  /* Show hidden */

160 161 162
  value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
				  SHOW_HIDDEN_KEY, &error);
  if (error)
163
    warn_if_invalid_key_and_clear_error (SHOW_HIDDEN_KEY, &error);
164 165
  else
    settings->show_hidden = value != FALSE;
166

167 168
  /* Expand folders */

169 170 171
  value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
				  EXPAND_FOLDERS_KEY, &error);
  if (error)
172
    warn_if_invalid_key_and_clear_error (EXPAND_FOLDERS_KEY, &error);
173 174
  else
    settings->expand_folders = value != FALSE;
175

176 177
  /* Show size column */

178 179 180 181 182 183 184
  value = g_key_file_get_boolean (key_file, SETTINGS_GROUP,
				  SHOW_SIZE_COLUMN_KEY, &error);
  if (error)
    warn_if_invalid_key_and_clear_error (SHOW_SIZE_COLUMN_KEY, &error);
  else
    settings->show_size_column = value != FALSE;

185 186
  /* Geometry */

187 188 189 190 191
  get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_X_KEY, &settings->geometry_x);
  get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_Y_KEY, &settings->geometry_y);
  get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_WIDTH_KEY, &settings->geometry_width);
  get_int_key (key_file, SETTINGS_GROUP, GEOMETRY_HEIGHT_KEY, &settings->geometry_height);

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
  /* Sort column */

  sort_column = g_key_file_get_string (key_file, SETTINGS_GROUP,
				       SORT_COLUMN_KEY, NULL);
  if (sort_column)
    {
      if (EQ (COLUMN_NAME_STRING, sort_column))
	settings->sort_column = FILE_LIST_COL_NAME;
      else if (EQ (COLUMN_MTIME_STRING, sort_column))
	settings->sort_column = FILE_LIST_COL_MTIME;
      else if (EQ (COLUMN_SIZE_STRING, sort_column))
	settings->sort_column = FILE_LIST_COL_SIZE;
      else
	g_warning ("Unknown sort column name '%s' encountered in filechooser settings",
		   sort_column);

      g_free (sort_column);
    }

  /* Sort order */

  sort_order = g_key_file_get_string (key_file, SETTINGS_GROUP,
				      SORT_ORDER_KEY, NULL);
  if (sort_order)
    {
      if (EQ (SORT_ASCENDING_STRING, sort_order))
	settings->sort_order = GTK_SORT_ASCENDING;
      else if (EQ (SORT_DESCENDING_STRING, sort_order))
	settings->sort_order = GTK_SORT_DESCENDING;
      else
	g_warning ("Unknown sort column order '%s' encountered in filechooser settings",
		   sort_order);

      g_free (sort_order);
    }

228
 out:
229

230 231
  g_key_file_free (key_file);
  g_free (filename);
232 233 234 235

  settings->settings_read = TRUE;
}

Matthias Clasen's avatar
Matthias Clasen committed
236
G_DEFINE_TYPE (GtkFileChooserSettings, _gtk_file_chooser_settings, G_TYPE_OBJECT)
237 238 239 240 241 242 243 244 245

static void
_gtk_file_chooser_settings_class_init (GtkFileChooserSettingsClass *class)
{
}

static void
_gtk_file_chooser_settings_init (GtkFileChooserSettings *settings)
{
246
  settings->location_mode = LOCATION_MODE_PATH_BAR;
247 248
  settings->sort_order = GTK_SORT_ASCENDING;
  settings->sort_column = FILE_LIST_COL_NAME;
249 250
  settings->show_hidden = FALSE;
  settings->expand_folders = FALSE;
251
  settings->show_size_column = TRUE;
252 253 254 255
  settings->geometry_x	    = -1;
  settings->geometry_y	    = -1;
  settings->geometry_width  = -1;
  settings->geometry_height = -1;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
}

GtkFileChooserSettings *
_gtk_file_chooser_settings_new (void)
{
  return g_object_new (GTK_FILE_CHOOSER_SETTINGS_TYPE, NULL);
}

LocationMode
_gtk_file_chooser_settings_get_location_mode (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->location_mode;
}

void
_gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings,
					      LocationMode location_mode)
{
  settings->location_mode = location_mode;
}

gboolean
_gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->show_hidden;
}

void
_gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings,
					    gboolean show_hidden)
{
289
  settings->show_hidden = show_hidden != FALSE;
290 291
}

292 293 294 295 296 297 298
gboolean
_gtk_file_chooser_settings_get_expand_folders (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->expand_folders;
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312
void
_gtk_file_chooser_settings_set_show_size_column (GtkFileChooserSettings *settings,
					         gboolean show_column)
{
  settings->show_size_column = show_column != FALSE;
}

gboolean
_gtk_file_chooser_settings_get_show_size_column (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->show_size_column;
}

313 314 315 316
void
_gtk_file_chooser_settings_set_expand_folders (GtkFileChooserSettings *settings,
					       gboolean expand_folders)
{
317
  settings->expand_folders = expand_folders != FALSE;
318 319
}

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
void
_gtk_file_chooser_settings_get_geometry (GtkFileChooserSettings *settings,
					 int                    *out_x,
					 int                    *out_y,
					 int                    *out_width,
					 int                    *out_height)
{
  ensure_settings_read (settings);

  *out_x      = settings->geometry_x;
  *out_y      = settings->geometry_y;
  *out_width  = settings->geometry_width;
  *out_height = settings->geometry_height;
}

void
_gtk_file_chooser_settings_set_geometry (GtkFileChooserSettings *settings,
					 int                     x,
					 int                     y,
					 int                     width,
					 int                     height)
{
  settings->geometry_x	    = x;
  settings->geometry_y	    = y;
  settings->geometry_width  = width;
  settings->geometry_height = height;
}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
gint
_gtk_file_chooser_settings_get_sort_column (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->sort_column;
}

void
_gtk_file_chooser_settings_set_sort_column (GtkFileChooserSettings *settings,
					    gint sort_column)
{
  settings->sort_column = sort_column;
}

GtkSortType
_gtk_file_chooser_settings_get_sort_order (GtkFileChooserSettings *settings)
{
  ensure_settings_read (settings);
  return settings->sort_order;
}

void
_gtk_file_chooser_settings_set_sort_order (GtkFileChooserSettings *settings,
					   GtkSortType sort_order)
{
  settings->sort_order = sort_order;
}

376 377 378
gboolean
_gtk_file_chooser_settings_save (GtkFileChooserSettings *settings,
				 GError                **error)
379
{
380 381 382 383
  const gchar *location_mode_str;
  gchar *filename;
  gchar *dirname;
  gchar *contents;
384 385
  gchar *sort_column;
  gchar *sort_order;
386 387 388 389 390 391 392 393 394 395
  gsize len;
  gboolean retval;
  GKeyFile *key_file;

  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  filename = get_config_filename ();
  dirname = NULL;

  retval = FALSE;
396 397 398 399 400 401 402 403

  if (settings->location_mode == LOCATION_MODE_PATH_BAR)
    location_mode_str = MODE_PATH_BAR;
  else if (settings->location_mode == LOCATION_MODE_FILENAME_ENTRY)
    location_mode_str = MODE_FILENAME_ENTRY;
  else
    {
      g_assert_not_reached ();
404
      return FALSE;
405 406
    }

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
  switch (settings->sort_column)
    {
    case FILE_LIST_COL_NAME:
      sort_column = COLUMN_NAME_STRING;
      break;

    case FILE_LIST_COL_MTIME:
      sort_column = COLUMN_MTIME_STRING;
      break;

    case FILE_LIST_COL_SIZE:
      sort_column = COLUMN_SIZE_STRING;
      break;

    default:
      g_assert_not_reached ();
      sort_column = NULL;
    }

  switch (settings->sort_order)
    {
    case GTK_SORT_ASCENDING:
      sort_order = SORT_ASCENDING_STRING;
      break;

    case GTK_SORT_DESCENDING:
      sort_order = SORT_DESCENDING_STRING;
      break;

    default:
      g_assert_not_reached ();
      sort_order = NULL;
    }

441
  key_file = g_key_file_new ();
442

443 444
  /* Initialise with the on-disk keyfile, so we keep unknown options */
  g_key_file_load_from_file (key_file, filename, 0, NULL);
445

446 447 448 449 450 451
  g_key_file_set_string (key_file, SETTINGS_GROUP,
			 LOCATION_MODE_KEY, location_mode_str);
  g_key_file_set_boolean (key_file, SETTINGS_GROUP,
			  SHOW_HIDDEN_KEY, settings->show_hidden);
  g_key_file_set_boolean (key_file, SETTINGS_GROUP,
			  EXPAND_FOLDERS_KEY, settings->expand_folders);
452 453
  g_key_file_set_boolean (key_file, SETTINGS_GROUP,
			  SHOW_SIZE_COLUMN_KEY, settings->show_size_column);
454 455 456 457 458 459 460 461
  g_key_file_set_integer (key_file, SETTINGS_GROUP,
			  GEOMETRY_X_KEY, settings->geometry_x);
  g_key_file_set_integer (key_file, SETTINGS_GROUP,
			  GEOMETRY_Y_KEY, settings->geometry_y);
  g_key_file_set_integer (key_file, SETTINGS_GROUP,
			  GEOMETRY_WIDTH_KEY, settings->geometry_width);
  g_key_file_set_integer (key_file, SETTINGS_GROUP,
			  GEOMETRY_HEIGHT_KEY, settings->geometry_height);
462 463 464 465
  g_key_file_set_string (key_file, SETTINGS_GROUP,
			 SORT_COLUMN_KEY, sort_column);
  g_key_file_set_string (key_file, SETTINGS_GROUP,
			 SORT_ORDER_KEY, sort_order);
466

467 468
  contents = g_key_file_to_data (key_file, &len, error);
  g_key_file_free (key_file);
469

470 471
  if (!contents)
    goto out;
472

473
  if (!g_file_set_contents (filename, contents, len, NULL))
474 475 476 477 478 479 480 481 482 483 484 485 486
    {
      char *dirname;
      int saved_errno;

      /* Directory is not there? */

      dirname = get_config_dirname ();
      if (g_mkdir_with_parents (dirname, 0700) != 0) /* 0700 per the XDG basedir spec */
	{
	  saved_errno = errno;
	  g_set_error (error,
		       G_FILE_ERROR,
		       g_file_error_from_errno (saved_errno),
Matthias Clasen's avatar
Matthias Clasen committed
487 488
		       _("Error creating folder '%s': %s"),
		       dirname, g_strerror (saved_errno));
489 490 491
	  goto out;
	}

492
      if (!g_file_set_contents (filename, contents, len, error))
493 494 495 496 497 498 499 500 501 502 503 504 505
	goto out;
    }

  retval = TRUE;

 out:

  g_free (contents);
  g_free (dirname);
  g_free (filename);

  return retval;
}