[gnome-builder/wip/chergert/perspective] genesis: unify genesis of directory and git projects



commit 1e1b1d729a7cf501a3e237a40c06f2f7bb8ec787
Author: Christian Hergert <chergert redhat com>
Date:   Tue Dec 1 17:32:26 2015 -0800

    genesis: unify genesis of directory and git projects
    
    This moves more plumbing to the header bar instead of individual workflows
    for each genesis addin.

 data/ui/ide-genesis-perspective.ui             |   15 +++-
 libide/directory/ide-directory-genesis-addin.c |  123 +++++++++++++++++++++++-
 libide/genesis/ide-genesis-addin.c             |   28 +++++
 libide/genesis/ide-genesis-addin.h             |   26 ++++-
 libide/genesis/ide-genesis-perspective.c       |   84 +++++++++++++++-
 plugins/git/ide-git-clone-widget.c             |  127 ++++++++++++++++--------
 plugins/git/ide-git-clone-widget.h             |    8 ++
 plugins/git/ide-git-clone-widget.ui            |   29 ------
 plugins/git/ide-git-genesis-addin.c            |  117 ++++++++++++++++++++--
 9 files changed, 471 insertions(+), 86 deletions(-)
---
diff --git a/data/ui/ide-genesis-perspective.ui b/data/ui/ide-genesis-perspective.ui
index fd65884..d1c2937 100644
--- a/data/ui/ide-genesis-perspective.ui
+++ b/data/ui/ide-genesis-perspective.ui
@@ -36,7 +36,7 @@
     <property name="show-close-button">true</property>
     <property name="visible">true</property>
     <child>
-      <object class="GtkButton">
+      <object class="GtkButton" id="cancel_button">
         <property name="action-name">perspective.go-previous</property>
         <property name="visible">true</property>
         <style>
@@ -56,5 +56,18 @@
         <property name="visible">true</property>
       </object>
     </child>
+    <child>
+      <object class="GtkButton" id="continue_button">
+        <property name="label" translatable="yes">Co_ntinue</property>
+        <property name="use-underline">true</property>
+        <property name="sensitive">false</property>
+        <style>
+          <class name="suggested-action"/>
+        </style>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libide/directory/ide-directory-genesis-addin.c b/libide/directory/ide-directory-genesis-addin.c
index 6c347df..7832a09 100644
--- a/libide/directory/ide-directory-genesis-addin.c
+++ b/libide/directory/ide-directory-genesis-addin.c
@@ -21,11 +21,13 @@
 
 #include "ide-directory-genesis-addin.h"
 #include "ide-genesis-addin.h"
+#include "ide-gtk.h"
+#include "ide-workbench.h"
 
 struct _IdeDirectoryGenesisAddin
 {
   GObject               parent_instance;
-
+  guint                 is_ready : 1;
   GtkFileChooserWidget *widget;
 };
 
@@ -34,9 +36,57 @@ static void genesis_addin_iface_init (IdeGenesisAddinInterface *iface);
 G_DEFINE_TYPE_EXTENDED (IdeDirectoryGenesisAddin, ide_directory_genesis_addin, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_GENESIS_ADDIN, genesis_addin_iface_init))
 
