GDK_l, GDK_CONTROL_MASK,
"location-popup",
1, G_TYPE_STRING, "");
- /* FMQ: remove this? */
-#if 0
+
gtk_binding_entry_add_signal (binding_set,
GDK_slash, 0,
"location-popup",
GDK_asciitilde, 0,
"location-popup",
1, G_TYPE_STRING, "~");
-#endif
#endif
gtk_binding_entry_add_signal (binding_set,
g_object_unref (impl->file_system);
+ g_free (impl->browse_files_last_selected_name);
+
for (l = impl->filters; l; l = l->next)
{
GtkFileFilter *filter;
shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
}
else
- shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+ {
+ 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);
G_TYPE_BOOLEAN, /* is the previous column a volume? */
G_TYPE_BOOLEAN, /* removable */
G_TYPE_BOOLEAN, /* pixbuf cell visibility */
- G_TYPE_OBJECT); /* GtkFileSystemHandle */
+ G_TYPE_POINTER); /* GtkFileSystemHandle */
if (impl->file_system)
{
GdkEventKey *event,
GtkFileChooserDefault *impl)
{
- /* FMQ: remove this? */
-#if 0
if ((event->keyval == GDK_slash
|| event->keyval == GDK_KP_Divide
#ifdef G_OS_UNIX
location_popup_handler (impl, event->string);
return TRUE;
}
-#endif
+
return FALSE;
}
modifiers = gtk_accelerator_get_default_mod_mask ();
- /* FMQ: remove this? */
-#if 0
if ((event->keyval == GDK_slash
|| event->keyval == GDK_KP_Divide
#ifdef G_OS_UNIX
location_popup_handler (impl, event->string);
return TRUE;
}
-#endif
if ((event->keyval == GDK_Return
|| event->keyval == GDK_ISO_Enter
/* Configure the entry */
_gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder);
- location_entry_set_initial_text (impl);
/* Done */
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)
{
browse_files_center_selected_row (data->impl);
+ g_object_unref (data->impl);
gtk_file_paths_free (data->paths);
g_free (data);
}
g_assert (impl->browse_files_model != NULL);
g_assert (impl->sort_model != NULL);
- impl->processing_pending_selections = TRUE;
-
if (impl->pending_select_paths)
{
/* NULL GError */
browse_files_select_first_row (impl);
}
- impl->processing_pending_selections = FALSE;
-
g_assert (impl->pending_select_paths == NULL);
}
GtkTreeIter first_selected_iter;
};
+static gint
+compare_utf8_filenames (const gchar *a,
+ const gchar *b)
+{
+ gchar *a_folded, *b_folded;
+ gint retval;
+
+ a_folded = g_utf8_strdown (a, -1);
+ b_folded = g_utf8_strdown (b, -1);
+
+ retval = strcmp (a_folded, b_folded);
+
+ g_free (a_folded);
+ g_free (b_folded);
+
+ return retval;
+}
+
static void
update_chooser_entry_selected_foreach (GtkTreeModel *model,
GtkTreePath *path,
struct update_chooser_entry_selected_foreach_closure closure;
const char *file_part;
- if (impl->processing_pending_selections)
- return;
-
if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
|| ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
g_assert (impl->location_entry != NULL);
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 (closure.num_selected == 0)
{
- /* If nothing is selected, we only reset the file name entry if we are in
- * CREATE_FOLDER mode. In SAVE mode, nothing will be selected when the
- * user starts typeahead in the treeview, and we don't want to clear the
- * file name entry in that case --- the user could be typing-ahead to look
- * for a folder name. See http://bugzilla.gnome.org/show_bug.cgi?id=308332
- */
- if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- file_part = "";
+ goto maybe_clear_entry;
}
else if (closure.num_selected == 1)
{
info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+ g_free (impl->browse_files_last_selected_name);
+ impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
+
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ || 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 */
+ change_entry = TRUE; /* ... unless we are in one of the folder modes */
if (change_entry)
- file_part = gtk_file_info_get_display_name (info);
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
+
+ return;
}
else
{
+ g_assert (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER));
+
/* Multiple selection, so just clear the entry. */
- file_part = "";
+
+ g_free (impl->browse_files_last_selected_name);
+ impl->browse_files_last_selected_name = NULL;
+
+ _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
+ return;
}
- if (file_part)
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), file_part);
+ maybe_clear_entry:
+
+ if (impl->browse_files_last_selected_name)
+ {
+ const char *entry_text;
+ int len;
+ gboolean clear_entry;
+
+ 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;
+
+ 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 gboolean
GtkFileChooserDefault *impl;
GtkFilePath *path;
gboolean keep_trail;
+ GtkFilePath *original_path;
+ GError *original_error;
};
static void
if (error)
{
- error_changing_folder_dialog (impl, data->path, g_error_copy (error));
- goto out;
+ 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))
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_empty)
+ if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
{
- if (is_file_part_empty && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
- {
- gtk_file_path_free (info.path_from_entry);
- return NULL;
- }
+ 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;
}
+ 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 &&
g_object_unref (handle);
}
-struct SaveEntryData
+struct FileExistsData
{
GtkFileChooserDefault *impl;
gboolean file_exists_and_is_not_folder;
{
gboolean parent_is_folder;
gboolean cancelled = handle->cancelled;
- struct SaveEntryData *data = user_data;
+ struct FileExistsData *data = user_data;
if (handle != data->impl->should_respond_get_info_handle)
goto out;
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,
}
else
{
- 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_OPEN)
- retval = TRUE; /* user typed a filename; we are done */
- else 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;
- struct SaveEntryData *data;
-
- /* check that everything up to the last component exists */
+ struct FileExistsData *data;
- parent_path = gtk_file_path_copy (_gtk_file_chooser_entry_get_current_folder (entry));
+ /* We need to check whether path exists and is not a folder */
- data = g_new0 (struct SaveEntryData, 1);
- data->impl = g_object_ref (impl);
- data->file_exists_and_is_not_folder = file_exists_and_is_not_folder;
- data->parent_path = parent_path; /* Takes ownership */
- data->path = gtk_file_path_copy (path);
+ 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->should_respond_get_info_handle)
- gtk_file_system_cancel_operation (impl->should_respond_get_info_handle);
+ if (impl->file_exists_get_info_handle)
+ gtk_file_system_cancel_operation (impl->file_exists_get_info_handle);
- impl->should_respond_get_info_handle =
- gtk_file_system_get_info (impl->file_system, parent_path,
- GTK_FILE_INFO_IS_FOLDER,
- save_entry_get_info_cb,
- data);
- set_busy_cursor (impl, TRUE);
+ 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);
- retval = FALSE;
- }
+ set_busy_cursor (impl, TRUE);
+ retval = FALSE;
if (error != NULL)
g_error_free (error);
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,
NULL);
}
+static void
+location_set_user_text (GtkFileChooserDefault *impl,
+ const gchar *path)
+{
+ _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)
{
LocationMode new_mode;
- if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+ 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;
}
location_mode_set (impl, new_mode, TRUE);
+ if (new_mode == LOCATION_MODE_FILENAME_ENTRY)
+ {
+ if (path != NULL)
+ location_set_user_text (impl, path);
+ else
+ {
+ location_entry_set_initial_text (impl);
+ gtk_editable_select_region (GTK_EDITABLE (impl->location_entry), 0, -1);
+ }
+ }
}
else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- gtk_widget_grab_focus (impl->location_entry);
+ {
+ gtk_widget_grab_focus (impl->location_entry);
+ if (path != NULL)
+ location_set_user_text (impl, path);
+ }
else
g_assert_not_reached ();
}
return GTK_TREE_MODEL (model);
}
-
-#define __GTK_FILE_CHOOSER_DEFAULT_C__
-#include "gtkaliasdef.c"