[nautilus/recycle-popover-controllers: 5/5] rename-file-popover-controller: Make popover recyclable



commit 6f38def1c110def3be8c2e302cae24f1447da3b0
Author: Ernestas Kulik <ernestask gnome org>
Date:   Thu Mar 15 21:28:54 2018 +0200

    rename-file-popover-controller: Make popover recyclable
    
    Creating and destroying the controller each time we want to rename
    something results in not being able to pop down the popover, which leads
    to an inconsistent look.
    
    The “containing-directory” in the file name widget controller parent
    class needed to be made non-construct-only, as otherwise it would be
    impossible to reuse the same controller.
    
    Fixes https://gitlab.gnome.org/GNOME/nautilus/issues/260

 src/nautilus-file-name-widget-controller.c    |  34 +++--
 src/nautilus-file-name-widget-controller.h    |   3 +
 src/nautilus-files-view.c                     |  63 ++++++---
 src/nautilus-rename-file-popover-controller.c | 193 ++++++++++++++++----------
 src/nautilus-rename-file-popover-controller.h |  13 +-
 5 files changed, 200 insertions(+), 106 deletions(-)
---
diff --git a/src/nautilus-file-name-widget-controller.c b/src/nautilus-file-name-widget-controller.c
index 0deff902b..25fc5d690 100644
--- a/src/nautilus-file-name-widget-controller.c
+++ b/src/nautilus-file-name-widget-controller.c
@@ -63,6 +63,15 @@ nautilus_file_name_widget_controller_get_new_name (NautilusFileNameWidgetControl
     return NAUTILUS_FILE_NAME_WIDGET_CONTROLLER_GET_CLASS (self)->get_new_name (self);
 }
 
+void
+nautilus_file_name_widget_controller_set_containing_directory (NautilusFileNameWidgetController *self,
+                                                               NautilusDirectory                *directory)
+{
+    g_assert (NAUTILUS_IS_DIRECTORY (directory));
+
+    g_object_set (self, "containing-directory", directory, NULL);
+}
+
 static gboolean
 nautilus_file_name_widget_controller_name_is_valid (NautilusFileNameWidgetController  *self,
                                                     gchar                             *name,
@@ -161,6 +170,7 @@ file_name_widget_controller_process_new_name (NautilusFileNameWidgetController *
     priv = nautilus_file_name_widget_controller_get_instance_private (controller);
 
     name = nautilus_file_name_widget_controller_get_new_name (controller);
+    *duplicated_name = FALSE;
     *valid_name = nautilus_file_name_widget_controller_name_is_valid (controller,
                                                                       name,
                                                                       &error_message);
@@ -169,10 +179,13 @@ file_name_widget_controller_process_new_name (NautilusFileNameWidgetController *
     gtk_revealer_set_reveal_child (GTK_REVEALER (priv->error_revealer),
                                    error_message != NULL);
 
-    existing_file = nautilus_directory_get_file_by_name (priv->containing_directory, name);
-    *duplicated_name = existing_file != NULL &&
-                       !nautilus_file_name_widget_controller_ignore_existing_file (controller,
-                                                                                   existing_file);
+    if (priv->containing_directory != NULL)
+    {
+        existing_file = nautilus_directory_get_file_by_name (priv->containing_directory, name);
+        *duplicated_name = existing_file != NULL &&
+                           !nautilus_file_name_widget_controller_ignore_existing_file (controller,
+                                                                                       existing_file);
+    }
 
     gtk_widget_set_sensitive (priv->activate_button, *valid_name && !*duplicated_name);
 
@@ -289,6 +302,11 @@ file_name_widget_controller_on_activate (gpointer user_data)
 static void
 nautilus_file_name_widget_controller_init (NautilusFileNameWidgetController *self)
 {
+    NautilusFileNameWidgetControllerPrivate *priv;
+
+    priv = nautilus_file_name_widget_controller_get_instance_private (self);
+
+    priv->containing_directory = NULL;
 }
 
 static void
@@ -345,8 +363,9 @@ nautilus_file_name_widget_controller_set_property (GObject      *object,
 
         case PROP_CONTAINING_DIRECTORY:
         {
-            priv->containing_directory = NAUTILUS_DIRECTORY (g_value_get_object (value));
-            nautilus_directory_ref (priv->containing_directory);
+            g_clear_object (&priv->containing_directory);
+
+            priv->containing_directory = NAUTILUS_DIRECTORY (g_value_dup_object (value));
         }
         break;
 
@@ -460,6 +479,5 @@ nautilus_file_name_widget_controller_class_init (NautilusFileNameWidgetControlle
                              "Containing Directory",
                              "The directory used to check for duplicate names",
                              NAUTILUS_TYPE_DIRECTORY,
-                             G_PARAM_WRITABLE |
-                             G_PARAM_CONSTRUCT_ONLY));
+                             G_PARAM_WRITABLE));
 }
