gtkfilechooserdefault.c 173 KB
Newer Older
Owen Taylor's avatar
Owen Taylor committed
1
/* GTK - The GIMP Toolkit
2
 * gtkfilechooserdefault.c: Default implementation of GtkFileChooser
Owen Taylor's avatar
Owen Taylor committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

21
#include <config.h>
22
#include "gdk/gdkkeysyms.h"
23
#include "gtkalias.h"
24
#include "gtkalignment.h"
25
#include "gtkbindings.h"
26
#include "gtkbutton.h"
27
#include "gtkcelllayout.h"
28
#include "gtkcellrendererpixbuf.h"
29
#include "gtkcellrenderertext.h"
30
#include "gtkcellrenderertext.h"
Federico Mena Quintero's avatar
Federico Mena Quintero committed
31
#include "gtkcheckmenuitem.h"
32
#include "gtkcombobox.h"
33
#include "gtkentry.h"
34
#include "gtkeventbox.h"
35
#include "gtkexpander.h"
36
#include "gtkfilechooserdefault.h"
37
#include "gtkfilechooserembed.h"
38
#include "gtkfilechooserentry.h"
Owen Taylor's avatar
Owen Taylor committed
39 40 41
#include "gtkfilechooserutils.h"
#include "gtkfilechooser.h"
#include "gtkfilesystemmodel.h"
42 43 44
#include "gtkframe.h"
#include "gtkhbox.h"
#include "gtkhpaned.h"
Federico Mena Quintero's avatar
Federico Mena Quintero committed
45
#include "gtkiconfactory.h"
46 47
#include "gtkicontheme.h"
#include "gtkimage.h"
48
#include "gtkimagemenuitem.h"
49
#include "gtkintl.h"
50
#include "gtklabel.h"
51
#include "gtkmarshalers.h"
52
#include "gtkmenuitem.h"
53
#include "gtkmessagedialog.h"
54
#include "gtkpathbar.h"
55 56
#include "gtkprivate.h"
#include "gtkscrolledwindow.h"
57
#include "gtkseparatormenuitem.h"
58
#include "gtksizegroup.h"
59 60
#include "gtkstock.h"
#include "gtktable.h"
61 62
#include "gtktreednd.h"
#include "gtktreeprivate.h"
63 64 65 66
#include "gtktreeview.h"
#include "gtktreemodelsort.h"
#include "gtktreeselection.h"
#include "gtktreestore.h"
Matthias Clasen's avatar
Matthias Clasen committed
67
#include "gtktooltips.h"
68 69
#include "gtktypebuiltins.h"
#include "gtkvbox.h"
Owen Taylor's avatar
Owen Taylor committed
70

71 72 73 74 75 76
#if defined (G_OS_UNIX)
#include "gtkfilesystemunix.h"
#elif defined (G_OS_WIN32)
#include "gtkfilesystemwin32.h"
#endif

77
#include <errno.h>
78
#include <string.h>
Federico Mena Quintero's avatar
Federico Mena Quintero committed
79
#include <time.h>
80

81
typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
Owen Taylor's avatar
Owen Taylor committed
82

83 84 85
#define GTK_FILE_CHOOSER_DEFAULT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
#define GTK_IS_FILE_CHOOSER_DEFAULT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_CHOOSER_DEFAULT))
#define GTK_FILE_CHOOSER_DEFAULT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
Owen Taylor's avatar
Owen Taylor committed
86

Federico Mena Quintero's avatar
Federico Mena Quintero committed
87 88 89 90 91 92
typedef enum {
	LOAD_LOADING,
	LOAD_FINISHED
} LoadState;

#define MAX_LOADING_TIME 500
93

94
struct _GtkFileChooserDefaultClass
Owen Taylor's avatar
Owen Taylor committed
95 96 97 98
{
  GtkVBoxClass parent_class;
};

99
struct _GtkFileChooserDefault
Owen Taylor's avatar
Owen Taylor committed
100 101 102
{
  GtkVBox parent_instance;

103 104
  GtkFileChooserAction action;

Owen Taylor's avatar
Owen Taylor committed
105
  GtkFileSystem *file_system;
106

107 108
  /* Save mode widgets */
  GtkWidget *save_widgets;
109

110 111 112 113 114 115 116 117 118 119 120 121
  GtkWidget *save_file_name_entry;
  GtkWidget *save_folder_label;
  GtkWidget *save_folder_combo;
  GtkWidget *save_extra_align;
  GtkWidget *save_expander;

  /* The file browsing widgets */
  GtkWidget *browse_widgets;
  GtkWidget *browse_shortcuts_tree_view;
  GtkWidget *browse_shortcuts_add_button;
  GtkWidget *browse_shortcuts_remove_button;
  GtkWidget *browse_files_tree_view;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
122
  GtkWidget *browse_files_popup_menu;
123
  GtkWidget *browse_files_popup_menu_add_shortcut_item;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
