gtkfilechooserutils.c 17.1 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Owen Taylor's avatar
Owen Taylor committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 * gtkfilechooserutils.c: Private utility functions useful for
 *                        implementing a GtkFileChooser interface
 * Copyright (C) 2003, Red Hat, Inc.
 *
 * 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
Javier Jardon's avatar
Javier Jardon committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Owen Taylor's avatar
Owen Taylor committed
18 19
 */

20
#include "config.h"
Owen Taylor's avatar
Owen Taylor committed
21 22
#include "gtkfilechooserutils.h"
#include "gtkfilechooser.h"
23
#include "gtkfilesystem.h"
24
#include "gtktypebuiltins.h"
25
#include "gtkintl.h"
26

Owen Taylor's avatar
Owen Taylor committed
27

28
static gboolean       delegate_set_current_folder     (GtkFileChooser    *chooser,
29
						       GFile             *file,
30
						       GError           **error);
31
static GFile *        delegate_get_current_folder     (GtkFileChooser    *chooser);
32 33
static void           delegate_set_current_name       (GtkFileChooser    *chooser,
						       const gchar       *name);
34
static gchar *        delegate_get_current_name       (GtkFileChooser    *chooser);
35 36
static gboolean       delegate_select_file            (GtkFileChooser    *chooser,
						       GFile             *file,
37
						       GError           **error);
38 39
static void           delegate_unselect_file          (GtkFileChooser    *chooser,
						       GFile             *file);
40 41
static void           delegate_select_all             (GtkFileChooser    *chooser);
static void           delegate_unselect_all           (GtkFileChooser    *chooser);
42 43
static GSList *       delegate_get_files              (GtkFileChooser    *chooser);
static GFile *        delegate_get_preview_file       (GtkFileChooser    *chooser);
44
static GtkFileSystem *delegate_get_file_system        (GtkFileChooser    *chooser);
Owen Taylor's avatar
Owen Taylor committed
45 46 47 48 49
static void           delegate_add_filter             (GtkFileChooser    *chooser,
						       GtkFileFilter     *filter);
static void           delegate_remove_filter          (GtkFileChooser    *chooser,
						       GtkFileFilter     *filter);
static GSList *       delegate_list_filters           (GtkFileChooser    *chooser);
50
static gboolean       delegate_add_shortcut_folder    (GtkFileChooser    *chooser,
51
						       GFile             *file,
52 53
						       GError           **error);
static gboolean       delegate_remove_shortcut_folder (GtkFileChooser    *chooser,
54
						       GFile             *file,
55 56
						       GError           **error);
static GSList *       delegate_list_shortcut_folders  (GtkFileChooser    *chooser);
Owen Taylor's avatar
Owen Taylor committed
57 58 59
static void           delegate_notify                 (GObject           *object,
						       GParamSpec        *pspec,
						       gpointer           data);
60 61 62 63
static void           delegate_current_folder_changed (GtkFileChooser    *chooser,
						       gpointer           data);
static void           delegate_selection_changed      (GtkFileChooser    *chooser,
						       gpointer           data);
64 65
static void           delegate_update_preview         (GtkFileChooser    *chooser,
						       gpointer           data);
66 67
static void           delegate_file_activated         (GtkFileChooser    *chooser,
						       gpointer           data);
Owen Taylor's avatar
Owen Taylor committed
68

69 70
static GtkFileChooserConfirmation delegate_confirm_overwrite (GtkFileChooser    *chooser,
							      gpointer           data);
71 72 73 74 75 76 77 78 79 80 81 82 83
static void           delegate_add_choice             (GtkFileChooser  *chooser,
                                                       const char      *id,
                                                       const char      *label,
                                                       const char     **options,
                                                       const char     **option_labels);
static void           delegate_remove_choice          (GtkFileChooser  *chooser,
                                                       const char      *id);
static void           delegate_set_choice             (GtkFileChooser  *chooser,
                                                       const char      *id,
                                                       const char      *option);
static const char *   delegate_get_choice             (GtkFileChooser  *chooser,
                                                       const char      *id);

