Use a popover for creating new folders

This commit is contained in:
Matthias Clasen 2015-04-09 20:56:54 -04:00
parent 6c8790f62c
commit c41ab14730
2 changed files with 235 additions and 22 deletions

View File

@ -229,6 +229,10 @@ struct _GtkFileChooserWidgetPrivate {
GtkWidget *browse_path_bar_hbox;
GtkSizeGroup *browse_path_bar_size_group;
GtkWidget *browse_path_bar;
GtkWidget *new_folder_name_entry;
GtkWidget *new_folder_create_button;
GtkWidget *new_folder_error_label;
GtkWidget *new_folder_popover;
GtkFileSystemModel *browse_files_model;
char *browse_files_last_selected_name;
@ -937,6 +941,159 @@ new_folder_button_clicked (GtkButton *button,
gtk_tree_path_free (path);
}
static void
new_folder_popover_active (GtkWidget *button,
GParamSpec *pspec,
GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
gtk_entry_set_text (GTK_ENTRY (priv->new_folder_name_entry), "");
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), "");
}
struct FileExistsData
{
GtkFileChooserWidget *impl;
gboolean file_exists_and_is_not_folder;
GFile *parent_file;
GFile *file;
};
static void
name_exists_get_info_cb (GCancellable *cancellable,
GFileInfo *info,
const GError *error,
gpointer user_data)
{
struct FileExistsData *data = user_data;
GtkFileChooserWidget *impl = data->impl;
GtkFileChooserWidgetPrivate *priv = impl->priv;
if (cancellable != priv->file_exists_get_info_cancellable)
goto out;
priv->file_exists_get_info_cancellable = NULL;
if (g_cancellable_is_cancelled (cancellable))
goto out;
if (info != NULL)
{
const gchar *msg;
if (_gtk_file_info_consider_as_directory (info))
msg = _("A folder with that name already exists");
else
msg = _("A file with that name already exists");
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), msg);
}
else
{
gtk_widget_set_sensitive (priv->new_folder_create_button, TRUE);
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), "");
}
out:
g_object_unref (impl);
g_object_unref (data->file);
g_object_unref (data->parent_file);
g_free (data);
g_object_unref (cancellable);
}
static void
check_valid_folder_name (GtkFileChooserWidget *impl,
const gchar *name)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
if (name[0] == '\0')
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), "");
else if (strcmp (name, ".") == 0)
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label),
_("A folder cannot be called “.”"));
else if (strcmp (name, "..") == 0)
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label),
_("A folder cannot be called “..”"));
else if (strchr (name, '/') != NULL)
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label),
_("Folder names cannot contain “/”"));
else
{
GFile *file;
GError *error = NULL;
file = g_file_get_child_for_display_name (priv->current_folder, name, &error);
if (file == NULL)
{
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), error->message);
g_error_free (error);
}
else
{
struct FileExistsData *data;
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), "");
data = g_new0 (struct FileExistsData, 1);
data->impl = g_object_ref (impl);
data->parent_file = g_object_ref (priv->current_folder);
data->file = g_object_ref (file);
if (priv->file_exists_get_info_cancellable)
g_cancellable_cancel (priv->file_exists_get_info_cancellable);
priv->file_exists_get_info_cancellable =
_gtk_file_system_get_info (priv->file_system,
file,
"standard::type",
name_exists_get_info_cb,
data);
g_object_unref (file);
}
}
}
static void
new_folder_name_changed (GtkEntry *entry,
GtkFileChooserWidget *impl)
{
check_valid_folder_name (impl, gtk_entry_get_text (entry));
}
static void
new_folder_create_clicked (GtkButton *button,
GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
GError *error = NULL;
GFile *file;
const gchar *name;
name = gtk_entry_get_text (GTK_ENTRY (priv->new_folder_name_entry));
file = g_file_get_child_for_display_name (priv->current_folder, name, &error);
gtk_widget_hide (priv->new_folder_popover);
if (file)
{
if (g_file_make_directory (file, NULL, &error))
change_folder_and_display_error (impl, file, FALSE);
else
error_creating_folder_dialog (impl, file, error);
g_object_unref (file);
}
else
error_creating_folder_dialog (impl, file, error);
}
static GSource *
add_idle_while_impl_is_alive (GtkFileChooserWidget *impl, GCallback callback)
{
@ -5482,14 +5639,6 @@ should_respond_after_confirm_overwrite (GtkFileChooserWidget *impl,
}
}
struct FileExistsData
{
GtkFileChooserWidget *impl;
gboolean file_exists_and_is_not_folder;
GFile *parent_file;
GFile *file;
};
static void
name_entry_get_parent_info_cb (GCancellable *cancellable,
GFileInfo *info,
@ -7491,6 +7640,10 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_mtime_column);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_size_column);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_column);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_name_entry);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_create_button);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_error_label);
gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_popover);
/* And a *lot* of callbacks to bind ... */
gtk_widget_class_bind_template_callback (widget_class, browse_files_key_press_event_cb);
@ -7513,6 +7666,9 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_callback (widget_class, places_sidebar_show_enter_location_cb);
gtk_widget_class_bind_template_callback (widget_class, search_entry_activate_cb);
gtk_widget_class_bind_template_callback (widget_class, search_entry_stop_cb);
gtk_widget_class_bind_template_callback (widget_class, new_folder_popover_active);
gtk_widget_class_bind_template_callback (widget_class, new_folder_name_changed);
gtk_widget_class_bind_template_callback (widget_class, new_folder_create_clicked);
}
static void

View File

@ -78,22 +78,13 @@
</packing>
</child>
<child>
<object class="GtkButton" id="browse_new_folder_button">
<property name="tooltip-text" translatable="yes">Create Folder</property>
<object class="GtkMenuButton" id="browse_new_folder_button">
<property name="label" translatable="yes">Create _Folder</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="new_folder_button_clicked" swapped="no"/>
<style>
<class name="image-button"/>
</style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">list-add-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
<property name="popover">new_folder_popover</property>
<signal name="notify::active" handler="new_folder_popover_active"/>
</object>
<packing>
<property name="expand">False</property>
@ -372,4 +363,70 @@
<widget name="browse_new_folder_button"/>
</widgets>
</object>
<object class="GtkPopover" id="new_folder_popover">
<property name="modal">True</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="margin">10</property>
<property name="column-spacing">6</property>
<property name="row-spacing">6</property>
<property name="row-homogeneous">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Folder Name</property>
<property name="halign">start</property>
<property name="mnemonic_widget">new_folder_name_entry</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="new_folder_name_entry">
<property name="visible">True</property>
<property name="width-chars">25</property>
<signal name="changed" handler="new_folder_name_changed"/>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="new_folder_create_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="label" translatable="yes">_Create</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="new_folder_create_clicked"/>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="new_folder_error_label">
<property name="visible">True</property>
<property name="halign">start</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>