124
  GtkWidget *browse_files_popup_menu_hidden_files_item;
125 126 127
  GtkWidget *browse_new_folder_button;
  GtkWidget *browse_path_bar;
  GtkWidget *browse_extra_align;
128

129
  GtkFileSystemModel *browse_files_model;
130

131
  GtkWidget *filter_combo_hbox;
132
  GtkWidget *filter_combo;
133 134
  GtkWidget *preview_box;
  GtkWidget *preview_label;
135 136
  GtkWidget *preview_widget;
  GtkWidget *extra_widget;
137

138
  GtkListStore *shortcuts_model;
139 140
  GtkTreeModel *shortcuts_filter_model;

Owen Taylor's avatar
Owen Taylor committed
141
  GtkTreeModelSort *sort_model;
Owen Taylor's avatar
Owen Taylor committed
142

Federico Mena Quintero's avatar
Federico Mena Quintero committed
143 144 145
  LoadState load_state;
  guint load_timeout_id;

Owen Taylor's avatar
Owen Taylor committed
146 147
  GtkFileFilter *current_filter;
  GSList *filters;
148

Matthias Clasen's avatar
Matthias Clasen committed
149 150
  GtkTooltips *tooltips;

151 152
  gboolean has_home;
  gboolean has_desktop;
153 154

  int num_volumes;
155 156
  int num_shortcuts;
  int num_bookmarks;
157

158 159
  gulong volumes_changed_id;
  gulong bookmarks_changed_id;
160

161
  GtkFilePath *current_volume_path;
162
  GtkFilePath *current_folder;
163
  GtkFilePath *preview_path;
164
  char *preview_display_name;
165

166 167 168
  GtkTreeViewColumn *list_name_column;
  GtkCellRenderer *list_name_renderer;

Federico Mena Quintero's avatar
Federico Mena Quintero committed
169 170 171
  GSource *edited_idle;
  char *edited_new_text;

172
  gulong settings_signal_id;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
173 174
  int icon_size;

175 176 177
  gulong toplevel_set_focus_id;
  GtkWidget *toplevel_last_focus_widget;

178
#if 0
179 180
  GdkDragContext *shortcuts_drag_context;
  GSource *shortcuts_drag_outside_idle;
181
#endif
182

183 184
  /* Flags */

185 186
  guint local_only : 1;
  guint preview_widget_active : 1;
187
  guint use_preview_label : 1;
188 189
  guint select_multiple : 1;
  guint show_hidden : 1;
190
  guint list_sort_ascending : 1;
191
  guint changing_folder : 1;
192
  guint shortcuts_current_folder_active : 1;
193 194

#if 0
195
  guint shortcuts_drag_outside : 1;
196
#endif
197 198
};

199 200 201 202
/* Signal IDs */
enum {
  LOCATION_POPUP,
  UP_FOLDER,
203
  DOWN_FOLDER,
204 205 206 207 208 209
  HOME_FOLDER,
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

210
/* Column numbers for the shortcuts tree.  Keep these in sync with shortcuts_model_create() */
211 212 213
enum {
  SHORTCUTS_COL_PIXBUF,
  SHORTCUTS_COL_NAME,
Federico Mena Quintero's avatar
Federico Mena Quintero committed
214 215
  SHORTCUTS_COL_DATA,
  SHORTCUTS_COL_IS_VOLUME,
216
  SHORTCUTS_COL_REMOVABLE,
217
  SHORTCUTS_COL_PIXBUF_VISIBLE,
218
  SHORTCUTS_COL_NUM_COLUMNS
Owen Taylor's avatar
Owen Taylor committed
219 220
};

221 222 223 224 225 226 227 228
/* Column numbers for the file list */
enum {
  FILE_LIST_COL_NAME,
  FILE_LIST_COL_SIZE,
  FILE_LIST_COL_MTIME,
  FILE_LIST_COL_NUM_COLUMNS
};

229 230
/* Identifiers for target types */
enum {
231
  GTK_TREE_MODEL_ROW,
232 233 234
  TEXT_URI_LIST
};

235 236 237 238 239 240 241 242 243 244 245
/* Target types for dragging from the shortcuts list */
static GtkTargetEntry shortcuts_source_targets[] = {
  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
};

static const int num_shortcuts_source_targets = (sizeof (shortcuts_source_targets)
						 / sizeof (shortcuts_source_targets[0]));

/* Target types for dropping into the shortcuts list */
static GtkTargetEntry shortcuts_dest_targets[] = {
  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
246 247 248
  { "text/uri-list", 0, TEXT_URI_LIST }
};

249 250 251 252 253 254 255 256 257 258
static const int num_shortcuts_dest_targets = (sizeof (shortcuts_dest_targets)
					       / sizeof (shortcuts_dest_targets[0]));

/* Target types for DnD from the file list */
static GtkTargetEntry file_list_source_targets[] = {
  { "text/uri-list", 0, TEXT_URI_LIST }
};

static const int num_file_list_source_targets = (sizeof (file_list_source_targets)
						 / sizeof (file_list_source_targets[0]));
259

260 261 262 263 264 265
/* Interesting places in the shortcuts bar */
typedef enum {
  SHORTCUTS_HOME,
  SHORTCUTS_DESKTOP,
  SHORTCUTS_VOLUMES,
  SHORTCUTS_SHORTCUTS,
266 267 268 269
  SHORTCUTS_BOOKMARKS_SEPARATOR,
  SHORTCUTS_BOOKMARKS,
  SHORTCUTS_CURRENT_FOLDER_SEPARATOR,
  SHORTCUTS_CURRENT_FOLDER
270 271
} ShortcutsIndex;

Federico Mena Quintero's avatar
Federico Mena Quintero committed
272 273 274
/* Icon size for if we can't get it from the theme */
#define FALLBACK_ICON_SIZE 20

275 276 277
#define PREVIEW_HBOX_SPACING 12
#define NUM_LINES 40
#define NUM_CHARS 60
278

279 280 281 282
static void gtk_file_chooser_default_class_init       (GtkFileChooserDefaultClass *class);
static void gtk_file_chooser_default_iface_init       (GtkFileChooserIface        *iface);
static void gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface   *iface);
static void gtk_file_chooser_default_init             (GtkFileChooserDefault      *impl);
283 284 285 286 287 288 289 290 291 292 293 294 295

