[gtk+/save-popover: 1/2] Use a popover for creating new folders



commit 5e35d3c8de8209bca2f9469a4e94441c8c290ca3
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Apr 9 20:56:54 2015 -0400

    Use a popover for creating new folders

 gtk/gtkfilechooserwidget.c     |  172 ++++++++++++++++++++++++++++++++++++++--
 gtk/ui/gtkfilechooserwidget.ui |   83 ++++++++++++++++---
 2 files changed, 233 insertions(+), 22 deletions(-)
---
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 8fada3b..3016d88 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -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
diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui
index 83e095c..40cfb3e 100644
--- a/gtk/ui/gtkfilechooserwidget.ui
+++ b/gtk/ui/gtkfilechooserwidget.ui
@@ -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,68 @@
       <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">10</property>
+        <property name="row-homogeneous">True</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Name</property>
+          </object>
+          <packing>
+            <property name="left-attach">0</property>
+            <property name="top-attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="orientation">horizontal</property>
+            <style>
+              <class name="linked"/>
+            </style>
+            <child>
+              <object class="GtkEntry" id="new_folder_name_entry">
+                <property name="visible">True</property>
+                <signal name="changed" handler="new_folder_name_changed"/>
+              </object>
+            </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>
+            </child>
+          </object>
+          <packing>
+            <property name="left-attach">1</property>
+            <property name="top-attach">0</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">1</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
 </interface>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]