gtkfilechooserdefault.c 172 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
  GtkWidget *save_file_name_entry;
  GtkWidget *save_folder_label;
  GtkWidget *save_folder_combo;
  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
121
  GtkWidget *browse_files_popup_menu;
122
  GtkWidget *browse_files_popup_menu_add_shortcut_item;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
123
  GtkWidget *browse_files_popup_menu_hidden_files_item;
124 125
  GtkWidget *browse_new_folder_button;
  GtkWidget *browse_path_bar;
126

127
  GtkFileSystemModel *browse_files_model;
128

129
  GtkWidget *filter_combo_hbox;
130
  GtkWidget *filter_combo;
131 132
  GtkWidget *preview_box;
  GtkWidget *preview_label;
133
  GtkWidget *preview_widget;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
134
  GtkWidget *extra_align;
135
  GtkWidget *extra_widget;
136

137
  GtkListStore *shortcuts_model;
138 139
  GtkTreeModel *shortcuts_filter_model;

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

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

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

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

150 151
  gboolean has_home;
  gboolean has_desktop;
152 153

  int num_volumes;
154 155
  int num_shortcuts;
  int num_bookmarks;
156

157 158
  gulong volumes_changed_id;
  gulong bookmarks_changed_id;
159

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

165 166 167
  GtkTreeViewColumn *list_name_column;
  GtkCellRenderer *list_name_renderer;

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

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

174 175 176
  gulong toplevel_set_focus_id;
  GtkWidget *toplevel_last_focus_widget;

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

182 183
  /* Flags */

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

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

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

static guint signals[LAST_SIGNAL] = { 0 };

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

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

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

234 235 236 237 238 239 240 241 242 243 244
/* 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 },
245 246 247
  { "text/uri-list", 0, TEXT_URI_LIST }
};

248 249 250 251 252 253 254 255 256 257
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]));
258

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

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

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

278 279 280 281
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);
282 283 284 285 286 287 288 289 290 291 292 293 294

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);
295
static void     gtk_file_chooser_default_dispose      (GObject               *object);
296
static void     gtk_file_chooser_default_show_all       (GtkWidget             *widget);
297 298
static void     gtk_file_chooser_default_hierarchy_changed (GtkWidget          *widget,
							    GtkWidget          *previous_toplevel);
299 300 301 302
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);
303

304 305 306
static gboolean       gtk_file_chooser_default_set_current_folder 	   (GtkFileChooser    *chooser,
									    const GtkFilePath *path,
									    GError           **error);
307 308
static GtkFilePath *  gtk_file_chooser_default_get_current_folder 	   (GtkFileChooser    *chooser);
static void           gtk_file_chooser_default_set_current_name   	   (GtkFileChooser    *chooser,
309
									    const gchar       *name);
310 311 312
static gboolean       gtk_file_chooser_default_select_path        	   (GtkFileChooser    *chooser,
									    const GtkFilePath *path,
									    GError           **error);
313
static void           gtk_file_chooser_default_unselect_path      	   (GtkFileChooser    *chooser,
314
									    const GtkFilePath *path);
315 316 317 318 319 320
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,
321
									    GtkFileFilter     *filter);
322
static void           gtk_file_chooser_default_remove_filter      	   (GtkFileChooser    *chooser,
323
									    GtkFileFilter     *filter);
324 325 326 327 328 329 330 331
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);
332

333 334 335 336 337 338
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);
339
static gboolean       gtk_file_chooser_default_should_respond         (GtkFileChooserEmbed *chooser_embed);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
340
static void           gtk_file_chooser_default_initial_focus          (GtkFileChooserEmbed *chooser_embed);
341

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

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

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

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

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

376 377
static void bookmarks_check_add_sensitivity (GtkFileChooserDefault *impl);

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

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

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

396 397 398 399 400
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
401 402 403 404 405
static void list_icon_data_func (GtkTreeViewColumn *tree_column,
				 GtkCellRenderer   *cell,
				 GtkTreeModel      *tree_model,
				 GtkTreeIter       *iter,
				 gpointer           data);
406 407 408 409 410
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
411
#if 0
412 413 414 415 416
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
417 418 419 420 421 422
#endif
static void list_mtime_data_func (GtkTreeViewColumn *tree_column,
				  GtkCellRenderer   *cell,
				  GtkTreeModel      *tree_model,
				  GtkTreeIter       *iter,
				  gpointer           data);
423

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

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

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

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

/* Drag and drop interface declarations */