static GObject* gtk_file_chooser_default_constructor  (GType                  type,
						       guint                  n_construct_properties,
						       GObjectConstructParam *construct_params);
static void     gtk_file_chooser_default_finalize     (GObject               *object);
static void     gtk_file_chooser_default_set_property (GObject               *object,
						       guint                  prop_id,
						       const GValue          *value,
						       GParamSpec            *pspec);
static void     gtk_file_chooser_default_get_property (GObject               *object,
						       guint                  prop_id,
						       GValue                *value,
						       GParamSpec            *pspec);
296
static void     gtk_file_chooser_default_dispose      (GObject               *object);
297
static void     gtk_file_chooser_default_show_all       (GtkWidget             *widget);
298 299
static void     gtk_file_chooser_default_hierarchy_changed (GtkWidget          *widget,
							    GtkWidget          *previous_toplevel);
300 301 302 303
static void     gtk_file_chooser_default_style_set      (GtkWidget             *widget,
							 GtkStyle              *previous_style);
static void     gtk_file_chooser_default_screen_changed (GtkWidget             *widget,
							 GdkScreen             *previous_screen);
304

305 306 307
static gboolean       gtk_file_chooser_default_set_current_folder 	   (GtkFileChooser    *chooser,
									    const GtkFilePath *path,
									    GError           **error);
308 309
static GtkFilePath *  gtk_file_chooser_default_get_current_folder 	   (GtkFileChooser    *chooser);
static void           gtk_file_chooser_default_set_current_name   	   (GtkFileChooser    *chooser,
310
									    const gchar       *name);
311 312 313
static gboolean       gtk_file_chooser_default_select_path        	   (GtkFileChooser    *chooser,
									    const GtkFilePath *path,
									    GError           **error);
314
static void           gtk_file_chooser_default_unselect_path      	   (GtkFileChooser    *chooser,
315
									    const GtkFilePath *path);
316 317 318 319 320 321
static void           gtk_file_chooser_default_select_all         	   (GtkFileChooser    *chooser);
static void           gtk_file_chooser_default_unselect_all       	   (GtkFileChooser    *chooser);
static GSList *       gtk_file_chooser_default_get_paths          	   (GtkFileChooser    *chooser);
static GtkFilePath *  gtk_file_chooser_default_get_preview_path   	   (GtkFileChooser    *chooser);
static GtkFileSystem *gtk_file_chooser_default_get_file_system    	   (GtkFileChooser    *chooser);
static void           gtk_file_chooser_default_add_filter         	   (GtkFileChooser    *chooser,
322
									    GtkFileFilter     *filter);
323
static void           gtk_file_chooser_default_remove_filter      	   (GtkFileChooser    *chooser,
324
									    GtkFileFilter     *filter);
325 326 327 328 329 330 331 332
static GSList *       gtk_file_chooser_default_list_filters       	   (GtkFileChooser    *chooser);
static gboolean       gtk_file_chooser_default_add_shortcut_folder    (GtkFileChooser    *chooser,
								       const GtkFilePath *path,
								       GError           **error);
static gboolean       gtk_file_chooser_default_remove_shortcut_folder (GtkFileChooser    *chooser,
								       const GtkFilePath *path,
								       GError           **error);
static GSList *       gtk_file_chooser_default_list_shortcut_folders  (GtkFileChooser    *chooser);
333

334 335 336 337 338 339
static void           gtk_file_chooser_default_get_default_size       (GtkFileChooserEmbed *chooser_embed,
								       gint                *default_width,
								       gint                *default_height);
