[gnome-builder] libide: add ide_project_rename_file_async()



commit 18863ccae90bcab050c0d8caf94dc456ea32c931
Author: Christian Hergert <christian hergert me>
Date:   Wed Apr 15 18:02:13 2015 -0700

    libide: add ide_project_rename_file_async()
    
    This will rename a file within the project tree and attach it to the
    new position in the tree.
    
    This process has lead me to believe we probably want to add tree observers
    to deal with movements/additions/deletes. It could really simplify
    things externally, like the project-tree UI.

 libide/ide-project-file.c  |   21 ++++---
 libide/ide-project-files.c |    3 +-
 libide/ide-project.c       |  155 ++++++++++++++++++++++++++++++++++++++++++++
 libide/ide-project.h       |   35 ++++++----
 4 files changed, 191 insertions(+), 23 deletions(-)
---
diff --git a/libide/ide-project-file.c b/libide/ide-project-file.c
index af24a43..d4ef827 100644
--- a/libide/ide-project-file.c
+++ b/libide/ide-project-file.c
@@ -71,9 +71,13 @@ ide_project_file_set_path (IdeProjectFile *self,
   IdeProjectFilePrivate *priv = ide_project_file_get_instance_private (self);
 
   g_return_if_fail (IDE_IS_PROJECT_FILE (self));
-  g_return_if_fail (!priv->path);
 
-  priv->path = g_strdup (path);
+  if (priv->path != path)
+    {
+      g_free (priv->path);
+      priv->path = g_strdup (path);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_PATH]);
+    }
 }
 
 const gchar *
@@ -149,7 +153,10 @@ ide_project_file_set_file_info (IdeProjectFile *file,
   g_return_if_fail (!file_info || G_IS_FILE_INFO (file_info));
 
   if (g_set_object (&priv->file_info, file_info))
-    g_object_notify_by_pspec (G_OBJECT (file), gParamSpecs [PROP_FILE_INFO]);
+    {
+      g_object_notify_by_pspec (G_OBJECT (file), gParamSpecs [PROP_FILE_INFO]);
+      g_object_notify_by_pspec (G_OBJECT (file), gParamSpecs [PROP_NAME]);
+    }
 }
 
 static void
@@ -250,9 +257,7 @@ ide_project_file_class_init (IdeProjectFileClass *klass)
                          _("File Info"),
                          _("The file information for the project file."),
                          G_TYPE_FILE_INFO,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT_ONLY |
-                          G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_FILE_INFO,
                                    gParamSpecs [PROP_FILE_INFO]);
 
@@ -279,9 +284,7 @@ ide_project_file_class_init (IdeProjectFileClass *klass)
                          _("Path"),
                          _("The path for the file within the project tree."),
                          NULL,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT_ONLY |
-                          G_PARAM_STATIC_STRINGS));
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_PATH,
                                    gParamSpecs [PROP_PATH]);
 }