84

85 86 87
/**
 * _gtk_file_chooser_install_properties:
 * @klass: the class structure for a type deriving from #GObject
88
 *
89 90 91 92
 * Installs the necessary properties for a class implementing
 * #GtkFileChooser. A #GtkParamSpecOverride property is installed
 * for each property, using the values from the #GtkFileChooserProp
 * enumeration. The caller must make sure itself that the enumeration
93
 * values don’t collide with some other property values they
94 95
 * are using.
 **/
Owen Taylor's avatar
Owen Taylor committed
96 97 98
void
_gtk_file_chooser_install_properties (GObjectClass *klass)
{
Owen Taylor's avatar
Owen Taylor committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_ACTION,
				    "action");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET,
				    "extra-widget");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_FILTER,
				    "filter");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_LOCAL_ONLY,
				    "local-only");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET,
				    "preview-widget");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE,
				    "preview-widget-active");
117 118 119
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL,
				    "use-preview-label");
Owen Taylor's avatar
Owen Taylor committed
120 121 122 123 124 125
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
				    "select-multiple");
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN,
				    "show-hidden");
126 127 128
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION,
				    "do-overwrite-confirmation");
129 130 131
  g_object_class_override_property (klass,
				    GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
				    "create-folders");
Owen Taylor's avatar
Owen Taylor committed
132 133
}

134 135 136
/**
 * _gtk_file_chooser_delegate_iface_init:
 * @iface: a #GtkFileChoserIface structure
137
 *
138 139 140 141 142 143 144
 * An interface-initialization function for use in cases where
 * an object is simply delegating the methods, signals of
 * the #GtkFileChooser interface to another object.
 * _gtk_file_chooser_set_delegate() must be called on each
 * instance of the object so that the delegate object can
 * be found.
 **/
Owen Taylor's avatar
Owen Taylor committed
145 146 147 148 149
void
_gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
{
  iface->set_current_folder = delegate_set_current_folder;
  iface->get_current_folder = delegate_get_current_folder;
150
  iface->set_current_name = delegate_set_current_name;
151
  iface->get_current_name = delegate_get_current_name;
152 153
  iface->select_file = delegate_select_file;
  iface->unselect_file = delegate_unselect_file;
Owen Taylor's avatar
Owen Taylor committed
154 155
  iface->select_all = delegate_select_all;
  iface->unselect_all = delegate_unselect_all;
156 157
  iface->get_files = delegate_get_files;
  iface->get_preview_file = delegate_get_preview_file;
158
  iface->get_file_system = delegate_get_file_system;
Owen Taylor's avatar
Owen Taylor committed
159 160 161
  iface->add_filter = delegate_add_filter;
  iface->remove_filter = delegate_remove_filter;
  iface->list_filters = delegate_list_filters;
162 163 164
  iface->add_shortcut_folder = delegate_add_shortcut_folder;
  iface->remove_shortcut_folder = delegate_remove_shortcut_folder;
  iface->list_shortcut_folders = delegate_list_shortcut_folders;
165 166 167 168
  iface->add_choice = delegate_add_choice;
  iface->remove_choice = delegate_remove_choice;
  iface->set_choice = delegate_set_choice;
  iface->get_choice = delegate_get_choice;
Owen Taylor's avatar
Owen Taylor committed
169 170
}

171 172
/**
 * _gtk_file_chooser_set_delegate:
173 174
 * @receiver: a #GObject implementing #GtkFileChooser
 * @delegate: another #GObject implementing #GtkFileChooser
175 176 177 178
 *
 * Establishes that calls on @receiver for #GtkFileChooser
 * methods should be delegated to @delegate, and that
 * #GtkFileChooser signals emitted on @delegate should be
Matthias Clasen's avatar
Matthias Clasen committed
179
 * forwarded to @receiver. Must be used in conjunction with
180 181
 * _gtk_file_chooser_delegate_iface_init().
 **/