+enum {
+  PROP_0,
+  PROP_IS_READY,
+  LAST_PROP
+};
+
+static gboolean
+ide_directory_genesis_addin_get_is_ready (IdeDirectoryGenesisAddin *self)
+{
+  g_autoptr(GFile) file = NULL;
+
+  g_assert (IDE_IS_DIRECTORY_GENESIS_ADDIN (self));
+
+  file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (self->widget));
+
+  return (file != NULL);
+}
+
+static void
+ide_directory_genesis_addin_get_property (GObject    *object,
+                                          guint       prop_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  IdeDirectoryGenesisAddin *self = IDE_DIRECTORY_GENESIS_ADDIN(object);
+
+  switch (prop_id)
+    {
+    case PROP_IS_READY:
+      g_value_set_boolean (value, ide_directory_genesis_addin_get_is_ready (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
 static void
 ide_directory_genesis_addin_class_init (IdeDirectoryGenesisAddinClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = ide_directory_genesis_addin_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_IS_READY,
+                                   g_param_spec_boolean ("is-ready",
+                                                         "Is Ready",
+                                                         "Is Ready",
+                                                         FALSE,
+                                                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
 }
 
 static void
@@ -57,6 +107,16 @@ ide_directory_genesis_addin_get_title (IdeGenesisAddin *addin)
 }
 
 static void
+ide_directory_genesis_addin_selection_changed (IdeDirectoryGenesisAddin *self,
+                                               GtkFileChooserWidget     *chooser)
+{
+  g_assert (IDE_IS_DIRECTORY_GENESIS_ADDIN (self));
+  g_assert (GTK_IS_FILE_CHOOSER_WIDGET (chooser));
+
+  g_object_notify (G_OBJECT (self), "is-ready");
+}
+
+static void
 ide_directory_genesis_addin_add_filters (GtkFileChooser *chooser)
 {
   PeasEngine *engine = peas_engine_get_default ();
@@ -125,6 +185,11 @@ ide_directory_genesis_addin_get_widget (IdeGenesisAddin *addin)
                                    "action", GTK_FILE_CHOOSER_ACTION_OPEN,
                                    "visible", TRUE,
                                    NULL);
+      g_signal_connect_object (self->widget,
+                               "selection-changed",
+                               G_CALLBACK (ide_directory_genesis_addin_selection_changed),
+                               self,
+                               G_CONNECT_SWAPPED);
       ide_directory_genesis_addin_add_filters (GTK_FILE_CHOOSER (self->widget));
     }
 
@@ -132,9 +197,65 @@ ide_directory_genesis_addin_get_widget (IdeGenesisAddin *addin)
 }
 
 static void
+ide_directory_genesis_addin_run_cb (GObject      *object,
+                                    GAsyncResult *result,
+                                    gpointer      user_data)
+{
+  IdeWorkbench *workbench = (IdeWorkbench *)object;
+  g_autoptr(GTask) task = user_data;
+  GError *error = NULL;
+
+  g_assert (IDE_IS_WORKBENCH (workbench));
+  g_assert (G_IS_TASK (task));
+
+  if (!ide_workbench_open_project_finish (workbench, result, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_directory_genesis_addin_run_async (IdeGenesisAddin     *addin,
+                                       GCancellable        *cancellable,
+                                       GAsyncReadyCallback  callback,
+                                       gpointer             user_data)
+{
+  IdeDirectoryGenesisAddin *self = (IdeDirectoryGenesisAddin *)addin;
+  g_autoptr(GTask) task = NULL;
+  g_autoptr(GFile) project_file = NULL;
+  IdeWorkbench *workbench;
+
+  g_assert (IDE_IS_DIRECTORY_GENESIS_ADDIN (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  workbench = ide_widget_get_workbench (GTK_WIDGET (self->widget));
+  project_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (self->widget));
+
+  ide_workbench_open_project_async (workbench,
+                                    project_file,
+                                    cancellable,
+                                    ide_directory_genesis_addin_run_cb,
+                                    g_object_ref (task));
+}
+
+static gboolean
+ide_directory_genesis_addin_run_finish (IdeGenesisAddin  *addin,
+                                        GAsyncResult     *result,
+                                        GError          **error)
+{
+  g_return_val_if_fail (IDE_IS_DIRECTORY_GENESIS_ADDIN (addin), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
 genesis_addin_iface_init (IdeGenesisAddinInterface *iface)
 {
   iface->get_title = ide_directory_genesis_addin_get_title;
   iface->get_icon_name = ide_directory_genesis_addin_get_icon_name;
   iface->get_widget = ide_directory_genesis_addin_get_widget;
+  iface->run_async = ide_directory_genesis_addin_run_async;
+  iface->run_finish = ide_directory_genesis_addin_run_finish;
 }
diff --git a/libide/genesis/ide-genesis-addin.c b/libide/genesis/ide-genesis-addin.c
index 14a0b8e..f5004a2 100644
--- a/libide/genesis/ide-genesis-addin.c
+++ b/libide/genesis/ide-genesis-addin.c
@@ -23,6 +23,12 @@ G_DEFINE_INTERFACE (IdeGenesisAddin, ide_genesis_addin, G_TYPE_OBJECT)
 static void
 ide_genesis_addin_default_init (IdeGenesisAddinInterface *iface)
 {
+  g_object_interface_install_property (iface,
+                                       g_param_spec_boolean ("is-ready",
+                                                             "Is Ready",
+                                                             "If the project genesis can be executed",
+                                                             FALSE,
+                                                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
 gchar *
@@ -53,3 +59,25 @@ ide_genesis_addin_get_widget (IdeGenesisAddin *self)
 
   return IDE_GENESIS_ADDIN_GET_IFACE (self)->get_widget (self);
 }
+
+void
+ide_genesis_addin_run_async (IdeGenesisAddin     *self,
+                             GCancellable        *cancellable,
+                             GAsyncReadyCallback  callback,
+                             gpointer             user_data)
+{
+  g_return_if_fail (IDE_IS_GENESIS_ADDIN (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  IDE_GENESIS_ADDIN_GET_IFACE (self)->run_async (self, cancellable, callback, user_data);
+}
+
+gboolean
+ide_genesis_addin_run_finish (IdeGenesisAddin  *self,
+                              GAsyncResult     *result,
+                              GError          **error)
+{
+  g_return_val_if_fail (IDE_IS_GENESIS_ADDIN (self), FALSE);
+
+  return IDE_GENESIS_ADDIN_GET_IFACE (self)->run_finish (self, result, error);
+}
diff --git a/libide/genesis/ide-genesis-addin.h b/libide/genesis/ide-genesis-addin.h
index 34d030c..d7fefab 100644
--- a/libide/genesis/ide-genesis-addin.h
+++ b/libide/genesis/ide-genesis-addin.h
@@ -31,14 +31,28 @@ struct _IdeGenesisAddinInterface
 {
   GTypeInterface parent_interface;
 
-  gchar     *(*get_title)     (IdeGenesisAddin *self);
-  gchar     *(*get_icon_name) (IdeGenesisAddin *self);
-  GtkWidget *(*get_widget)    (IdeGenesisAddin *self);
+  gchar     *(*get_title)     (IdeGenesisAddin      *self);
+  gchar     *(*get_icon_name) (IdeGenesisAddin      *self);
+  GtkWidget *(*get_widget)    (IdeGenesisAddin      *self);
+  void       (*run_async)     (IdeGenesisAddin      *self,
+                               GCancellable         *cancellable,
+                               GAsyncReadyCallback   callback,
+                               gpointer              user_data);
+  gboolean   (*run_finish)    (IdeGenesisAddin      *self,
+                               GAsyncResult         *result,
+                               GError              **error);
 };
 
-gchar     *ide_genesis_addin_get_title     (IdeGenesisAddin *self);
-gchar     *ide_genesis_addin_get_icon_name (IdeGenesisAddin *self);
-GtkWidget *ide_genesis_addin_get_widget    (IdeGenesisAddin *self);
+gchar     *ide_genesis_addin_get_title     (IdeGenesisAddin      *self);
+gchar     *ide_genesis_addin_get_icon_name (IdeGenesisAddin      *self);
+GtkWidget *ide_genesis_addin_get_widget    (IdeGenesisAddin      *self);
+void       ide_genesis_addin_run_async     (IdeGenesisAddin      *self,
+                                            GCancellable         *cancellable,
+                                            GAsyncReadyCallback   callback,
+                                            gpointer              user_data);
+gboolean   ide_genesis_addin_run_finish    (IdeGenesisAddin      *self,
+                                            GAsyncResult         *result,
+                                            GError              **error);
 
 G_END_DECLS
 
diff --git a/libide/genesis/ide-genesis-perspective.c b/libide/genesis/ide-genesis-perspective.c
index 55cd264..1d11c14 100644
--- a/libide/genesis/ide-genesis-perspective.c
+++ b/libide/genesis/ide-genesis-perspective.c
@@ -22,6 +22,7 @@
 #include "ide-genesis-addin.h"
 #include "ide-genesis-perspective.h"
 #include "ide-gtk.h"
+#include "ide-macros.h"
 #include "ide-workbench.h"
 
 struct _IdeGenesisPerspective
@@ -30,11 +31,15 @@ struct _IdeGenesisPerspective
 
   GActionGroup     *actions;
   PeasExtensionSet *addins;
+  GBinding         *continue_binding;
+  IdeGenesisAddin  *current_addin;
 
   GtkHeaderBar     *header_bar;
   GtkListBox       *list_box;
   GtkWidget        *main_page;
   GtkStack         *stack;
+  GtkButton        *continue_button;
+  GtkButton        *cancel_button;
 };
 
 static void perspective_iface_init (IdePerspectiveInterface *iface);
@@ -145,6 +150,7 @@ ide_genesis_perspective_row_activated (IdeGenesisPerspective *self,
 {
   IdeGenesisAddin *addin;
   GtkWidget *child;
+  GBinding *binding;
 
   g_assert (GTK_IS_LIST_BOX (list_box));
   g_assert (GTK_IS_LIST_BOX_ROW (row));
@@ -158,7 +164,65 @@ ide_genesis_perspective_row_activated (IdeGenesisPerspective *self,
   if (child == NULL)
     return;
 
+  binding = g_object_bind_property (addin, "is-ready",
+                                    self->continue_button, "sensitive",
+                                    G_BINDING_SYNC_CREATE);
+  ide_set_weak_pointer (&self->continue_binding, binding);
+
+  gtk_widget_show (GTK_WIDGET (self->continue_button));
+  gtk_header_bar_set_show_close_button (self->header_bar, FALSE);
+
   gtk_stack_set_visible_child (self->stack, child);
+
+  self->current_addin = addin;
+}
+
+static void
+ide_genesis_perspective_run_cb (GObject      *object,
+                                GAsyncResult *result,
+                                gpointer      user_data)
+{
+  IdeGenesisAddin *addin = (IdeGenesisAddin *)object;
+  g_autoptr(IdeGenesisPerspective) self = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (IDE_IS_GENESIS_ADDIN (addin));
+  g_assert (IDE_IS_GENESIS_PERSPECTIVE (self));
+
+  if (!ide_genesis_addin_run_finish (addin, result, &error))
+    {
+      GtkWidget *dialog;
+
+      dialog = gtk_message_dialog_new (NULL,
+                                       GTK_DIALOG_USE_HEADER_BAR,
+                                       GTK_MESSAGE_ERROR,
+                                       GTK_BUTTONS_CLOSE,
+                                       _("Failed to load the project"));
+      g_object_set (dialog,
+                    "secondary-text", error->message,
+                    NULL);
+
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+
+      /*
+       * TODO: Destroy workbench.
+       */
+    }
+}
+
+static void
+ide_genesis_perspective_continue_clicked (IdeGenesisPerspective *self,
+                                          GtkButton             *button)
+{
+  g_assert (IDE_IS_GENESIS_PERSPECTIVE (self));
+  g_assert (GTK_IS_BUTTON (button));
+  g_assert (self->current_addin != NULL);
+
+  ide_genesis_addin_run_async (self->current_addin,
+                               NULL,
+                               ide_genesis_perspective_run_cb,
+                               g_object_ref (self));
 }
 
 static void
@@ -178,10 +242,17 @@ ide_genesis_perspective_constructed (GObject *object)
                     "extension-added",
                     G_CALLBACK (ide_genesis_perspective_addin_added),
                     self);
+
   g_signal_connect (self->addins,
                     "extension-removed",
                     G_CALLBACK (ide_genesis_perspective_addin_removed),
                     self);
+
+  g_signal_connect_object (self->continue_button,
+                           "clicked",
+                           G_CALLBACK (ide_genesis_perspective_continue_clicked),
+                           self,
+                           G_CONNECT_SWAPPED);
 }
 
 static void
@@ -207,10 +278,12 @@ ide_genesis_perspective_class_init (IdeGenesisPerspectiveClass *klass)
 
   gtk_widget_class_set_css_name (widget_class, "genesisperspective");
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/ui/ide-genesis-perspective.ui");
+  gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, cancel_button);
+  gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, continue_button);
+  gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, header_bar);
   gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, list_box);
   gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, main_page);
   gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, stack);
-  gtk_widget_class_bind_template_child (widget_class, IdeGenesisPerspective, header_bar);
 }
 
 static void
@@ -256,6 +329,15 @@ go_previous (GSimpleAction *action,
 
   g_assert (IDE_IS_GENESIS_PERSPECTIVE (self));
 
+  if (self->continue_binding)
+    {
+      g_binding_unbind (self->continue_binding);
+      ide_clear_weak_pointer (&self->continue_binding);
+    }
+
+  gtk_widget_hide (GTK_WIDGET (self->continue_button));
+  gtk_header_bar_set_show_close_button (self->header_bar, TRUE);
+
   visible_child = gtk_stack_get_visible_child (self->stack);
 
   if (visible_child != self->main_page)
diff --git a/plugins/git/ide-git-clone-widget.c b/plugins/git/ide-git-clone-widget.c
index 404d780..29f55bb 100644
--- a/plugins/git/ide-git-clone-widget.c
+++ b/plugins/git/ide-git-clone-widget.c
@@ -34,21 +34,26 @@ struct _IdeGitCloneWidget
   GtkFileChooserButton *clone_location_button;
   GtkEntry             *clone_location_entry;
   GtkEntry             *clone_uri_entry;
-  GtkButton            *clone_button;
   GtkLabel             *clone_error_label;
   GtkProgressBar       *clone_progress;
-  GtkSpinner           *clone_spinner;
+
+  guint                 is_ready : 1;
 };
 
 typedef struct
 {
   gchar *uri;
   GFile *location;
+  GFile *project_file;
 } CloneRequest;
 
-G_DEFINE_TYPE (IdeGitCloneWidget, ide_git_clone_widget, GTK_TYPE_BIN)
+enum {
+  PROP_0,
+  PROP_IS_READY,
+  LAST_PROP
+};
 
-static void ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self);
+G_DEFINE_TYPE (IdeGitCloneWidget, ide_git_clone_widget, GTK_TYPE_BIN)
 
 static void
 clone_request_free (gpointer data)
@@ -59,6 +64,7 @@ clone_request_free (gpointer data)
     {
       g_clear_pointer (&req->uri, g_free);
       g_clear_object (&req->location);
+      g_clear_object (&req->project_file);
       g_slice_free (CloneRequest, req);
     }
 }
@@ -75,6 +81,7 @@ clone_request_new (const gchar *uri,
   req = g_slice_new0 (CloneRequest);
   req->uri = g_strdup (uri);
   req->location = g_object_ref (location);
+  req->project_file = NULL;
 
   return req;
 }
@@ -85,6 +92,7 @@ ide_git_clone_widget_uri_changed (IdeGitCloneWidget *self,
 {
   g_autoptr(IdeVcsUri) uri = NULL;
   const gchar *text;
+  gboolean is_ready = FALSE;
 
   g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
   g_assert (GTK_IS_ENTRY (entry));
@@ -113,6 +121,8 @@ ide_git_clone_widget_uri_changed (IdeGitCloneWidget *self,
             gtk_entry_set_text (self->clone_location_entry, name);
           g_free (name);
         }
+
+      is_ready = TRUE;
     }
   else
     {
@@ -121,22 +131,37 @@ ide_git_clone_widget_uri_changed (IdeGitCloneWidget *self,
                     "secondary-icon-tooltip-text", _("A valid Git URL is required"),
                     NULL);
     }
+
+  if (is_ready != self->is_ready)
+    {
+      self->is_ready = is_ready;
+      g_object_notify (G_OBJECT (self), "is-ready");
+    }
 }
 
 static void
-ide_git_clone_widget_clone_button_clicked (IdeGitCloneWidget *self,
-                                           GtkButton         *button)
+ide_git_clone_widget_finalize (GObject *object)
 {
-  g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
-  g_assert (GTK_IS_BUTTON (button));
-
-  ide_git_clone_widget_begin_clone (self);
+  G_OBJECT_CLASS (ide_git_clone_widget_parent_class)->finalize (object);
 }
 
 static void
-ide_git_clone_widget_finalize (GObject *object)
+ide_git_clone_widget_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
 {
-  G_OBJECT_CLASS (ide_git_clone_widget_parent_class)->finalize (object);
+  IdeGitCloneWidget *self = IDE_GIT_CLONE_WIDGET(object);
+
+  switch (prop_id)
+    {
+    case PROP_IS_READY:
+      g_value_set_boolean (value, self->is_ready);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
 }
 
 static void
@@ -146,15 +171,22 @@ ide_git_clone_widget_class_init (IdeGitCloneWidgetClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
   object_class->finalize = ide_git_clone_widget_finalize;
+  object_class->get_property = ide_git_clone_widget_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_IS_READY,
+                                   g_param_spec_boolean ("is-ready",
+                                                         "Is Ready",
+                                                         "If the widget is ready to continue.",
+                                                         FALSE,
+                                                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
 
   gtk_widget_class_set_css_name (widget_class, "gitclonewidget");
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/git/ide-git-clone-widget.ui");
-  gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_button);
   gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_error_label);
   gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_location_button);
   gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_location_entry);
   gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_progress);