diff --git a/src/nautilus-file-name-widget-controller.h b/src/nautilus-file-name-widget-controller.h
index 94b23b880..1bd481c43 100644
--- a/src/nautilus-file-name-widget-controller.h
+++ b/src/nautilus-file-name-widget-controller.h
@@ -45,3 +45,6 @@ struct _NautilusFileNameWidgetControllerClass
 };
 
 gchar * nautilus_file_name_widget_controller_get_new_name (NautilusFileNameWidgetController *controller);
+
+void    nautilus_file_name_widget_controller_set_containing_directory (NautilusFileNameWidgetController 
*controller,
+                                                                       NautilusDirectory                
*directory);
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index fe276e277..a1cd2c9cd 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -269,6 +269,9 @@ typedef struct
 
     GCancellable *starred_cancellable;
     NautilusTagManager *tag_manager;
+
+    gint name_accepted_handler_id;
+    gint cancelled_handler_id;
 } NautilusFilesViewPrivate;
 
 typedef struct
@@ -1884,6 +1887,29 @@ nautilus_files_view_compute_rename_popover_pointing_to (NautilusFilesView *view)
     return NAUTILUS_FILES_VIEW_CLASS (G_OBJECT_GET_CLASS (view))->compute_rename_popover_pointing_to (view);
 }
 
+static void
+disconnect_rename_controller_signals (NautilusFilesView *self)
+{
+    NautilusFilesViewPrivate *priv;
+
+    g_assert (NAUTILUS_IS_FILES_VIEW (self));
+
+    priv = nautilus_files_view_get_instance_private (self);
+
+    if (priv->name_accepted_handler_id != 0)
+    {
+        g_signal_handler_disconnect (priv->rename_file_controller, priv->name_accepted_handler_id);
+        priv->name_accepted_handler_id = 0;
+    }
+
+    if (priv->cancelled_handler_id != 0)
+    {
+        g_signal_handler_disconnect (priv->rename_file_controller,
+                                     priv->cancelled_handler_id);
+        priv->cancelled_handler_id = 0;
+    }
+}
+
 static void
 rename_file_popover_controller_on_name_accepted (NautilusFileNameWidgetController *controller,
                                                  gpointer                          user_data)
@@ -1908,7 +1934,7 @@ rename_file_popover_controller_on_name_accepted (NautilusFileNameWidgetControlle
 
     nautilus_rename_file (target_file, name, NULL, NULL);
 
-    g_clear_object (&priv->rename_file_controller);
+    disconnect_rename_controller_signals (view);
 }
 
 static void
@@ -1916,12 +1942,10 @@ rename_file_popover_controller_on_cancelled (NautilusFileNameWidgetController *c
                                              gpointer                          user_data)
 {
     NautilusFilesView *view;
-    NautilusFilesViewPrivate *priv;
 
     view = NAUTILUS_FILES_VIEW (user_data);
-    priv = nautilus_files_view_get_instance_private (view);
 
-    g_clear_object (&priv->rename_file_controller);
+    disconnect_rename_controller_signals (view);
 }
 
 static void