Owen Taylor's avatar
Owen Taylor committed
182 183 184 185 186 187
void
_gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
				GtkFileChooser *delegate)
{
  g_return_if_fail (GTK_IS_FILE_CHOOSER (receiver));
  g_return_if_fail (GTK_IS_FILE_CHOOSER (delegate));
188

189
  g_object_set_data (G_OBJECT (receiver), I_("gtk-file-chooser-delegate"), delegate);
Owen Taylor's avatar
Owen Taylor committed
190 191
  g_signal_connect (delegate, "notify",
		    G_CALLBACK (delegate_notify), receiver);
192
  g_signal_connect (delegate, "current-folder-changed",
Owen Taylor's avatar
Owen Taylor committed
193
		    G_CALLBACK (delegate_current_folder_changed), receiver);
194
  g_signal_connect (delegate, "selection-changed",
Owen Taylor's avatar
Owen Taylor committed
195
		    G_CALLBACK (delegate_selection_changed), receiver);
196 197
  g_signal_connect (delegate, "update-preview",
		    G_CALLBACK (delegate_update_preview), receiver);
198 199
  g_signal_connect (delegate, "file-activated",
		    G_CALLBACK (delegate_file_activated), receiver);
200 201
  g_signal_connect (delegate, "confirm-overwrite",
		    G_CALLBACK (delegate_confirm_overwrite), receiver);
Owen Taylor's avatar
Owen Taylor committed
202 203
}

204 205 206 207 208 209 210 211 212 213 214
GQuark
_gtk_file_chooser_delegate_get_quark (void)
{
  static GQuark quark = 0;

  if (G_UNLIKELY (quark == 0))
    quark = g_quark_from_static_string ("gtk-file-chooser-delegate");
  
  return quark;
}

215
static GtkFileChooser *
Owen Taylor's avatar
Owen Taylor committed
216 217
get_delegate (GtkFileChooser *receiver)
{
218 219
  return g_object_get_qdata (G_OBJECT (receiver),
			     GTK_FILE_CHOOSER_DELEGATE_QUARK);
Owen Taylor's avatar
Owen Taylor committed
220 221
}

222
static gboolean
223 224
delegate_select_file (GtkFileChooser    *chooser,
		      GFile             *file,
225
		      GError           **error)
Owen Taylor's avatar
Owen Taylor committed
226
{
227
  return gtk_file_chooser_select_file (get_delegate (chooser), file, error);
Owen Taylor's avatar
Owen Taylor committed
228 229 230
}

static void
231 232
delegate_unselect_file (GtkFileChooser *chooser,
			GFile          *file)
Owen Taylor's avatar
Owen Taylor committed
233
{
234
  gtk_file_chooser_unselect_file (get_delegate (chooser), file);
Owen Taylor's avatar
Owen Taylor committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
}

static void
delegate_select_all (GtkFileChooser *chooser)
{
  gtk_file_chooser_select_all (get_delegate (chooser));
}

static void
delegate_unselect_all (GtkFileChooser *chooser)
{
  gtk_file_chooser_unselect_all (get_delegate (chooser));
}

static GSList *
250
delegate_get_files (GtkFileChooser *chooser)
Owen Taylor's avatar
Owen Taylor committed
251
{
252
  return gtk_file_chooser_get_files (get_delegate (chooser));
253 254
}

255 256
static GFile *
delegate_get_preview_file (GtkFileChooser *chooser)
257
{
258
  return gtk_file_chooser_get_preview_file (get_delegate (chooser));
259 260
}

261 262 263 264
static GtkFileSystem *
delegate_get_file_system (GtkFileChooser *chooser)
{
  return _gtk_file_chooser_get_file_system (get_delegate (chooser));
Owen Taylor's avatar
Owen Taylor committed
265 266
}

Owen Taylor's avatar
Owen Taylor committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
static void
delegate_add_filter (GtkFileChooser *chooser,
		     GtkFileFilter  *filter)
{
  gtk_file_chooser_add_filter (get_delegate (chooser), filter);
}