-  gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_spinner);
   gtk_widget_class_bind_template_child (widget_class, IdeGitCloneWidget, clone_uri_entry);
 }
 
@@ -175,12 +207,6 @@ ide_git_clone_widget_init (IdeGitCloneWidget *self)
                            G_CALLBACK (ide_git_clone_widget_uri_changed),
                            self,
                            G_CONNECT_SWAPPED);
-
-  g_signal_connect_object (self->clone_button,
-                           "clicked",
-                           G_CALLBACK (ide_git_clone_widget_clone_button_clicked),
-                           self,
-                           G_CONNECT_SWAPPED);
 }
 
 static gboolean
@@ -191,19 +217,20 @@ open_after_timeout (gpointer user_data)
   g_autoptr(GTask) task = user_data;
   g_autoptr(GFile) file = NULL;
   g_autoptr(GError) error = NULL;
+  CloneRequest *req;
+
+  IDE_ENTRY;
 
   g_assert (G_IS_TASK (task));
 
   self = g_task_get_source_object (task);
+  req = g_task_get_task_data (task);
   workbench = ide_widget_get_workbench (GTK_WIDGET (self));
 
+  g_assert (req != NULL);
   g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
   g_assert (IDE_IS_WORKBENCH (workbench));
 
-  gtk_widget_hide (GTK_WIDGET (self->clone_spinner));
-
-  file = g_task_propagate_pointer (task, &error);
-
   if (error)
     {
       g_warning ("%s", error->message);
@@ -212,22 +239,25 @@ open_after_timeout (gpointer user_data)
     }
   else
     {
-      ide_workbench_open_project_async (workbench, file, NULL, NULL, NULL);
+      ide_workbench_open_project_async (workbench, req->project_file, NULL, NULL, NULL);
     }
 