static void           gtk_file_chooser_default_get_resizable_hints    (GtkFileChooserEmbed *chooser_embed,
								       gboolean            *resize_horizontally,
								       gboolean            *resize_vertically);
340
static gboolean       gtk_file_chooser_default_should_respond         (GtkFileChooserEmbed *chooser_embed);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
341
static void           gtk_file_chooser_default_initial_focus          (GtkFileChooserEmbed *chooser_embed);
342

343 344
static void location_popup_handler (GtkFileChooserDefault *impl,
				    const gchar           *path);
345
static void up_folder_handler      (GtkFileChooserDefault *impl);
346
static void down_folder_handler    (GtkFileChooserDefault *impl);
347
static void home_folder_handler    (GtkFileChooserDefault *impl);
348
static void update_appearance      (GtkFileChooserDefault *impl);
349

350 351 352 353
static void set_current_filter   (GtkFileChooserDefault *impl,
				  GtkFileFilter         *filter);
static void check_preview_change (GtkFileChooserDefault *impl);

354
static void filter_combo_changed       (GtkComboBox           *combo_box,
355
					GtkFileChooserDefault *impl);
356 357 358 359
static void     shortcuts_row_activated_cb (GtkTreeView           *tree_view,
					    GtkTreePath           *path,
					    GtkTreeViewColumn     *column,
					    GtkFileChooserDefault *impl);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
360 361 362 363 364

static gboolean shortcuts_key_press_event_cb (GtkWidget             *widget,
					      GdkEventKey           *event,
					      GtkFileChooserDefault *impl);

365 366 367
static gboolean shortcuts_select_func   (GtkTreeSelection      *selection,
					 GtkTreeModel          *model,
					 GtkTreePath           *path,
368
					 gboolean               path_currently_selected,
369
					 gpointer               data);
370 371
static void shortcuts_activate_iter (GtkFileChooserDefault *impl,
				     GtkTreeIter           *iter);
372 373
static int shortcuts_get_index (GtkFileChooserDefault *impl,
				ShortcutsIndex         where);
374 375
static int shortcut_find_position (GtkFileChooserDefault *impl,
				   const GtkFilePath     *path);
376

377 378
static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl);

379 380 381 382 383 384
static gboolean list_select_func   (GtkTreeSelection      *selection,
				    GtkTreeModel          *model,
				    GtkTreePath           *path,
				    gboolean               path_currently_selected,
				    gpointer               data);

385 386 387 388 389 390
static void list_selection_changed     (GtkTreeSelection      *tree_selection,
					GtkFileChooserDefault *impl);
static void list_row_activated         (GtkTreeView           *tree_view,
					GtkTreePath           *path,
					GtkTreeViewColumn     *column,
					GtkFileChooserDefault *impl);
391

392
static void path_bar_clicked           (GtkPathBar            *path_bar,
393
					GtkFilePath           *file_path,
Federico Mena Quintero's avatar
Federico Mena Quintero committed
394
					gboolean               child_is_hidden,
395
					GtkFileChooserDefault *impl);
396

397 398 399 400 401
static void add_bookmark_button_clicked_cb    (GtkButton             *button,
					       GtkFileChooserDefault *impl);
static void remove_bookmark_button_clicked_cb (GtkButton             *button,
					       GtkFileChooserDefault *impl);

Owen Taylor's avatar
Owen Taylor committed
402 403 404 405 406
static void list_icon_data_func (GtkTreeViewColumn *tree_column,
				 GtkCellRenderer   *cell,
				 GtkTreeModel      *tree_model,
				 GtkTreeIter       *iter,
				 gpointer           data);
407 408 409 410 411
static void list_name_data_func (GtkTreeViewColumn *tree_column,
				 GtkCellRenderer   *cell,
				 GtkTreeModel      *tree_model,
				 GtkTreeIter       *iter,
				 gpointer           data);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
412
#if 0
413 414 415 416 417
static void list_size_data_func (GtkTreeViewColumn *tree_column,
				 GtkCellRenderer   *cell,
				 GtkTreeModel      *tree_model,
				 GtkTreeIter       *iter,
				 gpointer           data);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
418 419 420 421 422 423
#endif
static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
				  GtkCellRenderer   *cell,
				  GtkTreeModel      *tree_model,
				  GtkTreeIter       *iter,
				  gpointer           data);
424

425 426 427
static const GtkFileInfo *get_list_file_info (GtkFileChooserDefault *impl,
					      GtkTreeIter           *iter);

Federico Mena Quintero's avatar
Federico Mena Quintero committed
428 429
static void load_remove_timer (GtkFileChooserDefault *impl);

Owen Taylor's avatar
Owen Taylor committed
430
static GObjectClass *parent_class;
431

432 433 434 435 436 437 438 439 440 441 442 443 444 445


/* Drag and drop interface declarations */

typedef struct {
  GtkTreeModelFilter parent;

  GtkFileChooserDefault *impl;
} ShortcutsModelFilter;