static void
delegate_remove_filter (GtkFileChooser *chooser,
			GtkFileFilter  *filter)
{
  gtk_file_chooser_remove_filter (get_delegate (chooser), filter);
}

static GSList *
delegate_list_filters (GtkFileChooser *chooser)
{
  return gtk_file_chooser_list_filters (get_delegate (chooser));
}

287
static gboolean
288 289 290
delegate_add_shortcut_folder (GtkFileChooser  *chooser,
			      GFile           *file,
			      GError         **error)
291
{
292
  return _gtk_file_chooser_add_shortcut_folder (get_delegate (chooser), file, error);
293 294 295
}

static gboolean
296 297 298
delegate_remove_shortcut_folder (GtkFileChooser  *chooser,
				 GFile           *file,
				 GError         **error)
299
{
300
  return _gtk_file_chooser_remove_shortcut_folder (get_delegate (chooser), file, error);
301 302 303 304 305
}

static GSList *
delegate_list_shortcut_folders (GtkFileChooser *chooser)
{
306
  return _gtk_file_chooser_list_shortcut_folder_files (get_delegate (chooser));
307 308
}

309
static gboolean
310 311 312
delegate_set_current_folder (GtkFileChooser  *chooser,
			     GFile           *file,
			     GError         **error)
Owen Taylor's avatar
Owen Taylor committed
313
{
314
  return gtk_file_chooser_set_current_folder_file (get_delegate (chooser), file, error);
Owen Taylor's avatar
Owen Taylor committed
315 316
}

317
static GFile *
Owen Taylor's avatar
Owen Taylor committed
318 319
delegate_get_current_folder (GtkFileChooser *chooser)
{
320
  return gtk_file_chooser_get_current_folder_file (get_delegate (chooser));
321 322 323 324 325 326 327
}

static void
delegate_set_current_name (GtkFileChooser *chooser,
			   const gchar    *name)
{
  gtk_file_chooser_set_current_name (get_delegate (chooser), name);
Owen Taylor's avatar
Owen Taylor committed
328 329
}

330 331 332 333 334 335
static gchar *
delegate_get_current_name (GtkFileChooser *chooser)
{
  return gtk_file_chooser_get_current_name (get_delegate (chooser));
}

Owen Taylor's avatar
Owen Taylor committed
336 337 338 339 340
static void
delegate_notify (GObject    *object,
		 GParamSpec *pspec,
		 gpointer    data)
{
341 342 343 344 345 346
  gpointer iface;

  iface = g_type_interface_peek (g_type_class_peek (G_OBJECT_TYPE (object)),
				 gtk_file_chooser_get_type ());
  if (g_object_interface_find_property (iface, pspec->name))
    g_object_notify (data, pspec->name);
Owen Taylor's avatar
Owen Taylor committed
347 348
}

Owen Taylor's avatar
Owen Taylor committed
349 350 351 352
static void
delegate_selection_changed (GtkFileChooser *chooser,
			    gpointer        data)
{
353
  g_signal_emit_by_name (data, "selection-changed");
Owen Taylor's avatar
Owen Taylor committed
354 355 356 357 358 359
}

static void
delegate_current_folder_changed (GtkFileChooser *chooser,
				 gpointer        data)
{
360 361 362 363 364 365 366 367
  g_signal_emit_by_name (data, "current-folder-changed");
}

static void
delegate_update_preview (GtkFileChooser    *chooser,
			 gpointer           data)
{
  g_signal_emit_by_name (data, "update-preview");
Owen Taylor's avatar
Owen Taylor committed
368
}
369 370 371 372 373 374 375

static void
delegate_file_activated (GtkFileChooser    *chooser,
			 gpointer           data)
{
  g_signal_emit_by_name (data, "file-activated");
}
376

377 378 379 380 381 382 383 384 385
static GtkFileChooserConfirmation
delegate_confirm_overwrite (GtkFileChooser    *chooser,
			    gpointer           data)
{
  GtkFileChooserConfirmation conf;

  g_signal_emit_by_name (data, "confirm-overwrite", &conf);
  return conf;
}
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400