-  return G_SOURCE_REMOVE;
+  g_task_return_boolean (task, TRUE);
+
+  IDE_RETURN (G_SOURCE_REMOVE);
 }
 
-static void
-ide_git_clone_widget_clone_cb (GObject      *object,
-                               GAsyncResult *result,
-                               gpointer      user_data)
+static gboolean
+finish_animation_in_idle (gpointer data)
 {
-  IdeGitCloneWidget *self = (IdeGitCloneWidget *)object;
-  GTask *task = (GTask *)result;
+  g_autoptr(GTask) task = data;
+  IdeGitCloneWidget *self;
+
+  IDE_ENTRY;
 
-  g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
   g_assert (G_IS_TASK (task));
+  self = g_task_get_source_object (task);
+  g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
 
   egg_object_animate_full (self->clone_progress,
                            EGG_ANIMATION_EASE_IN_OUT_QUAD,
@@ -243,6 +273,8 @@ ide_git_clone_widget_clone_cb (GObject      *object,
    * the project. Otherwise, it's pretty jarring to the user.
    */
   g_timeout_add (ANIMATION_DURATION_MSEC, open_after_timeout, g_object_ref (task));
+
+  IDE_RETURN (G_SOURCE_REMOVE);
 }
 
 static void
@@ -290,14 +322,17 @@ ide_git_clone_widget_worker (GTask        *task,
       return;
     }
 
-  workdir = ggit_repository_get_workdir (repository);
-  g_task_return_pointer (task, g_object_ref (workdir), g_object_unref);
+  req->project_file = ggit_repository_get_workdir (repository);
+  g_timeout_add (0, finish_animation_in_idle, g_object_ref (task));
 
   g_clear_object (&repository);
 }
 
-static void
-ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self)
+void
+ide_git_clone_widget_clone_async (IdeGitCloneWidget   *self,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
   g_autoptr(GFile) location = NULL;
@@ -306,11 +341,10 @@ ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self)
   const gchar *uri;
   const gchar *child_name;
 