typedef struct {
  GtkTreeModelFilterClass parent_class;
} ShortcutsModelFilterClass;

446
#define SHORTCUTS_MODEL_FILTER_TYPE (_shortcuts_model_filter_get_type ())
447 448 449 450 451
#define SHORTCUTS_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_MODEL_FILTER_TYPE, ShortcutsModelFilter))

static void shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);

G_DEFINE_TYPE_WITH_CODE (ShortcutsModelFilter,
452
			 _shortcuts_model_filter,
453 454 455 456 457 458 459 460 461 462
			 GTK_TYPE_TREE_MODEL_FILTER,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
						shortcuts_model_filter_drag_source_iface_init));

static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
						 GtkTreeModel          *child_model,
						 GtkTreePath           *root);



Owen Taylor's avatar
Owen Taylor committed
463
GType
464
_gtk_file_chooser_default_get_type (void)
Owen Taylor's avatar
Owen Taylor committed
465
{
466
  static GType file_chooser_default_type = 0;
Owen Taylor's avatar
Owen Taylor committed
467

468
  if (!file_chooser_default_type)
Owen Taylor's avatar
Owen Taylor committed
469
    {
470
      static const GTypeInfo file_chooser_default_info =
Owen Taylor's avatar
Owen Taylor committed
471
      {
472
	sizeof (GtkFileChooserDefaultClass),
Owen Taylor's avatar
Owen Taylor committed
473 474
	NULL,		/* base_init */
	NULL,		/* base_finalize */
475
	(GClassInitFunc) gtk_file_chooser_default_class_init,
Owen Taylor's avatar
Owen Taylor committed
476 477
	NULL,		/* class_finalize */
	NULL,		/* class_data */
478
	sizeof (GtkFileChooserDefault),
Owen Taylor's avatar
Owen Taylor committed
479
	0,		/* n_preallocs */
480
	(GInstanceInitFunc) gtk_file_chooser_default_init,
Owen Taylor's avatar
Owen Taylor committed
481
      };
482

Owen Taylor's avatar
Owen Taylor committed
483 484
      static const GInterfaceInfo file_chooser_info =
      {
485
	(GInterfaceInitFunc) gtk_file_chooser_default_iface_init, /* interface_init */
Owen Taylor's avatar
Owen Taylor committed
486 487 488 489
	NULL,			                                       /* interface_finalize */
	NULL			                                       /* interface_data */
      };

490 491 492 493 494 495 496
      static const GInterfaceInfo file_chooser_embed_info =
      {
	(GInterfaceInitFunc) gtk_file_chooser_embed_default_iface_init, /* interface_init */
	NULL,			                                       /* interface_finalize */
	NULL			                                       /* interface_data */
      };

497 498
      file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserDefault",
							 &file_chooser_default_info, 0);
499

500
      g_type_add_interface_static (file_chooser_default_type,
Owen Taylor's avatar
Owen Taylor committed
501 502
				   GTK_TYPE_FILE_CHOOSER,
				   &file_chooser_info);
503 504 505
      g_type_add_interface_static (file_chooser_default_type,
				   GTK_TYPE_FILE_CHOOSER_EMBED,
				   &file_chooser_embed_info);
Owen Taylor's avatar
Owen Taylor committed
506 507
    }

508
  return file_chooser_default_type;
Owen Taylor's avatar
Owen Taylor committed
509 510 511
}

static void
512
gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
Owen Taylor's avatar
Owen Taylor committed
513 514
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Owen Taylor's avatar
Owen Taylor committed
515
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
516
  GtkBindingSet *binding_set;
Owen Taylor's avatar
Owen Taylor committed
517

Owen Taylor's avatar
Owen Taylor committed
518 519
  parent_class = g_type_class_peek_parent (class);

520 521 522 523
  gobject_class->finalize = gtk_file_chooser_default_finalize;
  gobject_class->constructor = gtk_file_chooser_default_constructor;
  gobject_class->set_property = gtk_file_chooser_default_set_property;
  gobject_class->get_property = gtk_file_chooser_default_get_property;
524
  gobject_class->dispose = gtk_file_chooser_default_dispose;
Owen Taylor's avatar
Owen Taylor committed
525

526
  widget_class->show_all = gtk_file_chooser_default_show_all;
527
  widget_class->hierarchy_changed = gtk_file_chooser_default_hierarchy_changed;
528 529
  widget_class->style_set = gtk_file_chooser_default_style_set;
  widget_class->screen_changed = gtk_file_chooser_default_screen_changed;
Owen Taylor's avatar
Owen Taylor committed
530

531 532 533 534 535 536
  signals[LOCATION_POPUP] =
    _gtk_binding_signal_new ("location-popup",
			     G_OBJECT_CLASS_TYPE (class),
			     G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			     G_CALLBACK (location_popup_handler),
			     NULL, NULL,
537 538
			     _gtk_marshal_VOID__STRING,
			     G_TYPE_NONE, 1, G_TYPE_STRING);