static GFile *
get_parent_for_uri (const char *uri)
{
  GFile *file;
  GFile *parent;

  file = g_file_new_for_uri (uri);
  parent = g_file_get_parent (file);

  g_object_unref (file);
  return parent;
	
}

401 402
/* Extracts the parent folders out of the supplied list of GtkRecentInfo* items, and returns
 * a list of GFile* for those unique parents.
403 404
 */
GList *
405
_gtk_file_chooser_extract_recent_folders (GList *infos)
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 441
{
  GList *l;
  GList *result;
  GHashTable *folders;

  result = NULL;

  folders = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);

  for (l = infos; l; l = l->next)
    {
      GtkRecentInfo *info = l->data;
      const char *uri;
      GFile *parent;

      uri = gtk_recent_info_get_uri (info);
      parent = get_parent_for_uri (uri);

      if (parent)
	{
	  if (!g_hash_table_lookup (folders, parent))
	    {
	      g_hash_table_insert (folders, parent, (gpointer) 1);
	      result = g_list_prepend (result, g_object_ref (parent));
	    }

	  g_object_unref (parent);
	}
    }

  result = g_list_reverse (result);

  g_hash_table_destroy (folders);

  return result;
}
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468

GSettings *
_gtk_file_chooser_get_settings_for_widget (GtkWidget *widget)
{
  static GQuark file_chooser_settings_quark = 0;
  GtkSettings *gtksettings;
  GSettings *settings;

  if (G_UNLIKELY (file_chooser_settings_quark == 0))
    file_chooser_settings_quark = g_quark_from_static_string ("-gtk-file-chooser-settings");

  gtksettings = gtk_widget_get_settings (widget);
  settings = g_object_get_qdata (G_OBJECT (gtksettings), file_chooser_settings_quark);

  if (G_UNLIKELY (settings == NULL))
    {
      settings = g_settings_new ("org.gtk.Settings.FileChooser");
      g_settings_delay (settings);

      g_object_set_qdata_full (G_OBJECT (gtksettings),
                               file_chooser_settings_quark,
                               settings,
                               g_object_unref);
    }

  return settings;
}
Matthias Clasen's avatar
Matthias Clasen committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

gchar *
_gtk_file_chooser_label_for_file (GFile *file)
{
  const gchar *path, *start, *end, *p;
  gchar *uri, *host, *label;

  uri = g_file_get_uri (file);

  start = strstr (uri, "://");
  if (start)
    {
      start += 3;
      path = strchr (start, '/');
      if (path)
        end = path;
      else
        {
          end = uri + strlen (uri);
          path = "/";
        }

      /* strip username */
      p = strchr (start, '@');
      if (p && p < end)
        start = p + 1;

      p = strchr (start, ':');
      if (p && p < end)
        end = p;

      host = g_strndup (start, end - start);
      /* Translators: the first string is a path and the second string 
       * is a hostname. Nautilus and the panel contain the same string 
       * to translate. 
       */
      label = g_strdup_printf (_("%1$s on %2$s"), path, host);

      g_free (host);
    }
  else
    {
      label = g_strdup (uri);
    }

  g_free (uri);

  return label;
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
static void
delegate_add_choice (GtkFileChooser *chooser,
                     const char      *id,
                     const char      *label,
                     const char     **options,
                     const char     **option_labels)
{
  gtk_file_chooser_add_choice (get_delegate (chooser),
                               id, label, options, option_labels);
}
static void
delegate_remove_choice (GtkFileChooser  *chooser,
                        const char      *id)
{
  gtk_file_chooser_remove_choice (get_delegate (chooser), id);
}

static void
delegate_set_choice (GtkFileChooser  *chooser,
                     const char      *id,
                     const char      *option)
{
  gtk_file_chooser_set_choice (get_delegate (chooser), id, option);
}


static const char *
delegate_get_choice (GtkFileChooser  *chooser,
                     const char      *id)
{
  return gtk_file_chooser_get_choice (get_delegate (chooser), id);
}