-  g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+  g_return_if_fail (IDE_IS_GIT_CLONE_WIDGET (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  gtk_widget_set_sensitive (GTK_WIDGET (self->clone_button), FALSE);
   gtk_label_set_label (self->clone_error_label, NULL);
-  gtk_widget_show (GTK_WIDGET (self->clone_spinner));
 
   uri = gtk_entry_get_text (self->clone_uri_entry);
   child_name = gtk_entry_get_text (self->clone_location_entry);
@@ -326,7 +360,18 @@ ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self)
       req = clone_request_new (uri, location);
     }
 
-  task = g_task_new (self, NULL, ide_git_clone_widget_clone_cb, self);
+  task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_task_data (task, req, clone_request_free);
   g_task_run_in_thread (task, ide_git_clone_widget_worker);
 }
+
+gboolean
+ide_git_clone_widget_clone_finish (IdeGitCloneWidget  *self,
+                                   GAsyncResult       *result,
+                                   GError            **error)
+{
+  g_return_val_if_fail (IDE_IS_GIT_CLONE_WIDGET (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/plugins/git/ide-git-clone-widget.h b/plugins/git/ide-git-clone-widget.h
index 53e6eed..01f88b8 100644
--- a/plugins/git/ide-git-clone-widget.h
+++ b/plugins/git/ide-git-clone-widget.h
@@ -27,6 +27,14 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeGitCloneWidget, ide_git_clone_widget, IDE, GIT_CLONE_WIDGET, GtkBin)
 
+void     ide_git_clone_widget_clone_async  (IdeGitCloneWidget    *self,
+                                            GCancellable         *cancellable,
+                                            GAsyncReadyCallback   callback,
+                                            gpointer              user_data);
+gboolean ide_git_clone_widget_clone_finish (IdeGitCloneWidget    *self,
+                                            GAsyncResult         *result,
+                                            GError              **error);
+
 G_END_DECLS
 
 #endif /* IDE_GIT_CLONE_WIDGET_H */
diff --git a/plugins/git/ide-git-clone-widget.ui b/plugins/git/ide-git-clone-widget.ui
index a7a2882..be90425 100644
--- a/plugins/git/ide-git-clone-widget.ui
+++ b/plugins/git/ide-git-clone-widget.ui
@@ -152,35 +152,6 @@
                 <property name="pack-type">end</property>
               </packing>
             </child>
-            <child>
-              <object class="GtkSpinner" id="clone_spinner">
-                <property name="vexpand">false</property>
-                <property name="active">true</property>
-                <property name="margin">24</property>
-                <property name="width-request">24</property>
-                <property name="height-request">24</property>
-              </object>
-              <packing>
-                <property name="pack-type">end</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="clone_button">
-                <property name="halign">center</property>
-                <property name="visible">true</property>
-                <property name="margin-top">24</property>
-                <property name="label" translatable="yes">Cl_one Repository</property>
-                <property name="use-underline">true</property>
-                <style>
-                  <class name="suggested-action"/>
-                </style>
-              </object>
-              <packing>
-                <property name="pack-type">end</property>
-                <property name="position">3</property>
-              </packing>
-            </child>
           </object>
         </child>
       </object>
diff --git a/plugins/git/ide-git-genesis-addin.c b/plugins/git/ide-git-genesis-addin.c
index e738b26..54be903 100644
--- a/plugins/git/ide-git-genesis-addin.c
+++ b/plugins/git/ide-git-genesis-addin.c
@@ -24,9 +24,8 @@
 
 struct _IdeGitGenesisAddin
 {
-  GObject    parent_instance;
-
-  GtkWidget *clone_widget;
+  GObject            parent_instance;
+  IdeGitCloneWidget *clone_widget;
 };
 
 static void genesis_addin_iface_init (IdeGenesisAddinInterface *iface);
@@ -34,9 +33,47 @@ static void genesis_addin_iface_init (IdeGenesisAddinInterface *iface);
 G_DEFINE_TYPE_EXTENDED (IdeGitGenesisAddin, ide_git_genesis_addin, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_GENESIS_ADDIN, genesis_addin_iface_init))
 
+enum {
+  PROP_0,
+  PROP_IS_READY
+};
+
+static void
+ide_git_genesis_addin_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  IdeGitGenesisAddin *self = IDE_GIT_GENESIS_ADDIN(object);
+
+  switch (prop_id)
+    {
+    case PROP_IS_READY:
+      if (self->clone_widget != NULL)
+        g_object_get_property (G_OBJECT (self->clone_widget), "is-ready", value);
+      else
+        g_value_set_boolean (value, FALSE);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+    }
+}
+
 static void
 ide_git_genesis_addin_class_init (IdeGitGenesisAddinClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = ide_git_genesis_addin_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_IS_READY,
+                                   g_param_spec_boolean ("is-ready",
+                                                         "Is Ready",
+                                                         "If the widget is ready to continue.",
+                                                         FALSE,
+                                                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
 }
 
 static void
@@ -56,6 +93,16 @@ ide_git_genesis_addin_get_title (IdeGenesisAddin *addin)
   return g_strdup (_("From a existing project in a Git repository"));
 }
 