@@ -1933,11 +1957,6 @@ nautilus_files_view_rename_file_popover_new (NautilusFilesView *view,
 
     priv = nautilus_files_view_get_instance_private (view);
 
-    if (priv->rename_file_controller != NULL)
-    {
-        return;
-    }
-
     /* Make sure the whole item is visible. The selection is a single item, the
      * one to rename with the popover, so we can use reveal_selection() for this.
      */
@@ -1945,19 +1964,19 @@ nautilus_files_view_rename_file_popover_new (NautilusFilesView *view,
 
     pointing_to = nautilus_files_view_compute_rename_popover_pointing_to (view);
 
-    priv->rename_file_controller =
-        nautilus_rename_file_popover_controller_new (target_file,
-                                                     pointing_to,
-                                                     GTK_WIDGET (view));
+    nautilus_rename_file_popover_controller_show_for_file (priv->rename_file_controller,
+                                                           target_file,
+                                                           pointing_to,
+                                                           GTK_WIDGET (view));
 
-    g_signal_connect (priv->rename_file_controller,
-                      "name-accepted",
-                      (GCallback) rename_file_popover_controller_on_name_accepted,
-                      view);
-    g_signal_connect (priv->rename_file_controller,
-                      "cancelled",
-                      (GCallback) rename_file_popover_controller_on_cancelled,
-                      view);
+    priv->name_accepted_handler_id = g_signal_connect (priv->rename_file_controller,
+                                                       "name-accepted",
+                                                       G_CALLBACK 
(rename_file_popover_controller_on_name_accepted),
+                                                       view);
+    priv->cancelled_handler_id = g_signal_connect (priv->rename_file_controller,
+                                                   "cancelled",
+                                                   G_CALLBACK (rename_file_popover_controller_on_cancelled),
+                                                   view);
 }
 
 static void
@@ -9649,6 +9668,8 @@ nautilus_files_view_init (NautilusFilesView *view)
     priv->starred_cancellable = g_cancellable_new ();
     priv->tag_manager = nautilus_tag_manager_get ();
 
+    priv->rename_file_controller = nautilus_rename_file_popover_controller_new ();
+
     nautilus_profile_end (NULL);
 }
 
diff --git a/src/nautilus-rename-file-popover-controller.c b/src/nautilus-rename-file-popover-controller.c
index 5806315fb..b195e4d3b 100644
--- a/src/nautilus-rename-file-popover-controller.c
+++ b/src/nautilus-rename-file-popover-controller.c
@@ -38,13 +38,52 @@ struct _NautilusRenameFilePopoverController
     gboolean target_is_folder;
 
     GtkWidget *rename_file_popover;
+    GtkWidget *name_entry;
+    GtkWidget *name_label;
 
     gint closed_handler_id;
     gint file_changed_handler_id;
+    gint key_press_event_handler_id;
 };
 
 G_DEFINE_TYPE (NautilusRenameFilePopoverController, nautilus_rename_file_popover_controller, 
NAUTILUS_TYPE_FILE_NAME_WIDGET_CONTROLLER)
 
+static void
+disconnect_signal_handlers (NautilusRenameFilePopoverController *self)
+{
+    g_assert (NAUTILUS_IS_RENAME_FILE_POPOVER_CONTROLLER (self));
+
+    if (self->closed_handler_id != 0)
+    {
+        g_signal_handler_disconnect (self->rename_file_popover, self->closed_handler_id);
+        self->closed_handler_id = 0;
+    }
+
+    if (self->file_changed_handler_id != 0)
+    {
+        g_signal_handler_disconnect (self->target_file, self->file_changed_handler_id);
+        self->file_changed_handler_id = 0;
+    }
+
+    if (self->key_press_event_handler_id != 0)
+    {
+        g_signal_handler_disconnect (self->name_entry, self->key_press_event_handler_id);
+        self->key_press_event_handler_id = 0;
+    }
+}
+
+static void
+reset_state (NautilusRenameFilePopoverController *self)
+{
+    g_assert (NAUTILUS_IS_RENAME_FILE_POPOVER_CONTROLLER (self));
+
+    disconnect_signal_handlers (self);
+
+    g_clear_object (&self->target_file);
+
+    gtk_popover_popdown (GTK_POPOVER (self->rename_file_popover));
+}
+
 static void
 rename_file_popover_controller_on_closed (GtkPopover *popover,
                                           gpointer    user_data)
