[nautilus/wip/antoniof/update-starred-uris: 1/2] tag-manager: Update starred URIs on move & rename




commit 135190900b7f5b9bad0fc41a4aac8b88e0dd4c7f
Author: António Fernandes <antoniof gnome org>
Date:   Wed Sep 9 23:32:01 2020 +0100

    tag-manager: Update starred URIs on move & rename
    
    We don't rely on tracker-miner-fs's rename tracking for starred files
    anymore, as explained in 29105fc9f6abf2eca6f986104763d21b9f22f0fb.
    
    However, losing track of starred files, when they or their containing
    folders are renamed or moved, is a major regression for this feature.
    
    The common case is that the operation is performed using this very app,
    so, we can largely restore the feature by updating URI on every rename
    and move operation we perform.
    
    Additionally, this allows us to finally close a couple of old issues.
    
    Fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/161
    and fixes https://gitlab.gnome.org/GNOME/nautilus/-/issues/169

 src/nautilus-file-changes-queue.c |   6 ++
 src/nautilus-file.c               |  13 +++-
 src/nautilus-tag-manager.c        | 134 ++++++++++++++++++++++++++++++++++++++
 src/nautilus-tag-manager.h        |   3 +
 4 files changed, 154 insertions(+), 2 deletions(-)
---
diff --git a/src/nautilus-file-changes-queue.c b/src/nautilus-file-changes-queue.c
index 8f042fa7f..d1bdc46b2 100644
--- a/src/nautilus-file-changes-queue.c
+++ b/src/nautilus-file-changes-queue.c
@@ -21,6 +21,7 @@
 #include "nautilus-file-changes-queue.h"
 
 #include "nautilus-directory-notify.h"