+static void
+widget_is_ready (GtkWidget          *widget,
+                 GParamSpec         *pspec,
+                 IdeGitGenesisAddin *self)
+{
+  g_assert (IDE_IS_GIT_GENESIS_ADDIN (self));
+
+  g_object_notify (G_OBJECT (self), "is-ready");
+}
+
 static GtkWidget *
 ide_git_genesis_addin_get_widget (IdeGenesisAddin *addin)
 {
@@ -64,11 +111,65 @@ ide_git_genesis_addin_get_widget (IdeGenesisAddin *addin)
   g_assert (IDE_IS_GIT_GENESIS_ADDIN (self));
 
   if (self->clone_widget == NULL)
-    self->clone_widget = g_object_new (IDE_TYPE_GIT_CLONE_WIDGET,
-                                       "visible", TRUE,
-                                       NULL);
+    {
+      self->clone_widget = g_object_new (IDE_TYPE_GIT_CLONE_WIDGET,
+                                         "visible", TRUE,
+                                         NULL);
+      g_signal_connect (self->clone_widget,
+                        "notify::is-ready",
+                        G_CALLBACK (widget_is_ready),
+                        self);
+    }
+
+  return GTK_WIDGET (self->clone_widget);
+}
+
+static void
+ide_git_genesis_addin_run_cb (GObject      *object,
+                              GAsyncResult *result,
+                              gpointer      user_data)
+{
+  IdeGitCloneWidget *widget = (IdeGitCloneWidget *)object;
+  g_autoptr(GTask) task = user_data;
+  GError *error = NULL;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (IDE_IS_GIT_CLONE_WIDGET (widget));
+
+  if (!ide_git_clone_widget_clone_finish (widget, result, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_git_genesis_addin_run_async (IdeGenesisAddin     *addin,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  IdeGitGenesisAddin *self = (IdeGitGenesisAddin *)addin;
+  GTask *task;
+
+  g_return_if_fail (IDE_IS_GIT_GENESIS_ADDIN (addin));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  ide_git_clone_widget_clone_async (self->clone_widget,
+                                    cancellable,
+                                    ide_git_genesis_addin_run_cb,
+                                    task);
+}
+
+static gboolean
+ide_git_genesis_addin_run_finish (IdeGenesisAddin  *addin,
+                                  GAsyncResult     *result,
+                                  GError          **error)
+{
+  g_return_val_if_fail (IDE_IS_GIT_GENESIS_ADDIN (addin), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
-  return self->clone_widget;
+  return g_task_propagate_boolean (G_TASK (result), error);
 }
 
 static void
@@ -77,4 +178,6 @@ genesis_addin_iface_init (IdeGenesisAddinInterface *iface)
   iface->get_title = ide_git_genesis_addin_get_title;
   iface->get_icon_name = ide_git_genesis_addin_get_icon_name;
   iface->get_widget = ide_git_genesis_addin_get_widget;
+  iface->run_async = ide_git_genesis_addin_run_async;
+  iface->run_finish = ide_git_genesis_addin_run_finish;
 }


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