#include <config.h>
#include "gdk/gdkkeysyms.h"
-#include "gtkalias.h"
#include "gtkalignment.h"
#include "gtkbindings.h"
#include "gtkbutton.h"
#include "gtkcellrenderertext.h"
#include "gtkcellrenderertext.h"
#include "gtkcheckmenuitem.h"
+#include "gtkclipboard.h"
#include "gtkcombobox.h"
#include "gtkentry.h"
#include "gtkeventbox.h"
#include "gtkexpander.h"
+#include "gtkfilechooserprivate.h"
#include "gtkfilechooserdefault.h"
#include "gtkfilechooserembed.h"
#include "gtkfilechooserentry.h"
+#include "gtkfilechoosersettings.h"
#include "gtkfilechooserutils.h"
#include "gtkfilechooser.h"
#include "gtkfilesystemmodel.h"
#include "gtkmessagedialog.h"
#include "gtkpathbar.h"
#include "gtkprivate.h"
+#include "gtkradiobutton.h"
#include "gtkscrolledwindow.h"
#include "gtkseparatormenuitem.h"
#include "gtksizegroup.h"
#include "gtktable.h"
#include "gtktreednd.h"
#include "gtktreeprivate.h"
-#include "gtktreeview.h"
-#include "gtktreemodelsort.h"
#include "gtktreeselection.h"
-#include "gtktreestore.h"
-#include "gtktooltips.h"
#include "gtktypebuiltins.h"
#include "gtkvbox.h"
#include "gtkfilesystemwin32.h"
#endif
+#include "gtkalias.h"
+
#include <errno.h>
#include <string.h>
#include <time.h>
-typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
-
-#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))
-
-typedef enum {
- LOAD_EMPTY, /* There is no model */
- LOAD_PRELOAD, /* Model is loading and a timer is running; model isn't inserted into the tree yet */
- LOAD_LOADING, /* Timeout expired, model is inserted into the tree, but not fully loaded yet */
- LOAD_FINISHED /* Model is fully loaded and inserted into the tree */
-} LoadState;
-
-#define MAX_LOADING_TIME 500
-
-struct _GtkFileChooserDefaultClass
-{
- GtkVBoxClass parent_class;
-};
-
-struct _GtkFileChooserDefault
-{
- GtkVBox parent_instance;
-
- GtkFileChooserAction action;
-
- GtkFileSystem *file_system;
-
- /* Save mode widgets */
- GtkWidget *save_widgets;
-
- 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;
- GtkWidget *browse_files_popup_menu;
- GtkWidget *browse_files_popup_menu_add_shortcut_item;
- GtkWidget *browse_files_popup_menu_hidden_files_item;
- GtkWidget *browse_new_folder_button;
- GtkWidget *browse_path_bar;
-
- GtkFileSystemModel *browse_files_model;
-
- GtkWidget *filter_combo_hbox;
- GtkWidget *filter_combo;
- GtkWidget *preview_box;
- GtkWidget *preview_label;
- GtkWidget *preview_widget;
- GtkWidget *extra_align;
- GtkWidget *extra_widget;
-
- GtkListStore *shortcuts_model;
- GtkTreeModel *shortcuts_filter_model;
+\f
- GtkTreeModelSort *sort_model;
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
- LoadState load_state;
- guint load_timeout_id;
+/* Profiling stuff */
+#undef PROFILE_FILE_CHOOSER
+#ifdef PROFILE_FILE_CHOOSER
- GSList *pending_select_paths;
- GtkFileFilter *current_filter;
- GSList *filters;
+#ifndef F_OK
+#define F_OK 0
+#endif
- GtkTooltips *tooltips;
+#define PROFILE_INDENT 4
+static int profile_indent;
- gboolean has_home;
- gboolean has_desktop;
+static void
+profile_add_indent (int indent)
+{
+ profile_indent += indent;
+ if (profile_indent < 0)
+ g_error ("You screwed up your indentation");
+}
- int num_volumes;
- int num_shortcuts;
- int num_bookmarks;
+void
+_gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, const char *msg2)
+{
+ char *str;
- gulong volumes_changed_id;
- gulong bookmarks_changed_id;
+ if (indent < 0)
+ profile_add_indent (indent);
- GtkFilePath *current_volume_path;
- GtkFilePath *current_folder;
- GtkFilePath *preview_path;
- char *preview_display_name;
+ if (profile_indent == 0)
+ str = g_strdup_printf ("MARK: %s %s %s", func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
+ else
+ str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func ? func : "", msg1 ? msg1 : "", msg2 ? msg2 : "");
- GtkTreeViewColumn *list_name_column;
- GtkCellRenderer *list_name_renderer;
+ access (str, F_OK);
+ g_free (str);
- GSource *edited_idle;
- char *edited_new_text;
+ if (indent > 0)
+ profile_add_indent (indent);
+}
- gulong settings_signal_id;
- int icon_size;
+#define profile_start(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, PROFILE_INDENT, x, y)
+#define profile_end(x, y) _gtk_file_chooser_profile_log (G_STRFUNC, -PROFILE_INDENT, x, y)
+#define profile_msg(x, y) _gtk_file_chooser_profile_log (NULL, 0, x, y)
+#else
+#define profile_start(x, y)
+#define profile_end(x, y)
+#define profile_msg(x, y)
+#endif
- gulong toplevel_set_focus_id;
- GtkWidget *toplevel_last_focus_widget;
+\f
-#if 0
- GdkDragContext *shortcuts_drag_context;
- GSource *shortcuts_drag_outside_idle;
-#endif
+typedef struct _GtkFileChooserDefaultClass GtkFileChooserDefaultClass;
- /* Flags */
+#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))
- guint local_only : 1;
- guint preview_widget_active : 1;
- guint use_preview_label : 1;
- guint select_multiple : 1;
- guint show_hidden : 1;
- guint list_sort_ascending : 1;
- guint changing_folder : 1;
- guint shortcuts_current_folder_active : 1;
+#define MAX_LOADING_TIME 500
-#if 0
- guint shortcuts_drag_outside : 1;
-#endif
+struct _GtkFileChooserDefaultClass
+{
+ GtkVBoxClass parent_class;
};
/* Signal IDs */
enum {
LOCATION_POPUP,
+ LOCATION_POPUP_ON_PASTE,
UP_FOLDER,
DOWN_FOLDER,
HOME_FOLDER,
+ DESKTOP_FOLDER,
+ QUICK_BOOKMARK,
LAST_SIGNAL
};
SHORTCUTS_COL_IS_VOLUME,
SHORTCUTS_COL_REMOVABLE,
SHORTCUTS_COL_PIXBUF_VISIBLE,
+ SHORTCUTS_COL_HANDLE,
SHORTCUTS_COL_NUM_COLUMNS
};
};
/* Target types for dragging from the shortcuts list */
-static GtkTargetEntry shortcuts_source_targets[] = {
+static const GtkTargetEntry shortcuts_source_targets[] = {
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
};
/ sizeof (shortcuts_source_targets[0]));
/* Target types for dropping into the shortcuts list */
-static GtkTargetEntry shortcuts_dest_targets[] = {
+static const GtkTargetEntry shortcuts_dest_targets[] = {
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
{ "text/uri-list", 0, TEXT_URI_LIST }
};
/ sizeof (shortcuts_dest_targets[0]));
/* Target types for DnD from the file list */
-static GtkTargetEntry file_list_source_targets[] = {
+static const 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]));
+/* Target types for dropping into the file list */
+static const GtkTargetEntry file_list_dest_targets[] = {
+ { "text/uri-list", 0, TEXT_URI_LIST }
+};
+
+static const int num_file_list_dest_targets = (sizeof (file_list_dest_targets)
+ / sizeof (file_list_dest_targets[0]));
+
+
/* Interesting places in the shortcuts bar */
typedef enum {
SHORTCUTS_HOME,
#define NUM_LINES 40
#define NUM_CHARS 60
-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);
static GObject* gtk_file_chooser_default_constructor (GType type,
guint n_construct_properties,
static void gtk_file_chooser_default_dispose (GObject *object);
static void gtk_file_chooser_default_show_all (GtkWidget *widget);
static void gtk_file_chooser_default_map (GtkWidget *widget);
+static void gtk_file_chooser_default_unmap (GtkWidget *widget);
static void gtk_file_chooser_default_hierarchy_changed (GtkWidget *widget,
GtkWidget *previous_toplevel);
static void gtk_file_chooser_default_style_set (GtkWidget *widget,
static gboolean gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
const GtkFilePath *path,
GError **error);
+static gboolean gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
+ const GtkFilePath *path,
+ gboolean keep_trail,
+ GError **error);
static GtkFilePath * gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser);
static void gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
const gchar *name);
static void location_popup_handler (GtkFileChooserDefault *impl,
const gchar *path);
+static void location_popup_on_paste_handler (GtkFileChooserDefault *impl);
static void up_folder_handler (GtkFileChooserDefault *impl);
static void down_folder_handler (GtkFileChooserDefault *impl);
static void home_folder_handler (GtkFileChooserDefault *impl);
+static void desktop_folder_handler (GtkFileChooserDefault *impl);
+static void quick_bookmark_handler (GtkFileChooserDefault *impl,
+ gint bookmark_index);
static void update_appearance (GtkFileChooserDefault *impl);
static void set_current_filter (GtkFileChooserDefault *impl,
static void path_bar_clicked (GtkPathBar *path_bar,
GtkFilePath *file_path,
+ GtkFilePath *child_path,
gboolean child_is_hidden,
GtkFileChooserDefault *impl);
GtkFileChooserDefault *impl);
static void remove_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl);
+static void save_folder_combo_changed_cb (GtkComboBox *combo,
+ GtkFileChooserDefault *impl);
static void list_icon_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeIter *iter);
static void load_remove_timer (GtkFileChooserDefault *impl);
+static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
+
+static void location_button_toggled_cb (GtkToggleButton *toggle,
+ GtkFileChooserDefault *impl);
+static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
-static GObjectClass *parent_class;
\f
_shortcuts_model_filter,
GTK_TYPE_TREE_MODEL_FILTER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
- shortcuts_model_filter_drag_source_iface_init));
+ shortcuts_model_filter_drag_source_iface_init))
static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
GtkTreeModel *child_model,
\f
-GType
-_gtk_file_chooser_default_get_type (void)
-{
- static GType file_chooser_default_type = 0;
-
- if (!file_chooser_default_type)
- {
- static const GTypeInfo file_chooser_default_info =
- {
- sizeof (GtkFileChooserDefaultClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_file_chooser_default_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkFileChooserDefault),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_file_chooser_default_init,
- };
-
- static const GInterfaceInfo file_chooser_info =
- {
- (GInterfaceInitFunc) gtk_file_chooser_default_iface_init, /* interface_init */
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- static const GInterfaceInfo file_chooser_embed_info =
- {
- (GInterfaceInitFunc) gtk_file_chooser_embed_default_iface_init, /* interface_init */
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- file_chooser_default_type = g_type_register_static (GTK_TYPE_VBOX, "GtkFileChooserDefault",
- &file_chooser_default_info, 0);
-
- g_type_add_interface_static (file_chooser_default_type,
- GTK_TYPE_FILE_CHOOSER,
- &file_chooser_info);
- g_type_add_interface_static (file_chooser_default_type,
- GTK_TYPE_FILE_CHOOSER_EMBED,
- &file_chooser_embed_info);
- }
-
- return file_chooser_default_type;
-}
+G_DEFINE_TYPE_WITH_CODE (GtkFileChooserDefault, _gtk_file_chooser_default, GTK_TYPE_VBOX,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER,
+ gtk_file_chooser_default_iface_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_CHOOSER_EMBED,
+ gtk_file_chooser_embed_default_iface_init));
static void
-gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
+_gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
{
+ static const guint quick_bookmark_keyvals[10] = {
+ GDK_1, GDK_2, GDK_3, GDK_4, GDK_5, GDK_6, GDK_7, GDK_8, GDK_9, GDK_0
+ };
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkBindingSet *binding_set;
-
- parent_class = g_type_class_peek_parent (class);
+ int i;
gobject_class->finalize = gtk_file_chooser_default_finalize;
gobject_class->constructor = gtk_file_chooser_default_constructor;
widget_class->show_all = gtk_file_chooser_default_show_all;
widget_class->map = gtk_file_chooser_default_map;
+ widget_class->unmap = gtk_file_chooser_default_unmap;
widget_class->hierarchy_changed = gtk_file_chooser_default_hierarchy_changed;
widget_class->style_set = gtk_file_chooser_default_style_set;
widget_class->screen_changed = gtk_file_chooser_default_screen_changed;
signals[LOCATION_POPUP] =
- _gtk_binding_signal_new ("location-popup",
+ _gtk_binding_signal_new (I_("location-popup"),
G_OBJECT_CLASS_TYPE (class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_CALLBACK (location_popup_handler),
NULL, NULL,
_gtk_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
+ signals[LOCATION_POPUP_ON_PASTE] =
+ _gtk_binding_signal_new ("location-popup-on-paste",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_CALLBACK (location_popup_on_paste_handler),
+ NULL, NULL,
+ _gtk_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals[UP_FOLDER] =
- _gtk_binding_signal_new ("up-folder",
+ _gtk_binding_signal_new (I_("up-folder"),
G_OBJECT_CLASS_TYPE (class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_CALLBACK (up_folder_handler),
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[DOWN_FOLDER] =
- _gtk_binding_signal_new ("down-folder",
+ _gtk_binding_signal_new (I_("down-folder"),
G_OBJECT_CLASS_TYPE (class),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
G_CALLBACK (down_folder_handler),
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
signals[HOME_FOLDER] =
- _gtk_binding_signal_new ("home-folder",
+ _gtk_binding_signal_new (I_("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);
+ signals[DESKTOP_FOLDER] =
+ _gtk_binding_signal_new (I_("desktop-folder"),
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_CALLBACK (desktop_folder_handler),
+ NULL, NULL,
+ _gtk_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[QUICK_BOOKMARK] =
+ _gtk_binding_signal_new (I_("quick-bookmark"),
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_CALLBACK (quick_bookmark_handler),
+ NULL, NULL,
+ _gtk_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
binding_set = gtk_binding_set_by_class (class);
GDK_slash, 0,
"location-popup",
1, G_TYPE_STRING, "/");
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Divide, 0,
+ "location-popup",
+ 1, G_TYPE_STRING, "/");
+
+#ifdef G_OS_UNIX
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_asciitilde, 0,
+ "location-popup",
+ 1, G_TYPE_STRING, "~");
+#endif
+
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_v, GDK_CONTROL_MASK,
+ "location-popup-on-paste",
+ 0);
gtk_binding_entry_add_signal (binding_set,
GDK_Up, GDK_MOD1_MASK,
GDK_KP_Home, GDK_MOD1_MASK,
"home-folder",
0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_d, GDK_MOD1_MASK,
+ "desktop-folder",
+ 0);
+
+ for (i = 0; i < 10; i++)
+ gtk_binding_entry_add_signal (binding_set,
+ quick_bookmark_keyvals[i], GDK_MOD1_MASK,
+ "quick-bookmark",
+ 1, G_TYPE_INT, i);
_gtk_file_chooser_install_properties (gobject_class);
P_("Default file chooser backend"),
P_("Name of the GtkFileChooser backend to use by default"),
NULL,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
}
static void
iface->should_respond = gtk_file_chooser_default_should_respond;
iface->initial_focus = gtk_file_chooser_default_initial_focus;
}
+
static void
-gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
+_gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
{
+ profile_start ("start", NULL);
+#ifdef PROFILE_FILE_CHOOSER
+ access ("MARK: *** CREATE FILE CHOOSER", F_OK);
+#endif
impl->local_only = TRUE;
impl->preview_widget_active = TRUE;
impl->use_preview_label = TRUE;
impl->show_hidden = FALSE;
impl->icon_size = FALLBACK_ICON_SIZE;
impl->load_state = LOAD_EMPTY;
+ impl->reload_state = RELOAD_EMPTY;
impl->pending_select_paths = NULL;
+ impl->location_mode = LOCATION_MODE_PATH_BAR;
- gtk_widget_set_redraw_on_allocate (GTK_WIDGET (impl), TRUE);
gtk_box_set_spacing (GTK_BOX (impl), 12);
impl->tooltips = gtk_tooltips_new ();
- g_object_ref (impl->tooltips);
- gtk_object_sink (GTK_OBJECT (impl->tooltips));
+ g_object_ref_sink (impl->tooltips);
+
+ profile_end ("end", NULL);
}
/* Frees the data columns for the specified iter in the shortcuts model*/
{
gpointer col_data;
gboolean is_volume;
+ GtkFileSystemHandle *handle;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
SHORTCUTS_COL_DATA, &col_data,
SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_HANDLE, &handle,
-1);
+
+ if (handle)
+ gtk_file_system_cancel_operation (handle);
+
if (!col_data)
return;
shortcuts_free (impl);
- g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
- impl->volumes_changed_id = 0;
- g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
- impl->bookmarks_changed_id = 0;
g_object_unref (impl->file_system);
+ g_free (impl->browse_files_last_selected_name);
+
for (l = impl->filters; l; l = l->next)
{
GtkFileFilter *filter;
if (impl->preview_path)
gtk_file_path_free (impl->preview_path);
- pending_select_paths_free (impl);
-
load_remove_timer (impl);
/* Free all the Models we have */
g_object_unref (impl->tooltips);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->finalize (object);
}
/* Shows an error dialog set as transient for the specified window */
msg);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", detail);
+
+ if (parent->group)
+ gtk_window_group_add_window (parent->group, GTK_WINDOW (dialog));
+
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
path, error);
}
+/* Shows an error about not being able to create a folder because a file with
+ * the same name is already there.
+ */
+static void
+error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GError *error)
+{
+ error_dialog (impl,
+ _("The folder could not be created, as a file with the same name "
+ "already exists. Try using a different name for the folder, "
+ "or rename the file first."),
+ path, error);
+}
+
/* Shows an error dialog about not being able to create a filename */
static void
error_building_filename_dialog (GtkFileChooserDefault *impl,
gboolean result;
GtkFilePath *path_copy;
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ profile_start ("start", (char *) path);
+
/* We copy the path because of this case:
*
* list_row_activated()
path_copy = gtk_file_path_copy (path);
error = NULL;
- result = _gtk_file_chooser_set_current_folder_path (GTK_FILE_CHOOSER (impl), path_copy, &error);
+ result = gtk_file_chooser_default_update_current_folder (GTK_FILE_CHOOSER (impl), path_copy, TRUE, &error);
if (!result)
error_changing_folder_dialog (impl, path_copy, error);
gtk_file_path_free (path_copy);
+ profile_end ("end", (char *) path);
+
return result;
}
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_label_set_ellipsize (GTK_LABEL (impl->preview_label), PANGO_ELLIPSIZE_MIDDLE);
gtk_widget_show (impl->preview_label);
}
}
}
/* Re-reads all the icons for the shortcuts, used when the theme changes */
+struct ReloadIconsData
+{
+ GtkFileChooserDefault *impl;
+ GtkTreeRowReference *row_ref;
+};
+
+static void
+shortcuts_reload_icons_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ GdkPixbuf *pixbuf;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ gboolean cancelled = handle->cancelled;
+ struct ReloadIconsData *data = user_data;
+
+ if (!g_slist_find (data->impl->reload_icon_handles, handle))
+ goto out;
+
+ data->impl->reload_icon_handles = g_slist_remove (data->impl->reload_icon_handles, handle);
+
+ if (cancelled || error)
+ goto out;
+
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (data->impl),
+ data->impl->icon_size, NULL);
+
+ path = gtk_tree_row_reference_get_path (data->row_ref);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (data->impl->shortcuts_model), &iter, path);
+ gtk_list_store_set (data->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ -1);
+ gtk_tree_path_free (path);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+out:
+ gtk_tree_row_reference_free (data->row_ref);
+ g_object_unref (data->impl);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static void
shortcuts_reload_icons (GtkFileChooserDefault *impl)
{
+ GSList *l;
GtkTreeIter iter;
+ profile_start ("start", NULL);
+
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
- return;
+ goto out;
+
+ for (l = impl->reload_icon_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle = GTK_FILE_SYSTEM_HANDLE (l->data);
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->reload_icon_handles);
+ impl->reload_icon_handles = NULL;
- do {
- gpointer data;
- gboolean is_volume;
- gboolean pixbuf_visible;
- GdkPixbuf *pixbuf;
+ do
+ {
+ gpointer data;
+ gboolean is_volume;
+ gboolean pixbuf_visible;
+ GdkPixbuf *pixbuf;
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
- SHORTCUTS_COL_DATA, &data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
- SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
- -1);
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_DATA, &data,
+ SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
+ -1);
- if (pixbuf_visible && data)
- {
- if (is_volume)
- {
- GtkFileSystemVolume *volume;
+ if (pixbuf_visible && data)
+ {
+ if (is_volume)
+ {
+ GtkFileSystemVolume *volume;
- volume = data;
- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
- impl->icon_size, NULL);
- }
- else
- {
- const GtkFilePath *path;
+ volume = data;
+ pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
+ impl->icon_size, NULL);
- path = data;
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
- }
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ -1);
- gtk_list_store_set (impl->shortcuts_model, &iter,
- SHORTCUTS_COL_PIXBUF, pixbuf,
- -1);
- if (pixbuf)
- g_object_unref (pixbuf);
- }
- } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ }
+ else
+ {
+ const GtkFilePath *path;
+ struct ReloadIconsData *info;
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+
+ path = data;
+
+ info = g_new0 (struct ReloadIconsData, 1);
+ info->impl = g_object_ref (impl);
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_ICON,
+ shortcuts_reload_icons_get_info_cb,
+ info);
+ impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
+ }
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+
+ out:
+
+ profile_end ("end", NULL);
}
static void
shortcuts_find_folder (impl, impl->current_folder);
}
-/* Convenience function to get the display name and icon info for a path */
-static GtkFileInfo *
-get_file_info (GtkFileSystem *file_system,
- const GtkFilePath *path,
- gboolean name_only,
- GError **error)
+/* Removes the specified number of rows from the shortcuts list */
+static void
+shortcuts_remove_rows (GtkFileChooserDefault *impl,
+ int start_row,
+ int n_rows)
{
- GtkFilePath *parent_path;
- GtkFileFolder *parent_folder;
- GtkFileInfo *info;
- GError *tmp = NULL;
-
- parent_path = NULL;
- info = NULL;
-
- if (!gtk_file_system_get_parent (file_system, path, &parent_path, &tmp))
- goto out;
+ GtkTreePath *path;
- parent_folder = gtk_file_system_get_folder (file_system, parent_path ? parent_path : path,
- GTK_FILE_INFO_DISPLAY_NAME
- | (name_only ? 0 : GTK_FILE_INFO_IS_FOLDER),
- &tmp);
- if (!parent_folder)
- goto out;
+ path = gtk_tree_path_new_from_indices (start_row, -1);
- info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, &tmp);
- g_object_unref (parent_folder);
+ for (; n_rows; n_rows--)
+ {
+ GtkTreeIter iter;
- out:
- if (parent_path)
- gtk_file_path_free (parent_path);
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+ g_assert_not_reached ();
- if (tmp)
- {
- g_set_error (error,
- GTK_FILE_CHOOSER_ERROR,
- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
- _("Could not get information about '%s': %s"),
- gtk_file_path_get_string (path),
- tmp->message);
- g_error_free (tmp);
+ shortcuts_free_row_data (impl, &iter);
+ gtk_list_store_remove (impl->shortcuts_model, &iter);
}
- return info;
+ gtk_tree_path_free (path);
}
-/* Returns whether a path is a folder */
-static gboolean
-check_is_folder (GtkFileSystem *file_system,
- const GtkFilePath *path,
- GError **error)
+static void
+shortcuts_update_count (GtkFileChooserDefault *impl,
+ ShortcutsIndex type,
+ gint value)
{
- GtkFileFolder *folder;
+ switch (type)
+ {
+ case SHORTCUTS_HOME:
+ if (value < 0)
+ impl->has_home = FALSE;
+ else
+ impl->has_home = TRUE;
+ break;
- folder = gtk_file_system_get_folder (file_system, path, 0, error);
- if (!folder)
- return FALSE;
+ case SHORTCUTS_DESKTOP:
+ if (value < 0)
+ impl->has_desktop = FALSE;
+ else
+ impl->has_desktop = TRUE;
+ break;
- g_object_unref (folder);
- return TRUE;
+ case SHORTCUTS_VOLUMES:
+ impl->num_volumes += value;
+ break;
+
+ case SHORTCUTS_SHORTCUTS:
+ impl->num_shortcuts += value;
+ break;
+
+ case SHORTCUTS_BOOKMARKS:
+ impl->num_bookmarks += value;
+ break;
+
+ case SHORTCUTS_CURRENT_FOLDER:
+ if (value < 0)
+ impl->shortcuts_current_folder_active = FALSE;
+ else
+ impl->shortcuts_current_folder_active = TRUE;
+ break;
+
+ default:
+ /* nothing */
+ break;
+ }
}
-/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
- * inserts a volume. A position of -1 indicates the end of the tree.
- */
-static gboolean
-shortcuts_insert_path (GtkFileChooserDefault *impl,
- int pos,
- gboolean is_volume,
- GtkFileSystemVolume *volume,
- const GtkFilePath *path,
- const char *label,
- gboolean removable,
- GError **error)
+struct ShortcutsInsertRequest
{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *parent_path;
+ GtkFilePath *path;
+ int pos;
char *label_copy;
+ GtkTreeRowReference *row_ref;
+ ShortcutsIndex type;
+ gboolean name_only;
+ gboolean removable;
+};
+
+static void
+get_file_info_finished (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer data)
+{
+ gint pos = -1;
+ gboolean cancelled = handle->cancelled;
+ gboolean is_volume = FALSE;
GdkPixbuf *pixbuf;
- gpointer data;
+ GtkTreePath *path;
GtkTreeIter iter;
+ GtkFileSystemHandle *model_handle;
+ struct ShortcutsInsertRequest *request = data;
- if (is_volume)
- {
- data = volume;
- label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
- pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
+ path = gtk_tree_row_reference_get_path (request->row_ref);
+ if (!path)
+ /* Handle doesn't exist anymore in the model */
+ goto out;
+
+ pos = gtk_tree_path_get_indices (path)[0];
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (request->impl->shortcuts_model),
+ &iter, path);
+ gtk_tree_path_free (path);
+
+ /* validate handle, else goto out */
+ gtk_tree_model_get (GTK_TREE_MODEL (request->impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_HANDLE, &model_handle,
+ -1);
+ if (handle != model_handle)
+ goto out;
+
+ /* set the handle to NULL in the model (we unref later on) */
+ gtk_list_store_set (request->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_HANDLE, NULL,
+ -1);
+
+ if (cancelled)
+ goto out;
+
+ if (!info)
+ {
+ gtk_list_store_remove (request->impl->shortcuts_model, &iter);
+ shortcuts_update_count (request->impl, request->type, -1);
+
+ if (request->type == SHORTCUTS_HOME)
+ {
+ const char *home = g_get_home_dir ();
+ GtkFilePath *home_path;
+
+ home_path = gtk_file_system_filename_to_path (request->impl->file_system, home);
+ error_getting_info_dialog (request->impl, home_path, g_error_copy (error));
+ gtk_file_path_free (home_path);
+ }
+ else if (request->type == SHORTCUTS_CURRENT_FOLDER)
+ {
+ /* Remove the current folder separator */
+ gint separator_pos = shortcuts_get_index (request->impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+ shortcuts_remove_rows (request->impl, separator_pos, 1);
+ }
+
+ goto out;
+ }
+
+ if (!request->label_copy)
+ request->label_copy = g_strdup (gtk_file_info_get_display_name (info));
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (request->impl),
+ request->impl->icon_size, NULL);
+
+ gtk_list_store_set (request->impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+ SHORTCUTS_COL_NAME, request->label_copy,
+ SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_REMOVABLE, request->removable,
+ -1);
+
+ if (request->impl->shortcuts_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_filter_model));
+
+ if (request->type == SHORTCUTS_CURRENT_FOLDER
+ && request->impl->save_folder_combo != NULL)
+ {
+ /* The current folder is updated via _activate_iter(), don't
+ * have save_folder_combo_changed_cb() call _activate_iter()
+ * again.
+ */
+ g_signal_handlers_block_by_func (request->impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ request->impl);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
+ g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ request->impl);
+ }
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+out:
+ g_object_unref (request->impl);
+ gtk_file_path_free (request->parent_path);
+ gtk_file_path_free (request->path);
+ gtk_tree_row_reference_free (request->row_ref);
+ g_free (request->label_copy);
+ g_free (request);
+
+ g_object_unref (handle);
+}
+
+/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
+ * inserts a volume. A position of -1 indicates the end of the tree.
+ */
+static void
+shortcuts_insert_path (GtkFileChooserDefault *impl,
+ int pos,
+ gboolean is_volume,
+ GtkFileSystemVolume *volume,
+ const GtkFilePath *path,
+ const char *label,
+ gboolean removable,
+ ShortcutsIndex type)
+{
+ char *label_copy;
+ GdkPixbuf *pixbuf = NULL;
+ gpointer data = NULL;
+ GtkTreeIter iter;
+
+ profile_start ("start", is_volume ? "volume" : (char *) path);
+
+ if (is_volume)
+ {
+ data = volume;
+ label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
+ pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
impl->icon_size, NULL);
}
else
{
- if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
-
+ struct ShortcutsInsertRequest *request;
+ GtkFileSystemHandle *handle;
+ GtkTreePath *p;
+
+ request = g_new0 (struct ShortcutsInsertRequest, 1);
+ request->impl = g_object_ref (impl);
+ request->path = gtk_file_path_copy (path);
+ request->name_only = TRUE;
+ request->removable = removable;
+ request->pos = pos;
+ request->type = type;
if (label)
- label_copy = g_strdup (label);
+ request->label_copy = g_strdup (label);
+
+ if (pos == -1)
+ gtk_list_store_append (impl->shortcuts_model, &iter);
else
- {
- GtkFileInfo *info = get_file_info (impl->file_system, path, TRUE, error);
+ gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
- if (!info)
- return FALSE;
+ p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
+ gtk_tree_path_free (p);
- label_copy = g_strdup (gtk_file_info_get_display_name (info));
- gtk_file_info_free (info);
- }
+ handle = gtk_file_system_get_info (request->impl->file_system, request->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
+ get_file_info_finished, request);
+
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
+ SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_HANDLE, handle,
+ -1);
+
+ shortcuts_update_count (impl, type, 1);
- data = gtk_file_path_copy (path);
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
+ return;
}
+ if (!data)
+ data = gtk_file_path_copy (path);
+
if (pos == -1)
gtk_list_store_append (impl->shortcuts_model, &iter);
else
gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
+ shortcuts_update_count (impl, type, 1);
+
gtk_list_store_set (impl->shortcuts_model, &iter,
SHORTCUTS_COL_PIXBUF, pixbuf,
SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
SHORTCUTS_COL_DATA, data,
SHORTCUTS_COL_IS_VOLUME, is_volume,
SHORTCUTS_COL_REMOVABLE, removable,
+ SHORTCUTS_COL_HANDLE, NULL,
-1);
+ if (impl->shortcuts_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+
+ if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
+ {
+ /* The current folder is updated via _activate_iter(), don't
+ * have save_folder_combo_changed_cb() call _activate_iter()
+ * again.
+ */
+ gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
+ g_signal_handlers_block_by_func (impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ impl);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
+ g_signal_handlers_unblock_by_func (impl->save_folder_combo,
+ G_CALLBACK (save_folder_combo_changed_cb),
+ impl);
+ }
+
g_free (label_copy);
if (pixbuf)
g_object_unref (pixbuf);
- return TRUE;
+ profile_end ("end", NULL);
}
/* Appends an item for the user's home directory to the shortcuts model */
{
const char *home;
GtkFilePath *home_path;
- GError *error;
+
+ profile_start ("start", NULL);
home = g_get_home_dir ();
if (home == NULL)
- return;
+ {
+ profile_end ("end - no home directory!?", NULL);
+ return;
+ }
home_path = gtk_file_system_filename_to_path (impl->file_system, home);
- error = NULL;
- impl->has_home = shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, _("Home"), FALSE, &error);
- if (!impl->has_home)
- error_getting_info_dialog (impl, home_path, error);
+ shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
gtk_file_path_free (home_path);
+
+ profile_end ("end", NULL);
}
/* Appends the ~/Desktop directory to the shortcuts model */
shortcuts_append_desktop (GtkFileChooserDefault *impl)
{
char *name;
+ const char *home;
GtkFilePath *path;
+ profile_start ("start", NULL);
+
#ifdef G_OS_WIN32
name = _gtk_file_system_win32_get_desktop ();
#else
- const char *home = g_get_home_dir ();
+ home = g_get_home_dir ();
if (home == NULL)
- return;
+ {
+ profile_end ("end - no home directory!?", NULL);
+ return;
+ }
name = g_build_filename (home, "Desktop", NULL);
#endif
path = gtk_file_system_filename_to_path (impl->file_system, name);
g_free (name);
- impl->has_desktop = shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, NULL);
+ shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
/* We do not actually pop up an error dialog if there is no desktop directory
* because some people may really not want to have one.
*/
gtk_file_path_free (path);
+
+ profile_end ("end", NULL);
}
/* Appends a list of GtkFilePath to the shortcuts model; returns how many were inserted */
{
int start_row;
int num_inserted;
+ gchar *label;
+
+ profile_start ("start", NULL);
/* As there is no separator now, we want to start there.
*/
for (; paths; paths = paths->next)
{
GtkFilePath *path;
- GError *error;
path = paths->data;
- error = NULL;
if (impl->local_only &&
!gtk_file_system_path_is_local (impl->file_system, path))
continue;
+ label = gtk_file_system_get_bookmark_label (impl->file_system, path);
+
/* NULL GError, but we don't really want to show error boxes here */
- if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, NULL, TRUE, NULL))
- num_inserted++;
+ shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
+ num_inserted++;
+
+ g_free (label);
}
+ profile_end ("end", NULL);
+
return num_inserted;
}
return n;
}
-/* Removes the specified number of rows from the shortcuts list */
-static void
-shortcuts_remove_rows (GtkFileChooserDefault *impl,
- int start_row,
- int n_rows)
-{
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_indices (start_row, -1);
-
- for (; n_rows; n_rows--)
- {
- GtkTreeIter iter;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
- g_assert_not_reached ();
-
- shortcuts_free_row_data (impl, &iter);
- gtk_list_store_remove (impl->shortcuts_model, &iter);
- }
-
- gtk_tree_path_free (path);
-}
-
/* Adds all the file system volumes to the shortcuts model */
static void
shortcuts_add_volumes (GtkFileChooserDefault *impl)
int n;
gboolean old_changing_folders;
+ profile_start ("start", NULL);
+
old_changing_folders = impl->changing_folder;
impl->changing_folder = TRUE;
if (impl->local_only)
{
- GtkFilePath *base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
- gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
- gtk_file_path_free (base_path);
-
- if (!is_local)
+ if (gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
{
- gtk_file_system_volume_free (impl->file_system, volume);
- continue;
+ GtkFilePath *base_path;
+
+ base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ if (base_path != NULL)
+ {
+ gboolean is_local = gtk_file_system_path_is_local (impl->file_system, base_path);
+ gtk_file_path_free (base_path);
+
+ if (!is_local)
+ {
+ gtk_file_system_volume_free (impl->file_system, volume);
+ continue;
+ }
+ }
}
}
- if (shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, NULL))
- n++;
- else
- gtk_file_system_volume_free (impl->file_system, volume);
+ shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
+ n++;
}
impl->num_volumes = n;
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
impl->changing_folder = old_changing_folders;
+
+ profile_end ("end", NULL);
}
/* Inserts a separator node in the shortcuts list */
GtkFilePath *combo_selected = NULL;
gboolean is_volume;
gpointer col_data;
+
+ profile_start ("start", NULL);
+
old_changing_folders = impl->changing_folder;
impl->changing_folder = TRUE;
shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
impl->num_bookmarks + 1);
+ impl->num_bookmarks = 0;
+
bookmarks = gtk_file_system_list_bookmarks (impl->file_system);
- impl->num_bookmarks = shortcuts_append_paths (impl, bookmarks);
+ shortcuts_append_paths (impl, bookmarks);
gtk_file_paths_free (bookmarks);
if (impl->num_bookmarks > 0)
}
impl->changing_folder = old_changing_folders;
+
+ profile_end ("end", NULL);
}
/* Appends a separator and a row to the shortcuts list for the current folder */
if (base_path &&
strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
{
- success = shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, NULL);
- if (success)
- volume = NULL;
+ shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
}
else
- success = shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, NULL);
-
- if (volume)
- gtk_file_system_volume_free (impl->file_system, volume);
+ {
+ shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+ if (volume)
+ gtk_file_system_volume_free (impl->file_system, volume);
+ }
if (base_path)
gtk_file_path_free (base_path);
-
- if (!success)
- shortcuts_remove_rows (impl, pos - 1, 1); /* remove the separator */
-
- impl->shortcuts_current_folder_active = success;
}
-
- if (success)
+ else if (impl->save_folder_combo != NULL)
gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
}
G_TYPE_POINTER, /* path or volume */
G_TYPE_BOOLEAN, /* is the previous column a volume? */
G_TYPE_BOOLEAN, /* removable */
- G_TYPE_BOOLEAN); /* pixbuf cell visibility */
+ G_TYPE_BOOLEAN, /* pixbuf cell visibility */
+ G_TYPE_POINTER); /* GtkFileSystemHandle */
if (impl->file_system)
{
shortcuts_append_home (impl);
shortcuts_append_desktop (impl);
shortcuts_add_volumes (impl);
- shortcuts_add_bookmarks (impl);
}
impl->shortcuts_filter_model = shortcuts_model_filter_new (impl,
gtk_tree_path_free (path);
}
+static void
+edited_idle_create_folder_cb (GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ const GError *error,
+ gpointer data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = data;
+
+ if (!g_slist_find (impl->pending_handles, handle))
+ goto out;
+
+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+ if (cancelled)
+ goto out;
+
+ if (!error)
+ change_folder_and_display_error (impl, path);
+ else
+ error_creating_folder_dialog (impl, path, g_error_copy (error));
+
+ out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
/* Idle handler for creating a new folder after editing its name cell, or for
* canceling the editing.
*/
GtkFilePath *file_path;
error = NULL;
- file_path = gtk_file_system_make_path (impl->file_system, impl->current_folder, impl->edited_new_text,
+ file_path = gtk_file_system_make_path (impl->file_system,
+ impl->current_folder,
+ impl->edited_new_text,
&error);
if (file_path)
{
- error = NULL;
- if (gtk_file_system_create_folder (impl->file_system, file_path, &error))
- change_folder_and_display_error (impl, file_path);
- else
- error_creating_folder_dialog (impl, file_path, error);
+ GtkFileSystemHandle *handle;
+
+ handle = gtk_file_system_create_folder (impl->file_system, file_path,
+ edited_idle_create_folder_cb,
+ g_object_ref (impl));
+ impl->pending_handles = g_slist_append (impl->pending_handles, handle);
gtk_file_path_free (file_path);
}
* just now.
*/
- g_assert (!impl->edited_idle);
- g_assert (!impl->edited_new_text);
-
- impl->edited_idle = g_idle_source_new ();
- g_source_set_closure (impl->edited_idle,
- g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
- G_OBJECT (impl)));
- g_source_attach (impl->edited_idle, NULL);
+ if (!impl->edited_idle)
+ {
+ impl->edited_idle = g_idle_source_new ();
+ g_source_set_closure (impl->edited_idle,
+ g_cclosure_new_object (G_CALLBACK (edited_idle_cb),
+ G_OBJECT (impl)));
+ g_source_attach (impl->edited_idle, NULL);
+ }
- if (new_text)
- impl->edited_new_text = g_strdup (new_text);
+ g_free (impl->edited_new_text);
+ impl->edited_new_text = g_strdup (new_text);
}
/* Callback used from the text cell renderer when the new folder is named */
filter_create (GtkFileChooserDefault *impl)
{
impl->filter_combo = gtk_combo_box_new_text ();
+ gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (impl->filter_combo), FALSE);
+
g_signal_connect (impl->filter_combo, "changed",
G_CALLBACK (filter_combo_changed), impl);
GCallback callback)
{
GtkWidget *button;
- GtkWidget *hbox;
- GtkWidget *widget;
- GtkWidget *align;
-
- button = gtk_button_new ();
- hbox = gtk_hbox_new (FALSE, 2);
- align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
-
- gtk_container_add (GTK_CONTAINER (button), align);
- gtk_container_add (GTK_CONTAINER (align), hbox);
- widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
-
- gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+ GtkWidget *image;
- widget = gtk_label_new_with_mnemonic (text);
- gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (button));
- gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
+ button = gtk_button_new_with_mnemonic (text);
+ image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_sensitive (button, sensitive);
g_signal_connect (button, "clicked", callback, impl);
- gtk_widget_show_all (align);
-
if (show)
gtk_widget_show (button);
current_folder_separator_idx = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+#if 0
+ /* FIXME: is this still needed? */
+ if (current_folder_separator_idx >= impl->shortcuts_model->length)
+ return -1;
+#endif
+
for (i = 0; i < current_folder_separator_idx; i++)
{
gpointer col_data;
volume = col_data;
base_path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
- exists = strcmp (gtk_file_path_get_string (path),
- gtk_file_path_get_string (base_path)) == 0;
+ exists = base_path && strcmp (gtk_file_path_get_string (path),
+ gtk_file_path_get_string (base_path)) == 0;
g_free (base_path);
if (exists)
}
}
- gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ if (i < current_folder_separator_idx - 1)
+ {
+ if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
+ g_assert_not_reached ();
+ }
}
return -1;
{
GError *error;
+ g_return_val_if_fail (path != NULL, FALSE);
+
if (shortcut_find_position (impl, path) != -1)
return FALSE;
- /* FIXME: this check really belongs in gtk_file_system_insert_bookmark. */
- error = NULL;
- if (!check_is_folder (impl->file_system, path, &error))
- {
- error_adding_bookmark_dialog (impl, path, error);
- return FALSE;
- }
-
error = NULL;
if (!gtk_file_system_insert_bookmark (impl->file_system, path, pos, &error))
{
{
GtkTreeIter iter;
gpointer col_data;
- gboolean is_volume;
GtkFilePath *path;
gboolean removable;
GError *error;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
SHORTCUTS_COL_REMOVABLE, &removable,
-1);
g_assert (col_data != NULL);
- g_assert (!is_volume);
if (!removable)
return;
g_free (name);
}
+static void
+shortcuts_check_popup_sensitivity (GtkFileChooserDefault *impl)
+{
+ GtkTreeIter iter;
+ gboolean removable = FALSE;
+
+ if (impl->browse_shortcuts_popup_menu == NULL)
+ return;
+
+ if (shortcuts_get_selected (impl, &iter))
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_REMOVABLE, &removable,
+ -1);
+
+ gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_remove_item, removable);
+ gtk_widget_set_sensitive (impl->browse_shortcuts_popup_menu_rename_item, removable);
+}
+
/* GtkWidget::drag-begin handler for the shortcuts list. */
static void
shortcuts_drag_begin_cb (GtkWidget *widget,
GdkDragContext *context,
GtkFileChooserDefault *impl)
{
- g_signal_stop_emission_by_name (widget, "drag-data-delete");
+ g_signal_stop_emission_by_name (widget, "drag_data_delete");
}
#if 0
NULL,
GTK_TREE_VIEW_DROP_BEFORE);
- g_signal_stop_emission_by_name (widget, "drag-leave");
+ g_signal_stop_emission_by_name (widget, "drag_leave");
}
/* Computes the appropriate row and position for dropping */
out:
- g_signal_stop_emission_by_name (widget, "drag-motion");
+ g_signal_stop_emission_by_name (widget, "drag_motion");
if (action != 0)
{
shortcuts_cancel_drag_outside_idle (impl);
#endif
- g_signal_stop_emission_by_name (widget, "drag-drop");
+ g_signal_stop_emission_by_name (widget, "drag_drop");
return TRUE;
}
const GtkFilePath *file_path;
GtkFilePath *file_path_copy;
GError *error;
+ gchar *name;
/* Get the selected path */
g_assert (old_position >= 0 && old_position < impl->num_bookmarks);
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_NAME, &name,
SHORTCUTS_COL_DATA, &col_data,
SHORTCUTS_COL_IS_VOLUME, &is_volume,
-1);
g_assert (col_data != NULL);
g_assert (!is_volume);
-
+
file_path = col_data;
file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
error = NULL;
if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
- shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
+ {
+ shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
+ gtk_file_system_set_bookmark_label (impl->file_system, file_path_copy, name);
+ }
else
error_adding_bookmark_dialog (impl, file_path_copy, error);
g_assert (position >= bookmarks_index);
position -= bookmarks_index;
- if (selection_data->target == gdk_atom_intern ("text/uri-list", FALSE))
- shortcuts_drop_uris (impl, selection_data->data, position);
- else if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+ if (selection_data->target == gdk_atom_intern_static_string ("text/uri-list"))
+ shortcuts_drop_uris (impl, (const char *) selection_data->data, position);
+ else if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
shortcuts_reorder (impl, position);
- g_signal_stop_emission_by_name (widget, "drag-data-received");
+ g_signal_stop_emission_by_name (widget, "drag_data_received");
}
/* Callback used when the selection in the shortcuts tree changes */
GtkFileChooserDefault *impl)
{
bookmarks_check_remove_sensitivity (impl);
+ shortcuts_check_popup_sensitivity (impl);
}
static gboolean
GdkEventKey *event,
GtkFileChooserDefault *impl)
{
- if (event->keyval == GDK_slash &&
- ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+ if ((event->keyval == GDK_slash
+ || event->keyval == GDK_KP_Divide
+#ifdef G_OS_UNIX
+ || event->keyval == GDK_asciitilde
+#endif
+ ) && ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
{
- location_popup_handler (impl, "/");
+ location_popup_handler (impl, event->string);
return TRUE;
}
-
+
return FALSE;
}
-
-/* Creates the widgets for the shortcuts and bookmarks tree */
-static GtkWidget *
-shortcuts_list_create (GtkFileChooserDefault *impl)
+/* Callback used when the file list's popup menu is detached */
+static void
+shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
+ GtkMenu *menu)
{
- GtkWidget *swin;
- GtkTreeSelection *selection;
- GtkTreeViewColumn *column;
- GtkCellRenderer *renderer;
+ GtkFileChooserDefault *impl;
+
+ impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
+ g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
- /* Scrolled window */
+ impl->browse_shortcuts_popup_menu = NULL;
+ impl->browse_shortcuts_popup_menu_remove_item = NULL;
+ impl->browse_shortcuts_popup_menu_rename_item = NULL;
+}
- swin = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
- GTK_SHADOW_IN);
- gtk_widget_show (swin);
+static void
+remove_shortcut_cb (GtkMenuItem *item,
+ GtkFileChooserDefault *impl)
+{
+ remove_selected_bookmarks (impl);
+}
- /* Tree */
+/* Rename the selected bookmark */
+static void
+rename_selected_bookmark (GtkFileChooserDefault *impl)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GList *renderers;
- impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
- g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
- G_CALLBACK (tree_view_keybinding_cb), impl);
- atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Shortcuts"));
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), FALSE);
+ if (shortcuts_get_selected (impl, &iter))
+ {
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), 0);
+ renderers = gtk_tree_view_column_get_cell_renderers (column);
+ cell = g_list_nth_data (renderers, 1);
+ g_list_free (renderers);
+ g_object_set (cell, "editable", TRUE, NULL);
+ gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+ path, column, cell, TRUE);
+ gtk_tree_path_free (path);
+ }
+}
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
+static void
+rename_shortcut_cb (GtkMenuItem *item,
+ GtkFileChooserDefault *impl)
+{
+ rename_selected_bookmark (impl);
+}
+
+/* Constructs the popup menu for the file list if needed */
+static void
+shortcuts_build_popup_menu (GtkFileChooserDefault *impl)
+{
+ GtkWidget *item;
+
+ if (impl->browse_shortcuts_popup_menu)
+ return;
+
+ impl->browse_shortcuts_popup_menu = gtk_menu_new ();
+ gtk_menu_attach_to_widget (GTK_MENU (impl->browse_shortcuts_popup_menu),
+ impl->browse_shortcuts_tree_view,
+ shortcuts_popup_menu_detach_cb);
+
+ item = gtk_image_menu_item_new_with_label (_("Remove"));
+ impl->browse_shortcuts_popup_menu_remove_item = item;
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
+ gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
+ g_signal_connect (item, "activate",
+ G_CALLBACK (remove_shortcut_cb), impl);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
+
+ item = gtk_menu_item_new_with_label (_("Rename..."));
+ impl->browse_shortcuts_popup_menu_rename_item = item;
+ g_signal_connect (item, "activate",
+ G_CALLBACK (rename_shortcut_cb), impl);
+ gtk_widget_show (item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu), item);
+
+ shortcuts_check_popup_sensitivity (impl);
+}
+
+static void
+shortcuts_update_popup_menu (GtkFileChooserDefault *impl)
+{
+ shortcuts_build_popup_menu (impl);
+}
+
+static void
+popup_position_func (GtkMenu *menu,
+ gint *x,
+ gint *y,
+ gboolean *push_in,
+ gpointer user_data);
+
+static void
+shortcuts_popup_menu (GtkFileChooserDefault *impl,
+ GdkEventButton *event)
+{
+ shortcuts_update_popup_menu (impl);
+ if (event)
+ gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+ NULL, NULL, NULL, NULL,
+ event->button, event->time);
+ else
+ {
+ gtk_menu_popup (GTK_MENU (impl->browse_shortcuts_popup_menu),
+ NULL, NULL,
+ popup_position_func, impl->browse_shortcuts_tree_view,
+ 0, GDK_CURRENT_TIME);
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (impl->browse_shortcuts_popup_menu),
+ FALSE);
+ }
+}
+
+/* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
+static gboolean
+shortcuts_popup_menu_cb (GtkWidget *widget,
+ GtkFileChooserDefault *impl)
+{
+ shortcuts_popup_menu (impl, NULL);
+ return TRUE;
+}
+
+/* Callback used when a button is pressed on the shortcuts list.
+ * We trap button 3 to bring up a popup menu.
+ */
+static gboolean
+shortcuts_button_press_event_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkFileChooserDefault *impl)
+{
+ static gboolean in_press = FALSE;
+ gboolean handled;
+
+ if (in_press)
+ return FALSE;
+
+ if (event->button != 3)
+ return FALSE;
+
+ in_press = TRUE;
+ handled = gtk_widget_event (impl->browse_shortcuts_tree_view, (GdkEvent *) event);
+ in_press = FALSE;
+
+ if (!handled)
+ return FALSE;
+
+ shortcuts_popup_menu (impl, event);
+ return TRUE;
+}
+
+static void
+shortcuts_edited (GtkCellRenderer *cell,
+ gchar *path_string,
+ gchar *new_text,
+ GtkFileChooserDefault *impl)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GtkFilePath *shortcut;
+
+ g_object_set (cell, "editable", FALSE, NULL);
+
+ path = gtk_tree_path_new_from_string (path_string);
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path))
+ g_assert_not_reached ();
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
+ SHORTCUTS_COL_DATA, &shortcut,
+ -1);
+ gtk_tree_path_free (path);
+
+ gtk_file_system_set_bookmark_label (impl->file_system, shortcut, new_text);
+}
+
+static void
+shortcuts_editing_canceled (GtkCellRenderer *cell,
+ GtkFileChooserDefault *impl)
+{
+ g_object_set (cell, "editable", FALSE, NULL);
+}
+
+/* Creates the widgets for the shortcuts and bookmarks tree */
+static GtkWidget *
+shortcuts_list_create (GtkFileChooserDefault *impl)
+{
+ GtkWidget *swin;
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ /* Scrolled window */
+
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
+ GTK_SHADOW_IN);
+ gtk_widget_show (swin);
+
+ /* Tree */
+
+ impl->browse_shortcuts_tree_view = gtk_tree_view_new ();
+#ifdef PROFILE_FILE_CHOOSER
+ g_object_set_data (G_OBJECT (impl->browse_shortcuts_tree_view), "fmq-name", "shortcuts");
+#endif
+ g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
+ G_CALLBACK (tree_view_keybinding_cb), impl);
+ g_signal_connect (impl->browse_shortcuts_tree_view, "popup_menu",
+ G_CALLBACK (shortcuts_popup_menu_cb), impl);
+ g_signal_connect (impl->browse_shortcuts_tree_view, "button_press_event",
+ G_CALLBACK (shortcuts_button_press_event_cb), impl);
+ /* Accessible object name for the file chooser's shortcuts pane */
+ atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
GDK_BUTTON1_MASK,
g_signal_connect (selection, "changed",
G_CALLBACK (shortcuts_selection_changed_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "row-activated",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "row_activated",
G_CALLBACK (shortcuts_row_activated_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "key-press-event",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "key_press_event",
G_CALLBACK (shortcuts_key_press_event_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-begin",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_begin",
G_CALLBACK (shortcuts_drag_begin_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-end",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_end",
G_CALLBACK (shortcuts_drag_end_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-delete",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_delete",
G_CALLBACK (shortcuts_drag_data_delete_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-leave",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_leave",
G_CALLBACK (shortcuts_drag_leave_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-motion",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_motion",
G_CALLBACK (shortcuts_drag_motion_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-drop",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_drop",
G_CALLBACK (shortcuts_drag_drop_cb), impl);
- g_signal_connect (impl->browse_shortcuts_tree_view, "drag-data-received",
+ g_signal_connect (impl->browse_shortcuts_tree_view, "drag_data_received",
G_CALLBACK (shortcuts_drag_data_received_cb), impl);
gtk_container_add (GTK_CONTAINER (swin), impl->browse_shortcuts_tree_view);
/* Column */
column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, _("Folder"));
+ /* Column header for the file chooser's shortcuts pane */
+ gtk_tree_view_column_set_title (column, _("_Places"));
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
NULL);
renderer = gtk_cell_renderer_text_new ();
+ g_signal_connect (renderer, "edited",
+ G_CALLBACK (shortcuts_edited), impl);
+ g_signal_connect (renderer, "editing-canceled",
+ G_CALLBACK (shortcuts_editing_canceled), impl);
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_set_attributes (column, renderer,
"text", SHORTCUTS_COL_NAME,
G_CALLBACK (add_bookmark_button_clicked_cb));
gtk_box_pack_start (GTK_BOX (hbox), impl->browse_shortcuts_add_button, TRUE, TRUE, 0);
gtk_tooltips_set_tip (impl->tooltips, impl->browse_shortcuts_add_button,
- _("Add the selected folder to the bookmarks"), NULL);
+ _("Add the selected folder to the Bookmarks"), NULL);
/* Remove bookmark button */
gpointer data)
{
GtkFileChooserDefault *impl;
+ int modifiers;
impl = (GtkFileChooserDefault *) data;
-
- if (event->keyval == GDK_slash &&
- ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
+
+ if ((event->keyval == GDK_slash
+ || event->keyval == GDK_KP_Divide
+#ifdef G_OS_UNIX
+ || event->keyval == GDK_asciitilde
+#endif
+ ) && ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
{
- location_popup_handler (impl, "/");
+ location_popup_handler (impl, event->string);
return TRUE;
}
|| event->keyval == GDK_ISO_Enter
|| event->keyval == GDK_KP_Enter
|| event->keyval == GDK_space)
+ && ((event->state & modifiers) == 0)
&& !(impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
{
impl->browse_files_popup_menu_hidden_files_item = NULL;
}
-/* Callback used when the "Add to Shortcuts" menu item is activated */
+/* Callback used when the "Add to Bookmarks" menu item is activated */
static void
add_to_shortcuts_cb (GtkMenuItem *item,
GtkFileChooserDefault *impl)
bookmarks_add_selected_folder (impl);
}
-/* Callback used when the "Open Location" menu item is activated */
-static void
-open_location_cb (GtkMenuItem *item,
- GtkFileChooserDefault *impl)
-{
- location_popup_handler (impl, "");
-}
-
/* Callback used when the "Show Hidden Files" menu item is toggled */
static void
show_hidden_toggled_cb (GtkCheckMenuItem *item,
NULL);
}
+/* Shows an error dialog about not being able to select a dragged file */
+static void
+error_selecting_dragged_file_dialog (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GError *error)
+{
+ error_dialog (impl,
+ _("Could not select file"),
+ path, error);
+}
+
+static void
+file_list_drag_data_select_uris (GtkFileChooserDefault *impl,
+ gchar **uris)
+{
+ int i;
+ char *uri;
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER (impl);
+
+ for (i = 1; uris[i]; i++)
+ {
+ GtkFilePath *path;
+
+ uri = uris[i];
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+ if (path)
+ {
+ GError *error = NULL;
+
+ gtk_file_chooser_default_select_path (chooser, path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (impl, path, error);
+
+ gtk_file_path_free (path);
+ }
+ }
+}
+
+struct FileListDragData
+{
+ GtkFileChooserDefault *impl;
+ gchar **uris;
+ GtkFilePath *path;
+};
+
+static void
+file_list_drag_data_received_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct FileListDragData *data = user_data;
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER (data->impl);
+
+ if (handle != data->impl->file_list_drag_data_received_handle)
+ goto out;
+
+ data->impl->file_list_drag_data_received_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
+
+ if ((data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+ data->uris[1] == 0 && !error &&
+ gtk_file_info_get_is_folder (info))
+ change_folder_and_display_error (data->impl, data->path);
+ else
+ {
+ GError *error = NULL;
+
+ gtk_file_chooser_default_unselect_all (chooser);
+ gtk_file_chooser_default_select_path (chooser, data->path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (data->impl, data->path, error);
+ else
+ browse_files_center_selected_row (data->impl);
+ }
+
+ if (data->impl->select_multiple)
+ file_list_drag_data_select_uris (data->impl, data->uris);
+
+out:
+ g_object_unref (data->impl);
+ g_strfreev (data->uris);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static void
+file_list_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time_,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+ GtkFileChooser *chooser;
+ gchar **uris;
+ char *uri;
+ GtkFilePath *path;
+ GError *error = NULL;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+ chooser = GTK_FILE_CHOOSER (data);
+
+ /* Parse the text/uri-list string, navigate to the first one */
+ uris = g_uri_list_extract_uris ((const char *) selection_data->data);
+ if (uris[0])
+ {
+ uri = uris[0];
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+ if (path)
+ {
+ struct FileListDragData *data;
+
+ data = g_new0 (struct FileListDragData, 1);
+ data->impl = g_object_ref (impl);
+ data->uris = uris;
+ data->path = path;
+
+ if (impl->file_list_drag_data_received_handle)
+ gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+
+ impl->file_list_drag_data_received_handle =
+ gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_IS_FOLDER,
+ file_list_drag_data_received_get_info_cb,
+ data);
+ goto out;
+ }
+ else
+ {
+ g_set_error (&error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+ _("Could not select file '%s' "
+ "because it is an invalid path name."),
+ uri);
+ error_selecting_dragged_file_dialog (impl, NULL, error);
+ }
+
+ if (impl->select_multiple)
+ file_list_drag_data_select_uris (impl, uris);
+ }
+
+ g_strfreev (uris);
+
+out:
+ g_signal_stop_emission_by_name (widget, "drag_data_received");
+}
+
+/* Don't do anything with the drag_drop signal */
+static gboolean
+file_list_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_,
+ GtkFileChooserDefault *impl)
+{
+ g_signal_stop_emission_by_name (widget, "drag_drop");
+ return TRUE;
+}
+
+/* Disable the normal tree drag motion handler, it makes it look like you're
+ dropping the dragged item onto a tree item */
+static gboolean
+file_list_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_,
+ GtkFileChooserDefault *impl)
+{
+ g_signal_stop_emission_by_name (widget, "drag_motion");
+ return TRUE;
+}
+
/* Constructs the popup menu for the file list if needed */
static void
file_list_build_popup_menu (GtkFileChooserDefault *impl)
impl->browse_files_tree_view,
popup_menu_detach_cb);
- item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Shortcuts"));
+ item = gtk_image_menu_item_new_with_mnemonic (_("_Add to Bookmarks"));
impl->browse_files_popup_menu_add_shortcut_item = item;
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
- item = gtk_image_menu_item_new_with_mnemonic (_("Open _Location"));
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
- gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
- g_signal_connect (item, "activate",
- G_CALLBACK (open_location_cb), impl);
- gtk_widget_show (item);
- gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
-
item = gtk_separator_menu_item_new ();
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item);
{
file_list_build_popup_menu (impl);
- /* The sensitivity of the Add to Shortcuts item is set in
+ /* The sensitivity of the Add to Bookmarks item is set in
* bookmarks_check_add_sensitivity()
*/
GdkEventButton *event,
GtkFileChooserDefault *impl)
{
+ static gboolean in_press = FALSE;
+ gboolean handled;
+
+ if (in_press)
+ return FALSE;
+
if (event->button != 3)
return FALSE;
+ in_press = TRUE;
+ handled = gtk_widget_event (impl->browse_files_tree_view, (GdkEvent *) event);
+ in_press = FALSE;
+
file_list_popup_menu (impl, event);
return TRUE;
}
/* Tree/list view */
impl->browse_files_tree_view = gtk_tree_view_new ();
- g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "GtkFileChooserDefault", impl);
+#ifdef PROFILE_FILE_CHOOSER
+ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), "fmq-name", "file_list");
+#endif
+ g_object_set_data (G_OBJECT (impl->browse_files_tree_view), I_("GtkFileChooserDefault"), impl);
atk_object_set_name (gtk_widget_get_accessible (impl->browse_files_tree_view), _("Files"));
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (impl->browse_files_tree_view), TRUE);
gtk_container_add (GTK_CONTAINER (swin), impl->browse_files_tree_view);
- g_signal_connect (impl->browse_files_tree_view, "row-activated",
+
+ gtk_drag_dest_set (impl->browse_files_tree_view,
+ GTK_DEST_DEFAULT_ALL,
+ file_list_dest_targets,
+ num_file_list_dest_targets,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+
+ g_signal_connect (impl->browse_files_tree_view, "row_activated",
G_CALLBACK (list_row_activated), impl);
- g_signal_connect (impl->browse_files_tree_view, "key-press-event",
+ g_signal_connect (impl->browse_files_tree_view, "key_press_event",
G_CALLBACK (trap_activate_cb), impl);
- g_signal_connect (impl->browse_files_tree_view, "popup-menu",
+ g_signal_connect (impl->browse_files_tree_view, "popup_menu",
G_CALLBACK (list_popup_menu_cb), impl);
- g_signal_connect (impl->browse_files_tree_view, "button-press-event",
+ g_signal_connect (impl->browse_files_tree_view, "button_press_event",
G_CALLBACK (list_button_press_event_cb), impl);
+ g_signal_connect (impl->browse_files_tree_view, "drag_data_received",
+ G_CALLBACK (file_list_drag_data_received_cb), impl);
+ g_signal_connect (impl->browse_files_tree_view, "drag_drop",
+ G_CALLBACK (file_list_drag_drop_cb), impl);
+ g_signal_connect (impl->browse_files_tree_view, "drag_motion",
+ G_CALLBACK (file_list_drag_motion_cb), impl);
+
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_selection_set_select_function (selection,
list_select_func,
NULL);
g_signal_connect (impl->list_name_renderer, "edited",
G_CALLBACK (renderer_edited_cb), impl);
- g_signal_connect (impl->list_name_renderer, "editing-canceled",
+ g_signal_connect (impl->list_name_renderer, "editing_canceled",
G_CALLBACK (renderer_editing_canceled_cb), impl);
gtk_tree_view_column_pack_start (impl->list_name_column, impl->list_name_renderer, TRUE);
gtk_tree_view_column_set_cell_data_func (impl->list_name_column, impl->list_name_renderer,
gtk_tree_view_column_set_title (column, _("Size"));
renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */
gtk_tree_view_column_set_cell_data_func (column, renderer,
list_size_data_func, impl, NULL);
gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
- /* The path bar and 'Create Folder' button */
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_widget_show (hbox);
- impl->browse_path_bar = create_path_bar (impl);
- g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
- gtk_widget_show_all (impl->browse_path_bar);
- gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
-
- /* Create Folder */
- impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
- g_signal_connect (impl->browse_new_folder_button, "clicked",
- G_CALLBACK (new_folder_button_clicked), impl);
- gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
/* Box for lists and preview */
hbox = gtk_hbox_new (FALSE, PREVIEW_HBOX_SPACING);
return vbox;
}
+
/* Callback used when the "Browse for more folders" expander is toggled */
static void
expander_changed_cb (GtkExpander *expander,
}
/* Creates the widgets specific to Save mode */
-static GtkWidget *
+static void
save_widgets_create (GtkFileChooserDefault *impl)
{
GtkWidget *vbox;
GtkWidget *widget;
GtkWidget *alignment;
+ if (impl->save_widgets != NULL)
+ return;
+
+ location_switch_to_path_bar (impl);
+
vbox = gtk_vbox_new (FALSE, 12);
table = gtk_table_new (2, 2, FALSE);
gtk_table_set_row_spacings (GTK_TABLE (table), 12);
gtk_table_set_col_spacings (GTK_TABLE (table), 12);
- /* Name entry */
+ /* Label */
widget = gtk_label_new_with_mnemonic (_("_Name:"));
gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
0, 0);
gtk_widget_show (widget);
- impl->save_file_name_entry = _gtk_file_chooser_entry_new (TRUE);
- _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
+ /* Location entry */
+
+ impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+ _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
impl->file_system);
- gtk_entry_set_width_chars (GTK_ENTRY (impl->save_file_name_entry), 45);
- gtk_entry_set_activates_default (GTK_ENTRY (impl->save_file_name_entry), TRUE);
- gtk_table_attach (GTK_TABLE (table), impl->save_file_name_entry,
+ gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45);
+ gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+ gtk_table_attach (GTK_TABLE (table), impl->location_entry,
1, 2, 0, 1,
GTK_EXPAND | GTK_FILL, 0,
0, 0);
- gtk_widget_show (impl->save_file_name_entry);
- gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->save_file_name_entry);
+ gtk_widget_show (impl->location_entry);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->location_entry);
/* Folder combo */
impl->save_folder_label = gtk_label_new (NULL);
impl);
gtk_widget_show_all (alignment);
- return vbox;
+ impl->save_widgets = vbox;
+ gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (impl), impl->save_widgets, 0);
+ gtk_widget_show (impl->save_widgets);
}
-/* Creates the main hpaned with the widgets shared by Open and Save mode */
-static GtkWidget *
+/* Destroys the widgets specific to Save mode */
+static void
+save_widgets_destroy (GtkFileChooserDefault *impl)
+{
+ if (impl->save_widgets == NULL)
+ return;
+
+ gtk_widget_destroy (impl->save_widgets);
+ impl->save_widgets = NULL;
+ impl->location_entry = NULL;
+ impl->save_folder_label = NULL;
+ impl->save_folder_combo = NULL;
+ impl->save_expander = NULL;
+}
+
+/* Turns on the path bar widget. Can be called even if we are already in that
+ * mode.
+ */
+static void
+location_switch_to_path_bar (GtkFileChooserDefault *impl)
+{
+ if (impl->location_entry)
+ {
+ gtk_widget_destroy (impl->location_entry);
+ impl->location_entry = NULL;
+ }
+
+ gtk_widget_hide (impl->location_entry_box);
+}
+
+/* Sets the full path of the current folder as the text in the location entry. */
+static void
+location_entry_set_initial_text (GtkFileChooserDefault *impl)
+{
+ char *text;
+
+ if (!impl->current_folder)
+ return;
+
+ if (gtk_file_system_path_is_local (impl->file_system, impl->current_folder))
+ {
+ char *filename;
+
+ filename = gtk_file_system_path_to_filename (impl->file_system, impl->current_folder);
+ if (filename)
+ {
+ text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+ g_free (filename);
+ }
+ else
+ text = NULL;
+ }
+ else
+ text = gtk_file_system_path_to_uri (impl->file_system, impl->current_folder);
+
+ if (text)
+ {
+ gboolean need_slash;
+ int len;
+
+ len = strlen (text);
+ need_slash = (text[len - 1] != G_DIR_SEPARATOR);
+
+ if (need_slash)
+ {
+ char *slash_text;
+
+ slash_text = g_new (char, len + 2);
+ strcpy (slash_text, text);
+ slash_text[len] = G_DIR_SEPARATOR;
+ slash_text[len + 1] = 0;
+
+ g_free (text);
+ text = slash_text;
+ }
+
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text);
+ g_free (text);
+ }
+}
+
+/* Turns on the location entry. Can be called even if we are already in that
+ * mode.
+ */
+static void
+location_switch_to_filename_entry (GtkFileChooserDefault *impl)
+{
+ if (impl->location_entry)
+ gtk_widget_destroy (impl->location_entry);
+
+ /* Box */
+
+ gtk_widget_show (impl->location_entry_box);
+
+ /* Entry */
+
+ impl->location_entry = _gtk_file_chooser_entry_new (TRUE);
+ _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+ impl->file_system);
+ gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE);
+ _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+
+ gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry);
+
+ /* Configure the entry */
+
+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
+
+ /* Done */
+
+ gtk_widget_show (impl->location_entry);
+ gtk_widget_grab_focus (impl->location_entry);
+}
+
+/* Sets a new location mode. set_buttons determines whether the toggle button
+ * for the mode will also be changed.
+ */
+static void
+location_mode_set (GtkFileChooserDefault *impl,
+ LocationMode new_mode,
+ gboolean set_button)
+{
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ GtkWindow *toplevel;
+ GtkWidget *current_focus;
+ gboolean button_active;
+ gboolean switch_to_file_list;
+
+ switch (new_mode)
+ {
+ case LOCATION_MODE_PATH_BAR:
+ button_active = FALSE;
+
+ /* The location_entry will disappear when we switch to path bar mode. So,
+ * we'll focus the file list in that case, to avoid having a window with
+ * no focused widget.
+ */
+ toplevel = get_toplevel (GTK_WIDGET (impl));
+ switch_to_file_list = FALSE;
+ if (toplevel)
+ {
+ current_focus = gtk_window_get_focus (toplevel);
+ if (!current_focus || current_focus == impl->location_entry)
+ switch_to_file_list = TRUE;
+ }
+
+ location_switch_to_path_bar (impl);
+
+ if (switch_to_file_list)
+ gtk_widget_grab_focus (impl->browse_files_tree_view);
+
+ break;
+
+ case LOCATION_MODE_FILENAME_ENTRY:
+ button_active = TRUE;
+ location_switch_to_filename_entry (impl);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+
+ if (set_button)
+ {
+ g_signal_handlers_block_by_func (impl->location_button,
+ G_CALLBACK (location_button_toggled_cb), impl);
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->location_button), button_active);
+
+ g_signal_handlers_unblock_by_func (impl->location_button,
+ G_CALLBACK (location_button_toggled_cb), impl);
+ }
+ }
+
+ impl->location_mode = new_mode;
+}
+
+/* Callback used when one of the location mode buttons is toggled */
+static void
+location_button_toggled_cb (GtkToggleButton *toggle,
+ GtkFileChooserDefault *impl)
+{
+ gboolean is_active;
+ LocationMode new_mode;
+
+ is_active = gtk_toggle_button_get_active (toggle);
+
+ if (is_active)
+ {
+ g_assert (impl->location_mode == LOCATION_MODE_PATH_BAR);
+ new_mode = LOCATION_MODE_FILENAME_ENTRY;
+ }
+ else
+ {
+ g_assert (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY);
+ new_mode = LOCATION_MODE_PATH_BAR;
+ }
+
+ location_mode_set (impl, new_mode, FALSE);
+}
+
+/* Creates a toggle button for the location entry. */
+static void
+location_button_create (GtkFileChooserDefault *impl)
+{
+ GtkWidget *image;
+ const char *str;
+
+ image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON);
+ gtk_widget_show (image);
+
+ impl->location_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
+ "image", image,
+ NULL);
+
+ g_signal_connect (impl->location_button, "toggled",
+ G_CALLBACK (location_button_toggled_cb), impl);
+
+ str = _("Type a file name");
+
+ gtk_tooltips_set_tip (impl->tooltips, impl->location_button, str, NULL);
+ atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str);
+}
+
+/* Creates the main hpaned with the widgets shared by Open and Save mode */
+static GtkWidget *
browse_widgets_create (GtkFileChooserDefault *impl)
{
GtkWidget *vbox;
+ GtkWidget *hbox;
GtkWidget *hpaned;
GtkWidget *widget;
GtkSizeGroup *size_group;
+ gchar *text;
/* size group is used by the [+][-] buttons and the filter combo */
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
vbox = gtk_vbox_new (FALSE, 12);
+ /* Location widgets */
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ location_button_create (impl);
+ gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
+
+ /* Path bar */
+
+ impl->browse_path_bar = create_path_bar (impl);
+ g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
+ gtk_widget_show_all (impl->browse_path_bar);
+ gtk_box_pack_start (GTK_BOX (hbox), impl->browse_path_bar, TRUE, TRUE, 0);
+
+ /* Create Folder */
+ impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
+ g_signal_connect (impl->browse_new_folder_button, "clicked",
+ G_CALLBACK (new_folder_button_clicked), impl);
+ gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
+
+ /* Box for the location label and entry */
+
+ impl->location_entry_box = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0);
+
+ text = g_strconcat ("<b>", _("_Location:"), "</b>", NULL);
+ impl->location_label = gtk_label_new_with_mnemonic (text);
+ g_free (text);
+ gtk_label_set_use_markup (GTK_LABEL (impl->location_label), TRUE);
+ gtk_widget_show (impl->location_label);
+ gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0);
+
/* Paned widget */
hpaned = gtk_hpaned_new ();
gtk_widget_show (hpaned);
GtkFileChooserDefault *impl;
GObject *object;
- object = parent_class->constructor (type,
- n_construct_properties,
- construct_params);
+ profile_start ("start", NULL);
+
+ object = G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_params);
impl = GTK_FILE_CHOOSER_DEFAULT (object);
g_assert (impl->file_system);
shortcuts_model_create (impl);
- /* Widgets for Save mode */
- impl->save_widgets = save_widgets_create (impl);
- gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
-
/* The browse widgets */
impl->browse_widgets = browse_widgets_create (impl);
gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
gtk_widget_pop_composite_child ();
update_appearance (impl);
+ profile_end ("end", NULL);
+
return object;
}
bookmarks_check_add_sensitivity (impl);
bookmarks_check_remove_sensitivity (impl);
+ shortcuts_check_popup_sensitivity (impl);
}
/* Sets the file chooser to multiple selection mode */
set_file_system_backend (GtkFileChooserDefault *impl,
const char *backend)
{
+ profile_start ("start for backend", backend ? backend : "default");
+
if (impl->file_system)
{
g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
G_CALLBACK (bookmarks_changed_cb),
impl);
}
+
+ profile_end ("end", NULL);
}
/* This function is basically a do_all function.
{
const char *text;
- gtk_widget_show (impl->save_widgets);
+ gtk_widget_hide (impl->location_button);
+ save_widgets_create (impl);
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
text = _("Save in _folder:");
else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
{
- gtk_widget_hide (impl->save_widgets);
+ gtk_widget_show (impl->location_button);
+ save_widgets_destroy (impl);
gtk_widget_show (impl->browse_widgets);
+ location_mode_set (impl, impl->location_mode, TRUE);
}
+ if (impl->location_entry)
+ _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action);
+
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
gtk_widget_hide (impl->browse_new_folder_button);
else
gtk_widget_show (impl->browse_new_folder_button);
+ /* This *is* needed; we need to redraw the file list because the "sensitivity"
+ * of files may change depending whether we are in a file or folder-only mode.
+ */
gtk_widget_queue_draw (impl->browse_files_tree_view);
g_signal_emit_by_name (impl, "default-size-changed");
{
gtk_file_chooser_default_unselect_all (GTK_FILE_CHOOSER (impl));
- if (action == GTK_FILE_CHOOSER_ACTION_SAVE && impl->select_multiple)
+ if ((action == GTK_FILE_CHOOSER_ACTION_SAVE || action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ && impl->select_multiple)
{
- g_warning ("Multiple selection mode is not allowed in Save mode");
+ g_warning ("Tried to change the file chooser action to SAVE or CREATE_FOLDER, but "
+ "this is not allowed in multiple selection mode. Resetting the file chooser "
+ "to single selection mode.");
set_select_multiple (impl, FALSE, TRUE);
}
impl->action = action;
update_appearance (impl);
}
-
- if (impl->save_file_name_entry)
- _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
- action);
}
break;
+
case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
set_file_system_backend (impl, g_value_get_string (value));
break;
+
case GTK_FILE_CHOOSER_PROP_FILTER:
set_current_filter (impl, g_value_get_object (value));
break;
+
case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
set_local_only (impl, g_value_get_boolean (value));
break;
+
case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
set_preview_widget (impl, g_value_get_object (value));
break;
+
case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
impl->preview_widget_active = g_value_get_boolean (value);
update_preview_widget_visibility (impl);
break;
+
case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
impl->use_preview_label = g_value_get_boolean (value);
update_preview_widget_visibility (impl);
break;
+
case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
set_extra_widget (impl, g_value_get_object (value));
break;
+
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
{
gboolean select_multiple = g_value_get_boolean (value);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE && select_multiple)
+ if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ && select_multiple)
{
- g_warning ("Multiple selection mode is not allowed in Save mode");
+ g_warning ("Tried to set the file chooser to multiple selection mode, but this is "
+ "not allowed in SAVE or CREATE_FOLDER modes. Ignoring the change and "
+ "leaving the file chooser in single selection mode.");
return;
}
set_select_multiple (impl, select_multiple, FALSE);
}
break;
+
case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
{
gboolean show_hidden = g_value_get_boolean (value);
}
}
break;
+
+ case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
+ {
+ gboolean do_overwrite_confirmation = g_value_get_boolean (value);
+ impl->do_overwrite_confirmation = do_overwrite_confirmation;
+ }
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case GTK_FILE_CHOOSER_PROP_ACTION:
g_value_set_enum (value, impl->action);
break;
+
case GTK_FILE_CHOOSER_PROP_FILTER:
g_value_set_object (value, impl->current_filter);
break;
+
case GTK_FILE_CHOOSER_PROP_LOCAL_ONLY:
g_value_set_boolean (value, impl->local_only);
break;
+
case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET:
g_value_set_object (value, impl->preview_widget);
break;
+
case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
g_value_set_boolean (value, impl->preview_widget_active);
break;
+
case GTK_FILE_CHOOSER_PROP_USE_PREVIEW_LABEL:
g_value_set_boolean (value, impl->use_preview_label);
break;
+
case GTK_FILE_CHOOSER_PROP_EXTRA_WIDGET:
g_value_set_object (value, impl->extra_widget);
break;
+
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
g_value_set_boolean (value, impl->select_multiple);
break;
+
case GTK_FILE_CHOOSER_PROP_SHOW_HIDDEN:
g_value_set_boolean (value, impl->show_hidden);
break;
+
+ case GTK_FILE_CHOOSER_PROP_DO_OVERWRITE_CONFIRMATION:
+ g_value_set_boolean (value, impl->do_overwrite_confirmation);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
static void
gtk_file_chooser_default_dispose (GObject *object)
{
+ GSList *l;
GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
if (impl->extra_widget)
impl->extra_widget = NULL;
}
+ if (impl->volumes_changed_id > 0)
+ {
+ g_signal_handler_disconnect (impl->file_system, impl->volumes_changed_id);
+ impl->volumes_changed_id = 0;
+ }
+
+ if (impl->bookmarks_changed_id > 0)
+ {
+ g_signal_handler_disconnect (impl->file_system, impl->bookmarks_changed_id);
+ impl->bookmarks_changed_id = 0;
+ }
+
+ pending_select_paths_free (impl);
+
+ /* cancel all pending operations */
+ if (impl->pending_handles)
+ {
+ for (l = impl->pending_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->pending_handles);
+ impl->pending_handles = NULL;
+ }
+
+ if (impl->reload_icon_handles)
+ {
+ for (l = impl->reload_icon_handles; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->reload_icon_handles);
+ impl->reload_icon_handles = NULL;
+ }
+
+ if (impl->loading_shortcuts)
+ {
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *handle =l->data;
+ gtk_file_system_cancel_operation (handle);
+ }
+ g_slist_free (impl->loading_shortcuts);
+ impl->loading_shortcuts = NULL;
+ }
+
+ if (impl->file_list_drag_data_received_handle)
+ {
+ gtk_file_system_cancel_operation (impl->file_list_drag_data_received_handle);
+ impl->file_list_drag_data_received_handle = NULL;
+ }
+
+ if (impl->update_current_folder_handle)
+ {
+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+ impl->update_current_folder_handle = NULL;
+ }
+
+ if (impl->show_and_select_paths_handle)
+ {
+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+ impl->show_and_select_paths_handle = NULL;
+ }
+
+ if (impl->should_respond_get_info_handle)
+ {
+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+ impl->should_respond_get_info_handle = NULL;
+ }
+
+ if (impl->update_from_entry_handle)
+ {
+ gtk_file_system_cancel_operation (impl->update_from_entry_handle);
+ impl->update_from_entry_handle = NULL;
+ }
+
+ if (impl->shortcuts_activate_iter_handle)
+ {
+ gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+ impl->shortcuts_activate_iter_handle = NULL;
+ }
+
remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
- G_OBJECT_CLASS (parent_class)->dispose (object);
+ G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
}
/* We override show-all since we have internal widgets that
toplevel = gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
{
- impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set-focus",
+ impl->toplevel_set_focus_id = g_signal_connect (toplevel, "set_focus",
G_CALLBACK (toplevel_set_focus_cb), impl);
impl->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
}
GtkSettings *settings;
gint width, height;
+ profile_start ("start", NULL);
+
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
shortcuts_reload_icons (impl);
gtk_widget_queue_resize (impl->browse_files_tree_view);
+
+ profile_end ("end", NULL);
}
/* Callback used when a GtkSettings value changes */
{
const char *name;
+ profile_start ("start", NULL);
+
name = g_param_spec_get_name (pspec);
if (strcmp (name, "gtk-icon-theme-name") == 0
|| strcmp (name, "gtk-icon-sizes") == 0)
change_icon_theme (impl);
+
+ profile_end ("end", NULL);
}
/* Installs a signal handler for GtkSettings so that we can monitor changes in
{
GtkSettings *settings;
+ profile_start ("start", NULL);
+
if (impl->settings_signal_id)
- return;
+ {
+ profile_end ("end", NULL);
+ return;
+ }
if (gtk_widget_has_screen (GTK_WIDGET (impl)))
{
change_icon_theme (impl);
}
+
+ profile_end ("end", NULL);
}
static void
{
GtkFileChooserDefault *impl;
+ profile_start ("start", NULL);
+
impl = GTK_FILE_CHOOSER_DEFAULT (widget);
- if (GTK_WIDGET_CLASS (parent_class)->style_set)
- GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
+ profile_msg (" parent class style_set start", NULL);
+ if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set)
+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->style_set (widget, previous_style);
+ profile_msg (" parent class style_set end", NULL);
if (gtk_widget_has_screen (GTK_WIDGET (impl)))
change_icon_theme (impl);
+ profile_msg (" emit default-size-changed start", NULL);
g_signal_emit_by_name (widget, "default-size-changed");
+ profile_msg (" emit default-size-changed end", NULL);
+
+ profile_end ("end", NULL);
}
static void
{
GtkFileChooserDefault *impl;
+ profile_start ("start", NULL);
+
impl = GTK_FILE_CHOOSER_DEFAULT (widget);
- if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
- GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
+ if (GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed)
+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->screen_changed (widget, previous_screen);
remove_settings_signal (impl, previous_screen);
check_icon_theme (impl);
g_signal_emit_by_name (widget, "default-size-changed");
+
+ profile_end ("end", NULL);
}
static gboolean
return !result;
}
-/* GtkWidget::map method */
static void
-gtk_file_chooser_default_map (GtkWidget *widget)
+settings_load (GtkFileChooserDefault *impl)
{
- GtkFileChooserDefault *impl;
+ GtkFileChooserSettings *settings;
+ LocationMode location_mode;
+ gboolean show_hidden;
- impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+ settings = _gtk_file_chooser_settings_new ();
- GTK_WIDGET_CLASS (parent_class)->map (widget);
+ location_mode = _gtk_file_chooser_settings_get_location_mode (settings);
+ show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings);
- if (impl->current_folder)
- {
- pending_select_paths_store_selection (impl);
- change_folder_and_display_error (impl, impl->current_folder);
- }
+ g_object_unref (settings);
- bookmarks_changed_cb (impl->file_system, impl);
+ location_mode_set (impl, location_mode, TRUE);
+ gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
}
-static gboolean
-list_model_filter_func (GtkFileSystemModel *model,
- GtkFilePath *path,
- const GtkFileInfo *file_info,
- gpointer user_data)
+static void
+settings_save (GtkFileChooserDefault *impl)
{
- GtkFileChooserDefault *impl = user_data;
+ GtkFileChooserSettings *settings;
- if (!impl->current_filter)
- return TRUE;
+ settings = _gtk_file_chooser_settings_new ();
- if (gtk_file_info_get_is_folder (file_info))
- return TRUE;
+ _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode);
+ _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
- return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
+ /* NULL GError */
+ _gtk_file_chooser_settings_save (settings, NULL);
+
+ g_object_unref (settings);
}
+/* GtkWidget::map method */
static void
-install_list_model_filter (GtkFileChooserDefault *impl)
+gtk_file_chooser_default_map (GtkWidget *widget)
{
- GtkFileSystemModelFilter filter;
- gpointer data;
+ GtkFileChooserDefault *impl;
+ char *current_working_dir;
- g_assert (impl->browse_files_model != NULL);
+ profile_start ("start", NULL);
- if (impl->current_filter)
- {
- filter = list_model_filter_func;
- data = impl;
- }
- else
+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
+
+ switch (impl->reload_state)
{
- filter = NULL;
- data = NULL;
+ case RELOAD_EMPTY:
+ /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
+ current_working_dir = g_get_current_dir ();
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
+ g_free (current_working_dir);
+ break;
+
+ case RELOAD_HAS_FOLDER:
+ /* Nothing; we are already loading or loaded, so we don't need to reload */
+ break;
+
+ case RELOAD_WAS_UNMAPPED:
+ /* Just reload the current folder; else continue the pending load. */
+ if (impl->current_folder)
+ {
+ pending_select_paths_store_selection (impl);
+ change_folder_and_display_error (impl, impl->current_folder);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ bookmarks_changed_cb (impl->file_system, impl);
+
+ settings_load (impl);
+
+ profile_end ("end", NULL);
+}
+
+/* GtkWidget::unmap method */
+static void
+gtk_file_chooser_default_unmap (GtkWidget *widget)
+{
+ GtkFileChooserDefault *impl;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+ settings_save (impl);
+
+ GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
+
+ impl->reload_state = RELOAD_WAS_UNMAPPED;
+}
+
+static gboolean
+list_model_filter_func (GtkFileSystemModel *model,
+ GtkFilePath *path,
+ const GtkFileInfo *file_info,
+ gpointer user_data)
+{
+ GtkFileChooserDefault *impl = user_data;
+
+ if (!impl->current_filter)
+ return TRUE;
+
+ if (gtk_file_info_get_is_folder (file_info))
+ return TRUE;
+
+ return !get_is_file_filtered (impl, path, (GtkFileInfo *) file_info);
+}
+
+static void
+install_list_model_filter (GtkFileChooserDefault *impl)
+{
+ GtkFileSystemModelFilter filter;
+ gpointer data;
+
+ g_assert (impl->browse_files_model != NULL);
+
+ if (impl->current_filter)
+ {
+ filter = list_model_filter_func;
+ data = impl;
+ }
+ else
+ {
+ filter = NULL;
+ data = NULL;
}
_gtk_file_system_model_set_filter (impl->browse_files_model,
static void
load_set_model (GtkFileChooserDefault *impl)
{
+ profile_start ("start", NULL);
+
g_assert (impl->browse_files_model != NULL);
g_assert (impl->sort_model == NULL);
+ profile_msg (" gtk_tree_model_sort_new_with_model start", NULL);
impl->sort_model = (GtkTreeModelSort *)gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (impl->browse_files_model));
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, name_sort_func, impl, NULL);
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_SIZE, size_sort_func, impl, NULL);
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (impl->sort_model), NULL, NULL, NULL);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->sort_model), FILE_LIST_COL_NAME, GTK_SORT_ASCENDING);
impl->list_sort_ascending = TRUE;
+ profile_msg (" gtk_tree_model_sort_new_with_model end", NULL);
- g_signal_connect (impl->sort_model, "sort-column-changed",
+ g_signal_connect (impl->sort_model, "sort_column_changed",
G_CALLBACK (list_sort_column_changed_cb), impl);
+ profile_msg (" gtk_tree_view_set_model start", NULL);
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view),
GTK_TREE_MODEL (impl->sort_model));
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_view_set_search_column (GTK_TREE_VIEW (impl->browse_files_tree_view),
GTK_FILE_SYSTEM_MODEL_DISPLAY_NAME);
+ profile_msg (" gtk_tree_view_set_model end", NULL);
+
+ profile_end ("end", NULL);
}
/* Timeout callback used when the loading timer expires */
{
GtkFileChooserDefault *impl;
+ profile_start ("start", NULL);
+
GDK_THREADS_ENTER ();
impl = GTK_FILE_CHOOSER_DEFAULT (data);
GDK_THREADS_LEAVE ();
+ profile_end ("end", NULL);
+
return FALSE;
}
-/* Sets up a new load timer for the model and switches to the LOAD_LOADING state */
+/* Sets up a new load timer for the model and switches to the LOAD_PRELOAD state */
static void
load_setup_timer (GtkFileChooserDefault *impl)
{
gtk_tree_selection_selected_foreach (selection, center_selected_row_foreach_cb, &closure);
}
-static gboolean
-show_and_select_paths (GtkFileChooserDefault *impl,
- const GtkFilePath *parent_path,
- const GtkFilePath *only_one_path,
- GSList *paths,
- GError **error)
+struct ShowAndSelectPathsData
+{
+ GtkFileChooserDefault *impl;
+ GSList *paths;
+};
+
+static void
+show_and_select_paths_finished_loading (GtkFileFolder *folder,
+ gpointer user_data)
{
- GtkFileFolder *folder;
- gboolean success;
gboolean have_hidden;
gboolean have_filtered;
+ GSList *l;
+ struct ShowAndSelectPathsData *data = user_data;
- if (!only_one_path && !paths)
- return TRUE;
-
- folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
- if (!folder)
- return FALSE;
-
- success = FALSE;
have_hidden = FALSE;
have_filtered = FALSE;
- if (only_one_path)
+ for (l = data->paths; l; l = l->next)
{
+ const GtkFilePath *path;
GtkFileInfo *info;
- info = gtk_file_folder_get_info (folder, only_one_path, error);
+ path = l->data;
+
+ /* NULL GError */
+ info = gtk_file_folder_get_info (folder, path, NULL);
if (info)
{
- success = TRUE;
- have_hidden = gtk_file_info_get_is_hidden (info);
- have_filtered = get_is_file_filtered (impl, only_one_path, info);
+ if (!have_hidden)
+ have_hidden = gtk_file_info_get_is_hidden (info);
+
+ if (!have_filtered)
+ have_filtered = !gtk_file_info_get_is_folder (info) && get_is_file_filtered (data->impl, path, info);
+
gtk_file_info_free (info);
+
+ if (have_hidden && have_filtered)
+ break; /* we now have all the information we need */
}
}
- else
- {
- GSList *l;
-
- for (l = paths; l; l = l->next)
- {
- const GtkFilePath *path;
- GtkFileInfo *info;
- path = l->data;
+ g_signal_handlers_disconnect_by_func (folder,
+ show_and_select_paths_finished_loading,
+ user_data);
- /* NULL GError */
- info = gtk_file_folder_get_info (folder, path, NULL);
- if (info)
- {
- if (!have_hidden)
- have_hidden = gtk_file_info_get_is_hidden (info);
+ g_object_unref (folder);
- if (!have_filtered)
- have_filtered = get_is_file_filtered (impl, path, info);
+ if (have_hidden)
+ g_object_set (data->impl, "show-hidden", TRUE, NULL);
- gtk_file_info_free (info);
+ if (have_filtered)
+ set_current_filter (data->impl, NULL);
- if (have_hidden && have_filtered)
- break; /* we now have all the information we need */
- }
- }
+ for (l = data->paths; l; l = l->next)
+ {
+ const GtkFilePath *path;
- success = TRUE;
+ path = l->data;
+ _gtk_file_system_model_path_do (data->impl->browse_files_model, path,
+ select_func, data->impl);
}
- g_object_unref (folder);
+ browse_files_center_selected_row (data->impl);
- if (!success)
- return FALSE;
+ g_object_unref (data->impl);
+ gtk_file_paths_free (data->paths);
+ g_free (data);
+}
- if (have_hidden)
- g_object_set (impl, "show-hidden", TRUE, NULL);
+static void
+show_and_select_paths_get_folder_cb (GtkFileSystemHandle *handle,
+ GtkFileFolder *folder,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct ShowAndSelectPathsData *data = user_data;
- if (have_filtered)
- set_current_filter (impl, NULL);
+ if (data->impl->show_and_select_paths_handle != handle)
+ goto out;
+
+ data->impl->show_and_select_paths_handle = NULL;
+
+ if (cancelled || error)
+ goto out;
- if (only_one_path)
- _gtk_file_system_model_path_do (impl->browse_files_model, only_one_path, select_func, impl);
+ g_object_unref (handle);
+
+ if (gtk_file_folder_is_finished_loading (folder))
+ show_and_select_paths_finished_loading (folder, user_data);
else
- {
- GSList *l;
+ g_signal_connect (folder, "finished-loading",
+ G_CALLBACK (show_and_select_paths_finished_loading),
+ user_data);
- for (l = paths; l; l = l->next)
- {
- const GtkFilePath *path;
+ return;
- path = l->data;
- _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
- }
+out:
+ g_object_unref (data->impl);
+ gtk_file_paths_free (data->paths);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static gboolean
+show_and_select_paths (GtkFileChooserDefault *impl,
+ const GtkFilePath *parent_path,
+ GSList *paths,
+ GError **error)
+{
+ struct ShowAndSelectPathsData *info;
+
+ profile_start ("start", NULL);
+
+ if (!paths)
+ {
+ profile_end ("end", NULL);
+ return TRUE;
}
+ info = g_new (struct ShowAndSelectPathsData, 1);
+ info->impl = g_object_ref (impl);
+ info->paths = gtk_file_paths_copy (paths);
+
+ if (impl->show_and_select_paths_handle)
+ gtk_file_system_cancel_operation (impl->show_and_select_paths_handle);
+
+ impl->show_and_select_paths_handle =
+ gtk_file_system_get_folder (impl->file_system, parent_path,
+ GTK_FILE_INFO_IS_FOLDER | GTK_FILE_INFO_IS_HIDDEN,
+ show_and_select_paths_get_folder_cb, info);
+
+ profile_end ("end", NULL);
return TRUE;
}
if (impl->pending_select_paths)
{
/* NULL GError */
- show_and_select_paths (impl, impl->current_folder, NULL, impl->pending_select_paths, NULL);
+ show_and_select_paths (impl, impl->current_folder, impl->pending_select_paths, NULL);
pending_select_paths_free (impl);
browse_files_center_selected_row (impl);
}
* that case, the chooser's selection should be what the caller expects,
* as the user can't see that something else got selected. See bug #165264.
*
- * Also, we don't select the first file if we are in SAVE or CREATE_FOLDER
- * modes. Doing so would change the contents of the filename entry.
+ * Also, we don't select the first file if we are not in OPEN mode. Doing
+ * so would change the contents of the filename entry for SAVE or
+ * CREATE_FOLDER, which is undesired; in SELECT_FOLDER, we don't want to
+ * select a *different* folder from the one into which the user just
+ * navigated.
*/
- if (GTK_WIDGET_MAPPED (impl)
- && !(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
+ if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
browse_files_select_first_row (impl);
}
browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
GtkFileChooserDefault *impl)
{
+ profile_start ("start", NULL);
+
if (impl->load_state == LOAD_PRELOAD)
{
load_remove_timer (impl);
/* We can't g_assert_not_reached(), as something other than us may have
* initiated a folder reload. See #165556.
*/
+ profile_end ("end", NULL);
return;
}
pending_select_paths_process (impl);
set_busy_cursor (impl, FALSE);
+#ifdef PROFILE_FILE_CHOOSER
+ access ("MARK: *** FINISHED LOADING", F_OK);
+#endif
+
+ profile_end ("end", NULL);
}
/* Gets rid of the old list model and creates a new one for the current folder */
{
g_assert (impl->current_folder != NULL);
+ profile_start ("start", NULL);
+
load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
if (impl->browse_files_model)
if (!impl->browse_files_model)
{
set_busy_cursor (impl, FALSE);
+ profile_end ("end", NULL);
return FALSE;
}
install_list_model_filter (impl);
+ profile_end ("end", NULL);
+
return TRUE;
}
-static void
-update_chooser_entry (GtkFileChooserDefault *impl)
+struct update_chooser_entry_selected_foreach_closure {
+ int num_selected;
+ GtkTreeIter first_selected_iter;
+};
+
+static gint
+compare_utf8_filenames (const gchar *a,
+ const gchar *b)
{
- GtkTreeSelection *selection;
- const GtkFileInfo *info;
- GtkTreeIter iter;
- GtkTreeIter child_iter;
+ gchar *a_folded, *b_folded;
+ gint retval;
- if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
- return;
+ a_folded = g_utf8_strdown (a, -1);
+ b_folded = g_utf8_strdown (b, -1);
- g_assert (!impl->select_multiple);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ retval = strcmp (a_folded, b_folded);
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
- return;
+ g_free (a_folded);
+ g_free (b_folded);
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- &iter);
+ return retval;
+}
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+static void
+update_chooser_entry_selected_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ struct update_chooser_entry_selected_foreach_closure *closure;
- if (!gtk_file_info_get_is_folder (info))
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
- gtk_file_info_get_display_name (info));
+ closure = data;
+ closure->num_selected++;
+
+ if (closure->num_selected == 1)
+ closure->first_selected_iter = *iter;
}
-static gboolean
-gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
- const GtkFilePath *path,
- GError **error)
+static void
+update_chooser_entry (GtkFileChooserDefault *impl)
{
- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
- gboolean result;
-
- g_assert (path != NULL);
+ GtkTreeSelection *selection;
+ struct update_chooser_entry_selected_foreach_closure closure;
+ const char *file_part;
- if (impl->local_only &&
- !gtk_file_system_path_is_local (impl->file_system, path))
- {
- g_set_error (error,
- GTK_FILE_CHOOSER_ERROR,
- GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
- _("Cannot change to folder because it is not local"));
+ if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+ || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)))
+ return;
- return FALSE;
- }
+ g_assert (impl->location_entry != NULL);
- /* Test validity of path here. */
- if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ closure.num_selected = 0;
+ gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure);
- if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, error))
- return FALSE;
+ file_part = NULL;
- if (impl->current_folder != path)
+ if (closure.num_selected == 0)
{
- if (impl->current_folder)
- gtk_file_path_free (impl->current_folder);
-
- impl->current_folder = gtk_file_path_copy (path);
+ goto maybe_clear_entry;
}
+ else if (closure.num_selected == 1)
+ {
+ GtkTreeIter child_iter;
+ const GtkFileInfo *info;
+ gboolean change_entry;
- /* Update the widgets that may trigger a folder change themselves. */
+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+ &child_iter,
+ &closure.first_selected_iter);
- if (!impl->changing_folder)
- {
- impl->changing_folder = TRUE;
+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- shortcuts_update_current_folder (impl);
+ g_free (impl->browse_files_last_selected_name);
+ impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
- impl->changing_folder = FALSE;
- }
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
+ else
+ change_entry = TRUE; /* ... unless we are in one of the folder modes */
- /* Set the folder on the save entry */
+ if (change_entry)
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
- impl->current_folder);
+ return;
+ }
+ else
+ {
+ g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
- /* Create a new list model. This is slightly evil; we store the result value
- * but perform more actions rather than returning immediately even if it
- * generates an error.
- */
- result = set_list_model (impl, error);
+ /* Multiple selection, so just clear the entry. */
- /* Refresh controls */
+ g_free (impl->browse_files_last_selected_name);
+ impl->browse_files_last_selected_name = NULL;
- shortcuts_find_current_folder (impl);
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+ return;
+ }
- g_signal_emit_by_name (impl, "current-folder-changed", 0);
+ maybe_clear_entry:
- check_preview_change (impl);
- bookmarks_check_add_sensitivity (impl);
+ if (impl->browse_files_last_selected_name)
+ {
+ const char *entry_text;
+ int len;
+ gboolean clear_entry;
- g_signal_emit_by_name (impl, "selection-changed", 0);
+ entry_text = gtk_entry_get_text (GTK_ENTRY (impl->location_entry));
+ len = strlen (entry_text);
+ if (len != 0)
+ {
+ /* The file chooser entry may have appended a "/" to its text. So
+ * take it out, and compare the result to the old selection.
+ */
+ if (entry_text[len - 1] == G_DIR_SEPARATOR)
+ {
+ char *tmp;
- return result;
+ tmp = g_strndup (entry_text, len - 1);
+ clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, tmp) == 0);
+ g_free (tmp);
+ }
+ else
+ clear_entry = (compare_utf8_filenames (impl->browse_files_last_selected_name, entry_text) == 0);
+ }
+ else
+ clear_entry = FALSE;
+
+ if (clear_entry)
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+ }
}
-static GtkFilePath *
-gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
+static gboolean
+gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
+ const GtkFilePath *path,
+ GError **error)
{
- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
-
- return gtk_file_path_copy (impl->current_folder);
+ return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
}
+
+struct UpdateCurrentFolderData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+ gboolean keep_trail;
+ GtkFilePath *original_path;
+ GError *original_error;
+};
+
static void
-gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
- const gchar *name)
+update_current_folder_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
{
- GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+ gboolean cancelled = handle->cancelled;
+ struct UpdateCurrentFolderData *data = user_data;
+ GtkFileChooserDefault *impl = data->impl;
- g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+ if (handle != impl->update_current_folder_handle)
+ goto out;
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), name);
+ impl->update_current_folder_handle = NULL;
+ impl->reload_state = RELOAD_EMPTY;
+
+ set_busy_cursor (impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ {
+ GtkFilePath *parent_path;
+
+ if (!data->original_path)
+ {
+ data->original_path = gtk_file_path_copy (data->path);
+ data->original_error = g_error_copy (error);
+ }
+
+ /* get parent path and try to change the folder to that */
+ if (gtk_file_system_get_parent (impl->file_system, data->path, &parent_path, NULL) &&
+ parent_path != NULL)
+ {
+ gtk_file_path_free (data->path);
+ data->path = parent_path;
+
+ g_object_unref (handle);
+
+ /* restart the update current folder operation */
+ impl->reload_state = RELOAD_HAS_FOLDER;
+
+ impl->update_current_folder_handle =
+ gtk_file_system_get_info (impl->file_system, data->path,
+ GTK_FILE_INFO_IS_FOLDER,
+ update_current_folder_get_info_cb,
+ data);
+
+ set_busy_cursor (impl, TRUE);
+
+ return;
+ }
+ else
+ {
+ /* error and bail out */
+ error_changing_folder_dialog (impl, data->original_path, data->original_error);
+
+ gtk_file_path_free (data->original_path);
+
+ goto out;
+ }
+ }
+
+ if (data->original_path)
+ {
+ error_changing_folder_dialog (impl, data->original_path, data->original_error);
+
+ gtk_file_path_free (data->original_path);
+ }
+
+ if (!gtk_file_info_get_is_folder (info))
+ goto out;
+
+ if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), data->path, data->keep_trail, NULL))
+ goto out;
+
+ if (impl->current_folder != data->path)
+ {
+ if (impl->current_folder)
+ gtk_file_path_free (impl->current_folder);
+
+ impl->current_folder = gtk_file_path_copy (data->path);
+
+ impl->reload_state = RELOAD_HAS_FOLDER;
+ }
+
+ /* Update the widgets that may trigger a folder change themselves. */
+
+ if (!impl->changing_folder)
+ {
+ impl->changing_folder = TRUE;
+
+ shortcuts_update_current_folder (impl);
+
+ impl->changing_folder = FALSE;
+ }
+
+ /* Set the folder on the save entry */
+
+ if (impl->location_entry)
+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
+ impl->current_folder);
+
+ /* Create a new list model. This is slightly evil; we store the result value
+ * but perform more actions rather than returning immediately even if it
+ * generates an error.
+ */
+ set_list_model (impl, NULL);
+
+ /* Refresh controls */
+
+ shortcuts_find_current_folder (impl);
+
+ g_signal_emit_by_name (impl, "current-folder-changed", 0);
+
+ check_preview_change (impl);
+ bookmarks_check_add_sensitivity (impl);
+
+ g_signal_emit_by_name (impl, "selection-changed", 0);
+
+out:
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static gboolean
+gtk_file_chooser_default_update_current_folder (GtkFileChooser *chooser,
+ const GtkFilePath *path,
+ gboolean keep_trail,
+ GError **error)
+{
+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+ struct UpdateCurrentFolderData *data;
+
+ profile_start ("start", (char *) path);
+
+ g_assert (path != NULL);
+
+ if (impl->local_only &&
+ !gtk_file_system_path_is_local (impl->file_system, path))
+ {
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+ _("Cannot change to folder because it is not local"));
+
+ profile_end ("end - not local", (char *) path);
+ return FALSE;
+ }
+
+ if (impl->update_current_folder_handle)
+ gtk_file_system_cancel_operation (impl->update_current_folder_handle);
+
+ /* Test validity of path here. */
+ data = g_new0 (struct UpdateCurrentFolderData, 1);
+ data->impl = impl;
+ data->path = gtk_file_path_copy (path);
+ data->keep_trail = keep_trail;
+
+ impl->reload_state = RELOAD_HAS_FOLDER;
+
+ impl->update_current_folder_handle =
+ gtk_file_system_get_info (impl->file_system, path, GTK_FILE_INFO_IS_FOLDER,
+ update_current_folder_get_info_cb,
+ data);
+
+ set_busy_cursor (impl, TRUE);
+
+ profile_end ("end", NULL);
+ return TRUE;
+}
+
+static GtkFilePath *
+gtk_file_chooser_default_get_current_folder (GtkFileChooser *chooser)
+{
+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+
+ if (impl->reload_state == RELOAD_EMPTY)
+ {
+ char *current_working_dir;
+ GtkFilePath *path;
+
+ /* We are unmapped, or we had an error while loading the last folder. We'll return
+ * the $cwd since once we get (re)mapped, we'll load $cwd anyway unless the caller
+ * explicitly calls set_current_folder() on us.
+ */
+ current_working_dir = g_get_current_dir ();
+ path = gtk_file_system_filename_to_path (impl->file_system, current_working_dir);
+ g_free (current_working_dir);
+ return path;
+ }
+
+ return gtk_file_path_copy (impl->current_folder);
+}
+
+static void
+gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser,
+ const gchar *name)
+{
+ GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+
+ g_return_if_fail (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+
+ pending_select_paths_free (impl);
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name);
}
static void
if (same_path && impl->load_state == LOAD_FINISHED)
{
gboolean result;
+ GSList paths;
- result = show_and_select_paths (impl, parent_path, path, NULL, error);
+ paths.data = (gpointer) path;
+ paths.next = NULL;
+
+ result = show_and_select_paths (impl, parent_path, &paths, error);
gtk_file_path_free (parent_path);
return result;
}
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_selection_unselect_all (selection);
+ pending_select_paths_free (impl);
}
-/* Checks whether the filename entry for the Save modes contains a valid filename */
-static GtkFilePath *
+/* Checks whether the filename entry for the Save modes contains a well-formed filename.
+ *
+ * is_well_formed_ret - whether what the user typed passes gkt_file_system_make_path()
+ *
+ * is_empty_ret - whether the file entry is totally empty
+ *
+ * is_file_part_empty_ret - whether the file part is empty (will be if user types "foobar/", and
+ * the path will be "$cwd/foobar")
+ */
+static void
check_save_entry (GtkFileChooserDefault *impl,
- gboolean *is_valid,
- gboolean *is_empty)
+ GtkFilePath **path_ret,
+ gboolean *is_well_formed_ret,
+ gboolean *is_empty_ret,
+ gboolean *is_file_part_empty_ret,
+ gboolean *is_folder)
{
GtkFileChooserEntry *chooser_entry;
const GtkFilePath *current_folder;
GError *error;
g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+ || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
+
+ chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
+
+ if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0)
+ {
+ *path_ret = NULL;
+ *is_well_formed_ret = TRUE;
+ *is_empty_ret = TRUE;
+ *is_file_part_empty_ret = TRUE;
+ *is_folder = FALSE;
- chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
+ return;
+ }
+
+ *is_empty_ret = FALSE;
current_folder = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
if (!file_part || file_part[0] == '\0')
{
- *is_valid = FALSE;
- *is_empty = TRUE;
- return NULL;
+ *path_ret = gtk_file_path_copy (current_folder);
+ *is_well_formed_ret = TRUE;
+ *is_file_part_empty_ret = TRUE;
+ *is_folder = TRUE;
+
+ return;
}
- *is_empty = FALSE;
+ *is_file_part_empty_ret = FALSE;
error = NULL;
path = gtk_file_system_make_path (impl->file_system, current_folder, file_part, &error);
if (!path)
{
error_building_filename_dialog (impl, current_folder, file_part, error);
- *is_valid = FALSE;
- return NULL;
+ *path_ret = NULL;
+ *is_well_formed_ret = FALSE;
+ *is_folder = FALSE;
+
+ return;
}
- *is_valid = TRUE;
- return path;
+ *path_ret = path;
+ *is_well_formed_ret = TRUE;
+ *is_folder = _gtk_file_chooser_entry_get_is_folder (chooser_entry, path);
}
struct get_paths_closure {
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
struct get_paths_closure info;
+ GtkWindow *toplevel;
+ GtkWidget *current_focus;
info.impl = impl;
info.result = NULL;
info.path_from_entry = NULL;
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- {
- gboolean is_valid, is_empty;
-
- info.path_from_entry = check_save_entry (impl, &is_valid, &is_empty);
- if (!is_valid && !is_empty)
- return NULL;
- }
+ toplevel = get_toplevel (GTK_WIDGET (impl));
+ if (toplevel)
+ current_focus = gtk_window_get_focus (toplevel);
+ else
+ current_focus = NULL;
- if (!info.path_from_entry || impl->select_multiple)
+ if (current_focus == impl->browse_files_tree_view)
{
GtkTreeSelection *selection;
+ file_list:
+
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
+
+ /* If there is no selection in the file list, we probably have this situation:
+ *
+ * 1. The user typed a filename in the SAVE filename entry ("foo.txt").
+ * 2. He then double-clicked on a folder ("bar") in the file list
+ *
+ * So we want the selection to be "bar/foo.txt". Jump to the case for the
+ * filename entry to see if that is the case.
+ */
+ if (info.result == NULL && impl->location_entry)
+ goto file_entry;
+ }
+ else if (impl->location_entry && current_focus == impl->location_entry)
+ {
+ gboolean is_well_formed, is_empty, is_file_part_empty, is_folder;
+
+ file_entry:
+
+ check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
+
+ if (is_empty)
+ goto out;
+
+ if (!is_well_formed)
+ return NULL;
+
+ if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ gtk_file_path_free (info.path_from_entry);
+ return NULL;
+ }
+
+ g_assert (info.path_from_entry != NULL);
+ info.result = g_slist_prepend (info.result, info.path_from_entry);
+ }
+ else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
+ goto file_list;
+ else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
+ goto file_entry;
+ else
+ {
+ /* The focus is on a dialog's action area button or something else */
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ goto file_entry;
+ else
+ goto file_list;
}
- if (info.path_from_entry)
- info.result = g_slist_prepend (info.result, info.path_from_entry);
+ out:
/* If there's no folder selected, and we're in SELECT_FOLDER mode, then we
* fall back to the current directory */
if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER &&
info.result == NULL)
{
- info.result = g_slist_prepend (info.result, gtk_file_path_copy (impl->current_folder));
+ info.result = g_slist_prepend (info.result, _gtk_file_chooser_get_current_folder_path (chooser));
}
return g_slist_reverse (info.result);
return;
}
- g_object_ref (filter);
- gtk_object_sink (GTK_OBJECT (filter));
+ g_object_ref_sink (filter);
impl->filters = g_slist_append (impl->filters, filter);
name = gtk_file_filter_get_name (filter);
/* Remove row from the combo box */
model = gtk_combo_box_get_model (GTK_COMBO_BOX (impl->filter_combo));
- gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_index);
+ if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, filter_index))
+ g_assert_not_reached ();
+
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
g_object_unref (filter);
return pos + shortcuts_get_index (impl, SHORTCUTS_SHORTCUTS);
}
+struct AddShortcutData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+};
+
+static void
+add_shortcut_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ int pos;
+ gboolean cancelled = handle->cancelled;
+ struct AddShortcutData *data = user_data;
+
+ if (!g_slist_find (data->impl->loading_shortcuts, handle))
+ goto out;
+
+ data->impl->loading_shortcuts = g_slist_remove (data->impl->loading_shortcuts, handle);
+
+ if (cancelled || error || !gtk_file_info_get_is_folder (info))
+ goto out;
+
+ pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
+
+ shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
static gboolean
gtk_file_chooser_default_add_shortcut_folder (GtkFileChooser *chooser,
const GtkFilePath *path,
GError **error)
{
+ GtkFileSystemHandle *handle;
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
- gboolean result;
+ struct AddShortcutData *data;
+ GSList *l;
int pos;
- /* Test validity of path here. */
- if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
+ /* Avoid adding duplicates */
+ pos = shortcut_find_position (impl, path);
+ if (pos >= 0 && pos < shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR))
+ {
+ gchar *uri;
+
+ uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ /* translators, "Shortcut" means "Bookmark" here */
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+ _("Shortcut %s already exists"),
+ uri);
+ g_free (uri);
+
+ return FALSE;
+ }
- pos = shortcuts_get_pos_for_shortcut_folder (impl, impl->num_shortcuts);
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *h = l->data;
+ GtkFilePath *p;
- result = shortcuts_insert_path (impl, pos, FALSE, NULL, path, NULL, FALSE, error);
+ p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+ if (p && !gtk_file_path_compare (path, p))
+ {
+ gchar *uri;
- if (result)
- impl->num_shortcuts++;
+ uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+ _("Shortcut %s already exists"),
+ uri);
+ g_free (uri);
- if (impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ return FALSE;
+ }
+ }
- return result;
+ data = g_new0 (struct AddShortcutData, 1);
+ data->impl = g_object_ref (impl);
+ data->path = gtk_file_path_copy (path);
+
+ handle = gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_IS_FOLDER,
+ add_shortcut_get_info_cb, data);
+
+ if (!handle)
+ return FALSE;
+
+ impl->loading_shortcuts = g_slist_append (impl->loading_shortcuts, handle);
+ g_object_set_data (G_OBJECT (handle), "add-shortcut-path-key", data->path);
+
+ return TRUE;
}
static gboolean
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
int pos;
GtkTreeIter iter;
+ GSList *l;
char *uri;
int i;
+ for (l = impl->loading_shortcuts; l; l = l->next)
+ {
+ GtkFileSystemHandle *h = l->data;
+ GtkFilePath *p;
+
+ p = g_object_get_data (G_OBJECT (h), "add-shortcut-path-key");
+ if (p && !gtk_file_path_compare (path, p))
+ {
+ impl->loading_shortcuts = g_slist_remove (impl->loading_shortcuts, h);
+ gtk_file_system_cancel_operation (h);
+ return TRUE;
+ }
+ }
+
if (impl->num_shortcuts == 0)
goto out;
out:
uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ /* translators, "Shortcut" means "Bookmark" here */
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
change_folder_and_display_error (impl, closure.path);
}
+/* Gets the GtkFileInfo for the selected row in the file list; assumes single
+ * selection mode.
+ */
+static const GtkFileInfo *
+get_selected_file_info_from_file_list (GtkFileChooserDefault *impl,
+ gboolean *had_selection)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter, child_iter;
+ const GtkFileInfo *info;
+
+ g_assert (!impl->select_multiple);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ *had_selection = FALSE;
+ return NULL;
+ }
+
+ *had_selection = TRUE;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+ &child_iter,
+ &iter);
+
+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+ return info;
+}
+
+/* Gets the display name of the selected file in the file list; assumes single
+ * selection mode and that something is selected.
+ */
+static const gchar *
+get_display_name_from_file_list (GtkFileChooserDefault *impl)
+{
+ const GtkFileInfo *info;
+ gboolean had_selection;
+
+ info = get_selected_file_info_from_file_list (impl, &had_selection);
+ g_assert (had_selection);
+ g_assert (info != NULL);
+
+ return gtk_file_info_get_display_name (info);
+}
+
+static void
+add_custom_button_to_dialog (GtkDialog *dialog,
+ const gchar *mnemonic_label,
+ const gchar *stock_id,
+ gint response_id)
+{
+ GtkWidget *button;
+
+ button = gtk_button_new_with_mnemonic (mnemonic_label);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_button_set_image (GTK_BUTTON (button),
+ gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON));
+ gtk_widget_show (button);
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
+}
+
+/* Presents an overwrite confirmation dialog; returns whether we should accept
+ * the filename.
+ */
+static gboolean
+confirm_dialog_should_accept_filename (GtkFileChooserDefault *impl,
+ const gchar *file_part,
+ const gchar *folder_display_name)
+{
+ GtkWindow *toplevel;
+ GtkWidget *dialog;
+ int response;
+
+ toplevel = get_toplevel (GTK_WIDGET (impl));
+
+ dialog = gtk_message_dialog_new (toplevel,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("A file named \"%s\" already exists. Do you want to replace it?"),
+ file_part);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ _("The file already exists in \"%s\". Replacing it will "
+ "overwrite its contents."),
+ folder_display_name);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ add_custom_button_to_dialog (GTK_DIALOG (dialog), _("_Replace"), GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+
+ if (toplevel->group)
+ gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ gtk_widget_destroy (dialog);
+
+ return (response == GTK_RESPONSE_ACCEPT);
+}
+
+struct GetDisplayNameData
+{
+ GtkFileChooserDefault *impl;
+ gchar *file_part;
+};
+
+static void
+confirmation_confirm_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ gboolean should_respond = FALSE;
+ struct GetDisplayNameData *data = user_data;
+
+ if (handle != data->impl->should_respond_get_info_handle)
+ goto out;
+
+ data->impl->should_respond_get_info_handle = NULL;
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ /* Huh? Did the folder disappear? Let the caller deal with it */
+ should_respond = TRUE;
+ else
+ should_respond = confirm_dialog_should_accept_filename (data->impl, data->file_part, gtk_file_info_get_display_name (info));
+
+ set_busy_cursor (data->impl, FALSE);
+ if (should_respond)
+ g_signal_emit_by_name (data->impl, "response-requested");
+
+out:
+ g_object_unref (data->impl);
+ g_free (data->file_part);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+/* Does overwrite confirmation if appropriate, and returns whether the dialog
+ * should respond. Can get the file part from the file list or the save entry.
+ */
+static gboolean
+should_respond_after_confirm_overwrite (GtkFileChooserDefault *impl,
+ const gchar *file_part,
+ const GtkFilePath *parent_path)
+{
+ GtkFileChooserConfirmation conf;
+
+ if (!impl->do_overwrite_confirmation)
+ return TRUE;
+
+ conf = GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM;
+
+ g_signal_emit_by_name (impl, "confirm-overwrite", &conf);
+
+ switch (conf)
+ {
+ case GTK_FILE_CHOOSER_CONFIRMATION_CONFIRM:
+ {
+ struct GetDisplayNameData *data;
+
+ g_assert (file_part != NULL);
+
+ data = g_new0 (struct GetDisplayNameData, 1);
+ data->impl = g_object_ref (impl);
+ data->file_part = g_strdup (file_part);
+
+ if (impl->should_respond_get_info_handle)
+ gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+
+ impl->should_respond_get_info_handle =
+ gtk_file_system_get_info (impl->file_system, parent_path,
+ GTK_FILE_INFO_DISPLAY_NAME,
+ confirmation_confirm_get_info_cb,
+ data);
+ set_busy_cursor (data->impl, TRUE);
+ return FALSE;
+ }
+
+ case GTK_FILE_CHOOSER_CONFIRMATION_ACCEPT_FILENAME:
+ return TRUE;
+
+ case GTK_FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN:
+ return FALSE;
+
+ default:
+ g_assert_not_reached ();
+ return FALSE;
+ }
+}
+
+static void
+action_create_folder_cb (GtkFileSystemHandle *handle,
+ const GtkFilePath *path,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = user_data;
+
+ if (!g_slist_find (impl->pending_handles, handle))
+ goto out;
+
+ impl->pending_handles = g_slist_remove (impl->pending_handles, handle);
+
+ set_busy_cursor (impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ error_creating_folder_dialog (impl, path, g_error_copy (error));
+ else
+ g_signal_emit_by_name (impl, "response-requested");
+
+out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
+struct FileExistsData
+{
+ GtkFileChooserDefault *impl;
+ gboolean file_exists_and_is_not_folder;
+ GtkFilePath *parent_path;
+ GtkFilePath *path;
+};
+
+static void
+save_entry_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean parent_is_folder;
+ gboolean cancelled = handle->cancelled;
+ struct FileExistsData *data = user_data;
+
+ if (handle != data->impl->should_respond_get_info_handle)
+ goto out;
+
+ data->impl->should_respond_get_info_handle = NULL;
+
+ set_busy_cursor (data->impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (!info)
+ parent_is_folder = FALSE;
+ else
+ parent_is_folder = gtk_file_info_get_is_folder (info);
+
+ if (parent_is_folder)
+ {
+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ if (data->file_exists_and_is_not_folder)
+ {
+ gboolean retval;
+ const char *file_part;
+
+ file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry));
+ retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path);
+
+ if (retval)
+ g_signal_emit_by_name (data->impl, "response-requested");
+ }
+ else
+ g_signal_emit_by_name (data->impl, "response-requested");
+ }
+ else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+ {
+ GtkFileSystemHandle *handle;
+
+ g_object_ref (data->impl);
+ handle = gtk_file_system_create_folder (data->impl->file_system,
+ data->path,
+ action_create_folder_cb,
+ data->impl);
+ data->impl->pending_handles = g_slist_append (data->impl->pending_handles, handle);
+ set_busy_cursor (data->impl, TRUE);
+ }
+ }
+ else
+ {
+ /* This will display an error, which is what we want */
+ change_folder_and_display_error (data->impl, data->parent_path);
+ }
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ gtk_file_path_free (data->parent_path);
+ g_free (data);
+
+ g_object_unref (handle);
+}
+
+static void
+file_exists_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean data_ownership_taken = FALSE;
+ gboolean cancelled = handle->cancelled;
+ gboolean file_exists_and_is_not_folder;
+ struct FileExistsData *data = user_data;
+
+ if (handle != data->impl->file_exists_get_info_handle)
+ goto out;
+
+ data->impl->file_exists_get_info_handle = NULL;
+
+ set_busy_cursor (data->impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ file_exists_and_is_not_folder = info && !gtk_file_info_get_is_folder (info);
+
+ if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ /* user typed a filename; we are done */
+ g_signal_emit_by_name (data->impl, "response-requested");
+ else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+ && file_exists_and_is_not_folder)
+ {
+ /* Oops, the user typed the name of an existing path which is not
+ * a folder
+ */
+ error_creating_folder_over_existing_file_dialog (data->impl, data->path,
+ g_error_copy (error));
+ }
+ else
+ {
+ /* check that everything up to the last component exists */
+
+ data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
+ data_ownership_taken = TRUE;
+
+ if (data->impl->should_respond_get_info_handle)
+ gtk_file_system_cancel_operation (data->impl->should_respond_get_info_handle);
+
+ data->impl->should_respond_get_info_handle =
+ gtk_file_system_get_info (data->impl->file_system,
+ data->parent_path,
+ GTK_FILE_INFO_IS_FOLDER,
+ save_entry_get_info_cb,
+ data);
+ set_busy_cursor (data->impl, TRUE);
+ }
+
+out:
+ if (!data_ownership_taken)
+ {
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ gtk_file_path_free (data->parent_path);
+ g_free (data);
+ }
+
+ g_object_unref (handle);
+}
+
+static void
+paste_text_received (GtkClipboard *clipboard,
+ const gchar *text,
+ GtkFileChooserDefault *impl)
+{
+ GtkFilePath *path;
+
+ if (!text)
+ return;
+
+ path = gtk_file_system_uri_to_path (impl->file_system, text);
+ if (!path)
+ {
+ if (!g_path_is_absolute (text))
+ {
+ location_popup_handler (impl, text);
+ return;
+ }
+
+ path = gtk_file_system_filename_to_path (impl->file_system, text);
+ if (!path)
+ {
+ location_popup_handler (impl, text);
+ return;
+ }
+ }
+
+ if (!gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (impl), path, NULL))
+ location_popup_handler (impl, text);
+
+ gtk_file_path_free (path);
+}
+
+/* Handler for the "location-popup-on-paste" keybinding signal */
+static void
+location_popup_on_paste_handler (GtkFileChooserDefault *impl)
+{
+ GtkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (impl),
+ GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_request_text (clipboard,
+ (GtkClipboardTextReceivedFunc) paste_text_received,
+ impl);
+}
+
+
/* Implementation for GtkFileChooserEmbed::should_respond() */
static gboolean
gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
if (current_focus == impl->browse_files_tree_view)
{
+ /* The following array encodes what we do based on the impl->action and the
+ * number of files selected.
+ */
+ typedef enum {
+ NOOP, /* Do nothing (don't respond) */
+ RESPOND, /* Respond immediately */
+ RESPOND_OR_SWITCH, /* Respond immediately if the selected item is a file; switch to it if it is a folder */
+ ALL_FILES, /* Respond only if everything selected is a file */
+ ALL_FOLDERS, /* Respond only if everything selected is a folder */
+ SAVE_ENTRY, /* Go to the code for handling the save entry */
+ NOT_REACHED /* Sanity check */
+ } ActionToTake;
+ static const ActionToTake what_to_do[4][3] = {
+ /* 0 selected 1 selected many selected */
+ /* ACTION_OPEN */ { NOOP, RESPOND_OR_SWITCH, ALL_FILES },
+ /* ACTION_SAVE */ { SAVE_ENTRY, RESPOND_OR_SWITCH, NOT_REACHED },
+ /* ACTION_SELECT_FOLDER */ { RESPOND, ALL_FOLDERS, ALL_FOLDERS },
+ /* ACTION_CREATE_FOLDER */ { SAVE_ENTRY, ALL_FOLDERS, NOT_REACHED }
+ };
+
int num_selected;
gboolean all_files, all_folders;
+ int k;
+ ActionToTake action;
file_list:
+ g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+
selection_check (impl, &num_selected, &all_files, &all_folders);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ if (num_selected > 2)
+ k = 2;
+ else
+ k = num_selected;
+
+ action = what_to_do [impl->action] [k];
+
+ switch (action)
{
- if (num_selected != 1)
- return TRUE; /* zero means current folder; more than one means use the whole selection */
- else if (current_focus != impl->browse_files_tree_view)
+ case NOOP:
+ return FALSE;
+
+ case RESPOND:
+ return TRUE;
+
+ case RESPOND_OR_SWITCH:
+ g_assert (num_selected == 1);
+
+ if (all_folders)
{
- /* a single folder is selected and a button was clicked */
- switch_to_selected_folder (impl);
- return TRUE;
+ switch_to_selected_folder (impl);
+ return FALSE;
}
- }
-
- if (num_selected == 0)
- {
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- goto save_entry; /* it makes sense to use the typed name */
+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ return should_respond_after_confirm_overwrite (impl,
+ get_display_name_from_file_list (impl),
+ impl->current_folder);
else
- return FALSE;
- }
+ return TRUE;
- if (num_selected == 1 && all_folders)
- {
- switch_to_selected_folder (impl);
- return FALSE;
+ case ALL_FILES:
+ return all_files;
+
+ case ALL_FOLDERS:
+ return all_folders;
+
+ case SAVE_ENTRY:
+ goto save_entry;
+
+ default:
+ g_assert_not_reached ();
}
- else
- return all_files;
}
- else if (current_focus == impl->save_file_name_entry)
+ else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry))
{
GtkFilePath *path;
- gboolean is_valid, is_empty;
+ gboolean is_well_formed, is_empty, is_file_part_empty;
gboolean is_folder;
gboolean retval;
- GtkFileChooserEntry *entry;
+ GtkFileChooserEntry *entry;
+ GError *error;
save_entry:
g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+ || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY));
- entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
- path = check_save_entry (impl, &is_valid, &is_empty);
+ entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry);
+ check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
- if (!is_empty && !is_valid)
+ if (is_empty || !is_well_formed)
return FALSE;
- if (is_empty)
- path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
-
- is_folder = check_is_folder (impl->file_system, path, NULL);
+ g_assert (path != NULL);
+
+ error = NULL;
if (is_folder)
{
- _gtk_file_chooser_entry_set_file_part (entry, "");
- change_folder_and_display_error (impl, path);
- retval = FALSE;
- }
- else
- {
- /* check that everything up to the last component exists */
- gtk_file_path_free (path);
- path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
- is_folder = check_is_folder (impl->file_system, path, NULL);
- if (!is_folder)
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
{
+ _gtk_file_chooser_entry_set_file_part (entry, "");
change_folder_and_display_error (impl, path);
retval = FALSE;
}
+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
+ || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ {
+ /* The folder already exists, so we do not need to create it.
+ * Just respond to terminate the dialog.
+ */
+ retval = TRUE;
+ }
else
- retval = TRUE;
+ {
+ g_assert_not_reached ();
+ retval = FALSE;
+ }
+ }
+ else
+ {
+ struct FileExistsData *data;
+
+ /* We need to check whether path exists and is not a folder */
+
+ data = g_new0 (struct FileExistsData, 1);
+ data->impl = g_object_ref (impl);
+ data->path = gtk_file_path_copy (path);
+ data->parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+
+ if (impl->file_exists_get_info_handle)
+ gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
+
+ impl->file_exists_get_info_handle =
+ gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_IS_FOLDER,
+ file_exists_get_info_cb,
+ data);
+
+ set_busy_cursor (impl, TRUE);
+ retval = FALSE;
+
+ if (error != NULL)
+ g_error_free (error);
}
gtk_file_path_free (path);
*/
goto file_list;
}
+ else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
+ {
+ /* The focus is on a dialog's action area button, *and* the widget that
+ * was focused immediately before it is the location entry.
+ */
+ goto save_entry;
+ }
else
/* The focus is on a dialog's action area button or something else */
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
|| impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
- widget = impl->browse_files_tree_view;
+ {
+ if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+ widget = impl->browse_files_tree_view;
+ else
+ widget = impl->location_entry;
+ }
else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- widget = impl->save_file_name_entry;
+ widget = impl->location_entry;
else
{
g_assert_not_reached ();
widget = NULL;
}
+ g_assert (widget != NULL);
gtk_widget_grab_focus (widget);
}
impl->current_filter = filter;
if (impl->current_filter)
{
- g_object_ref (impl->current_filter);
- gtk_object_sink (GTK_OBJECT (filter));
+ g_object_ref_sink (impl->current_filter);
}
if (impl->filters)
GtkTreeIter iter;
GtkTreeIter child_iter;
- gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
+ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path))
+ g_assert_not_reached ();
+
gtk_tree_path_free (cursor_path);
gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
}
}
+static void
+shortcuts_activate_volume_mount_cb (GtkFileSystemHandle *handle,
+ GtkFileSystemVolume *volume,
+ const GError *error,
+ gpointer data)
+{
+ GtkFilePath *path;
+ gboolean cancelled = handle->cancelled;
+ GtkFileChooserDefault *impl = data;
+
+ if (handle != impl->shortcuts_activate_iter_handle)
+ goto out;
+
+ impl->shortcuts_activate_iter_handle = NULL;
+
+ set_busy_cursor (impl, FALSE);
+
+ if (cancelled)
+ goto out;
+
+ if (error)
+ {
+ char *msg;
+
+ msg = g_strdup_printf (_("Could not mount %s"),
+ gtk_file_system_volume_get_display_name (impl->file_system, volume));
+ error_message (impl, msg, error->message);
+ g_free (msg);
+
+ goto out;
+ }
+
+ path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ if (path != NULL)
+ {
+ change_folder_and_display_error (impl, path);
+ gtk_file_path_free (path);
+ }
+
+out:
+ g_object_unref (impl);
+ g_object_unref (handle);
+}
+
+
/* Activates a volume by mounting it if necessary and then switching to its
* base path.
*/
if (!gtk_file_system_volume_get_is_mounted (impl->file_system, volume))
{
- GError *error;
- gboolean result;
-
set_busy_cursor (impl, TRUE);
- error = NULL;
- result = gtk_file_system_volume_mount (impl->file_system, volume, &error);
+ impl->shortcuts_activate_iter_handle =
+ gtk_file_system_volume_mount (impl->file_system, volume,
+ shortcuts_activate_volume_mount_cb,
+ g_object_ref (impl));
+ }
+ else
+ {
+ path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
+ if (path != NULL)
+ {
+ change_folder_and_display_error (impl, path);
+ gtk_file_path_free (path);
+ }
+ }
- if (!result)
- {
- char *msg;
+ g_object_unref (impl);
+}
- msg = g_strdup_printf (_("Could not mount %s"),
- gtk_file_system_volume_get_display_name (impl->file_system, volume));
- error_message (impl, msg, error->message);
- g_free (msg);
- g_error_free (error);
- }
+/* Opens the folder or volume at the specified iter in the shortcuts model */
+struct ShortcutsActivateData
+{
+ GtkFileChooserDefault *impl;
+ GtkFilePath *path;
+};
- set_busy_cursor (impl, FALSE);
+static void
+shortcuts_activate_get_info_cb (GtkFileSystemHandle *handle,
+ const GtkFileInfo *info,
+ const GError *error,
+ gpointer user_data)
+{
+ gboolean cancelled = handle->cancelled;
+ struct ShortcutsActivateData *data = user_data;
- if (!result)
- goto out;
- }
+ if (handle != data->impl->shortcuts_activate_iter_handle)
+ goto out;
- path = gtk_file_system_volume_get_base_path (impl->file_system, volume);
- change_folder_and_display_error (impl, path);
- gtk_file_path_free (path);
+ data->impl->shortcuts_activate_iter_handle = NULL;
- out:
+ if (cancelled)
+ goto out;
- g_object_unref (impl);
+ if (!error && gtk_file_info_get_is_folder (info))
+ change_folder_and_display_error (data->impl, data->path);
+ else
+ gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl), data->path, NULL);
+
+out:
+ g_object_unref (data->impl);
+ gtk_file_path_free (data->path);
+ g_free (data);
+
+ g_object_unref (handle);
}
-/* Opens the folder or volume at the specified iter in the shortcuts model */
static void
shortcuts_activate_iter (GtkFileChooserDefault *impl,
GtkTreeIter *iter)
gpointer col_data;
gboolean is_volume;
+ if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY && impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
SHORTCUTS_COL_DATA, &col_data,
SHORTCUTS_COL_IS_VOLUME, &is_volume,
if (!col_data)
return; /* We are on a separator */
+ if (impl->shortcuts_activate_iter_handle)
+ {
+ gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
+ impl->shortcuts_activate_iter_handle = NULL;
+ }
+
if (is_volume)
{
GtkFileSystemVolume *volume;
}
else
{
- const GtkFilePath *file_path;
+ struct ShortcutsActivateData *data;
- file_path = col_data;
- change_folder_and_display_error (impl, file_path);
+ data = g_new0 (struct ShortcutsActivateData, 1);
+ data->impl = g_object_ref (impl);
+ data->path = gtk_file_path_copy (col_data);
+
+ impl->shortcuts_activate_iter_handle =
+ gtk_file_system_get_info (impl->file_system, data->path,
+ GTK_FILE_INFO_IS_FOLDER,
+ shortcuts_activate_get_info_cb, data);
}
}
return TRUE;
}
+ if ((event->keyval == GDK_F2)
+ && (event->state & modifiers) == 0)
+ {
+ rename_selected_bookmark (impl);
+ return TRUE;
+ }
+
return FALSE;
}
/* See if we are in the new folder editable row for Save mode */
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
{
- GtkTreeSelection *selection;
- GtkTreeIter iter, child_iter;
const GtkFileInfo *info;
+ gboolean had_selection;
- g_assert (!impl->select_multiple);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
- if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
- return;
-
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- &iter);
+ info = get_selected_file_info_from_file_list (impl, &had_selection);
+ if (!had_selection)
+ goto out; /* normal processing */
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
if (!info)
return; /* We are on the editable row for New Folder */
}
+ out:
+
update_chooser_entry (impl);
check_preview_change (impl);
bookmarks_check_add_sensitivity (impl);
static void
path_bar_clicked (GtkPathBar *path_bar,
GtkFilePath *file_path,
+ GtkFilePath *child_path,
gboolean child_is_hidden,
GtkFileChooserDefault *impl)
{
+ if (child_path)
+ pending_select_paths_add (impl, child_path);
+
if (!change_folder_and_display_error (impl, file_path))
return;
GdkPixbuf *pixbuf;
const GtkFileInfo *info;
gboolean sensitive = TRUE;
+
+ profile_start ("start", NULL);
info = get_list_file_info (impl, iter);
if (path)
{
- /* FIXME: NULL GError */
- pixbuf = gtk_file_system_render_icon (impl->file_system, path, GTK_WIDGET (impl),
- impl->icon_size, NULL);
+ pixbuf = NULL;
+
+ if (info)
+ {
+ /* FIXME: NULL GError */
+ pixbuf = gtk_file_info_render_icon (info, GTK_WIDGET (impl),
+ impl->icon_size, NULL);
+ }
}
else
{
if (pixbuf)
g_object_unref (pixbuf);
+
+ profile_end ("end", NULL);
}
static void
if (!info || gtk_file_info_get_is_folder (info))
{
- g_object_set (cell,"sensitive", sensitive, NULL);
+ g_object_set (cell,
+ "text", NULL,
+ "sensitive", sensitive,
+ NULL);
return;
}
size = gtk_file_info_get_size (info);
-
+#if 0
if (size < (gint64)1024)
str = g_strdup_printf (ngettext ("%d byte", "%d bytes", (gint)size), (gint)size);
else if (size < (gint64)1024*1024)
- str = g_strdup_printf (_("%.1f K"), size / (1024.));
+ str = g_strdup_printf (_("%.1f KB"), size / (1024.));
else if (size < (gint64)1024*1024*1024)
- str = g_strdup_printf (_("%.1f M"), size / (1024.*1024.));
+ str = g_strdup_printf (_("%.1f MB"), size / (1024.*1024.));
else
- str = g_strdup_printf (_("%.1f G"), size / (1024.*1024.*1024.));
-
+ str = g_strdup_printf (_("%.1f GB"), size / (1024.*1024.*1024.));
+#endif
+ str = g_strdup_printf ("%" G_GINT64_FORMAT, size);
if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
sensitive = FALSE;
g_object_set (cell,
"text", str,
"sensitive", sensitive,
+ "alignment", PANGO_ALIGN_RIGHT,
NULL);
g_free (str);
{
GtkFileChooserDefault *impl;
const GtkFileInfo *info;
- GtkFileTime time_mtime, time_now;
+ GtkFileTime time_mtime;
GDate mtime, now;
int days_diff;
char buf[256];
}
time_mtime = gtk_file_info_get_modification_time (info);
- g_date_set_time (&mtime, (GTime) time_mtime);
-
- time_now = (GTime ) time (NULL);
- g_date_set_time (&now, (GTime) time_now);
- days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
-
- if (days_diff == 0)
- strcpy (buf, _("Today"));
- else if (days_diff == 1)
- strcpy (buf, _("Yesterday"));
+ if (time_mtime == 0)
+ strcpy (buf, _("Unknown"));
else
{
- char *format;
+ time_t time_now;
+ g_date_set_time_t (&mtime, time_mtime);
+ time_now = time (NULL);
+ g_date_set_time_t (&now, time_now);
+
+ days_diff = g_date_get_julian (&now) - g_date_get_julian (&mtime);
- if (days_diff > 1 && days_diff < 7)
- format = "%A"; /* Days from last week */
+ if (days_diff == 0)
+ strcpy (buf, _("Today"));
+ else if (days_diff == 1)
+ strcpy (buf, _("Yesterday"));
else
- format = "%x"; /* Any other date */
+ {
+ char *format;
+
+ if (days_diff > 1 && days_diff < 7)
+ format = "%A"; /* Days from last week */
+ else
+ format = "%x"; /* Any other date */
- if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
- strcpy (buf, _("Unknown"));
+ if (g_date_strftime (buf, sizeof (buf), format, &mtime) == 0)
+ strcpy (buf, _("Unknown"));
+ }
}
if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
NULL);
}
-static GtkWidget *
-location_entry_create (GtkFileChooserDefault *impl,
- const gchar *path)
-{
- GtkWidget *entry;
-
- entry = _gtk_file_chooser_entry_new (TRUE);
- /* Pick a good width for the entry */
- gtk_entry_set_width_chars (GTK_ENTRY (entry), 30);
- gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
- _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (entry), impl->file_system);
- _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (entry), impl->action);
- if (path[0])
- {
- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry),
- gtk_file_path_new_steal ((gchar *)path));
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), path);
- }
- else
- {
- _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), "");
- else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry),
- gtk_entry_get_text (GTK_ENTRY (impl->save_file_name_entry)));
- else
- g_assert_not_reached ();
- }
-
- return GTK_WIDGET (entry);
-}
-
-static gboolean
-update_from_entry (GtkFileChooserDefault *impl,
- GtkWindow *parent,
- GtkFileChooserEntry *chooser_entry)
+static void
+location_set_user_text (GtkFileChooserDefault *impl,
+ const gchar *path)
{
- const GtkFilePath *folder_path;
- const char *file_part;
-
- folder_path = _gtk_file_chooser_entry_get_current_folder (chooser_entry);
- file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry);
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path)
- {
- error_message_with_parent (parent,
- _("Cannot change folder"),
- _("The folder you specified is an invalid path."));
- return FALSE;
- }
-
- if (file_part[0] == '\0')
- return change_folder_and_display_error (impl, folder_path);
- else
- {
- GtkFileFolder *folder = NULL;
- GtkFilePath *subfolder_path = NULL;
- GtkFileInfo *info = NULL;
- GError *error;
- gboolean result;
-
- result = FALSE;
-
- /* If the file part is non-empty, we need to figure out if it refers to a
- * folder within folder. We could optimize the case here where the folder
- * is already loaded for one of our tree models.
- */
-
- error = NULL;
- folder = gtk_file_system_get_folder (impl->file_system, folder_path, GTK_FILE_INFO_IS_FOLDER, &error);
-
- if (!folder)
- {
- error_getting_info_dialog (impl, folder_path, error);
- goto out;
- }
-
- error = NULL;
- subfolder_path = gtk_file_system_make_path (impl->file_system, folder_path, file_part, &error);
-
- if (!subfolder_path)
- {
- char *msg;
- char *uri;
-
- uri = gtk_file_system_path_to_uri (impl->file_system, folder_path);
- msg = g_strdup_printf (_("Could not build file name from '%s' and '%s'"),
- uri, file_part);
- error_message (impl, msg, error->message);
- g_free (uri);
- g_free (msg);
- goto out;
- }
-
- error = NULL;
- info = gtk_file_folder_get_info (folder, subfolder_path, &error);
-
- if (!info)
- {
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- {
- if (!change_folder_and_display_error (impl, folder_path))
- goto out;
-
- gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (impl), file_part);
- }
- else
- error_getting_info_dialog (impl, subfolder_path, error);
-
- goto out;
- }
-
- if (gtk_file_info_get_is_folder (info))
- result = change_folder_and_display_error (impl, subfolder_path);
- else
- {
- GError *error;
-
- error = NULL;
- result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error);
- if (!result)
- error_dialog (impl, _("Could not select item"),
- subfolder_path, error);
- }
-
- out:
-
- if (folder)
- g_object_unref (folder);
-
- gtk_file_path_free (subfolder_path);
-
- if (info)
- gtk_file_info_free (info);
-
- return result;
- }
-
- g_assert_not_reached ();
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), path);
+ gtk_editable_set_position (GTK_EDITABLE (impl->location_entry), -1);
}
static void
location_popup_handler (GtkFileChooserDefault *impl,
const gchar *path)
{
- GtkWidget *dialog;
- GtkWindow *toplevel;
- GtkWidget *hbox;
- GtkWidget *label;
- GtkWidget *entry;
- gboolean refocus;
- const char *title;
- const char *accept_stock;
-
- /* Create dialog */
-
- toplevel = get_toplevel (GTK_WIDGET (impl));
-
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
|| impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
{
- title = _("Open Location");
- accept_stock = GTK_STOCK_OPEN;
- }
- else
- {
- g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
- title = _("Save in Location");
- accept_stock = GTK_STOCK_SAVE;
- }
-
- dialog = gtk_dialog_new_with_buttons (title,
- toplevel,
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- accept_stock, GTK_RESPONSE_ACCEPT,
- NULL);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1);
- gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
- gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
- gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-
- gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
- GTK_RESPONSE_ACCEPT,
- GTK_RESPONSE_CANCEL,
- -1);
-
- hbox = gtk_hbox_new (FALSE, 12);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
-
- label = gtk_label_new_with_mnemonic (_("_Location:"));
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-
- entry = location_entry_create (impl, path);
+ LocationMode new_mode;
- gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
-
- /* Run */
-
- gtk_widget_show_all (dialog);
- /* If the dialog is brought up by typing the first characters
- * of a path, unselect the text in the entry, so that you can
- * just type on without erasing the initial part.
- */
- if (path[0])
- gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1);
-
- refocus = TRUE;
+ if (path != NULL)
+ {
+ /* since the user typed something, we unconditionally want to turn on the entry */
+ new_mode = LOCATION_MODE_FILENAME_ENTRY;
+ }
+ else if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+ new_mode = LOCATION_MODE_FILENAME_ENTRY;
+ else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+ new_mode = LOCATION_MODE_PATH_BAR;
+ else
+ {
+ g_assert_not_reached ();
+ return;
+ }
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
- {
- if (update_from_entry (impl, GTK_WINDOW (dialog), GTK_FILE_CHOOSER_ENTRY (entry)))
+ location_mode_set (impl, new_mode, TRUE);
+ if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
{
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
- {
- gtk_widget_grab_focus (impl->browse_files_tree_view);
- }
+ if (path != NULL)
+ location_set_user_text (impl, path);
else
{
- g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
- gtk_widget_grab_focus (impl->save_file_name_entry);
+ location_entry_set_initial_text (impl);
+ gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
}
- refocus = FALSE;
}
}
-
- if (refocus)
+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
- GtkWindow *toplevel;
-
- toplevel = get_toplevel (GTK_WIDGET (impl));
- if (toplevel && toplevel->focus_widget)
- gtk_widget_grab_focus (toplevel->focus_widget);
+ gtk_widget_grab_focus (impl->location_entry);
+ if (path != NULL)
+ location_set_user_text (impl, path);
}
-
- gtk_widget_destroy (dialog);
+ else
+ g_assert_not_reached ();
}
/* Handler for the "up-folder" keybinding signal */
static void
up_folder_handler (GtkFileChooserDefault *impl)
{
- pending_select_paths_add (impl, impl->current_folder);
_gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
}
_gtk_path_bar_down (GTK_PATH_BAR (impl->browse_path_bar));
}
-/* Handler for the "home-folder" keybinding signal */
+/* Switches to the shortcut in the specified index */
static void
-home_folder_handler (GtkFileChooserDefault *impl)
+switch_to_shortcut (GtkFileChooserDefault *impl,
+ int pos)
{
- int pos;
GtkTreeIter iter;
- if (!impl->has_home)
- return; /* Should we put up an error dialog? */
-
- pos = shortcuts_get_index (impl, SHORTCUTS_HOME);
if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (impl->shortcuts_model), &iter, NULL, pos))
g_assert_not_reached ();
shortcuts_activate_iter (impl, &iter);
}
+/* Handler for the "home-folder" keybinding signal */
+static void
+home_folder_handler (GtkFileChooserDefault *impl)
+{
+ if (impl->has_home)
+ switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_HOME));
+}
+
+/* Handler for the "desktop-folder" keybinding signal */
+static void
+desktop_folder_handler (GtkFileChooserDefault *impl)
+{
+ if (impl->has_desktop)
+ switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_DESKTOP));
+}
+
+static void
+quick_bookmark_handler (GtkFileChooserDefault *impl,
+ gint bookmark_index)
+{
+ int bookmark_pos;
+ GtkTreePath *path;
+
+ if (bookmark_index < 0 || bookmark_index >= impl->num_bookmarks)
+ return;
+
+ bookmark_pos = shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS) + bookmark_index;
+
+ path = gtk_tree_path_new_from_indices (bookmark_pos, -1);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
+ path, NULL,
+ FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+
+ switch_to_shortcut (impl, bookmark_pos);
+}
+
\f
/* Drag and drop interfaces */
ShortcutsModelFilter *model;
model = g_object_new (SHORTCUTS_MODEL_FILTER_TYPE,
- "child_model", child_model,
- "virtual_root", root,
+ "child-model", child_model,
+ "virtual-root", root,
NULL);
model->impl = impl;