539 540 541 542 543 544 545 546
  signals[UP_FOLDER] =
    _gtk_binding_signal_new ("up-folder",
			     G_OBJECT_CLASS_TYPE (class),
			     G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			     G_CALLBACK (up_folder_handler),
			     NULL, NULL,
			     _gtk_marshal_VOID__VOID,
			     G_TYPE_NONE, 0);
547 548 549 550 551 552 553 554
  signals[DOWN_FOLDER] =
    _gtk_binding_signal_new ("down-folder",
			     G_OBJECT_CLASS_TYPE (class),
			     G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			     G_CALLBACK (down_folder_handler),
			     NULL, NULL,
			     _gtk_marshal_VOID__VOID,
			     G_TYPE_NONE, 0);
555 556 557 558 559 560 561 562 563 564 565 566 567 568
  signals[HOME_FOLDER] =
    _gtk_binding_signal_new ("home-folder",
			     G_OBJECT_CLASS_TYPE (class),
			     G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
			     G_CALLBACK (home_folder_handler),
			     NULL, NULL,
			     _gtk_marshal_VOID__VOID,
			     G_TYPE_NONE, 0);

  binding_set = gtk_binding_set_by_class (class);

  gtk_binding_entry_add_signal (binding_set,
				GDK_l, GDK_CONTROL_MASK,
				"location-popup",
569
				1, G_TYPE_STRING, "");
570

571 572 573
  gtk_binding_entry_add_signal (binding_set,
				GDK_slash, 0,
				"location-popup",
574
				1, G_TYPE_STRING, "/");
575

576
  gtk_binding_entry_add_signal (binding_set,
577
				GDK_Up, GDK_MOD1_MASK,
578 579
				"up-folder",
				0);
580 581 582 583
  gtk_binding_entry_add_signal (binding_set,
		  		GDK_BackSpace, 0,
				"up-folder",
				0);
584
  gtk_binding_entry_add_signal (binding_set,
585
				GDK_KP_Up, GDK_MOD1_MASK,
586 587 588
				"up-folder",
				0);

589 590 591 592 593 594 595 596 597
  gtk_binding_entry_add_signal (binding_set,
				GDK_Down, GDK_MOD1_MASK,
				"down-folder",
				0);
  gtk_binding_entry_add_signal (binding_set,
				GDK_KP_Down, GDK_MOD1_MASK,
				"down-folder",
				0);

598
  gtk_binding_entry_add_signal (binding_set,
599 600
				GDK_Home, GDK_MOD1_MASK,
				"home-folder",
601 602
				0);
  gtk_binding_entry_add_signal (binding_set,
603 604
				GDK_KP_Home, GDK_MOD1_MASK,
				"home-folder",
605 606
				0);

Owen Taylor's avatar
Owen Taylor committed
607
  _gtk_file_chooser_install_properties (gobject_class);
608

Owen Taylor's avatar
Owen Taylor committed
609 610 611 612 613
  gtk_settings_install_property (g_param_spec_string ("gtk-file-chooser-backend",
						      P_("Default file chooser backend"),
						      P_("Name of the GtkFileChooser backend to use by default"),
						      NULL,
						      G_PARAM_READWRITE));
Owen Taylor's avatar
Owen Taylor committed
614 615 616
}

static void
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
gtk_file_chooser_default_iface_init (GtkFileChooserIface *iface)
{
  iface->select_path = gtk_file_chooser_default_select_path;
  iface->unselect_path = gtk_file_chooser_default_unselect_path;
  iface->select_all = gtk_file_chooser_default_select_all;
  iface->unselect_all = gtk_file_chooser_default_unselect_all;
  iface->get_paths = gtk_file_chooser_default_get_paths;
  iface->get_preview_path = gtk_file_chooser_default_get_preview_path;
  iface->get_file_system = gtk_file_chooser_default_get_file_system;
  iface->set_current_folder = gtk_file_chooser_default_set_current_folder;
  iface->get_current_folder = gtk_file_chooser_default_get_current_folder;
  iface->set_current_name = gtk_file_chooser_default_set_current_name;
  iface->add_filter = gtk_file_chooser_default_add_filter;
  iface->remove_filter = gtk_file_chooser_default_remove_filter;
  iface->list_filters = gtk_file_chooser_default_list_filters;
  iface->add_shortcut_folder = gtk_file_chooser_default_add_shortcut_folder;
  iface->remove_shortcut_folder = gtk_file_chooser_default_remove_shortcut_folder;
  iface->list_shortcut_folders = gtk_file_chooser_default_list_shortcut_folders;
Owen Taylor's avatar
Owen Taylor committed
635 636
}

