#include <config.h>
#include "gdk/gdkkeysyms.h"
-#include "gtkalias.h"
#include "gtkalignment.h"
#include "gtkbindings.h"
#include "gtkbutton.h"
#include "gtkfilesystemwin32.h"
#endif
+#include "gtkalias.h"
+
#include <errno.h>
#include <string.h>
#include <time.h>
+\f
+
+/* Profiling stuff */
+
+#define PROFILE_FILE_CHOOSER
+#ifdef PROFILE_FILE_CHOOSER
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+
+#define PROFILE_INDENT 4
+static int profile_indent;
+
+static void
+profile_add_indent (int indent)
+{
+ profile_indent += indent;
+ if (profile_indent < 0)
+ g_error ("You screwed up your indentation");
+}
+
+void
+_gtk_file_chooser_profile_log (const char *func, int indent, const char *msg1, const char *msg2)
+{
+ char *str;
+
+ if (indent < 0)
+ profile_add_indent (indent);
+
+ if (profile_indent == 0)
+ str = g_strdup_printf ("MARK: %s %s %s", func, msg1 ? msg1 : "", msg2 ? msg2 : "");
+ else
+ str = g_strdup_printf ("MARK: %*c %s %s %s", profile_indent - 1, ' ', func, msg1 ? msg1 : "", msg2 ? msg2 : "");
+
+ access (str, F_OK);
+ g_free (str);
+
+ if (indent > 0)
+ profile_add_indent (indent);
+}
+
+#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
+
+\f
+
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_FILE_CHOOSER_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_CHOOSER_DEFAULT, GtkFileChooserDefaultClass))
typedef enum {
- LOAD_LOADING,
- LOAD_FINISHED
+ 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
GtkVBoxClass parent_class;
};
-typedef enum {
- PENDING_OP_NONE,
- PENDING_OP_SELECT_PATH,
- PENDING_OP_SELECT_FIRST
-} PendingOp;
-
struct _GtkFileChooserDefault
{
GtkVBox parent_instance;
GtkWidget *browse_shortcuts_tree_view;
GtkWidget *browse_shortcuts_add_button;
GtkWidget *browse_shortcuts_remove_button;
+ GtkWidget *browse_shortcuts_popup_menu;
+ GtkWidget *browse_shortcuts_popup_menu_remove_item;
+ GtkWidget *browse_shortcuts_popup_menu_rename_item;
GtkWidget *browse_files_tree_view;
GtkWidget *browse_files_popup_menu;
GtkWidget *browse_files_popup_menu_add_shortcut_item;
LoadState load_state;
guint load_timeout_id;
- PendingOp pending_op;
- GtkFilePath *pending_select_path;
+ GSList *pending_select_paths;
GtkFileFilter *current_filter;
GSList *filters;
guint use_preview_label : 1;
guint select_multiple : 1;
guint show_hidden : 1;
+ guint do_overwrite_confirmation : 1;
guint list_sort_ascending : 1;
guint changing_folder : 1;
guint shortcuts_current_folder_active : 1;
};
/* 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,
} ShortcutsIndex;
/* Icon size for if we can't get it from the theme */
-#define FALLBACK_ICON_SIZE 20
+#define FALLBACK_ICON_SIZE 16
#define PREVIEW_HBOX_SPACING 12
#define NUM_LINES 40
GParamSpec *pspec);
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_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);
GtkTreePath *path,
gboolean path_currently_selected,
gpointer data);
+static gboolean shortcuts_get_selected (GtkFileChooserDefault *impl,
+ GtkTreeIter *iter);
static void shortcuts_activate_iter (GtkFileChooserDefault *impl,
GtkTreeIter *iter);
static int shortcuts_get_index (GtkFileChooserDefault *impl,
GtkTreeIter *iter);
static void load_remove_timer (GtkFileChooserDefault *impl);
+static void browse_files_center_selected_row (GtkFileChooserDefault *impl);
static GObjectClass *parent_class;
gobject_class->dispose = gtk_file_chooser_default_dispose;
widget_class->show_all = gtk_file_chooser_default_show_all;
+ widget_class->map = gtk_file_chooser_default_map;
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;
P_("Default file chooser backend"),
P_("Name of the GtkFileChooser backend to use by default"),
NULL,
- G_PARAM_READWRITE));
+ GTK_PARAM_READWRITE));
}
static void
static void
gtk_file_chooser_default_init (GtkFileChooserDefault *impl)
{
+ profile_start ("start", NULL);
+
impl->local_only = TRUE;
impl->preview_widget_active = TRUE;
impl->use_preview_label = TRUE;
impl->select_multiple = FALSE;
impl->show_hidden = FALSE;
impl->icon_size = FALLBACK_ICON_SIZE;
- impl->load_state = LOAD_FINISHED;
- impl->pending_op = PENDING_OP_NONE;
- impl->pending_select_path = NULL;
+ impl->load_state = LOAD_EMPTY;
+ impl->pending_select_paths = NULL;
- 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));
+
+ profile_end ("end", NULL);
}
/* Frees the data columns for the specified iter in the shortcuts model*/
impl->shortcuts_model = NULL;
}
+static void
+pending_select_paths_free (GtkFileChooserDefault *impl)
+{
+ GSList *l;
+
+ for (l = impl->pending_select_paths; l; l = l->next)
+ {
+ GtkFilePath *path;
+
+ path = l->data;
+ gtk_file_path_free (path);
+ }
+
+ g_slist_free (impl->pending_select_paths);
+ impl->pending_select_paths = NULL;
+}
+
+static void
+pending_select_paths_add (GtkFileChooserDefault *impl,
+ const GtkFilePath *path)
+{
+ impl->pending_select_paths = g_slist_prepend (impl->pending_select_paths, gtk_file_path_copy (path));
+}
+
+/* Used from gtk_tree_selection_selected_foreach() */
+static void
+store_selection_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+ GtkTreeIter child_iter;
+ const GtkFilePath *file_path;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, iter);
+
+ file_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+ pending_select_paths_add (impl, file_path);
+}
+
+/* Stores the current selection in the list of paths to select; this is used to
+ * preserve the selection when reloading the current folder.
+ */
+static void
+pending_select_paths_store_selection (GtkFileChooserDefault *impl)
+{
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ gtk_tree_selection_selected_foreach (selection, store_selection_foreach, impl);
+}
+
static void
gtk_file_chooser_default_finalize (GObject *object)
{
if (impl->preview_path)
gtk_file_path_free (impl->preview_path);
- if (impl->pending_op == PENDING_OP_SELECT_PATH)
- {
- g_assert (impl->pending_select_path != NULL);
- gtk_file_path_free (impl->pending_select_path);
- }
+ pending_select_paths_free (impl);
load_remove_timer (impl);
/* Shows an error dialog set as transient for the specified window */
static void
error_message_with_parent (GtkWindow *parent,
- const char *msg)
+ const char *msg,
+ const char *detail)
{
GtkWidget *dialog;
GTK_BUTTONS_OK,
"%s",
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);
}
/* Shows an error dialog for the file chooser */
static void
error_message (GtkFileChooserDefault *impl,
- const char *msg)
+ const char *msg,
+ const char *detail)
{
- error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg);
+ error_message_with_parent (get_toplevel (GTK_WIDGET (impl)), msg, detail);
}
/* Shows a simple error dialog relative to a path. Frees the GError as well. */
const GtkFilePath *path,
GError *error)
{
- g_return_if_fail (path != NULL);
-
if (error)
{
- char *uri = gtk_file_system_path_to_uri (impl->file_system, path);
- char *text = g_strdup_printf (msg,
- uri,
- error->message);
- error_message (impl, text);
+ char *uri = NULL;
+ char *text;
+
+ if (path)
+ uri = gtk_file_system_path_to_uri (impl->file_system, path);
+ text = g_strdup_printf (msg, uri);
+ error_message (impl, text, error->message);
g_free (text);
g_free (uri);
g_error_free (error);
GError *error)
{
error_dialog (impl,
- _("Could not retrieve information about %s:\n%s"),
+ _("Could not retrieve information about the file"),
path, error);
}
/* Shows an error dialog about not being able to add a bookmark */
static void
-error_could_not_add_bookmark_dialog (GtkFileChooserDefault *impl,
- const GtkFilePath *path,
- GError *error)
+error_adding_bookmark_dialog (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GError *error)
+{
+ error_dialog (impl,
+ _("Could not add a bookmark"),
+ path, error);
+}
+
+/* Shows an error dialog about not being able to remove a bookmark */
+static void
+error_removing_bookmark_dialog (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GError *error)
+{
+ error_dialog (impl,
+ _("Could not remove bookmark"),
+ path, error);
+}
+
+/* Shows an error dialog about not being able to create a folder */
+static void
+error_creating_folder_dialog (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GError *error)
+{
+ error_dialog (impl,
+ _("The folder could not be created"),
+ 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,
- _("Could not add a bookmark for %s:\n%s"),
+ _("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 compose a filename */
+/* Shows an error dialog about not being able to create a filename */
static void
error_building_filename_dialog (GtkFileChooserDefault *impl,
- const GtkFilePath *base_path,
+ const GtkFilePath *folder_part,
const char *file_part,
GError *error)
{
- char *uri;
- char *msg;
-
- uri = gtk_file_system_path_to_uri (impl->file_system, base_path);
- msg = g_strdup_printf (_("Could not build file name from '%s' and '%s':\n%s"),
- uri, file_part,
- error->message);
- error_message (impl, msg);
- g_free (uri);
- g_free (msg);
- g_error_free (error);
+ error_dialog (impl, _("Invalid file name"),
+ NULL, error);
}
/* Shows an error dialog when we cannot switch to a folder */
const GtkFilePath *path,
GError *error)
{
- error_dialog (impl,
- _("Could not change the current folder to %s:\n%s"),
- path,
- error);
+ error_dialog (impl, _("The folder contents could not be displayed"),
+ path, error);
}
/* Changes folders, displaying an error dialog if this fails */
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);
}
}
{
GtkTreeIter iter;
+ profile_start ("start", NULL);
+
if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->shortcuts_model), &iter))
- return;
+ goto out;
do {
gpointer data;
g_object_unref (pixbuf);
}
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->shortcuts_model),&iter));
+
+ out:
+
+ profile_end ("end", NULL);
}
-/* If a shortcut corresponds to the current folder, selects it */
-static void
-shortcuts_find_current_folder (GtkFileChooserDefault *impl)
+static void
+shortcuts_find_folder (GtkFileChooserDefault *impl,
+ GtkFilePath *folder)
{
GtkTreeSelection *selection;
int pos;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
- pos = shortcut_find_position (impl, impl->current_folder);
+ g_assert (folder != NULL);
+ pos = shortcut_find_position (impl, folder);
if (pos == -1)
{
gtk_tree_selection_unselect_all (selection);
gtk_tree_path_free (path);
}
+/* If a shortcut corresponds to the current folder, selects it */
+static void
+shortcuts_find_current_folder (GtkFileChooserDefault *impl)
+{
+ 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)
+get_file_info (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ gboolean name_only,
+ GError **error)
{
GtkFilePath *parent_path;
GtkFileFolder *parent_folder;
GtkFileInfo *info;
+ GError *tmp = NULL;
+ profile_start ("start", (char *) path);
+
+ parent_path = NULL;
info = NULL;
- if (!gtk_file_system_get_parent (file_system, path, &parent_path, error))
- return NULL;
+ if (!gtk_file_system_get_parent (file_system, path, &parent_path, &tmp))
+ goto out;
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),
- error);
+ &tmp);
if (!parent_folder)
goto out;
- info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, error);
+ info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, &tmp);
g_object_unref (parent_folder);
out:
+ if (parent_path)
+ gtk_file_path_free (parent_path);
+
+ 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);
+ }
+
+ profile_end ("end", (char *) path);
- gtk_file_path_free (parent_path);
return info;
}
/* Returns whether a path is a folder */
static gboolean
-check_is_folder (GtkFileSystem *file_system, const GtkFilePath *path, GError **error)
+check_is_folder (GtkFileSystem *file_system,
+ const GtkFilePath *path,
+ GError **error)
{
- GtkFileInfo *info;
- gboolean is_folder;
+ GtkFileFolder *folder;
- /* Use get_file_info() rather than trying get_folder() and checking
- * for an error directly because older versions of the gnome-vfs
- * backend don't return an error immediately. This way is also
- * more efficient if we already have the parent folder.
- */
- info = get_file_info (file_system, path, FALSE, error);
-
- if (!info)
- return FALSE;
-
- is_folder = gtk_file_info_get_is_folder (info);
+ profile_start ("start", (char *) path);
- if (!is_folder)
- g_set_error (error,
- GTK_FILE_SYSTEM_ERROR,
- GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
- "%s: %s",
- gtk_file_info_get_display_name (info),
- g_strerror (ENOTDIR));
+ folder = gtk_file_system_get_folder (file_system, path, 0, error);
+ if (!folder)
+ {
+ profile_end ("end - is not folder", (char *) path);
+ return FALSE;
+ }
- gtk_file_info_free (info);
+ g_object_unref (folder);
- return is_folder;
+ profile_end ("end", (char *) path);
+ return TRUE;
}
/* Inserts a path in the shortcuts tree, making a copy of it; alternatively,
gpointer data;
GtkTreeIter iter;
+ profile_start ("start", is_volume ? "volume" : (char *) path);
+
if (is_volume)
{
data = volume;
else
{
if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
+ {
+ profile_end ("end - is not folder", NULL);
+ return FALSE;
+ }
if (label)
label_copy = g_strdup (label);
GtkFileInfo *info = get_file_info (impl->file_system, path, TRUE, error);
if (!info)
- return FALSE;
+ {
+ profile_end ("end - could not get info", (char *) path);
+ return FALSE;
+ }
label_copy = g_strdup (gtk_file_info_get_display_name (info));
gtk_file_info_free (info);
if (pixbuf)
g_object_unref (pixbuf);
+ profile_end ("end", NULL);
+
return TRUE;
}
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_getting_info_dialog (impl, home_path, error);
gtk_file_path_free (home_path);
+
+ profile_end ("end", NULL);
}
/* Appends the ~/Desktop directory to the shortcuts model */
static void
shortcuts_append_desktop (GtkFileChooserDefault *impl)
{
- const char *home;
char *name;
GtkFilePath *path;
- home = g_get_home_dir ();
+ profile_start ("start", NULL);
+
+#ifdef G_OS_WIN32
+ name = _gtk_file_system_win32_get_desktop ();
+#else
+ const char *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);
*/
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.
*/
!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))
+ if (shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, NULL))
num_inserted++;
+
+ g_free (label);
}
+ profile_end ("end", NULL);
+
return num_inserted;
}
int n;
gboolean old_changing_folders;
+ profile_start ("start", NULL);
+
old_changing_folders = impl->changing_folder;
impl->changing_folder = TRUE;
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 */
{
GSList *bookmarks;
gboolean old_changing_folders;
+ GtkTreeIter iter;
+ GtkFilePath *list_selected = NULL;
+ GtkFilePath *combo_selected = NULL;
+ gboolean is_volume;
+ gpointer col_data;
+ profile_start ("start", NULL);
+
old_changing_folders = impl->changing_folder;
impl->changing_folder = TRUE;
+ if (shortcuts_get_selected (impl, &iter))
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
+ &iter,
+ SHORTCUTS_COL_DATA, &col_data,
+ SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ -1);
+
+ if (col_data && !is_volume)
+ list_selected = gtk_file_path_copy (col_data);
+ }
+
+ if (impl->save_folder_combo &&
+ gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo),
+ &iter))
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
+ &iter,
+ SHORTCUTS_COL_DATA, &col_data,
+ SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ -1);
+
+ if (col_data && !is_volume)
+ combo_selected = gtk_file_path_copy (col_data);
+ }
+
if (impl->num_bookmarks > 0)
shortcuts_remove_rows (impl,
shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
gtk_file_paths_free (bookmarks);
if (impl->num_bookmarks > 0)
- {
- shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
- }
+ shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
+
if (impl->shortcuts_filter_model)
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ if (list_selected)
+ {
+ shortcuts_find_folder (impl, list_selected);
+ gtk_file_path_free (list_selected);
+ }
+
+ if (combo_selected)
+ {
+ gint pos;
+
+ pos = shortcut_find_position (impl, combo_selected);
+ if (pos != -1)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
+ pos);
+ gtk_file_path_free (combo_selected);
+ }
+
impl->changing_folder = old_changing_folders;
+
+ profile_end ("end", NULL);
}
/* Appends a separator and a row to the shortcuts list for the current folder */
success = TRUE;
+ g_assert (impl->current_folder != NULL);
+
pos = shortcut_find_position (impl, impl->current_folder);
if (pos == -1)
{
static gboolean
edited_idle_cb (GtkFileChooserDefault *impl)
{
+ GDK_THREADS_ENTER ();
+
g_source_destroy (impl->edited_idle);
impl->edited_idle = NULL;
if (gtk_file_system_create_folder (impl->file_system, file_path, &error))
change_folder_and_display_error (impl, file_path);
else
- error_dialog (impl,
- _("Could not create folder %s:\n%s"),
- file_path, error);
+ error_creating_folder_dialog (impl, file_path, error);
gtk_file_path_free (file_path);
}
else
- error_building_filename_dialog (impl, impl->current_folder, impl->edited_new_text, error);
+ error_creating_folder_dialog (impl, file_path, error);
g_free (impl->edited_new_text);
impl->edited_new_text = NULL;
}
+ GDK_THREADS_LEAVE ();
+
return FALSE;
}
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);
+ GtkWidget *image;
- 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);
-
- 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);
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)
{
GError *error;
+ g_return_val_if_fail (path != NULL, FALSE);
+
if (shortcut_find_position (impl, path) != -1)
return FALSE;
error = NULL;
if (!check_is_folder (impl->file_system, path, &error))
{
- error_dialog (impl,
- _("Could not add bookmark for %s because it is not a folder."),
- 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))
{
- error_could_not_add_bookmark_dialog (impl, path, error);
+ error_adding_bookmark_dialog (impl, path, error);
return FALSE;
}
GtkTreeSelection *selection;
GtkTreeIter parent_iter;
+ if (!impl->browse_shortcuts_tree_view)
+ return FALSE;
+
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
{
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;
error = NULL;
if (!gtk_file_system_remove_bookmark (impl->file_system, path, &error))
- {
- error_dialog (impl,
- _("Could not remove bookmark for %s:\n%s"),
- path,
- error);
- }
+ error_removing_bookmark_dialog (impl, path, error);
}
/* Callback used when the "Remove bookmark" button is clicked */
gtk_tree_model_sort_convert_iter_to_child_iter (closure->impl->sort_model, &child_iter, iter);
info = _gtk_file_system_model_get_info (closure->impl->browse_files_model, &child_iter);
- is_folder = gtk_file_info_get_is_folder (info);
+ is_folder = info ? gtk_file_info_get_is_folder (info) : FALSE;
closure->all_folders = closure->all_folders && is_folder;
closure->all_files = closure->all_files && !is_folder;
selection_check (impl, &num_selected, NULL, &all_folders);
if (num_selected == 0)
- active = (shortcut_find_position (impl, impl->current_folder) == -1);
+ active = (impl->current_folder != NULL) && (shortcut_find_position (impl, impl->current_folder) == -1);
else if (num_selected == 1)
{
const GtkFilePath *path;
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,
static gboolean
shortcuts_drag_outside_idle_cb (GtkFileChooserDefault *impl)
{
+ GDK_THREADS_ENTER ();
+
shortcuts_drag_set_delete_cursor (impl, TRUE);
impl->shortcuts_drag_outside = TRUE;
shortcuts_cancel_drag_outside_idle (impl);
+
+ GDK_THREADS_LEAVE ();
+
return FALSE;
}
#endif
}
else
{
- char *msg;
+ GError *error;
- msg = g_strdup_printf (_("Could not add a bookmark for %s because it is an invalid path name."),
- uri);
- error_message (impl, msg);
- g_free (msg);
+ g_set_error (&error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+ _("Could not add a bookmark for '%s' "
+ "because it is an invalid path name."),
+ uri);
+ error_adding_bookmark_dialog (impl, path, error);
}
}
if (gtk_file_system_remove_bookmark (impl->file_system, file_path_copy, &error))
shortcuts_add_bookmark_from_path (impl, file_path_copy, new_position);
else
- error_could_not_add_bookmark_dialog (impl, file_path_copy, error);
+ error_adding_bookmark_dialog (impl, file_path_copy, error);
out:
GtkFileChooserDefault *impl)
{
bookmarks_check_remove_sensitivity (impl);
+ shortcuts_check_popup_sensitivity (impl);
}
static gboolean
return FALSE;
}
+/* Callback used when the file list's popup menu is detached */
+static void
+shortcuts_popup_menu_detach_cb (GtkWidget *attach_widget,
+ GtkMenu *menu)
+{
+ GtkFileChooserDefault *impl;
+
+ impl = g_object_get_data (G_OBJECT (attach_widget), "GtkFileChooserDefault");
+ g_assert (GTK_IS_FILE_CHOOSER_DEFAULT (impl));
+
+ impl->browse_shortcuts_popup_menu = NULL;
+ impl->browse_shortcuts_popup_menu_remove_item = NULL;
+ impl->browse_shortcuts_popup_menu_rename_item = NULL;
+}
+
+static void
+remove_shortcut_cb (GtkMenuItem *item,
+ GtkFileChooserDefault *impl)
+{
+ remove_selected_bookmarks (impl);
+}
+
+static void
+rename_shortcut_cb (GtkMenuItem *item,
+ GtkFileChooserDefault *impl)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+ GList *renderers;
+
+ 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);
+ }
+}
+
+/* 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)
+{
+ if (event->button != 3)
+ 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);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->shortcuts_model), &iter, path);
+ 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 *
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);
+ 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);
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);
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;
+
+ modifiers = gtk_accelerator_get_default_mod_mask ();
if (event->keyval == GDK_slash &&
- ! (event->state & (~GDK_SHIFT_MASK & gtk_accelerator_get_default_mod_mask ())))
+ ! (event->state & (~GDK_SHIFT_MASK & modifiers)))
{
location_popup_handler (impl, "/");
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_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;
+ gint i;
+
+ 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 (selection_data->data);
+ if (uris[0])
+ {
+ uri = uris[0];
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+ if (path)
+ {
+ if ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
+ impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) &&
+ uris[1] == 0 &&
+ check_is_folder (impl->file_system, path, NULL))
+ change_folder_and_display_error (impl, path);
+ else
+ {
+ gtk_file_chooser_default_unselect_all (chooser);
+ gtk_file_chooser_default_select_path (chooser, path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (impl, path, error);
+ else
+ browse_files_center_selected_row (impl);
+ }
+
+ gtk_file_path_free (path);
+ }
+ 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)
+ {
+ for (i = 1; uris[i]; i++)
+ {
+ uri = uris[i];
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+
+ if (path)
+ {
+ gtk_file_chooser_default_select_path (chooser, path, &error);
+ if (error)
+ error_selecting_dragged_file_dialog (impl, path, error);
+
+ gtk_file_path_free (path);
+ }
+ }
+ }
+ }
+
+ g_strfreev (uris);
+
+ 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()
*/
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);
+
+ 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, "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,
GtkWidget *combo;
GtkCellRenderer *cell;
- combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (impl->shortcuts_model));
+ combo = g_object_new (GTK_TYPE_COMBO_BOX,
+ "model", impl->shortcuts_model,
+ "focus-on-click", FALSE,
+ NULL);
gtk_widget_show (combo);
cell = gtk_cell_renderer_pixbuf_new ();
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.
{
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;
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;
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
- if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_SMALL_TOOLBAR, &width, &height))
+ if (gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU, &width, &height))
impl->icon_size = MAX (width, height);
else
impl->icon_size = FALLBACK_ICON_SIZE;
{
GtkFileChooserDefault *impl;
+ profile_start ("start", NULL);
+
impl = GTK_FILE_CHOOSER_DEFAULT (widget);
if (GTK_WIDGET_CLASS (parent_class)->style_set)
change_icon_theme (impl);
g_signal_emit_by_name (widget, "default-size-changed");
+
+ profile_end ("end", NULL);
}
static void
}
static gboolean
-list_model_filter_func (GtkFileSystemModel *model,
- GtkFilePath *path,
- const GtkFileInfo *file_info,
- gpointer user_data)
+get_is_file_filtered (GtkFileChooserDefault *impl,
+ const GtkFilePath *path,
+ GtkFileInfo *file_info)
{
- GtkFileChooserDefault *impl = user_data;
GtkFileFilterInfo filter_info;
GtkFileFilterFlags needed;
gboolean result;
if (!impl->current_filter)
- return TRUE;
-
- if (gtk_file_info_get_is_folder (file_info))
- return TRUE;
+ return FALSE;
filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME | GTK_FILE_FILTER_MIME_TYPE;
if (filter_info.uri)
g_free ((gchar *)filter_info.uri);
- return result;
+ return !result;
+}
+
+/* GtkWidget::map method */
+static void
+gtk_file_chooser_default_map (GtkWidget *widget)
+{
+ GtkFileChooserDefault *impl;
+
+ profile_start ("start", NULL);
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (widget);
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ if (impl->current_folder)
+ {
+ pending_select_paths_store_selection (impl);
+ change_folder_and_display_error (impl, impl->current_folder);
+ }
+
+ bookmarks_changed_cb (impl->file_system, impl);
+
+ profile_end ("end", NULL);
+}
+
+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)
- _gtk_file_system_model_set_filter (impl->browse_files_model,
- list_model_filter_func,
- impl);
+ {
+ filter = list_model_filter_func;
+ data = impl;
+ }
+ else
+ {
+ filter = NULL;
+ data = NULL;
+ }
+
+ _gtk_file_system_model_set_filter (impl->browse_files_model,
+ filter,
+ data);
}
#define COMPARE_DIRECTORIES \
{
GtkFileChooserDefault *impl;
+ profile_start ("start", NULL);
+
+ GDK_THREADS_ENTER ();
+
impl = GTK_FILE_CHOOSER_DEFAULT (data);
- g_assert (impl->load_state == LOAD_LOADING);
+ g_assert (impl->load_state == LOAD_PRELOAD);
g_assert (impl->load_timeout_id != 0);
g_assert (impl->browse_files_model != NULL);
impl->load_timeout_id = 0;
- impl->load_state = LOAD_FINISHED;
+ impl->load_state = LOAD_LOADING;
load_set_model (impl);
+ GDK_THREADS_LEAVE ();
+
+ profile_end ("end", NULL);
+
return FALSE;
}
load_setup_timer (GtkFileChooserDefault *impl)
{
g_assert (impl->load_timeout_id == 0);
- g_assert (impl->load_state == LOAD_FINISHED);
+ g_assert (impl->load_state != LOAD_PRELOAD);
impl->load_timeout_id = g_timeout_add (MAX_LOADING_TIME, load_timeout_cb, impl);
- impl->load_state = LOAD_LOADING;
+ impl->load_state = LOAD_PRELOAD;
}
/* Removes the load timeout and switches to the LOAD_FINISHED state */
{
if (impl->load_timeout_id != 0)
{
- g_assert (impl->load_state == LOAD_LOADING);
+ g_assert (impl->load_state == LOAD_PRELOAD);
g_source_remove (impl->load_timeout_id);
impl->load_timeout_id = 0;
- impl->load_state = LOAD_FINISHED;
+ impl->load_state = LOAD_EMPTY;
}
else
- g_assert (impl->load_state == LOAD_FINISHED);
-}
-
-/* Queues a pending operation relative to selecting a file when the current
- * folder finishes loading.
- */
-static void
-pending_op_queue (GtkFileChooserDefault *impl, PendingOp op, const GtkFilePath *path)
-{
- if (impl->pending_op == PENDING_OP_SELECT_PATH)
- {
- g_assert (impl->pending_select_path != NULL);
- gtk_file_path_free (impl->pending_select_path);
-
- impl->pending_select_path = NULL;
- }
-
- impl->pending_op = op;
-
- if (impl->pending_op == PENDING_OP_SELECT_PATH)
- {
- g_assert (path != NULL);
- impl->pending_select_path = gtk_file_path_copy (path);
- }
+ g_assert (impl->load_state == LOAD_EMPTY ||
+ impl->load_state == LOAD_LOADING ||
+ impl->load_state == LOAD_FINISHED);
}
/* Selects the first row in the file list */
{
GtkTreePath *path;
+ if (!impl->sort_model)
+ return;
+
path = gtk_tree_path_new_from_indices (0, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), path, NULL, FALSE);
gtk_tree_path_free (path);
}
-/* Processes the pending operation when a folder is finished loading */
+struct center_selected_row_closure {
+ GtkFileChooserDefault *impl;
+ gboolean already_centered;
+};
+
+/* Callback used from gtk_tree_selection_selected_foreach(); centers the
+ * selected row in the tree view.
+ */
static void
-pending_op_process (GtkFileChooserDefault *impl)
+center_selected_row_foreach_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
{
- switch (impl->pending_op)
+ struct center_selected_row_closure *closure;
+
+ closure = data;
+ if (closure->already_centered)
+ return;
+
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (closure->impl->browse_files_tree_view), path, NULL, TRUE, 0.5, 0.0);
+ closure->already_centered = TRUE;
+}
+
+/* Centers the selected row in the tree view */
+static void
+browse_files_center_selected_row (GtkFileChooserDefault *impl)
+{
+ struct center_selected_row_closure closure;
+ GtkTreeSelection *selection;
+
+ closure.impl = impl;
+ closure.already_centered = FALSE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ 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)
+{
+ GtkFileFolder *folder;
+ gboolean success;
+ gboolean have_hidden;
+ gboolean have_filtered;
+
+ profile_start ("start", NULL);
+
+ if (!only_one_path && !paths)
{
- case PENDING_OP_NONE:
- break;
+ profile_end ("end", NULL);
+ return TRUE;
+ }
- case PENDING_OP_SELECT_PATH:
- g_assert (impl->pending_select_path != NULL);
+ folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
+ if (!folder)
+ {
+ profile_end ("end", NULL);
+ return FALSE;
+ }
- _gtk_file_system_model_path_do (impl->browse_files_model, impl->pending_select_path, select_func, impl);
- gtk_file_path_free (impl->pending_select_path);
- impl->pending_select_path = NULL;
- impl->pending_op = PENDING_OP_NONE;
- break;
+ success = FALSE;
+ have_hidden = FALSE;
+ have_filtered = FALSE;
- case PENDING_OP_SELECT_FIRST:
- browse_files_select_first_row (impl);
- impl->pending_op = PENDING_OP_NONE;
- break;
+ if (only_one_path)
+ {
+ GtkFileInfo *info;
- default:
- g_assert_not_reached ();
+ info = gtk_file_folder_get_info (folder, only_one_path, error);
+ if (info)
+ {
+ success = TRUE;
+ have_hidden = gtk_file_info_get_is_hidden (info);
+ have_filtered = get_is_file_filtered (impl, only_one_path, info);
+ gtk_file_info_free (info);
+ }
}
+ else
+ {
+ GSList *l;
+
+ for (l = paths; l; l = l->next)
+ {
+ const GtkFilePath *path;
+ GtkFileInfo *info;
+
+ path = l->data;
- g_assert (impl->pending_op == PENDING_OP_NONE);
- g_assert (impl->pending_select_path == NULL);
+ /* 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);
+
+ if (!have_filtered)
+ have_filtered = get_is_file_filtered (impl, path, info);
+
+ gtk_file_info_free (info);
+
+ if (have_hidden && have_filtered)
+ break; /* we now have all the information we need */
+ }
+ }
+
+ success = TRUE;
+ }
+
+ g_object_unref (folder);
+
+ if (!success)
+ {
+ profile_end ("end", NULL);
+ return FALSE;
+ }
+
+ if (have_hidden)
+ g_object_set (impl, "show-hidden", TRUE, NULL);
+
+ if (have_filtered)
+ set_current_filter (impl, NULL);
+
+ if (only_one_path)
+ _gtk_file_system_model_path_do (impl->browse_files_model, only_one_path, select_func, impl);
+ else
+ {
+ GSList *l;
+
+ for (l = paths; l; l = l->next)
+ {
+ const GtkFilePath *path;
+
+ path = l->data;
+ _gtk_file_system_model_path_do (impl->browse_files_model, path, select_func, impl);
+ }
+ }
+
+ profile_end ("end", NULL);
+ return TRUE;
+}
+
+/* Processes the pending operation when a folder is finished loading */
+static void
+pending_select_paths_process (GtkFileChooserDefault *impl)
+{
+ g_assert (impl->load_state == LOAD_FINISHED);
+ g_assert (impl->browse_files_model != NULL);
+ g_assert (impl->sort_model != NULL);
+
+ if (impl->pending_select_paths)
+ {
+ /* NULL GError */
+ show_and_select_paths (impl, impl->current_folder, NULL, impl->pending_select_paths, NULL);
+ pending_select_paths_free (impl);
+ browse_files_center_selected_row (impl);
+ }
+ else
+ {
+ /* We only select the first row if the chooser is actually mapped ---
+ * selecting the first row is to help the user when he is interacting with
+ * the chooser, but sometimes a chooser works not on behalf of the user,
+ * but rather on behalf of something else like GtkFileChooserButton. In
+ * 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 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_OPEN)
+ browse_files_select_first_row (impl);
+ }
+
+ g_assert (impl->pending_select_paths == NULL);
}
/* Callback used when the file system model finishes loading */
browse_files_model_finished_loading_cb (GtkFileSystemModel *model,
GtkFileChooserDefault *impl)
{
- if (impl->load_state == LOAD_LOADING)
+ profile_start ("start", NULL);
+
+ if (impl->load_state == LOAD_PRELOAD)
{
load_remove_timer (impl);
load_set_model (impl);
}
+ else if (impl->load_state == LOAD_LOADING)
+ {
+ /* Nothing */
+ }
else
- g_assert (impl->load_state == LOAD_FINISHED);
+ {
+ /* 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;
+ }
+
+ g_assert (impl->load_timeout_id == 0);
- pending_op_process (impl);
+ impl->load_state = LOAD_FINISHED;
+
+ pending_select_paths_process (impl);
set_busy_cursor (impl, FALSE);
+
+ profile_end ("end", NULL);
}
/* Gets rid of the old list model and creates a new one for the current folder */
set_list_model (GtkFileChooserDefault *impl,
GError **error)
{
- load_remove_timer (impl);
+ 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;
}
- load_setup_timer (impl);
+ load_setup_timer (impl); /* This changes the state to LOAD_PRELOAD */
g_signal_connect (impl->browse_files_model, "finished-loading",
G_CALLBACK (browse_files_model_finished_loading_cb), impl);
install_list_model_filter (impl);
+ profile_end ("end", NULL);
+
return TRUE;
}
const GtkFileInfo *info;
GtkTreeIter iter;
GtkTreeIter child_iter;
+ gboolean change_entry;
- if (impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
+ if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER))
return;
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_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), "");
+ return;
+ }
gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
&child_iter,
info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- if (!gtk_file_info_get_is_folder (info))
+ if (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 CREATE_FOLDER mode */
+
+ if (change_entry)
_gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry),
gtk_file_info_get_display_name (info));
}
gtk_file_chooser_default_set_current_folder (GtkFileChooser *chooser,
const GtkFilePath *path,
GError **error)
+{
+ return gtk_file_chooser_default_update_current_folder (chooser, path, FALSE, error);
+}
+
+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);
gboolean result;
+ 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_SYSTEM_ERROR,
- GTK_FILE_SYSTEM_ERROR_FAILED,
+ 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;
}
/* Test validity of path here. */
if (!check_is_folder (impl->file_system, path, error))
- return FALSE;
+ {
+ profile_end ("end - not a folder", (char *) path);
+ return FALSE;
+ }
- if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, error))
- return FALSE;
+ if (!_gtk_path_bar_set_path (GTK_PATH_BAR (impl->browse_path_bar), path, keep_trail, error))
+ {
+ profile_end ("end - could not set path bar", (char *) path);
+ return FALSE;
+ }
if (impl->current_folder != path)
{
g_signal_emit_by_name (impl, "selection-changed", 0);
+ profile_end ("end", NULL);
return result;
}
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->save_file_name_entry), name);
}
gpointer user_data)
{
GtkFileChooserDefault *impl = user_data;
- GtkTreeView *tree_view = GTK_TREE_VIEW (impl->browse_files_tree_view);
- GtkTreePath *sorted_path;
+ GtkTreeSelection *selection;
+ GtkTreeIter sorted_iter;
- sorted_path = gtk_tree_model_sort_convert_child_path_to_path (impl->sort_model, path);
- gtk_tree_view_set_cursor (tree_view, sorted_path, NULL, FALSE);
- gtk_tree_view_scroll_to_cell (tree_view, sorted_path, NULL, FALSE, 0.0, 0.0);
- gtk_tree_path_free (sorted_path);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+
+ gtk_tree_model_sort_convert_child_iter_to_iter (impl->sort_model, &sorted_iter, iter);
+ gtk_tree_selection_select_iter (selection, &sorted_iter);
}
static gboolean
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
GtkFilePath *parent_path;
+ gboolean same_path;
if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, error))
return FALSE;
if (!parent_path)
return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
+
+ if (impl->load_state == LOAD_EMPTY)
+ same_path = FALSE;
else
{
- gboolean result;
- GtkFileFolder *folder;
- GtkFileInfo *info;
- gboolean is_hidden;
+ g_assert (impl->current_folder != NULL);
- result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
+ same_path = gtk_file_path_compare (parent_path, impl->current_folder) == 0;
+ }
- if (!result)
- {
- gtk_file_path_free (parent_path);
- return result;
- }
+ if (same_path && impl->load_state == LOAD_FINISHED)
+ {
+ gboolean result;
- folder = gtk_file_system_get_folder (impl->file_system, parent_path, GTK_FILE_INFO_IS_HIDDEN, error);
+ result = show_and_select_paths (impl, parent_path, path, NULL, error);
gtk_file_path_free (parent_path);
+ return result;
+ }
- if (!folder)
- return FALSE;
-
- info = gtk_file_folder_get_info (folder, path, error);
- g_object_unref (folder);
-
- if (!info)
- return FALSE;
-
- is_hidden = gtk_file_info_get_is_hidden (info);
- gtk_file_info_free (info);
+ pending_select_paths_add (impl, path);
- if (is_hidden)
- g_object_set (impl, "show-hidden", TRUE, NULL);
+ if (!same_path)
+ {
+ gboolean result;
- pending_op_queue (impl, PENDING_OP_SELECT_PATH, path);
- return TRUE;
+ result = _gtk_file_chooser_set_current_folder_path (chooser, parent_path, error);
+ gtk_file_path_free (parent_path);
+ return result;
}
- g_assert_not_reached ();
+ gtk_file_path_free (parent_path);
+ return TRUE;
}
static void
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)
{
GtkFileChooserEntry *chooser_entry;
const GtkFilePath *current_folder;
chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_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;
+
+ 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;
+
+ 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;
+
+ return;
}
- *is_valid = TRUE;
- return path;
+ *path_ret = path;
+ *is_well_formed_ret = TRUE;
}
struct get_paths_closure {
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
- gboolean is_valid, is_empty;
+ gboolean is_well_formed, is_empty, is_file_part_empty;
+
+ check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty);
- info.path_from_entry = check_save_entry (impl, &is_valid, &is_empty);
- if (!is_valid && !is_empty)
+ if (!is_well_formed)
return NULL;
+
+ if (!is_empty)
+ {
+ if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ gtk_file_path_free (info.path_from_entry);
+ return NULL;
+ }
+ }
}
if (!info.path_from_entry || impl->select_multiple)
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
- _("shortcut %s does not exist"),
+ _("Shortcut %s does not exist"),
uri);
g_free (uri);
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);
+}
+
+static char *
+get_display_name_for_folder (GtkFileChooserDefault *impl,
+ const GtkFilePath *path)
+{
+ char *display_name;
+ GtkFilePath *parent_path;
+ GtkFileFolder *parent_folder;
+ GtkFileInfo *info;
+
+ display_name = NULL;
+ parent_path = NULL;
+ parent_folder = NULL;
+ info = NULL;
+
+ if (!gtk_file_system_get_parent (impl->file_system, path, &parent_path, NULL))
+ goto out;
+
+ parent_folder = gtk_file_system_get_folder (impl->file_system,
+ parent_path ? parent_path : path,
+ GTK_FILE_INFO_DISPLAY_NAME,
+ NULL);
+ if (!parent_folder)
+ goto out;
+
+ info = gtk_file_folder_get_info (parent_folder, parent_path ? path : NULL, NULL);
+ if (!info)
+ goto out;
+
+ display_name = g_strdup (gtk_file_info_get_display_name (info));
+
+ out:
+
+ if (parent_path)
+ gtk_file_path_free (parent_path);
+
+ if (parent_folder)
+ g_object_unref (parent_folder);
+
+ if (info)
+ gtk_file_info_free (info);
+
+ return display_name;
+}
+
+/* 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:
+ {
+ char *parent_display_name;
+ gboolean retval;
+
+ g_assert (file_part != NULL);
+
+ parent_display_name = get_display_name_for_folder (impl, parent_path);
+ if (!parent_display_name)
+ return TRUE; /* Huh? Did the folder disappear? Let the caller deal with it */
+
+ retval = confirm_dialog_should_accept_filename (impl, file_part, parent_display_name);
+ g_free (parent_display_name);
+ return retval;
+ }
+
+ 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;
+ }
+}
+
/* 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
- || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- {
- if (num_selected > 0)
- return TRUE;
- }
+ if (num_selected > 2)
+ k = 2;
+ else
+ k = num_selected;
- 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
- return FALSE;
- }
+ action = what_to_do [impl->action] [k];
- if (num_selected == 1 && all_folders)
+ switch (action)
{
- switch_to_selected_folder (impl);
- pending_op_queue (impl, PENDING_OP_SELECT_FIRST, NULL);
+ case NOOP:
return FALSE;
+
+ case RESPOND:
+ return TRUE;
+
+ case RESPOND_OR_SWITCH:
+ g_assert (num_selected == 1);
+
+ if (all_folders)
+ {
+ switch_to_selected_folder (impl);
+ return FALSE;
+ }
+ 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 TRUE;
+
+ 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)
{
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:
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry);
- path = check_save_entry (impl, &is_valid, &is_empty);
+ check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty);
- 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;
+ is_folder = check_is_folder (impl->file_system, path, &error);
if (is_folder)
{
- _gtk_file_chooser_entry_set_file_part (entry, "");
- change_folder_and_display_error (impl, path);
- retval = FALSE;
+ if (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 /* 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;
+ {
+ gboolean file_exists_and_is_not_folder;
+
+ file_exists_and_is_not_folder = g_error_matches (error, GTK_FILE_SYSTEM_ERROR, GTK_FILE_SYSTEM_ERROR_NOT_FOLDER);
+
+ if (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 (impl, path, error);
+ error = NULL; /* as it will be freed below for the general case */
+ retval = FALSE;
+ }
+ else
+ {
+ GtkFilePath *parent_path;
+ gboolean parent_is_folder;
+
+ /* check that everything up to the last component exists */
+
+ parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+ parent_is_folder = check_is_folder (impl->file_system, parent_path, NULL);
+ if (parent_is_folder)
+ {
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ if (file_exists_and_is_not_folder)
+ {
+ const char *file_part;
+
+ file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry));
+ retval = should_respond_after_confirm_overwrite (impl, file_part, parent_path);
+ }
+ else
+ retval = TRUE;
+ }
+ else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */
+ {
+ GError *create_error;
+
+ create_error = NULL;
+ if (gtk_file_system_create_folder (impl->file_system, path, &create_error))
+ retval = TRUE;
+ else
+ {
+ error_creating_folder_dialog (impl, path, create_error);
+ retval = FALSE;
+ }
+ }
+ }
+ else
+ {
+ /* This will display an error, which is what we want */
+ change_folder_and_display_error (impl, parent_path);
+ retval = FALSE;
+ }
+
+ gtk_file_path_free (parent_path);
+ }
+
+ if (error != NULL)
+ g_error_free (error);
+ }
gtk_file_path_free (path);
return retval;
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
|| impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
- {
- if (impl->load_state == LOAD_FINISHED)
- browse_files_select_first_row (impl);
-
- widget = impl->browse_files_tree_view;
- }
+ widget = impl->browse_files_tree_view;
else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
widget = impl->save_file_name_entry;
{
int filter_index;
- /* If we have filters, new filter must be one of them
+ /* NULL filters are allowed to reset to non-filtered status
*/
filter_index = g_slist_index (impl->filters, filter);
- if (impl->filters && filter_index < 0)
+ if (impl->filters && filter && filter_index < 0)
return;
if (impl->current_filter)
{
char *msg;
- msg = g_strdup_printf ("Could not mount %s:\n%s",
- gtk_file_system_volume_get_display_name (impl->file_system, volume),
- error->message);
- error_message (impl, 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);
g_error_free (error);
}
info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- if (!gtk_file_info_get_is_folder (info))
+ if (info && !gtk_file_info_get_is_folder (info))
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);
GdkPixbuf *pixbuf;
const GtkFileInfo *info;
gboolean sensitive = TRUE;
+
+ profile_start ("start", NULL);
info = get_list_file_info (impl, iter);
if (pixbuf)
g_object_unref (pixbuf);
+
+ profile_end ("end", NULL);
}
static void
}
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;
+ g_date_set_time (&mtime, (GTime) time_mtime);
- if (days_diff > 1 && days_diff < 7)
- format = "%A"; /* Days from last week */
+ 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"));
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 ||
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path)
{
error_message_with_parent (parent,
- _("Cannot change to the folder you specified as it is an invalid path."));
+ _("Cannot change folder"),
+ _("The folder you specified is an invalid path."));
return FALSE;
}
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':\n%s"),
- uri, file_part,
- error->message);
- error_message (impl, msg);
+ 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;
result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (impl), subfolder_path, &error);
if (!result)
- error_dialog (impl,
- _("Could not select %s:\n%s"),
+ error_dialog (impl, _("Could not select item"),
subfolder_path, error);
}
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
accept_stock, GTK_RESPONSE_ACCEPT,
NULL);
+ if (toplevel->group)
+ gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog));
+
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);
static void
up_folder_handler (GtkFileChooserDefault *impl)
{
- pending_op_queue (impl, PENDING_OP_SELECT_PATH, impl->current_folder);
+ pending_select_paths_add (impl, impl->current_folder);
_gtk_path_bar_up (GTK_PATH_BAR (impl->browse_path_bar));
}
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;
return GTK_TREE_MODEL (model);
}
+
+#define __GTK_FILE_CHOOSER_DEFAULT_C__
+#include "gtkaliasdef.c"