[gitg/gtk3] details panel: show gravatar when changing the revision
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/gtk3] details panel: show gravatar when changing the revision
- Date: Thu, 21 Jul 2011 18:07:27 +0000 (UTC)
commit 381075db01e70f1a4e3613a199e97740bd485881
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Thu Jul 21 20:07:42 2011 +0200
details panel: show gravatar when changing the revision
gitg/Makefile.am | 2 +
gitg/gitg-avatar-cache.c | 371 +++++++++++++++++++++++++++++++++++
gitg/gitg-avatar-cache.h | 73 +++++++
gitg/gitg-revision-details-panel.c | 60 ++++++
gitg/gitg-revision-details-panel.ui | 317 ++++++++++++++++++------------
5 files changed, 698 insertions(+), 125 deletions(-)
---
diff --git a/gitg/Makefile.am b/gitg/Makefile.am
index 50dc17f..5358908 100644
--- a/gitg/Makefile.am
+++ b/gitg/Makefile.am
@@ -13,6 +13,7 @@ AM_CPPFLAGS = \
NOINST_H_FILES = \
gitg-activatable.h \
+ gitg-avatar-cache.h \
gitg-branch-actions.h \
gitg-cell-renderer-path.h \
gitg-commit-view.h \
@@ -36,6 +37,7 @@ gitg_SOURCES = \
$(BUILT_SOURCES) \
gitg.c \
gitg-activatable.c \
+ gitg-avatar-cache.c \
gitg-branch-actions.c \
gitg-cell-renderer-path.c \
gitg-commit-view.c \
diff --git a/gitg/gitg-avatar-cache.c b/gitg/gitg-avatar-cache.c
new file mode 100644
index 0000000..e95c78b
--- /dev/null
+++ b/gitg/gitg-avatar-cache.c
@@ -0,0 +1,371 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Mathias Hasselmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "gitg-avatar-cache.h"
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <string.h>
+
+#define AVATAR_SIZE 80
+
+typedef struct _GitgAvatarCacheLoader GitgAvatarCacheLoader;
+struct _GitgAvatarCacheLoader
+{
+ gchar *uri;
+ GitgAvatarCache *cache;
+ GCancellable *cancellable;
+ gchar buffer[8192];
+ GdkPixbufLoader *pixbuf_loader;
+ GdkPixbuf *pixbuf;
+ GSimpleAsyncResult *result;
+};
+
+struct _GitgAvatarCachePrivate
+{
+ GChecksum *checksum;
+ GHashTable *pixbuf_table;
+ GList *active_loaders;
+};
+
+G_DEFINE_TYPE (GitgAvatarCache, gitg_avatar_cache, G_TYPE_OBJECT)
+
+static void
+avatar_cache_loader_finish (GitgAvatarCacheLoader *loader,
+ GError *error)
+{
+ if (loader->cache)
+ {
+ g_object_remove_weak_pointer (G_OBJECT (loader->cache),
+ (gpointer) &loader->cache);
+ }
+
+ if (loader->cancellable)
+ {
+ g_cancellable_cancel (loader->cancellable);
+ g_object_unref (loader->cancellable);
+ }
+
+ if (loader->pixbuf_loader)
+ {
+ gdk_pixbuf_loader_close (loader->pixbuf_loader, NULL);
+ g_object_unref (loader->pixbuf_loader);
+ }
+
+ if (loader->pixbuf)
+ {
+ g_simple_async_result_set_op_res_gpointer (loader->result,
+ g_object_ref (loader->pixbuf),
+ g_object_unref);
+ }
+ else
+ {
+ g_simple_async_result_set_from_error (loader->result, error);
+ g_error_free (error);
+ }
+
+ g_simple_async_result_complete_in_idle (loader->result);
+ g_object_unref (loader->result);
+
+ g_slice_free (GitgAvatarCacheLoader, loader);
+}
+
+static void
+gitg_avatar_cache_init (GitgAvatarCache *cache)
+{
+ cache->priv = G_TYPE_INSTANCE_GET_PRIVATE (cache,
+ GITG_TYPE_AVATAR_CACHE,
+ GitgAvatarCachePrivate);
+
+}
+
+static void
+avatar_cache_insert (GitgAvatarCache *cache,
+ const gchar *uri,
+ GdkPixbuf *pixbuf)
+{
+ GitgAvatarCachePrivate *priv = cache->priv;
+
+ if (!priv->pixbuf_table)
+ {
+ priv->pixbuf_table = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+ }
+
+ g_hash_table_insert (priv->pixbuf_table, g_strdup (uri),
+ g_object_ref (pixbuf));
+}
+
+static void
+avatar_cache_close_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GitgAvatarCacheLoader *loader = user_data;
+ GInputStream *stream = G_INPUT_STREAM (object);
+ GError *error = NULL;
+
+ if (g_input_stream_close_finish (stream, result, &error) &&
+ gdk_pixbuf_loader_close (loader->pixbuf_loader, &error))
+ {
+ loader->pixbuf = gdk_pixbuf_loader_get_pixbuf (loader->pixbuf_loader);
+ avatar_cache_insert (loader->cache, loader->uri, loader->pixbuf);
+ g_object_unref (loader->pixbuf_loader);
+ loader->pixbuf_loader = NULL;
+ }
+
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+
+ avatar_cache_loader_finish (loader, error);
+}
+
+static void
+avatar_cache_read_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GitgAvatarCacheLoader *loader = user_data;
+ GInputStream *stream = G_INPUT_STREAM (object);
+ GError *error = NULL;
+ gssize len;
+
+ len = g_input_stream_read_finish (stream, result, &error);
+
+ if (len > 0)
+ {
+ if (gdk_pixbuf_loader_write (loader->pixbuf_loader, (gpointer)
+ loader->buffer, len, &error))
+ {
+ g_input_stream_read_async (stream, loader->buffer,
+ sizeof (loader->buffer),
+ G_PRIORITY_DEFAULT,
+ loader->cancellable,
+ avatar_cache_read_cb,
+ loader);
+ }
+ else
+ {
+ len = -2;
+ }
+ }
+
+ if (0 >= len)
+ {
+ g_input_stream_close_async (stream, G_PRIORITY_DEFAULT,
+ loader->cancellable,
+ avatar_cache_close_cb, loader);
+ }
+
+ if (error)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+
+ g_error_free (error);
+ }
+}
+
+static void
+avatar_cache_open_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GitgAvatarCacheLoader *loader = user_data;
+ GError *error = NULL;
+ GFileInputStream *stream;
+
+ stream = g_file_read_finish (G_FILE (object), result, &error);
+
+ if (stream)
+ {
+ g_input_stream_read_async (G_INPUT_STREAM (stream),
+ loader->buffer, sizeof (loader->buffer),
+ G_PRIORITY_DEFAULT, loader->cancellable,
+ avatar_cache_read_cb, loader);
+ }
+ else
+ {
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("%s: %s", G_STRFUNC, error->message);
+
+ avatar_cache_loader_finish (loader, error);
+ }
+}
+
+static void
+avatar_cache_finalize (GObject *object)
+{
+ GitgAvatarCachePrivate *priv = GITG_AVATAR_CACHE (object)->priv;
+ GitgAvatarCacheLoader *loader;
+ GList *l;
+
+ if (priv->pixbuf_table)
+ {
+ g_hash_table_unref (priv->pixbuf_table);
+ }
+
+ if (priv->checksum)
+ {
+ g_checksum_free (priv->checksum);
+ }
+
+ for (l = priv->active_loaders; l; l = g_list_delete_link (l, l))
+ {
+ loader = priv->active_loaders->data;
+ g_cancellable_cancel (loader->cancellable);
+ }
+
+ G_OBJECT_CLASS (gitg_avatar_cache_parent_class)->finalize (object);
+}
+
+static void
+gitg_avatar_cache_class_init (GitgAvatarCacheClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = avatar_cache_finalize;
+
+ g_type_class_add_private (class, sizeof (GitgAvatarCachePrivate));
+}
+
+GitgAvatarCache *
+gitg_avatar_cache_new (void)
+{
+ return g_object_new (GITG_TYPE_AVATAR_CACHE, NULL);
+}
+
+void
+gitg_avatar_cache_load_uri_async (GitgAvatarCache *cache,
+ const gchar *uri,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GitgAvatarCachePrivate *priv;
+ GdkPixbuf *pixbuf = NULL;
+ GSimpleAsyncResult *result;
+ GitgAvatarCacheLoader *loader;
+ GFile *file;
+
+ g_return_if_fail (GITG_IS_AVATAR_CACHE (cache));
+ g_return_if_fail (NULL != callback);
+ g_return_if_fail (NULL != uri);
+
+ priv = cache->priv;
+
+ result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data,
+ gitg_avatar_cache_load_uri_async);
+
+ if (priv->pixbuf_table)
+ pixbuf = g_hash_table_lookup (priv->pixbuf_table, uri);
+
+ if (pixbuf)
+ {
+ g_simple_async_result_set_op_res_gpointer (result,
+ g_object_ref (pixbuf),
+ g_object_unref);
+ g_simple_async_result_complete_in_idle (result);
+ }
+ else
+ {
+ if (cancellable)
+ {
+ g_object_ref (cancellable);
+ }
+ else
+ {
+ cancellable = g_cancellable_new ();
+ }
+
+ loader = g_slice_new0 (GitgAvatarCacheLoader);
+ loader->pixbuf_loader = gdk_pixbuf_loader_new ();
+ loader->result = g_object_ref (result);
+ loader->cancellable = cancellable;
+ loader->uri = g_strdup (uri);
+ loader->cache = cache;
+
+ g_object_add_weak_pointer (G_OBJECT (loader->cache),
+ (gpointer) &loader->cache);
+
+ file = g_file_new_for_uri (uri);
+
+ g_file_read_async (file, G_PRIORITY_DEFAULT, loader->cancellable,
+ avatar_cache_open_cb, loader);
+
+ g_object_unref (file);
+ }
+
+ g_object_unref (result);
+}
+
+GdkPixbuf *
+gitg_avatar_cache_load_finish (GitgAvatarCache *cache,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ gpointer source_tag;
+
+ g_return_val_if_fail (GITG_IS_AVATAR_CACHE (cache), NULL);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ source_tag = g_simple_async_result_get_source_tag (simple);
+
+ g_return_val_if_fail (source_tag == gitg_avatar_cache_load_uri_async, NULL);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ return g_simple_async_result_get_op_res_gpointer (simple);
+}
+
+gchar *
+gitg_avatar_cache_get_gravatar_uri (GitgAvatarCache *cache,
+ const gchar *gravatar_id)
+{
+ GitgAvatarCachePrivate *priv;
+
+ g_return_val_if_fail (GITG_IS_AVATAR_CACHE (cache), NULL);
+ g_return_val_if_fail (NULL != gravatar_id, NULL);
+
+ priv = cache->priv;
+
+ if (priv->checksum)
+ {
+ g_checksum_reset (priv->checksum);
+ }
+ else
+ {
+ priv->checksum = g_checksum_new (G_CHECKSUM_MD5);
+ }
+
+ g_checksum_update (priv->checksum, (gpointer) gravatar_id,
+ strlen (gravatar_id));
+
+ return g_strdup_printf ("http://www.gravatar.com/avatar/%s?s=%d",
+ g_checksum_get_string (priv->checksum),
+ AVATAR_SIZE);
+}
diff --git a/gitg/gitg-avatar-cache.h b/gitg/gitg-avatar-cache.h
new file mode 100644
index 0000000..dca9a34
--- /dev/null
+++ b/gitg/gitg-avatar-cache.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Mathias Hasselmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GITG_AVATAR_CACHE_H__
+#define __GITG_AVATAR_CACHE_H__
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GITG_TYPE_AVATAR_CACHE (gitg_avatar_cache_get_type ())
+#define GITG_AVATAR_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_AVATAR_CACHE, GitgAvatarCache))
+#define GITG_AVATAR_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_AVATAR_CACHE, GitgAvatarCacheClass))
+#define GITG_IS_AVATAR_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_AVATAR_CACHE))
+#define GITG_IS_AVATAR_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_AVATAR_CACHE))
+#define GITG_AVATAR_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_AVATAR_CACHE, GitgAvatarCacheClass))
+
+typedef struct _GitgAvatarCache GitgAvatarCache;
+typedef struct _GitgAvatarCachePrivate GitgAvatarCachePrivate;
+typedef struct _GitgAvatarCacheClass GitgAvatarCacheClass;
+
+struct _GitgAvatarCache
+{
+ GObject parent_instance;
+
+ GitgAvatarCachePrivate *priv;
+};
+
+struct _GitgAvatarCacheClass
+{
+ GObjectClass parent_class;
+};
+
+GType gitg_avatar_cache_get_type (void) G_GNUC_CONST;
+
+GitgAvatarCache *gitg_avatar_cache_new (void);
+
+void gitg_avatar_cache_load_uri_async (GitgAvatarCache *cache,
+ const gchar *uri,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GdkPixbuf *gitg_avatar_cache_load_finish (GitgAvatarCache *cache,
+ GAsyncResult *result,
+ GError **error);
+
+gchar *gitg_avatar_cache_get_gravatar_uri (GitgAvatarCache *cache,
+ const gchar *gravatar_id);
+
+G_END_DECLS
+
+#endif /* __GITG_AVATAR_CACHE_H__ */
+
diff --git a/gitg/gitg-revision-details-panel.c b/gitg/gitg-revision-details-panel.c
index 67b52da..5d0f6b6 100644
--- a/gitg/gitg-revision-details-panel.c
+++ b/gitg/gitg-revision-details-panel.c
@@ -26,6 +26,7 @@
#include "gitg-revision-panel.h"
#include "gitg-stat-view.h"
#include "gitg-uri.h"
+#include "gitg-avatar-cache.h"
#include <glib/gi18n.h>
#include <stdlib.h>
@@ -46,6 +47,7 @@ struct _GitgRevisionDetailsPanelPrivate
GtkLabel *committer;
GtkLabel *subject;
GtkTable *parents;
+ GtkImage *avatar;
GtkWidget *panel_widget;
GtkTextView *text_view;
@@ -60,6 +62,8 @@ struct _GitgRevisionDetailsPanelPrivate
GSList *stats;
GitgWindow *window;
+
+ GitgAvatarCache *cache;
};
static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface);
@@ -125,6 +129,7 @@ initialize_ui (GitgRevisionDetailsPanel *panel)
priv->subject = GTK_LABEL (gtk_builder_get_object (priv->builder, "label_subject"));
priv->parents = GTK_TABLE (gtk_builder_get_object (priv->builder, "table_parents"));
priv->text_view = GTK_TEXT_VIEW (gtk_builder_get_object (priv->builder, "text_view_details"));
+ priv->avatar = GTK_IMAGE (gtk_builder_get_object (priv->builder, "image_avatar"));
gchar const *lbls[] = {
"label_subject_lbl",
@@ -211,6 +216,12 @@ gitg_revision_details_panel_dispose (GObject *object)
panel->priv->shell = NULL;
}
+ if (panel->priv->cache)
+ {
+ g_object_unref (panel->priv->cache);
+ panel->priv->cache = NULL;
+ }
+
G_OBJECT_CLASS (gitg_revision_details_panel_parent_class)->dispose (object);
}
static void
@@ -548,6 +559,8 @@ gitg_revision_details_panel_init (GitgRevisionDetailsPanel *self)
"update",
G_CALLBACK (on_shell_update),
self);
+
+ self->priv->cache = gitg_avatar_cache_new ();
}
#define HASH_KEY "GitgRevisionDetailsPanelHashKey"
@@ -726,6 +739,50 @@ update_details (GitgRevisionDetailsPanel *panel)
}
static void
+avatar_ready (GObject *source_object,
+ GAsyncResult *res,
+ GitgRevisionDetailsPanel *panel)
+{
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ pixbuf = gitg_avatar_cache_load_finish (panel->priv->cache,
+ res,
+ &error);
+
+ if (error == NULL)
+ {
+ gtk_image_set_from_pixbuf (panel->priv->avatar,
+ pixbuf);
+ gtk_widget_show (GTK_WIDGET (panel->priv->avatar));
+ }
+}
+
+static void
+set_avatar (GitgRevisionDetailsPanel *panel,
+ const gchar *email)
+{
+ if (email == NULL || *email == '\0')
+ {
+ gtk_widget_hide (GTK_WIDGET (panel->priv->avatar));
+ }
+ else
+ {
+ gchar *uri;
+
+ uri = gitg_avatar_cache_get_gravatar_uri (panel->priv->cache,
+ email);
+ gitg_avatar_cache_load_uri_async (panel->priv->cache,
+ uri,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ (GAsyncReadyCallback)avatar_ready,
+ panel);
+ g_free (uri);
+ }
+}
+
+static void
reload (GitgRevisionDetailsPanel *panel)
{
GtkClipboard *cb;
@@ -775,6 +832,8 @@ reload (GitgRevisionDetailsPanel *panel)
gtk_clipboard_set_text (cb, sha, -1);
g_free (sha);
+
+ set_avatar (panel, gitg_revision_get_author_email (panel->priv->revision));
}
else
{
@@ -782,6 +841,7 @@ reload (GitgRevisionDetailsPanel *panel)
gtk_label_set_text (panel->priv->committer, "");
gtk_label_set_text (panel->priv->subject, "");
gtk_label_set_text (panel->priv->sha, "");
+ set_avatar (panel, NULL);
}
// Update parents
diff --git a/gitg/gitg-revision-details-panel.ui b/gitg/gitg-revision-details-panel.ui
index ff0cd79..85a988e 100644
--- a/gitg/gitg-revision-details-panel.ui
+++ b/gitg/gitg-revision-details-panel.ui
@@ -10,17 +10,177 @@
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
- <property name="n_rows">5</property>
- <property name="n_columns">2</property>
<child>
- <object class="GtkLabel" id="label_sha_lbl">
+ <object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="xalign">1</property>
- <property name="label" translatable="yes">SHA:</property>
- <property name="use_markup">True</property>
+ <property name="hexpand">True</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label_sha_lbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">SHA:</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_author_lbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Author:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_committer_lbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Committer:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_subject_lbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Subject:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_parent_lbl">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">Parent:</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table_parents">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">3</property>
+ <property name="row_spacing">2</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_subject">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_committer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_author">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sha">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="left_attach">0</property>
@@ -30,144 +190,51 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_author_lbl">
+ <object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="xalign">1</property>
- <property name="label" translatable="yes">Author:</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="image_avatar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="stock">gtk-missing-image</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label_committer_lbl">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">1</property>
- <property name="label" translatable="yes">Committer:</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkLabel" id="label_subject_lbl">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">1</property>
- <property name="label" translatable="yes">Subject:</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkLabel" id="label_parent_lbl">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">1</property>
- <property name="yalign">0</property>
- <property name="label" translatable="yes">Parent:</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">4</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkTable" id="table_parents">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">3</property>
- <property name="row_spacing">2</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">4</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_subject">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="use_markup">True</property>
- <property name="selectable">True</property>
- <property name="ellipsize">end</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkLabel" id="label_committer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="use_markup">True</property>
- <property name="selectable">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkLabel" id="label_author">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="use_markup">True</property>
- <property name="selectable">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
<child>
- <object class="GtkLabel" id="label_sha">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="use_markup">True</property>
- <property name="selectable">True</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
+ <placeholder/>
</child>
</object>
<packing>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]