diff --git a/libide/ide-project-files.c b/libide/ide-project-files.c
index 9238923..7f9568d 100644
--- a/libide/ide-project-files.c
+++ b/libide/ide-project-files.c
@@ -96,6 +96,7 @@ ide_project_files_find_child (IdeProjectItem *item,
  * @file: A #GFile.
  *
  * Tries to locate an #IdeProjectFile matching the given file.
+ * If @file is the working directory, @self is returned.
  *
  * Returns: (transfer none) (nullable): An #IdeProjectItem or %NULL.
  */
@@ -120,7 +121,7 @@ ide_project_files_find_file (IdeProjectFiles *self,
   workdir = ide_vcs_get_working_directory (vcs);
 
   if (g_file_equal (workdir, file))
-    return NULL;
+    return IDE_PROJECT_ITEM (self);
 
   path = g_file_get_relative_path (workdir, file);
   if (path == NULL)
diff --git a/libide/ide-project.c b/libide/ide-project.c
index aaae474..97b5079 100644
--- a/libide/ide-project.c
+++ b/libide/ide-project.c
@@ -19,6 +19,7 @@
 #include <glib/gi18n.h>
 
 #include "ide-context.h"
+#include "ide-debug.h"
 #include "ide-file.h"
 #include "ide-project.h"
 #include "ide-project-files.h"
@@ -32,6 +33,12 @@ typedef struct
   gchar          *name;
 } IdeProjectPrivate;
 
+typedef struct
+{
+  GFile *orig_file;
+  GFile *new_file;
+} RenameFile;
+
 G_DEFINE_TYPE_WITH_PRIVATE (IdeProject, ide_project, IDE_TYPE_OBJECT)
 
 enum {
@@ -400,3 +407,151 @@ ide_project_init (IdeProject *self)
 
   g_rw_lock_init (&priv->rw_lock);
 }
+
+static void
+ide_project_rename_file_worker (GTask        *task,
+                                gpointer      source_object,
+                                gpointer      task_data,
+                                GCancellable *cancellable)
+{
+  IdeProject *self = source_object;
+  IdeProjectFiles *files;
+  IdeProjectItem *item;
+  IdeContext *context;
+  IdeVcs *vcs;
+  RenameFile *op = task_data;
+  g_autoptr(GFileInfo) file_info = NULL;
+  g_autofree gchar *path = NULL;
+  GError *error = NULL;
+  GFile *workdir;
+
+  g_assert (IDE_IS_PROJECT (self));
+  g_assert (op != NULL);
+  g_assert (G_IS_FILE (op->orig_file));
+  g_assert (G_IS_FILE (op->new_file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ide_project_writer_lock (self);
+
+  files = ide_project_get_files (self);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+  path = g_file_get_relative_path (workdir, op->new_file);
+
+#ifndef IDE_DISABLE_TRACE
+  {
+    gchar *old_path = g_file_get_uri (op->orig_file);
+    gchar *new_path = g_file_get_uri (op->new_file);
+    IDE_TRACE_MSG ("Renaming %s to %s", old_path, new_path);
+    g_free (old_path);
+    g_free (new_path);
+  }
+#endif
+
+  if (path == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               _("Destination file must be within the project tree."));
+      goto cleanup;
+    }
+
+  item = ide_project_files_find_file (files, op->orig_file);
+
+  if (item == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               _("Source file must be within the project tree."));
+      goto cleanup;
+    }
+
+  if (!g_file_move (op->orig_file, op->new_file, G_FILE_COPY_NONE, cancellable, NULL, NULL, &error))
+    {
+      g_task_return_error (task, error);
+      goto cleanup;
+    }
+
+  file_info = g_file_query_info (op->new_file,
+                                 G_FILE_ATTRIBUTE_STANDARD_NAME","
+                                 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME","
+                                 G_FILE_ATTRIBUTE_STANDARD_TYPE,
+                                 G_FILE_QUERY_INFO_NONE,
+                                 cancellable,
+                                 &error);
+
+  if (file_info == NULL)
+    {
+      g_task_return_error (task, error);
+      goto cleanup;
+    }
+
+  g_object_ref (item);
+  ide_project_item_remove (ide_project_item_get_parent (item), item);
+  g_object_set (item,
+                "file", op->new_file,
+                "path", path,
+                "file-info", file_info,
+                NULL);
+  ide_project_files_add_file (files, IDE_PROJECT_FILE (item));
+  g_object_unref (item);
+
+  g_task_return_boolean (task, TRUE);
+
+cleanup:
+  ide_project_writer_unlock (self);
+}
+
+static void
+rename_file_free (gpointer data)
+{
+  RenameFile *op = data;
+
+  if (op != NULL)
+    {
+      g_object_unref (op->new_file);
+      g_object_unref (op->orig_file);
+      g_slice_free (RenameFile, op);
+    }
+}
+
+void
+ide_project_rename_file_async (IdeProject          *self,
+                               GFile               *orig_file,
+                               GFile               *new_file,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  RenameFile *op;
+
+  g_return_if_fail (IDE_IS_PROJECT (self));
+  g_return_if_fail (G_IS_FILE (orig_file));
+  g_return_if_fail (G_IS_FILE (new_file));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  op = g_slice_new0 (RenameFile);
+  op->orig_file = g_object_ref (orig_file);
+  op->new_file = g_object_ref (new_file);
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_task_data (task, op, rename_file_free);
+  g_task_run_in_thread (task, ide_project_rename_file_worker);
+}
+
+gboolean
+ide_project_rename_file_finish (IdeProject    *self,
+                                GAsyncResult  *result,
+                                GError       **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (IDE_IS_PROJECT (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (task), FALSE);
+
+  return g_task_propagate_boolean (task, error);
+}
diff --git a/libide/ide-project.h b/libide/ide-project.h
index 3fef16f..f631478 100644
--- a/libide/ide-project.h
+++ b/libide/ide-project.h
@@ -33,19 +33,28 @@ struct _IdeProjectClass
   IdeObjectClass parent;
 };
 
-IdeProjectItem  *ide_project_get_root          (IdeProject     *project);
-const gchar     *ide_project_get_name          (IdeProject     *project);
-IdeFile         *ide_project_get_file_for_path (IdeProject     *project,
-                                                const gchar    *path);
-IdeFile         *ide_project_get_project_file  (IdeProject     *self,
-                                                GFile          *gfile);
-void             ide_project_reader_lock       (IdeProject     *project);
-void             ide_project_reader_unlock     (IdeProject     *project);
-void             ide_project_writer_lock       (IdeProject     *project);
-void             ide_project_writer_unlock     (IdeProject     *project);
-void             ide_project_add_file          (IdeProject     *project,
-                                                IdeProjectFile *file);
-IdeProjectFiles *ide_project_get_files         (IdeProject     *self);
+IdeProjectItem  *ide_project_get_root           (IdeProject           *project);
+const gchar     *ide_project_get_name           (IdeProject           *project);
+IdeFile         *ide_project_get_file_for_path  (IdeProject           *project,
+                                                 const gchar          *path);
+IdeFile         *ide_project_get_project_file   (IdeProject           *self,
+                                                 GFile                *gfile);
+void             ide_project_reader_lock        (IdeProject           *project);
+void             ide_project_reader_unlock      (IdeProject           *project);
+void             ide_project_writer_lock        (IdeProject           *project);
+void             ide_project_writer_unlock      (IdeProject           *project);
+void             ide_project_add_file           (IdeProject           *project,
+                                                 IdeProjectFile       *file);
+IdeProjectFiles *ide_project_get_files          (IdeProject           *self);
+void             ide_project_rename_file_async  (IdeProject           *self,
+                                                 GFile                *orig_file,
+                                                 GFile                *new_file,
+                                                 GCancellable         *cancellable,
+                                                 GAsyncReadyCallback   callback,
+                                                 gpointer              user_data);
+gboolean         ide_project_rename_file_finish (IdeProject           *project,
+                                                 GAsyncResult         *result,
+                                                 GError              **error);
 
 G_END_DECLS
 


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