@@ -53,9 +92,7 @@ rename_file_popover_controller_on_closed (GtkPopover *popover,
 
     controller = NAUTILUS_RENAME_FILE_POPOVER_CONTROLLER (user_data);
 
-    g_signal_handler_disconnect (controller->rename_file_popover,
-                                 controller->closed_handler_id);
-    controller->closed_handler_id = 0;
+    reset_state (controller);
 
     g_signal_emit_by_name (controller, "cancelled");
 }
@@ -137,7 +174,7 @@ name_entry_on_f2_pressed (GtkWidget                           *widget,
     text_length = (guint) gtk_entry_get_text_length (GTK_ENTRY (widget));
     if (text_length == 0)
     {
-        return GDK_EVENT_PROPAGATE;
+        return GDK_EVENT_STOP;
     }
 
     gtk_editable_get_selection_bounds (GTK_EDITABLE (widget),
@@ -160,7 +197,7 @@ name_entry_on_f2_pressed (GtkWidget                           *widget,
                                     start_offset, end_offset);
     }
 
-    return GDK_EVENT_PROPAGATE;
+    return GDK_EVENT_STOP;
 }
 
 static gboolean
@@ -212,18 +249,14 @@ target_file_on_changed (NautilusFile *file,
 
     if (nautilus_file_is_gone (file))
     {
-        g_signal_handler_disconnect (controller->target_file,
-                                     controller->file_changed_handler_id);
-        controller->file_changed_handler_id = 0;
+        reset_state (controller);
 
         g_signal_emit_by_name (controller, "cancelled");
     }
 }
 
 NautilusRenameFilePopoverController *
-nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
-                                             GdkRectangle *pointing_to,
-                                             GtkWidget    *relative_to)
+nautilus_rename_file_popover_controller_new (void)
 {
     NautilusRenameFilePopoverController *self;
     g_autoptr (GtkBuilder) builder = NULL;
@@ -233,9 +266,6 @@ nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
     GtkWidget *name_entry;
     GtkWidget *activate_button;
     GtkWidget *name_label;
-    NautilusDirectory *containing_directory;
-    g_autofree char *display_name = NULL;
-    gint n_chars;
 
     builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-rename-file-popover.ui");
     rename_file_popover = GTK_WIDGET (gtk_builder_get_object (builder, "rename_file_popover"));
@@ -245,35 +275,69 @@ nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
     activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "rename_button"));
     name_label = GTK_WIDGET (gtk_builder_get_object (builder, "name_label"));
 
-    if (!nautilus_file_is_self_owned (target_file))
-    {
-        NautilusFile *parent_location;
+    self = g_object_new (NAUTILUS_TYPE_RENAME_FILE_POPOVER_CONTROLLER,
+                         "error-revealer", error_revealer,
+                         "error-label", error_label,
+                         "name-entry", name_entry,
+                         "activate-button", activate_button,
+                         NULL);
+
+    self->rename_file_popover = g_object_ref_sink (rename_file_popover);
+    self->name_entry = name_entry;
+    self->name_label = name_label;
+
+    gtk_popover_set_default_widget (GTK_POPOVER (rename_file_popover), name_entry);
+
+    g_clear_object (&builder);
 
-        parent_location = nautilus_file_get_parent (target_file);
-        containing_directory = nautilus_directory_get_for_file (parent_location);
+    return self;
+}
 
