bgo#629722 - file chooser should cope with typing a directory name and then Enter

file_exists_get_info_cb() used to let some actions fall through to
the code that checks for the file type of the selected file's parent
(e.g. to see if /foo/bar *is* indeed a folder if you type /foo/bar/baz).
However, we need to be more explicit for each file chooser action, as
in SELECT_FOLDER mode typing /foo/foldername and hitting Enter would not
give you an immediate selection, but rather the file chooser would
complain that it couldn't create that directory as it already exists.

Signed-off-by: Federico Mena Quintero <federico@novell.com>
This commit is contained in:
Stephen Shaw 2010-10-05 12:55:03 -05:00 committed by Federico Mena Quintero
parent fac5167404
commit c9ea622fc6

View File

@ -1014,6 +1014,19 @@ error_creating_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
file, error); file, error);
} }
/* Shows an error about not being able to select a folder because a file with
* the same name is already there.
*/
static void
error_selecting_folder_over_existing_file_dialog (GtkFileChooserDefault *impl,
GFile *file)
{
error_dialog (impl,
_("You may only select folders. The item that you selected is not a folder; "
"try using a different item."),
file, NULL);
}
/* Shows an error dialog about not being able to create a filename */ /* Shows an error dialog about not being able to create a filename */
static void static void
error_building_filename_dialog (GtkFileChooserDefault *impl, error_building_filename_dialog (GtkFileChooserDefault *impl,
@ -8377,7 +8390,9 @@ file_exists_get_info_cb (GCancellable *cancellable,
{ {
gboolean data_ownership_taken = FALSE; gboolean data_ownership_taken = FALSE;
gboolean cancelled = g_cancellable_is_cancelled (cancellable); gboolean cancelled = g_cancellable_is_cancelled (cancellable);
gboolean file_exists_and_is_not_folder; gboolean file_exists;
gboolean is_folder;
gboolean needs_file_type_check = FALSE;
struct FileExistsData *data = user_data; struct FileExistsData *data = user_data;
if (cancellable != data->impl->file_exists_get_info_cancellable) if (cancellable != data->impl->file_exists_get_info_cancellable)
@ -8390,29 +8405,63 @@ file_exists_get_info_cb (GCancellable *cancellable,
if (cancelled) if (cancelled)
goto out; goto out;
file_exists_and_is_not_folder = info && (! _gtk_file_info_consider_as_directory (info)); file_exists = (info != NULL);
is_folder = (file_exists && _gtk_file_info_consider_as_directory (info));
if (data->impl->action == GTK_FILE_CHOOSER_ACTION_OPEN) 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 /* user typed a filename; we are done */
* a folder g_signal_emit_by_name (data->impl, "response-requested");
*/ }
error_creating_folder_over_existing_file_dialog (data->impl, data->file, else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
g_error_copy (error)); {
if (file_exists && !is_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->file,
g_error_copy (error));
}
else
{
needs_file_type_check = TRUE;
}
}
else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
{
if (!file_exists)
{
needs_file_type_check = TRUE;
}
else
{
if (is_folder)
{
/* User typed a folder; we are done */
g_signal_emit_by_name (data->impl, "response-requested");
}
else
error_selecting_folder_over_existing_file_dialog (data->impl, data->file);
}
}
else if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
{
needs_file_type_check = TRUE;
} }
else else
{ {
/* check that everything up to the last component exists */ g_assert_not_reached();
}
data->file_exists_and_is_not_folder = file_exists_and_is_not_folder; if (needs_file_type_check) {
data_ownership_taken = TRUE; /* check that everything up to the last component exists */
if (data->impl->should_respond_get_info_cancellable) data->file_exists_and_is_not_folder = file_exists && !is_folder;
g_cancellable_cancel (data->impl->should_respond_get_info_cancellable); data_ownership_taken = TRUE;
if (data->impl->should_respond_get_info_cancellable)
g_cancellable_cancel (data->impl->should_respond_get_info_cancellable);
data->impl->should_respond_get_info_cancellable = data->impl->should_respond_get_info_cancellable =
_gtk_file_system_get_info (data->impl->file_system, _gtk_file_system_get_info (data->impl->file_system,
@ -8622,7 +8671,11 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
{ {
struct FileExistsData *data; struct FileExistsData *data;
/* We need to check whether file exists and is not a folder */ /* We need to check whether file exists and whether it is a folder -
* the GtkFileChooserEntry *does* report is_folder==FALSE as a false
* negative (it doesn't know yet if your last path component is a
* folder).
*/
data = g_new0 (struct FileExistsData, 1); data = g_new0 (struct FileExistsData, 1);
data->impl = g_object_ref (impl); data->impl = g_object_ref (impl);