+#include "nautilus-tag-manager.h"
 
 typedef enum
 {
@@ -206,6 +207,7 @@ pairs_list_free (GList *pairs)
 void
 nautilus_file_changes_consume_changes (gboolean consume_all)
 {
+    g_autoptr (NautilusTagManager) tag_manager = nautilus_tag_manager_get ();
     NautilusFileChange *change;
     GList *additions, *changes, *deletions, *moves;
     GFilePair *pair;
@@ -321,6 +323,10 @@ nautilus_file_changes_consume_changes (gboolean consume_all)
 
             case CHANGE_FILE_MOVED:
             {
+                nautilus_tag_manager_update_moved_uris (tag_manager,
+                                                        change->from,
+                                                        change->to);
+
                 pair = g_new (GFilePair, 1);
                 pair->from = change->from;
                 pair->to = change->to;
diff --git a/src/nautilus-file.c b/src/nautilus-file.c
index 6fcaea89b..3ba887e8d 100644
--- a/src/nautilus-file.c
+++ b/src/nautilus-file.c
@@ -1853,6 +1853,10 @@ rename_get_info_callback (GObject      *source_object,
     new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
     if (new_info != NULL)
     {
+        g_autoptr (NautilusTagManager) tag_manager = nautilus_tag_manager_get ();
+        g_autoptr (GFile) old_location = NULL;
+        g_autoptr (GFile) new_location = NULL;
+
         directory = op->file->details->directory;
 
         new_name = g_file_info_get_name (new_info);
@@ -1868,12 +1872,17 @@ rename_get_info_callback (GObject      *source_object,
             nautilus_file_changed (existing_file);
         }
 
-        old_uri = nautilus_file_get_uri (op->file);
+        old_location = nautilus_file_get_location (op->file);
+        old_uri = g_file_get_uri (old_location);
 
         update_info_and_name (op->file, new_info);
 
-        new_uri = nautilus_file_get_uri (op->file);
+        new_location = nautilus_file_get_location (op->file);
+        new_uri = g_file_get_uri (new_location);
+
         nautilus_directory_moved (old_uri, new_uri);
+        nautilus_tag_manager_update_moved_uris (tag_manager, old_location, new_location);
+
         g_free (new_uri);
         g_free (old_uri);
 
diff --git a/src/nautilus-tag-manager.c b/src/nautilus-tag-manager.c
index fbd8571e5..5486c5cb7 100644
--- a/src/nautilus-tag-manager.c
+++ b/src/nautilus-tag-manager.c
@@ -700,6 +700,140 @@ nautilus_tag_manager_can_star_contents (NautilusTagManager *tag_manager,
     return g_file_has_prefix (directory, tag_manager->home) || g_file_equal (directory, tag_manager->home);
 }
 
+static void
+update_moved_uris_callback (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
+{
+    g_autoptr (GError) error = NULL;
+    g_autoptr (GPtrArray) new_uris = user_data;
+
+    tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (object),
+                                             result,
+                                             &error);
+
+    if (error != NULL && error->code != G_IO_ERROR_CANCELLED)
+    {
+        g_warning ("Error updating moved uris: %s", error->message);
+    }
+    else
+    {
+        g_autolist (NautilusFile) updated_files = NULL;
+        g_autoptr (NautilusTagManager) tag_manager = NULL;
+
+        for (guint i = 0; i < new_uris->len; i++)
+        {
+            gchar *new_uri = g_ptr_array_index (new_uris, i);
+
+            updated_files = g_list_prepend (updated_files, nautilus_file_get_by_uri (new_uri));
+        }
+
+        tag_manager = nautilus_tag_manager_get ();
+        g_signal_emit_by_name (tag_manager, "starred-changed", updated_files);
+    }
+}
+
+/**
+ * nautilus_tag_manager_update_moved_uris:
+ * @self: The tag manager singleton
+ * @src: The original location as a #GFile
+ * @dest: The new location as a #GFile
+ *
+ * Checks whether the rename/move operation (@src to @dest) has modified
+ * the URIs of any starred files, and updates the database accordingly.
+ */
+void
+nautilus_tag_manager_update_moved_uris (NautilusTagManager *self,
+                                        GFile              *src,
+                                        GFile              *dest)
+{
+    GHashTableIter starred_iter;
+    gchar *starred_uri;
+    g_autoptr (GPtrArray) old_uris = NULL;
+    g_autoptr (GPtrArray) new_uris = NULL;
+    g_autoptr (GString) query = NULL;
+
+    if (!self->database_ok)
+    {
+        g_message ("nautilus-tag-manager: No Tracker connection");
+        return;
+    }
+
+    old_uris = g_ptr_array_new ();
+    new_uris = g_ptr_array_new_with_free_func (g_free);
+
+    g_hash_table_iter_init (&starred_iter, self->starred_file_uris);
+    while (g_hash_table_iter_next (&starred_iter, (gpointer *) &starred_uri, NULL))
+    {
+        g_autoptr (GFile) starred_location = NULL;
+        g_autofree gchar *relative_path = NULL;
+
+        starred_location = g_file_new_for_uri (starred_uri);
+
+        if (g_file_equal (starred_location, src))
+        {
+            /* The moved file/folder is starred */
+            g_ptr_array_add (old_uris, starred_uri);
+            g_ptr_array_add (new_uris, g_file_get_uri (dest));
+            continue;
+        }
+
+        relative_path = g_file_get_relative_path (src, starred_location);
+        if (relative_path != NULL)
+        {
+            /* The starred file/folder is descendant of the moved/renamed directory */
+            g_autoptr (GFile) new_location = NULL;
+
+            new_location = g_file_resolve_relative_path (dest, relative_path);
+
+            g_ptr_array_add (old_uris, starred_uri);
+            g_ptr_array_add (new_uris, g_file_get_uri (new_location));
+        }
+    }
+
+    if (new_uris->len == 0)
+    {
+        /* No starred files are affected by this move/rename */
+        return;
+    }
+
+    DEBUG ("Updating moved URI for %i starred files", new_uris->len);
+
+    query = g_string_new ("DELETE DATA {");
+
+    for (guint i = 0; i < old_uris->len; i++)
+    {
+        gchar *old_uri = g_ptr_array_index (old_uris, i);
+        g_string_append_printf (query,
+                                "    <%s> a nautilus:File ; "
+                                "        nautilus:starred true . ",
+                                old_uri);
+    }
+
+    g_string_append (query, "} ; INSERT DATA {");
+
+    for (guint i = 0; i < new_uris->len; i++)
+    {
+        gchar *new_uri = g_ptr_array_index (new_uris, i);
+        g_string_append_printf (query,
+                                "    <%s> a nautilus:File ; "
+                                "        nautilus:starred true . ",
+                                new_uri);
+    }
+
+    g_string_append (query, "}");
+
+    /* Forward the new_uris list to later pass in the ::files-changed signal.
+     * There is no need to pass the old_uris because the file model is updated
+     * independently; we need only inform the view where to display stars now.
+     */
+    tracker_sparql_connection_update_async (self->db,
+                                            query->str,
+                                            self->cancellable,
+                                            update_moved_uris_callback,
+                                            g_steal_pointer (&new_uris));
+}
+
 static void
 process_tracker2_data_cb (GObject      *source_object,
                           GAsyncResult *res,
diff --git a/src/nautilus-tag-manager.h b/src/nautilus-tag-manager.h
index 2e926ae75..1ba8a48dd 100644
--- a/src/nautilus-tag-manager.h
+++ b/src/nautilus-tag-manager.h
@@ -53,6 +53,9 @@ gboolean            nautilus_tag_manager_file_is_starred   (NautilusTagManager *
 
 gboolean            nautilus_tag_manager_can_star_contents (NautilusTagManager *self,
                                                             GFile              *directory);
+void                nautilus_tag_manager_update_moved_uris  (NautilusTagManager *tag_manager,
+                                                             GFile              *src,
+                                                             GFile              *dest);
 
 void                nautilus_tag_manager_maybe_migrate_tracker2_data (NautilusTagManager *self);
 


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