[gitg] Added async progress for branch actions
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: svn-commits-list gnome org
- Subject: [gitg] Added async progress for branch actions
- Date: Sun, 5 Jul 2009 01:13:55 +0000 (UTC)
commit 1f1c4358e8ec05d13e8095b04bfd51137ab270f0
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Sat Jul 4 19:01:53 2009 +0200
Added async progress for branch actions
gitg/gitg-branch-actions.c | 246 ++++++++++++++++++++++++++++++++++++++-----
gitg/gitg-branch-actions.h | 4 +-
gitg/gitg-repository.c | 2 +-
gitg/gitg-window.c | 39 +++++++-
4 files changed, 259 insertions(+), 32 deletions(-)
---
diff --git a/gitg/gitg-branch-actions.c b/gitg/gitg-branch-actions.c
index d2b6f50..10e77ed 100644
--- a/gitg/gitg-branch-actions.c
+++ b/gitg/gitg-branch-actions.c
@@ -2,6 +2,166 @@
#include "gitg-branch-actions.h"
+typedef enum
+{
+ GITG_PROGRESS_SUCCESS,
+ GITG_PROGRESS_ERROR,
+ GITG_PROGRESS_CANCELLED
+} GitgProgress;
+
+typedef void (*ProgressCallback)(GitgWindow *window, GitgProgress progress, gpointer data);
+
+typedef struct
+{
+ GitgWindow *window;
+ GitgRunner *runner;
+
+ ProgressCallback callback;
+ gpointer callback_data;
+
+ guint timeout_id;
+
+ GtkDialog *dialog;
+ GtkProgressBar *progress;
+} ProgressInfo;
+
+static void
+free_progress_info (ProgressInfo *info)
+{
+ if (info->timeout_id)
+ {
+ g_source_remove (info->timeout_id);
+ }
+
+ g_object_unref (info->runner);
+ g_slice_free (ProgressInfo, info);
+}
+
+static gchar const **
+parse_valist(va_list ap)
+{
+ gchar const *a;
+ gchar const **ret = NULL;
+ guint num = 0;
+
+ while ((a = va_arg(ap, gchar const *)) != NULL)
+ {
+ ret = g_realloc(ret, sizeof(gchar const *) * (++num + 1));
+ ret[num - 1] = a;
+ }
+
+ ret[num] = NULL;
+ return ret;
+}
+
+static void
+on_progress_end (GitgRunner *runner, gboolean cancelled, ProgressInfo *info)
+{
+ GitgProgress progress;
+
+ if (cancelled)
+ {
+ progress = GITG_PROGRESS_CANCELLED;
+ }
+ else if (gitg_runner_get_exit_status (runner) != 0)
+ {
+ progress = GITG_PROGRESS_ERROR;
+ }
+ else
+ {
+ progress = GITG_PROGRESS_SUCCESS;
+ }
+
+ info->callback (info->window, progress, info->callback_data);
+ free_progress_info (info);
+}
+
+static void
+on_progress_response (GtkDialog *dialog, GtkResponseType response, ProgressInfo *info)
+{
+ gitg_runner_cancel (info->runner);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static gboolean
+on_progress_timeout (ProgressInfo *info)
+{
+ gtk_progress_bar_pulse (info->progress);
+ return TRUE;
+}
+
+static GitgRunner *
+run_progress (GitgWindow *window,
+ gchar const *title,
+ gchar const *message,
+ ProgressCallback callback,
+ gpointer callback_data,
+ ...)
+{
+ va_list ap;
+
+ // Create runner
+ va_start (ap, callback_data);
+
+ GitgRunner *runner = gitg_runner_new (1000);
+ gchar const **argv = parse_valist (ap);
+
+ if (!gitg_repository_run_command (gitg_window_get_repository (window),
+ runner,
+ argv,
+ NULL))
+ {
+ g_free (argv);
+ g_object_unref (runner);
+
+ callback (window, GITG_PROGRESS_ERROR, callback_data);
+
+ return NULL;
+ }
+
+ g_free (argv);
+
+ // Create dialog to show progress
+ GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT;
+ GtkWidget *dlg;
+
+ dlg = gtk_message_dialog_new (GTK_WINDOW (window),
+ flags,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CANCEL,
+ "%s",
+ title);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg),
+ "%s",
+ message);
+
+ // Add progress bar
+ GtkWidget *area = gtk_dialog_get_content_area (GTK_DIALOG (dlg));
+ GtkWidget *progress = gtk_progress_bar_new ();
+ gtk_widget_show (progress);
+
+ gtk_box_pack_start (GTK_BOX (area), progress, FALSE, FALSE, 0);
+
+ gtk_widget_show (dlg);
+
+ ProgressInfo *info = g_slice_new0 (ProgressInfo);
+
+ info->dialog = GTK_DIALOG (dlg);
+ info->progress = GTK_PROGRESS_BAR (progress);
+ info->callback = callback;
+ info->callback_data = callback_data;
+ info->window = window;
+ info->runner = g_object_ref (runner);
+
+ info->timeout_id = g_timeout_add (100, (GSourceFunc)on_progress_timeout, info);
+
+ g_signal_connect (dlg, "response", G_CALLBACK (on_progress_response), info);
+ g_signal_connect (runner, "end-loading", G_CALLBACK (on_progress_end), info);
+
+ return runner;
+}
+
static gint
message_dialog (GitgWindow *window,
GtkMessageType type,
@@ -38,6 +198,7 @@ message_dialog (GitgWindow *window,
button = gtk_button_new_from_stock (accept ? GTK_STOCK_CANCEL : GTK_STOCK_OK);
gtk_widget_show (button);
+
gtk_dialog_add_action_widget (GTK_DIALOG (dlg),
button,
accept ? GTK_RESPONSE_CANCEL : GTK_RESPONSE_ACCEPT);
@@ -336,18 +497,48 @@ gitg_branch_actions_rebase (GitgWindow *window,
return FALSE;
}
+typedef struct
+{
+ GitgRef *source;
+ GitgRef *dest;
+} PushInfo;
-gboolean
+static void
+on_push_result (GitgWindow *window,
+ GitgProgress progress,
+ gpointer data)
+{
+ PushInfo *info = (PushInfo *)data;
+
+ if (progress == GITG_PROGRESS_ERROR)
+ {
+ message_dialog (window,
+ GTK_MESSAGE_ERROR,
+ _("Failed to push local branch <%s> to remote <%s>"),
+ NULL,
+ NULL,
+ gitg_ref_get_shortname (info->source),
+ gitg_ref_get_shortname (info->dest));
+ }
+ else if (progress == GITG_PROGRESS_SUCCESS)
+ {
+ gitg_repository_reload (gitg_window_get_repository (window));
+ }
+
+ gitg_ref_free (info->source);
+ gitg_ref_free (info->dest);
+ g_slice_free (PushInfo, info);
+}
+
+GitgRunner *
gitg_branch_actions_push (GitgWindow *window,
GitgRef *source,
GitgRef *dest)
{
- g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE);
- g_return_val_if_fail (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH, FALSE);
- g_return_val_if_fail (gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE, FALSE);
+ g_return_val_if_fail (GITG_IS_WINDOW (window), NULL);
+ g_return_val_if_fail (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH, NULL);
+ g_return_val_if_fail (gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE, NULL);
- GitgRepository *repository = gitg_window_get_repository (window);
-
if (message_dialog (window,
GTK_MESSAGE_QUESTION,
_("Are you sure you want to push <%s> to <%s>?"),
@@ -356,39 +547,36 @@ gitg_branch_actions_push (GitgWindow *window,
gitg_ref_get_shortname (source),
gitg_ref_get_shortname (dest)) != GTK_RESPONSE_ACCEPT)
{
- return FALSE;
+ return NULL;
}
gchar const *prefix = gitg_ref_get_prefix (dest);
gchar *local = gitg_ref_get_local_name (dest);
gchar const *name = gitg_ref_get_shortname (source);
- gboolean ret = FALSE;
gchar *spec = g_strconcat (name, ":", local, NULL);
+ gchar *message = g_strdup_printf (_("Pushing local branch `%s' to remote branch `%s'"),
+ gitg_ref_get_shortname (source),
+ gitg_ref_get_shortname (dest));
- if (!gitg_repository_commandv (repository,
- NULL,
- "push",
- prefix,
- spec,
- NULL))
- {
- message_dialog (window,
- GTK_MESSAGE_ERROR,
- _("Failed to push local branch <%s> to remote <%s>"),
- NULL,
- NULL,
- name,
- gitg_ref_get_shortname (dest));
- }
- else
- {
- gitg_repository_reload (repository);
- ret = TRUE;
- }
+ GitgRunner *ret;
+ PushInfo *info = g_slice_new (PushInfo);
+ info->source = gitg_ref_copy (source);
+ info->dest = gitg_ref_copy (dest);
- g_free (spec);
+ ret = run_progress (window,
+ _("Push"),
+ message,
+ on_push_result,
+ info,
+ "push",
+ prefix,
+ spec,
+ NULL);
+
+ g_free (message);
g_free (local);
+ g_free (spec);
return ret;
}
diff --git a/gitg/gitg-branch-actions.h b/gitg/gitg-branch-actions.h
index 9e0d6ea..cf47d87 100644
--- a/gitg/gitg-branch-actions.h
+++ b/gitg/gitg-branch-actions.h
@@ -32,7 +32,9 @@ gboolean gitg_branch_actions_remove (GitgWindow *window, GitgRef *ref);
gboolean gitg_branch_actions_checkout (GitgWindow *window, GitgRef *ref);
gboolean gitg_branch_actions_merge (GitgWindow *window, GitgRef *source, GitgRef *dest);
gboolean gitg_branch_actions_rebase (GitgWindow *window, GitgRef *source, GitgRef *dest);
-gboolean gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest);
+
+GitgRunner *gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest);
+
G_END_DECLS
#endif /* __GITG_BRANCH_ACTIONS_H__ */
diff --git a/gitg/gitg-repository.c b/gitg/gitg-repository.c
index 90f9d6d..e3aeac5 100644
--- a/gitg/gitg-repository.c
+++ b/gitg/gitg-repository.c
@@ -1276,7 +1276,7 @@ gitg_repository_command_with_output(GitgRepository *repository, gchar const **ar
return gitg_repository_command_with_input_and_output(repository, argv, NULL, error);
}
-gchar const **
+static gchar const **
parse_valist(va_list ap)
{
gchar const *a;
diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c
index e38f86f..0c1b65d 100644
--- a/gitg/gitg-window.c
+++ b/gitg/gitg-window.c
@@ -86,6 +86,8 @@ struct _GitgWindowPrivate
guint merge_rebase_uid;
GtkActionGroup *merge_rebase_action_group;
GitgRef *popup_ref;
+
+ GList *branch_actions;
};
static gboolean on_tree_view_motion(GtkTreeView *treeview, GdkEventMotion *event, GitgWindow *window);
@@ -100,6 +102,31 @@ static GtkBuildableIface parent_iface;
static GtkWindowClass *parent_class = NULL;
static void
+on_branch_action_runner_end (GitgRunner *runner, gboolean cancelled, GitgWindow *window)
+{
+ window->priv->branch_actions = g_list_remove (window->priv->branch_actions, runner);
+ g_object_unref (runner);
+}
+
+static gboolean
+add_branch_action (GitgWindow *window, GitgRunner *runner)
+{
+ if (runner != NULL && gitg_runner_running (runner))
+ {
+ window->priv->branch_actions = g_list_prepend (window->priv->branch_actions, runner);
+
+ g_signal_connect (runner, "end-loading", G_CALLBACK (on_branch_action_runner_end), window);
+ }
+ else if (runner)
+ {
+ g_object_unref (runner);
+ runner = NULL;
+ }
+
+ return runner != NULL;
+}
+
+static void
gitg_window_finalize(GObject *object)
{
GitgWindow *self = GITG_WINDOW(object);
@@ -107,6 +134,16 @@ gitg_window_finalize(GObject *object)
g_timer_destroy(self->priv->load_timer);
gdk_cursor_unref(self->priv->hand);
+ GList *copy = g_list_copy (self->priv->branch_actions);
+ GList *item;
+
+ for (item = copy; item; item = g_list_next (item))
+ {
+ gitg_runner_cancel (GITG_RUNNER (item->data));
+ }
+
+ g_list_free (copy);
+
G_OBJECT_CLASS(gitg_window_parent_class)->finalize(object);
}
@@ -471,7 +508,7 @@ on_refs_dnd (GitgRef *source, GitgRef *dest, gboolean dropped, GitgWindow *windo
if (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH &&
gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE)
{
- ret = gitg_branch_actions_push (window, source, dest);
+ ret = add_branch_action (window, gitg_branch_actions_push (window, source, dest));
}
gtk_statusbar_push (window->priv->statusbar, 0, "");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]