Compare commits
5 Commits
wip/ebassi
...
save-popov
Author | SHA1 | Date | |
---|---|---|---|
|
e2de76d465 | ||
|
0bb12749d1 | ||
|
24e1ecce23 | ||
|
86c97fd710 | ||
|
5e35d3c8de |
@@ -229,6 +229,10 @@ struct _GtkFileChooserWidgetPrivate {
|
|||||||
GtkWidget *browse_path_bar_hbox;
|
GtkWidget *browse_path_bar_hbox;
|
||||||
GtkSizeGroup *browse_path_bar_size_group;
|
GtkSizeGroup *browse_path_bar_size_group;
|
||||||
GtkWidget *browse_path_bar;
|
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;
|
GtkFileSystemModel *browse_files_model;
|
||||||
char *browse_files_last_selected_name;
|
char *browse_files_last_selected_name;
|
||||||
@@ -301,9 +305,6 @@ struct _GtkFileChooserWidgetPrivate {
|
|||||||
|
|
||||||
guint location_changed_id;
|
guint location_changed_id;
|
||||||
|
|
||||||
GSource *edited_idle;
|
|
||||||
char *edited_new_text;
|
|
||||||
|
|
||||||
gulong settings_signal_id;
|
gulong settings_signal_id;
|
||||||
int icon_size;
|
int icon_size;
|
||||||
|
|
||||||
@@ -655,8 +656,6 @@ gtk_file_chooser_widget_finalize (GObject *object)
|
|||||||
|
|
||||||
g_free (priv->preview_display_name);
|
g_free (priv->preview_display_name);
|
||||||
|
|
||||||
g_free (priv->edited_new_text);
|
|
||||||
|
|
||||||
impl->priv = NULL;
|
impl->priv = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_file_chooser_widget_parent_class)->finalize (object);
|
G_OBJECT_CLASS (gtk_file_chooser_widget_parent_class)->finalize (object);
|
||||||
@@ -937,113 +936,158 @@ new_folder_button_clicked (GtkButton *button,
|
|||||||
gtk_tree_path_free (path);
|
gtk_tree_path_free (path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSource *
|
static void
|
||||||
add_idle_while_impl_is_alive (GtkFileChooserWidget *impl, GCallback callback)
|
new_folder_popover_active (GtkWidget *button,
|
||||||
{
|
GParamSpec *pspec,
|
||||||
GSource *source;
|
GtkFileChooserWidget *impl)
|
||||||
|
|
||||||
source = g_idle_source_new ();
|
|
||||||
g_source_set_closure (source,
|
|
||||||
g_cclosure_new_object (callback, G_OBJECT (impl)));
|
|
||||||
g_source_attach (source, NULL);
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Idle handler for creating a new folder after editing its name cell, or for
|
|
||||||
* canceling the editing.
|
|
||||||
*/
|
|
||||||
static gboolean
|
|
||||||
edited_idle_cb (GtkFileChooserWidget *impl)
|
|
||||||
{
|
{
|
||||||
GtkFileChooserWidgetPrivate *priv = impl->priv;
|
GtkFileChooserWidgetPrivate *priv = impl->priv;
|
||||||
|
|
||||||
gdk_threads_enter ();
|
gtk_entry_set_text (GTK_ENTRY (priv->new_folder_name_entry), "");
|
||||||
|
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
|
||||||
g_source_destroy (priv->edited_idle);
|
gtk_label_set_text (GTK_LABEL (priv->new_folder_error_label), "");
|
||||||
priv->edited_idle = NULL;
|
}
|
||||||
|
|
||||||
_gtk_file_system_model_remove_editable (priv->browse_files_model);
|
struct FileExistsData
|
||||||
g_object_set (priv->list_name_renderer, "editable", FALSE, NULL);
|
{
|
||||||
|
GtkFileChooserWidget *impl;
|
||||||
|
gboolean file_exists_and_is_not_folder;
|
||||||
|
GFile *parent_file;
|
||||||
|
GFile *file;
|
||||||
|
};
|
||||||
|
|
||||||
gtk_widget_set_sensitive (priv->browse_new_folder_button, TRUE);
|
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 (priv->edited_new_text /* not cancelled? */
|
if (cancellable != priv->file_exists_get_info_cancellable)
|
||||||
&& (strlen (priv->edited_new_text) != 0)
|
goto out;
|
||||||
&& (strcmp (priv->edited_new_text, DEFAULT_NEW_FOLDER_NAME) != 0)) /* Don't create folder if name is empty or has not been edited */
|
|
||||||
|
priv->file_exists_get_info_cancellable = NULL;
|
||||||
|
|
||||||
|
if (g_cancellable_is_cancelled (cancellable))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (info != NULL)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
const gchar *msg;
|
||||||
GFile *file;
|
|
||||||
|
|
||||||
file = g_file_get_child_for_display_name (priv->current_folder,
|
if (_gtk_file_info_consider_as_directory (info))
|
||||||
priv->edited_new_text,
|
msg = _("A folder with that name already exists");
|
||||||
&error);
|
|
||||||
if (file)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
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
|
else
|
||||||
error_creating_folder_dialog (impl, file, error);
|
msg = _("A file with that name already exists");
|
||||||
|
|
||||||
g_free (priv->edited_new_text);
|
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
|
||||||
priv->edited_new_text = NULL;
|
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), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
gdk_threads_leave ();
|
out:
|
||||||
|
g_object_unref (impl);
|
||||||
return FALSE;
|
g_object_unref (data->file);
|
||||||
|
g_object_unref (data->parent_file);
|
||||||
|
g_free (data);
|
||||||
|
g_object_unref (cancellable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
queue_edited_idle (GtkFileChooserWidget *impl,
|
check_valid_folder_name (GtkFileChooserWidget *impl,
|
||||||
const gchar *new_text)
|
const gchar *name)
|
||||||
{
|
{
|
||||||
GtkFileChooserWidgetPrivate *priv = impl->priv;
|
GtkFileChooserWidgetPrivate *priv = impl->priv;
|
||||||
|
|
||||||
/* We create the folder in an idle handler so that we don't modify the tree
|
gtk_widget_set_sensitive (priv->new_folder_create_button, FALSE);
|
||||||
* just now.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!priv->edited_idle)
|
if (name[0] == '\0')
|
||||||
priv->edited_idle = add_idle_while_impl_is_alive (impl, G_CALLBACK (edited_idle_cb));
|
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;
|
||||||
|
|
||||||
g_free (priv->edited_new_text);
|
file = g_file_get_child_for_display_name (priv->current_folder, name, &error);
|
||||||
priv->edited_new_text = g_strdup (new_text);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback used from the text cell renderer when the new folder is named */
|
|
||||||
static void
|
static void
|
||||||
renderer_edited_cb (GtkCellRendererText *cell_renderer_text,
|
new_folder_name_changed (GtkEntry *entry,
|
||||||
const gchar *path,
|
GtkFileChooserWidget *impl)
|
||||||
const gchar *new_text,
|
|
||||||
GtkFileChooserWidget *impl)
|
|
||||||
{
|
{
|
||||||
/* work around bug #154921 */
|
check_valid_folder_name (impl, gtk_entry_get_text (entry));
|
||||||
g_object_set (cell_renderer_text,
|
|
||||||
"mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
|
|
||||||
queue_edited_idle (impl, new_text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback used from the text cell renderer when the new folder edition gets
|
|
||||||
* canceled.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
renderer_editing_canceled_cb (GtkCellRendererText *cell_renderer_text,
|
new_folder_create_clicked (GtkButton *button,
|
||||||
GtkFileChooserWidget *impl)
|
GtkFileChooserWidget *impl)
|
||||||
{
|
{
|
||||||
/* work around bug #154921 */
|
GtkFileChooserWidgetPrivate *priv = impl->priv;
|
||||||
g_object_set (cell_renderer_text,
|
GError *error = NULL;
|
||||||
"mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
|
GFile *file;
|
||||||
queue_edited_idle (impl, NULL);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
struct selection_check_closure {
|
struct selection_check_closure {
|
||||||
GtkFileChooserWidget *impl;
|
GtkFileChooserWidget *impl;
|
||||||
@@ -5482,14 +5526,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
|
static void
|
||||||
name_entry_get_parent_info_cb (GCancellable *cancellable,
|
name_entry_get_parent_info_cb (GCancellable *cancellable,
|
||||||
GFileInfo *info,
|
GFileInfo *info,
|
||||||
@@ -7491,6 +7527,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_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_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, 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 ... */
|
/* And a *lot* of callbacks to bind ... */
|
||||||
gtk_widget_class_bind_template_callback (widget_class, browse_files_key_press_event_cb);
|
gtk_widget_class_bind_template_callback (widget_class, browse_files_key_press_event_cb);
|
||||||
@@ -7503,8 +7543,6 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
|
|||||||
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_motion_cb);
|
gtk_widget_class_bind_template_callback (widget_class, file_list_drag_motion_cb);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, list_selection_changed);
|
gtk_widget_class_bind_template_callback (widget_class, list_selection_changed);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed);
|
gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, renderer_editing_canceled_cb);
|
|
||||||
gtk_widget_class_bind_template_callback (widget_class, renderer_edited_cb);
|
|
||||||
gtk_widget_class_bind_template_callback (widget_class, filter_combo_changed);
|
gtk_widget_class_bind_template_callback (widget_class, filter_combo_changed);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, new_folder_button_clicked);
|
gtk_widget_class_bind_template_callback (widget_class, new_folder_button_clicked);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, path_bar_clicked);
|
gtk_widget_class_bind_template_callback (widget_class, path_bar_clicked);
|
||||||
@@ -7513,6 +7551,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, 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_activate_cb);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, search_entry_stop_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
|
static void
|
||||||
|
@@ -78,22 +78,13 @@
|
|||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="browse_new_folder_button">
|
<object class="GtkMenuButton" id="browse_new_folder_button">
|
||||||
<property name="tooltip-text" translatable="yes">Create Folder</property>
|
<property name="label" translatable="yes">Create _Folder</property>
|
||||||
<property name="can_focus">True</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>
|
<property name="use_underline">True</property>
|
||||||
<signal name="clicked" handler="new_folder_button_clicked" swapped="no"/>
|
<property name="popover">new_folder_popover</property>
|
||||||
<style>
|
<signal name="notify::active" handler="new_folder_popover_active"/>
|
||||||
<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>
|
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
@@ -226,8 +217,6 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkCellRendererText" id="list_name_renderer">
|
<object class="GtkCellRendererText" id="list_name_renderer">
|
||||||
<property name="ellipsize">end</property>
|
<property name="ellipsize">end</property>
|
||||||
<signal name="edited" handler="renderer_edited_cb" swapped="no"/>
|
|
||||||
<signal name="editing-canceled" handler="renderer_editing_canceled_cb" swapped="no"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
@@ -372,4 +361,69 @@
|
|||||||
<widget name="browse_new_folder_button"/>
|
<widget name="browse_new_folder_button"/>
|
||||||
</widgets>
|
</widgets>
|
||||||
</object>
|
</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>
|
||||||
|
<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>
|
</interface>
|
||||||
|
Reference in New Issue
Block a user