637 638 639 640 641
static void
gtk_file_chooser_embed_default_iface_init (GtkFileChooserEmbedIface *iface)
{
  iface->get_default_size = gtk_file_chooser_default_get_default_size;
  iface->get_resizable_hints = gtk_file_chooser_default_get_resizable_hints;
642
  iface->should_respond = gtk_file_chooser_default_should_respond;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
643
  iface->initial_focus = gtk_file_chooser_default_initial_focus;
644
}
Owen Taylor's avatar
Owen Taylor committed
645
static void
646
gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
Owen Taylor's avatar
Owen Taylor committed
647
{
648 649
  impl->local_only = TRUE;
  impl->preview_widget_active = TRUE;
650
  impl->use_preview_label = TRUE;
651 652
  impl->select_multiple = FALSE;
  impl->show_hidden = FALSE;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
653
  impl->icon_size = FALLBACK_ICON_SIZE;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
654
  impl->load_state = LOAD_FINISHED;
655

656
  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (impl), TRUE);
657
  gtk_box_set_spacing (GTK_BOX (impl), 12);
Matthias Clasen's avatar
Matthias Clasen committed
658 659 660 661

  impl->tooltips = gtk_tooltips_new ();
  g_object_ref (impl->tooltips);
  gtk_object_sink (GTK_OBJECT (impl->tooltips));
662 663
}

Federico Mena Quintero's avatar
Federico Mena Quintero committed
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
/* Frees the data columns for the specified iter in the shortcuts model*/
static void
shortcuts_free_row_data (GtkFileChooserDefault *impl,
			 GtkTreeIter           *iter)
{
  gpointer col_data;
  gboolean is_volume;

  gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
		      SHORTCUTS_COL_DATA, &col_data,
		      SHORTCUTS_COL_IS_VOLUME, &is_volume,
		      -1);
  if (!col_data)
    return;

  if (is_volume)
    {
      GtkFileSystemVolume *volume;

      volume = col_data;
      gtk_file_system_volume_free (impl->file_system, volume);
    }
  else
    {
      GtkFilePath *path;

      path = col_data;
      gtk_file_path_free (path);
    }
}

/* Frees all the data columns in the shortcuts model */
static void
shortcuts_free (GtkFileChooserDefault *impl)
{
  GtkTreeIter iter;

  if (!impl->shortcuts_model)
    return;

  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
    do
      {
	shortcuts_free_row_data (impl, &iter);
      }
    while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter));

  g_object_unref (impl->shortcuts_model);
  impl->shortcuts_model = NULL;
}

715
static void
716
gtk_file_chooser_default_finalize (GObject *object)
717
{
718
  GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
719
  GSList *l;
720

Federico Mena Quintero's avatar
Federico Mena Quintero committed
721 722 723 724 725
  if (impl->shortcuts_filter_model)
    g_object_unref (impl->shortcuts_filter_model);

  shortcuts_free (impl);

726 727
  g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
  impl->volumes_changed_id = 0;
728 729
  g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
  impl->bookmarks_changed_id = 0;
730 731
  g_object_unref (impl->file_system);

732 733 734 735 736 737 738 739 740 741 742
  for (l = impl->filters; l; l = l->next)
    {
      GtkFileFilter *filter;

      filter = GTK_FILE_FILTER (l->data);
      g_object_unref (filter);
    }
  g_slist_free (impl->filters);

  if (impl->current_filter)
    g_object_unref (impl->current_filter);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
743 744 745 746 747 748 749 750 751 752

  if (impl->current_volume_path)
    gtk_file_path_free (impl->current_volume_path);

  if (impl->current_folder)
    gtk_file_path_free (impl->current_folder);

  if (impl->preview_path)
    gtk_file_path_free (impl->preview_path);

Federico Mena Quintero's avatar
Federico Mena Quintero committed
753 754
  load_remove_timer (impl);

755 756 757 758 759 760 761
  /* Free all the Models we have */
  if (impl->browse_files_model)
    g_object_unref (impl->browse_files_model);

  if (impl->sort_model)
    g_object_unref (impl->sort_model);

762 763
  g_free (impl->preview_display_name);

Federico Mena Quintero's avatar
Federico Mena Quintero committed
764 765
  g_free (impl->edited_new_text);

766 767
  g_object_unref (impl->tooltips);

768 769 770
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

771
/* Shows an error dialog set as transient for the specified window */
772
static void
773 774
error_message_with_parent (GtkWindow  *parent,
			   const char *msg)
775 776 777
{
  GtkWidget *dialog;

778
  dialog = gtk_message_dialog_new (parent,
779 780
				   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
				   GTK_MESSAGE_ERROR,
781
				   GTK_BUTTONS_OK,
782 783
				   "%s",
				   msg);
784 785 786 787
  gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);
}

Federico Mena Quintero's avatar
Federico Mena Quintero committed
788 789 790
/* Returns a toplevel GtkWindow, or NULL if none */
static GtkWindow *
get_toplevel (GtkWidget *widget)
Federico Mena Quintero's avatar
Federico Mena Quintero committed
791
{
792 793
  GtkWidget *toplevel;

Federico Mena Quintero's avatar
Federico Mena Quintero committed
794
  toplevel = gtk_widget_get_toplevel (widget);
795
  if (!GTK_WIDGET_TOPLEVEL (toplevel))
Federico Mena Quintero's avatar
Federico Mena Quintero committed
796 797 798 799
    return NULL;
  else
    return GTK_WINDOW (toplevel);
}
800