typedef struct {
  GtkTreeModelFilter parent;

  GtkFileChooserDefault *impl;
} ShortcutsModelFilter;

typedef struct {
  GtkTreeModelFilterClass parent_class;
} ShortcutsModelFilterClass;

445
#define SHORTCUTS_MODEL_FILTER_TYPE (_shortcuts_model_filter_get_type ())
446 447 448 449 450
#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,
451
			 _shortcuts_model_filter,
452 453 454 455 456 457 458 459 460 461
			 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
462
GType
463
_gtk_file_chooser_default_get_type (void)
Owen Taylor's avatar
Owen Taylor committed
464
{
465
  static GType file_chooser_default_type = 0;
Owen Taylor's avatar
Owen Taylor committed
466

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

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

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

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

499
      g_type_add_interface_static (file_chooser_default_type,
Owen Taylor's avatar
Owen Taylor committed
500 501
				   GTK_TYPE_FILE_CHOOSER,
				   &file_chooser_info);
502 503 504
      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
505 506
    }

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

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

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

519 520 521 522
  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;
523
  gobject_class->dispose = gtk_file_chooser_default_dispose;
Owen Taylor's avatar
Owen Taylor committed
524

525
  widget_class->show_all = gtk_file_chooser_default_show_all;
526
  widget_class->hierarchy_changed = gtk_file_chooser_default_hierarchy_changed;
527 528
  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
529

530 531 532 533 534 535
  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,
536 537
			     _gtk_marshal_VOID__STRING,
			     G_TYPE_NONE, 1, G_TYPE_STRING);
538 539 540 541 542 543 544 545
  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);
546 547 548 549 550 551 552 553
  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);
554 555 556 557 558 559 560 561 562 563 564 565 566 567
  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",
568
				1, G_TYPE_STRING, "");
569

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

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

588 589 590 591 592 593 594 595 596
  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);

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

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

Owen Taylor's avatar
Owen Taylor committed
608 609 610 611 612
  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
613 614 615
}

static void
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
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
634 635
}

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

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

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

Federico Mena Quintero's avatar
Federico Mena Quintero committed
663 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
/* 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;
}

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

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

  shortcuts_free (impl);

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

731 732 733 734 735 736 737 738 739 740 741
  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
742 743 744 745 746 747 748 749 750 751

  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
752 753
  load_remove_timer (impl);

754 755 756 757 758 759 760
  /* 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);

761 762
  g_free (impl->preview_display_name);

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

765 766
  g_object_unref (impl->tooltips);

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

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

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

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

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

Federico Mena Quintero's avatar
Federico Mena Quintero committed
800 801 802 803 804 805
/* 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);
806 807
}

808 809 810 811 812 813 814
/* 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)
{
815 816 817 818 819
  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
820 821 822
      char *text = g_strdup_printf (msg,
				    uri,
				    error->message);
823 824 825 826 827
      error_message (impl, text);
      g_free (text);
      g_free (uri);
      g_error_free (error);
    }
828 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
/* 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);
}

854 855 856 857 858 859 860
/* 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)
{
861
  char *uri;
862 863
  char *msg;

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

874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
/* 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
893 894 895 896 897 898 899 900 901 902 903 904
  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);
905 906

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

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

  gtk_file_path_free (path_copy);
913 914 915 916

  return result;
}

917
static void
918
update_preview_widget_visibility (GtkFileChooserDefault *impl)
919
{
920 921 922 923 924 925 926 927 928 929 930 931 932
  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)
933 934 935 936
	{
	  gtk_widget_destroy (impl->preview_label);
	  impl->preview_label = NULL;
	}
937 938
    }

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