[gnome-builder] git: more git clone porting to perspectives
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] git: more git clone porting to perspectives
- Date: Mon, 21 Dec 2015 07:55:42 +0000 (UTC)
commit 0c9b31ed938413130864a70385b7fb6f3b7f6719
Author: Christian Hergert <chergert redhat com>
Date: Mon Nov 30 21:41:15 2015 -0800
git: more git clone porting to perspectives
data/ui/ide-genesis-perspective.ui | 5 +-
data/ui/ide-greeter-perspective.ui | 6 +-
libide/genesis/ide-genesis-perspective.c | 69 ++++++-
plugins/git/ide-git-clone-widget.c | 302 +++++++++++++++++++++++++++---
plugins/git/ide-git-clone-widget.ui | 33 +++-
plugins/git/ide-git-genesis-addin.c | 2 +-
6 files changed, 372 insertions(+), 45 deletions(-)
---
diff --git a/data/ui/ide-genesis-perspective.ui b/data/ui/ide-genesis-perspective.ui
index b1eb27b..fd65884 100644
--- a/data/ui/ide-genesis-perspective.ui
+++ b/data/ui/ide-genesis-perspective.ui
@@ -9,7 +9,7 @@
<property name="expand">true</property>
<property name="visible">true</property>
<child>
- <object class="EggBox">
+ <object class="EggBox" id="main_page">
<property name="halign">center</property>
<property name="width-request">550</property>
<property name="max-width-request">550</property>
@@ -37,8 +37,7 @@
<property name="visible">true</property>
<child>
<object class="GtkButton">
- <property name="action-name">win.perspective</property>
- <property name="action-target">'greeter'</property>
+ <property name="action-name">perspective.go-previous</property>
<property name="visible">true</property>
<style>
<class name="image-button"/>
diff --git a/data/ui/ide-greeter-perspective.ui b/data/ui/ide-greeter-perspective.ui
index 28e1a1a..5397124 100644
--- a/data/ui/ide-greeter-perspective.ui
+++ b/data/ui/ide-greeter-perspective.ui
@@ -175,11 +175,11 @@
</object>
</child>
</object>
- <packing>
- <property name="name">assistants</property>
- </packing>
</child>
</object>
+ <packing>
+ <property name="name">assistants</property>
+ </packing>
</child>
</object>
</child>
diff --git a/libide/genesis/ide-genesis-perspective.c b/libide/genesis/ide-genesis-perspective.c
index 20f6b46..55cd264 100644
--- a/libide/genesis/ide-genesis-perspective.c
+++ b/libide/genesis/ide-genesis-perspective.c
@@ -21,15 +21,19 @@
#include "ide-genesis-addin.h"
#include "ide-genesis-perspective.h"
+#include "ide-gtk.h"
+#include "ide-workbench.h"
struct _IdeGenesisPerspective
{
GtkBin parent_instance;
+ GActionGroup *actions;
PeasExtensionSet *addins;
GtkHeaderBar *header_bar;
GtkListBox *list_box;
+ GtkWidget *main_page;
GtkStack *stack;
};
@@ -117,6 +121,9 @@ ide_genesis_perspective_addin_removed (PeasExtensionSet *set,
{
gpointer data = g_object_get_data (iter->data, "IDE_GENESIS_ADDIN");
+ if (data == NULL)
+ continue;
+
if (data == (gpointer)exten)
{
gtk_container_remove (GTK_CONTAINER (self->list_box), iter->data);
@@ -172,19 +179,20 @@ ide_genesis_perspective_constructed (GObject *object)
G_CALLBACK (ide_genesis_perspective_addin_added),
self);
g_signal_connect (self->addins,
- "extension-rmeoved",
+ "extension-removed",
G_CALLBACK (ide_genesis_perspective_addin_removed),
self);
}
static void
-ide_genesis_perspective_finalize (GObject *object)
+ide_genesis_perspective_destroy (GtkWidget *widget)
{
- IdeGenesisPerspective *self = (IdeGenesisPerspective *)object;
+ IdeGenesisPerspective *self = (IdeGenesisPerspective *)widget;
+ g_clear_object (&self->actions);
g_clear_object (&self->addins);
- G_OBJECT_CLASS (ide_genesis_perspective_parent_class)->finalize (object);
+ GTK_WIDGET_CLASS (ide_genesis_perspective_parent_class)->destroy (widget);
}
static void
@@ -194,11 +202,13 @@ ide_genesis_perspective_class_init (IdeGenesisPerspectiveClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = ide_genesis_perspective_constructed;
- object_class->finalize = ide_genesis_perspective_finalize;
+
+ widget_class->destroy = ide_genesis_perspective_destroy;
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, 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);
}
@@ -230,15 +240,62 @@ ide_genesis_perspective_is_early (IdePerspective *perspective)
static GtkWidget *
ide_genesis_perspective_get_titlebar (IdePerspective *perspective)
{
- g_return_val_if_fail (IDE_IS_GENESIS_PERSPECTIVE (perspective), NULL);
+ g_assert (IDE_IS_GENESIS_PERSPECTIVE (perspective));
return GTK_WIDGET (IDE_GENESIS_PERSPECTIVE (perspective)->header_bar);
}
static void
+go_previous (GSimpleAction *action,
+ GVariant *variant,
+ gpointer user_data)
+{
+ IdeGenesisPerspective *self = user_data;
+ IdeWorkbench *workbench;
+ GtkWidget *visible_child;
+
+ g_assert (IDE_IS_GENESIS_PERSPECTIVE (self));
+
+ visible_child = gtk_stack_get_visible_child (self->stack);
+
+ if (visible_child != self->main_page)
+ {
+ gtk_stack_set_visible_child (self->stack, self->main_page);
+ return;
+ }
+
+ workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+ ide_workbench_set_visible_perspective_name (workbench, "greeter");
+}
+
+static GActionGroup *
+ide_genesis_perspective_get_actions (IdePerspective *perspective)
+{
+ IdeGenesisPerspective *self = (IdeGenesisPerspective *)perspective;
+
+ g_assert (IDE_IS_GENESIS_PERSPECTIVE (self));
+
+ if (self->actions == NULL)
+ {
+ const GActionEntry entries[] = {
+ { "go-previous", go_previous },
+ };
+
+ self->actions = G_ACTION_GROUP (g_simple_action_group_new ());
+ g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+ entries, G_N_ELEMENTS (entries), self);
+ }
+
+ g_assert (G_IS_ACTION_GROUP (self->actions));
+
+ return self->actions;
+}
+
+static void
perspective_iface_init (IdePerspectiveInterface *iface)
{
iface->get_id = ide_genesis_perspective_get_id;
iface->is_early = ide_genesis_perspective_is_early;
iface->get_titlebar = ide_genesis_perspective_get_titlebar;
+ iface->get_actions = ide_genesis_perspective_get_actions;
}
diff --git a/plugins/git/ide-git-clone-widget.c b/plugins/git/ide-git-clone-widget.c
index 376c4e5..146196f 100644
--- a/plugins/git/ide-git-clone-widget.c
+++ b/plugins/git/ide-git-clone-widget.c
@@ -16,58 +16,127 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <glib/gi18n.h>
+#include <libgit2-glib/ggit.h>
+#include <ide.h>
+
+#include "egg-animation.h"
+
#include "ide-git-clone-widget.h"
+#include "ide-git-remote-callbacks.h"
+
+#define ANIMATION_DURATION_MSEC 250
struct _IdeGitCloneWidget
{
- GtkBin parent_instance;
+ GtkBin parent_instance;
+
+ 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;
};
-G_DEFINE_TYPE (IdeGitCloneWidget, ide_git_clone_widget, GTK_TYPE_BIN)
+typedef struct
+{
+ gchar *uri;
+ GFile *location;
+} CloneRequest;
-enum {
- PROP_0,
- LAST_PROP
-};
+G_DEFINE_TYPE (IdeGitCloneWidget, ide_git_clone_widget, GTK_TYPE_BIN)
-static GParamSpec *properties [LAST_PROP];
+static void ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self);
static void
-ide_git_clone_widget_finalize (GObject *object)
+clone_request_free (gpointer data)
{
- IdeGitCloneWidget *self = (IdeGitCloneWidget *)object;
+ CloneRequest *req = data;
- G_OBJECT_CLASS (ide_git_clone_widget_parent_class)->finalize (object);
+ if (req != NULL)
+ {
+ g_clear_pointer (&req->uri, g_free);
+ g_clear_object (&req->location);
+ g_slice_free (CloneRequest, req);
+ }
+}
+
+static CloneRequest *
+clone_request_new (const gchar *uri,
+ GFile *location)
+{
+ CloneRequest *req;
+
+ g_assert (uri);
+ g_assert (location);
+
+ req = g_slice_new0 (CloneRequest);
+ req->uri = g_strdup (uri);
+ req->location = g_object_ref (location);
+
+ return req;
}
static void
-ide_git_clone_widget_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+ide_git_clone_widget_uri_changed (IdeGitCloneWidget *self,
+ GtkEntry *entry)
{
- IdeGitCloneWidget *self = IDE_GIT_CLONE_WIDGET (object);
+ g_autoptr(IdeVcsUri) uri = NULL;
+ const gchar *text;
+
+ g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+ g_assert (GTK_IS_ENTRY (entry));
+
+ text = gtk_entry_get_text (entry);
+ uri = ide_vcs_uri_new (text);
+
+ if (uri != NULL)
+ {
+ const gchar *path;
+ gchar *name = NULL;
+
+ g_object_set (self->clone_uri_entry,
+ "secondary-icon-name", NULL,
+ "secondary-icon-tooltip-text", NULL,
+ NULL);
+
+ path = ide_vcs_uri_get_path (uri);
- switch (prop_id)
+ if (path != NULL)
+ {
+ name = g_path_get_basename (path);
+ if (g_str_has_suffix (name, ".git"))
+ *(strrchr (name, '.')) = '\0';
+ if (!g_str_equal (name, "/"))
+ gtk_entry_set_text (self->clone_location_entry, name);
+ g_free (name);
+ }
+ }
+ else
{
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ g_object_set (self->clone_uri_entry,
+ "secondary-icon-name", "dialog-warning-symbolic",
+ "secondary-icon-tooltip-text", _("A valid Git URL is required"),
+ NULL);
}
}
static void
-ide_git_clone_widget_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+ide_git_clone_widget_clone_button_clicked (IdeGitCloneWidget *self,
+ GtkButton *button)
{
- IdeGitCloneWidget *self = IDE_GIT_CLONE_WIDGET (object);
+ g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+ g_assert (GTK_IS_BUTTON (button));
- switch (prop_id)
- {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
+ ide_git_clone_widget_begin_clone (self);
+}
+
+static void
+ide_git_clone_widget_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (ide_git_clone_widget_parent_class)->finalize (object);
}
static void
@@ -77,15 +146,188 @@ 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;
- object_class->set_property = ide_git_clone_widget_set_property;
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);
}
static void
ide_git_clone_widget_init (IdeGitCloneWidget *self)
{
+ gchar *projects_dir;
+
gtk_widget_init_template (GTK_WIDGET (self));
+
+ projects_dir = g_build_filename (g_get_home_dir (), _("Projects"), NULL);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (self->clone_location_button),
+ projects_dir);
+ g_free (projects_dir);
+
+ g_signal_connect_object (self->clone_uri_entry,
+ "changed",
+ 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
+open_after_timeout (gpointer user_data)
+{
+ IdeGitCloneWidget *self;
+ IdeWorkbench *workbench;
+ g_autoptr(GTask) task = user_data;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GError) error = NULL;
+
+ g_assert (G_IS_TASK (task));
+
+ self = g_task_get_source_object (task);
+ workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+
+ 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);
+ gtk_label_set_label (self->clone_error_label, error->message);
+ gtk_widget_show (GTK_WIDGET (self->clone_error_label));
+ }
+ else
+ {
+ //g_signal_emit (self, signals [OPEN_PROJECT], 0, file);
+ ide_workbench_set_visible_perspective_name (workbench, "editor");
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+ide_git_clone_widget_clone_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeGitCloneWidget *self = (IdeGitCloneWidget *)object;
+ GTask *task = (GTask *)result;
+
+ g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+ g_assert (G_IS_TASK (task));
+
+ egg_object_animate_full (self->clone_progress,
+ EGG_ANIMATION_EASE_IN_OUT_QUAD,
+ ANIMATION_DURATION_MSEC,
+ NULL,
+ (GDestroyNotify)ide_widget_hide_with_fade,
+ self->clone_progress,
+ "fraction", 1.0,
+ NULL);
+
+ /*
+ * Wait for a second so animations can complete before opening
+ * the project. Otherwise, it's pretty jarring to the user.
+ */
+ g_timeout_add (ANIMATION_DURATION_MSEC, open_after_timeout, g_object_ref (task));
+}
+
+static void
+ide_git_clone_widget_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ IdeGitCloneWidget *self = source_object;
+ GgitRepository *repository;
+ g_autoptr(GFile) workdir = NULL;
+ CloneRequest *req = task_data;
+ GgitCloneOptions *clone_options;
+ GgitFetchOptions *fetch_options;
+ GgitRemoteCallbacks *callbacks;
+ IdeProgress *progress;
+ GError *error = NULL;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+ g_assert (req != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ callbacks = g_object_new (IDE_TYPE_GIT_REMOTE_CALLBACKS, NULL);
+ progress = ide_git_remote_callbacks_get_progress (IDE_GIT_REMOTE_CALLBACKS (callbacks));
+ g_object_bind_property (progress, "fraction", self->clone_progress, "fraction", 0);
+
+ fetch_options = ggit_fetch_options_new ();
+ ggit_fetch_options_set_remote_callbacks (fetch_options, callbacks);
+
+ clone_options = ggit_clone_options_new ();
+ ggit_clone_options_set_is_bare (clone_options, FALSE);
+ ggit_clone_options_set_checkout_branch (clone_options, "master");
+ ggit_clone_options_set_fetch_options (clone_options, fetch_options);
+ g_clear_pointer (&fetch_options, ggit_fetch_options_free);
+
+ repository = ggit_repository_clone (req->uri, req->location, clone_options, &error);
+
+ g_clear_object (&callbacks);
+ g_clear_object (&clone_options);
+
+ if (repository == NULL)
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ workdir = ggit_repository_get_workdir (repository);
+ g_task_return_pointer (task, g_object_ref (workdir), g_object_unref);
+
+ g_clear_object (&repository);
+}
+
+static void
+ide_git_clone_widget_begin_clone (IdeGitCloneWidget *self)
+{
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GFile) location = NULL;
+ g_autoptr(GFile) child = NULL;
+ CloneRequest *req;
+ const gchar *uri;
+ const gchar *child_name;
+
+ g_assert (IDE_IS_GIT_CLONE_WIDGET (self));
+
+ 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);
+ location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (self->clone_location_button));
+
+ if (child_name != NULL)
+ {
+ child = g_file_get_child (location, child_name);
+ req = clone_request_new (uri, child);
+ }
+ else
+ {
+ req = clone_request_new (uri, location);
+ }
+
+ task = g_task_new (self, NULL, ide_git_clone_widget_clone_cb, self);
+ g_task_set_task_data (task, req, clone_request_free);
+ g_task_run_in_thread (task, ide_git_clone_widget_worker);
}
diff --git a/plugins/git/ide-git-clone-widget.ui b/plugins/git/ide-git-clone-widget.ui
index 6f7739b..a7a2882 100644
--- a/plugins/git/ide-git-clone-widget.ui
+++ b/plugins/git/ide-git-clone-widget.ui
@@ -50,7 +50,7 @@
<property name="hexpand">true</property>
<property name="width-chars">35</property>
<property name="placeholder-text" translatable="yes">user
host:repository.git</property>
- <property name="tooltip-text" translatable="yes">Enter the URL of your project's
source code repository.</property>
+ <property name="tooltip-text" translatable="yes">Enter the URL of your project's
source code repository</property>
<property name="valign">baseline</property>
<property name="visible">true</property>
</object>
@@ -78,6 +78,7 @@
<object class="GtkEntry" id="clone_location_entry">
<property name="hexpand">true</property>
<property name="placeholder-text" translatable="yes">Directory</property>
+ <property name="tooltip-text" translatable="yes">Enter the name of the directory
to create</property>
<property name="valign">baseline</property>
<property name="visible">true</property>
</object>
@@ -128,15 +129,26 @@
</object>
</child>
<child>
+ <object class="GtkLabel">
+ <property name="visible">true</property>
+ <property name="vexpand">true</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="clone_error_label">
<property name="valign">start</property>
<property name="vexpand">true</property>
- <property name="visible">false</property>
+ <property name="visible">true</property>
<style>
<class name="error-label"/>
</style>
</object>
<packing>
+ <property name="position">1</property>
<property name="pack-type">end</property>
</packing>
</child>
@@ -150,6 +162,23 @@
</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>
diff --git a/plugins/git/ide-git-genesis-addin.c b/plugins/git/ide-git-genesis-addin.c
index 1cc812c..e738b26 100644
--- a/plugins/git/ide-git-genesis-addin.c
+++ b/plugins/git/ide-git-genesis-addin.c
@@ -53,7 +53,7 @@ ide_git_genesis_addin_get_icon_name (IdeGenesisAddin *addin)
static gchar *
ide_git_genesis_addin_get_title (IdeGenesisAddin *addin)
{
- return g_strdup (_("From a Git source code repository"));
+ return g_strdup (_("From a existing project in a Git repository"));
}
static GtkWidget *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]