Federico Mena Quintero's avatar
Federico Mena Quintero committed
801 802 803 804 805 806
/* Shows an error dialog for the file chooser */
static void
error_message (GtkFileChooserDefault *impl,
	       const char            *msg)
{
  error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg);
807 808
}

809 810 811 812 813 814 815
/* Shows a simple error dialog relative to a path.  Frees the GError as well. */
static void
error_dialog (GtkFileChooserDefault *impl,
	      const char            *msg,
	      const GtkFilePath     *path,
	      GError                *error)
{
816 817 818 819 820
  g_return_if_fail (path != NULL);

  if (error)
    {
      char *uri = gtk_file_system_path_to_uri (impl->file_system, path);
Morten Welinder's avatar
Morten Welinder committed
821 822 823
      char *text = g_strdup_printf (msg,
				    uri,
				    error->message);
824 825 826 827 828
      error_message (impl, text);
      g_free (text);
      g_free (uri);
      g_error_free (error);
    }
829 830
}

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
/* Displays an error message about not being able to get information for a file.
 * Frees the GError as well.
 */
static void
error_getting_info_dialog (GtkFileChooserDefault *impl,
			   const GtkFilePath     *path,
			   GError                *error)
{
  error_dialog (impl,
		_("Could not retrieve information about %s:\n%s"),
		path, error);
}

/* Shows an error dialog about not being able to add a bookmark */
static void
error_could_not_add_bookmark_dialog (GtkFileChooserDefault *impl,
				     const GtkFilePath     *path,
				     GError                *error)
{
  error_dialog (impl,
		_("Could not add a bookmark for %s:\n%s"),
		path, error);
}

855 856 857 858 859 860 861
/* Shows an error dialog about not being able to compose a filename */
static void
error_building_filename_dialog (GtkFileChooserDefault *impl,
				const GtkFilePath     *base_path,
				const char            *file_part,
				GError                *error)
{
862
  char *uri;
863 864
  char *msg;

865
  uri = gtk_file_system_path_to_uri (impl->file_system, base_path);
866
  msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
867
			 uri, file_part,
868 869
			 error->message);
  error_message (impl, msg);
870
  g_free (uri);
871 872 873 874
  g_free (msg);
  g_error_free (error);
}

875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
/* Shows an error dialog when we cannot switch to a folder */
static void
error_changing_folder_dialog (GtkFileChooserDefault *impl,
			      const GtkFilePath     *path,
			      GError                *error)
{
  error_dialog (impl,
		_("Could not change the current folder to %s:\n%s"),
		path,
		error);
}

/* Changes folders, displaying an error dialog if this fails */
static gboolean
change_folder_and_display_error (GtkFileChooserDefault *impl,
				 const GtkFilePath     *path)
{
  GError *error;
  gboolean result;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
894 895 896 897 898 899 900 901 902 903 904 905
  GtkFilePath *path_copy;

  /* We copy the path because of this case:
   *
   * list_row_activated()
   *   fetches path from model; path belongs to the model (*)
   *   calls change_folder_and_display_error()
   *     calls _gtk_file_chooser_set_current_folder_path()
   *       changing folders fails, sets model to NULL, thus freeing the path in (*)
   */

  path_copy = gtk_file_path_copy (path);
906 907

  error = NULL;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
908
  result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path_copy, &error);
909 910

  if (!result)
Federico Mena Quintero's avatar
Federico Mena Quintero committed
911 912 913
    error_changing_folder_dialog (impl, path_copy, error);

  gtk_file_path_free (path_copy);
914 915 916 917

  return result;
}

918
static void
919
update_preview_widget_visibility (GtkFileChooserDefault *impl)
920
{
921 922 923 924 925 926 927 928 929 930 931 932 933
  if (impl->use_preview_label)
    {
      if (!impl->preview_label)
	{
	  impl->preview_label = gtk_label_new (impl->preview_display_name);
	  gtk_box_pack_start (GTK_BOX (impl->preview_box), impl->preview_label, FALSE, FALSE, 0);
	  gtk_box_reorder_child (GTK_BOX (impl->preview_box), impl->preview_label, 0);
	  gtk_widget_show (impl->preview_label);
	}
    }
  else
    {
      if (impl->preview_label)
934 935 936 937
	{
	  gtk_widget_destroy (impl->preview_label);
	  impl->preview_label = NULL;
	}
938 939
    }

940
  if (impl->preview_widget_active && impl->preview_widget)
941
    gtk_widget_show (impl->preview_box);
942
  else
943
    gtk_widget_hide (impl->preview_box);
944 945

  g_signal_emit_by_name (impl, "default-size-changed");
946 947
}