-        nautilus_file_unref (parent_location);
+NautilusFile *
+nautilus_rename_file_popover_controller_get_target_file (NautilusRenameFilePopoverController *self)
+{
+    g_return_val_if_fail (NAUTILUS_IS_RENAME_FILE_POPOVER_CONTROLLER (self), NULL);
+
+    return self->target_file;
+}
+
+void
+nautilus_rename_file_popover_controller_show_for_file   (NautilusRenameFilePopoverController *self,
+                                                         NautilusFile                        *target_file,
+                                                         GdkRectangle                        *pointing_to,
+                                                         GtkWidget                           *relative_to)
+{
+    g_autoptr (NautilusDirectory) containing_directory = NULL;
+    g_autofree gchar *display_name = NULL;
+    gint n_chars;
+
+    g_assert (NAUTILUS_IS_RENAME_FILE_POPOVER_CONTROLLER (self));
+    g_assert (NAUTILUS_IS_FILE (target_file));
+
+    reset_state (self);
+
+    self->target_file = g_object_ref (target_file);
+
+    if (!nautilus_file_is_self_owned (self->target_file))
+    {
+        g_autoptr (NautilusFile) parent = NULL;
+
+        parent = nautilus_file_get_parent (self->target_file);
+        containing_directory = nautilus_directory_get_for_file (parent);
     }
     else
     {
-        containing_directory = nautilus_directory_get_for_file (target_file);
+        containing_directory = nautilus_directory_get_for_file (self->target_file);
     }
 
-    self = g_object_new (NAUTILUS_TYPE_RENAME_FILE_POPOVER_CONTROLLER,
-                         "error-revealer", error_revealer,
-                         "error-label", error_label,
-                         "name-entry", name_entry,
-                         "activate-button", activate_button,
-                         "containing-directory", containing_directory, NULL);
-
-    self->target_is_folder = nautilus_file_is_directory (target_file);
-    self->target_file = nautilus_file_ref (target_file);
+    nautilus_file_name_widget_controller_set_containing_directory (NAUTILUS_FILE_NAME_WIDGET_CONTROLLER 
(self),
+                                                                   containing_directory);
 
-    self->rename_file_popover = rename_file_popover;
+    self->target_is_folder = nautilus_file_is_directory (self->target_file);
 
-    self->closed_handler_id = g_signal_connect (rename_file_popover,
+    self->closed_handler_id = g_signal_connect (self->rename_file_popover,
                                                 "closed",
-                                                (GCallback) rename_file_popover_controller_on_closed,
+                                                G_CALLBACK (rename_file_popover_controller_on_closed),
                                                 self);
 
     self->file_changed_handler_id = g_signal_connect (self->target_file,
@@ -281,26 +345,25 @@ nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
                                                       G_CALLBACK (target_file_on_changed),
                                                       self);
 
-    g_signal_connect (name_entry,
-                      "key-press-event",
-                      G_CALLBACK (name_entry_on_key_pressed),
-                      self);
+    self->key_press_event_handler_id = g_signal_connect (self->name_entry,
+                                                         "key-press-event",
+                                                         G_CALLBACK (name_entry_on_key_pressed),
+                                                         self);
 
-    gtk_label_set_text (GTK_LABEL (name_label),
+    gtk_label_set_text (GTK_LABEL (self->name_label),
                         self->target_is_folder ? _("Folder name") :
                         _("File name"));
 
-    display_name = nautilus_file_get_display_name (target_file);
+    display_name = nautilus_file_get_display_name (self->target_file);
 
-    gtk_entry_set_text (GTK_ENTRY (name_entry), display_name);
+    gtk_entry_set_text (GTK_ENTRY (self->name_entry), display_name);
 
-    gtk_popover_set_default_widget (GTK_POPOVER (rename_file_popover), name_entry);
-    gtk_popover_set_pointing_to (GTK_POPOVER (rename_file_popover), pointing_to);
-    gtk_popover_set_relative_to (GTK_POPOVER (rename_file_popover), relative_to);
+    gtk_popover_set_pointing_to (GTK_POPOVER (self->rename_file_popover), pointing_to);
+    gtk_popover_set_relative_to (GTK_POPOVER (self->rename_file_popover), relative_to);
 
-    gtk_popover_popup (GTK_POPOVER (rename_file_popover));
+    gtk_popover_popup (GTK_POPOVER (self->rename_file_popover));
 
-    if (nautilus_file_is_regular_file (target_file))
+    if (nautilus_file_is_regular_file (self->target_file))
     {
         gint start_offset;
         gint end_offset;
@@ -308,31 +371,30 @@ nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
         /* Select the name part without the file extension */
         eel_filename_get_rename_region (display_name,
                                         &start_offset, &end_offset);
-        gtk_editable_select_region (GTK_EDITABLE (name_entry),
+        gtk_editable_select_region (GTK_EDITABLE (self->name_entry),
                                     start_offset, end_offset);
     }
 
     n_chars = g_utf8_strlen (display_name, -1);
-    gtk_entry_set_width_chars (GTK_ENTRY (name_entry),
+    gtk_entry_set_width_chars (GTK_ENTRY (self->name_entry),
                                MIN (MAX (n_chars, RENAME_ENTRY_MIN_CHARS),
                                     RENAME_ENTRY_MAX_CHARS));
-
-    nautilus_directory_unref (containing_directory);
-
-    return self;
 }
 
-NautilusFile *
-nautilus_rename_file_popover_controller_get_target_file (NautilusRenameFilePopoverController *self)
+static void
+on_name_accepted (NautilusFileNameWidgetController *controller)
 {
-    g_return_val_if_fail (NAUTILUS_IS_RENAME_FILE_POPOVER_CONTROLLER (self), NULL);
+    NautilusRenameFilePopoverController *self;
 
-    return self->target_file;
+    self = NAUTILUS_RENAME_FILE_POPOVER_CONTROLLER (controller);
+
+    reset_state (self);
 }
 
 static void
 nautilus_rename_file_popover_controller_init (NautilusRenameFilePopoverController *self)
 {
+    g_signal_connect_after (self, "name-accepted", G_CALLBACK (on_name_accepted), self);
 }
 
 static void
@@ -342,25 +404,10 @@ nautilus_rename_file_popover_controller_finalize (GObject *object)
 
     self = NAUTILUS_RENAME_FILE_POPOVER_CONTROLLER (object);
 
-    if (self->rename_file_popover)
-    {
-        if (self->closed_handler_id)
-        {
-            g_signal_handler_disconnect (self->rename_file_popover,
-                                         self->closed_handler_id);
-            self->closed_handler_id = 0;
-        }
-        gtk_popover_popdown (GTK_POPOVER (self->rename_file_popover));
-        g_clear_pointer (&self->rename_file_popover, gtk_widget_destroy);
-    }
+    reset_state (self);
 
-    if (self->file_changed_handler_id != 0)
-    {
-        g_signal_handler_disconnect (self->target_file,
-                                     self->file_changed_handler_id);
-        self->file_changed_handler_id = 0;
-    }
-    nautilus_file_unref (self->target_file);
+    gtk_widget_destroy (self->rename_file_popover);
+    g_clear_object (&self->rename_file_popover);
 
     G_OBJECT_CLASS (nautilus_rename_file_popover_controller_parent_class)->finalize (object);
 }
diff --git a/src/nautilus-rename-file-popover-controller.h b/src/nautilus-rename-file-popover-controller.h
index 3b55ffdb7..f27f45a9d 100644
--- a/src/nautilus-rename-file-popover-controller.h
+++ b/src/nautilus-rename-file-popover-controller.h
@@ -28,8 +28,13 @@
 #define NAUTILUS_TYPE_RENAME_FILE_POPOVER_CONTROLLER nautilus_rename_file_popover_controller_get_type ()
 G_DECLARE_FINAL_TYPE (NautilusRenameFilePopoverController, nautilus_rename_file_popover_controller, 
NAUTILUS, RENAME_FILE_POPOVER_CONTROLLER, NautilusFileNameWidgetController)
 
-NautilusRenameFilePopoverController * nautilus_rename_file_popover_controller_new (NautilusFile *target_file,
-                                                                                   GdkRectangle *pointing_to,
-                                                                                   GtkWidget    
*relative_to);
+NautilusRenameFilePopoverController * nautilus_rename_file_popover_controller_new (void);
 
-NautilusFile * nautilus_rename_file_popover_controller_get_target_file (NautilusRenameFilePopoverController 
*controller);
\ No newline at end of file
+NautilusFile * nautilus_rename_file_popover_controller_get_target_file (NautilusRenameFilePopoverController 
*controller);
+
+gboolean       nautilus_rename_file_popover_controller_is_active       (NautilusRenameFilePopoverController 
*controller);
+
+void           nautilus_rename_file_popover_controller_show_for_file   (NautilusRenameFilePopoverController 
*controller,
+                                                                        NautilusFile                        
*target_file,
+                                                                        GdkRectangle                        
*pointing_to,
+                                                                        GtkWidget                           
*relative_to);


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