Changed RvModel to proper Repository object

GitgRepository is now a custom GtkTreeModel instead of GtkListStore
Added git path utility functions to gitg-utils
This commit is contained in:
Jesse van den Kieboom 2008-06-26 22:15:18 +02:00
parent 917413b931
commit dda98d7a16
6 changed files with 565 additions and 224 deletions

View file

@ -12,13 +12,12 @@ INCLUDES = \
-DGITG_UI_DIR=\""$(datadir)/gitg/ui/"\" \
-DGITG_ICONDIR=\""$(datadir)/gitg/icons"\"
gitg_SOURCES = \
gitg.c \
gitg-revision.c \
gitg-rv-model.c \
gitg-loader.c \
gitg-runner.c \
gitg-utils.c \
gitg_SOURCES = \
gitg.c \
gitg-revision.c \
gitg-repository.c \
gitg-runner.c \
gitg-utils.c \
sexy-icon-entry.c
gitg_LDADD = $(PACKAGE_LIBS)

View file

@ -1,16 +1,21 @@
#include "gitg-rv-model.h"
#include "gitg-repository.h"
#include "gitg-utils.h"
#include <glib/gi18n.h>
#include <time.h>
#define GITG_RV_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GITG_TYPE_RV_MODEL, GitgRvModelPrivate))
#define GITG_REPOSITORY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GITG_TYPE_REPOSITORY, GitgRepositoryPrivate))
static void gitg_rv_model_tree_model_iface_init(GtkTreeModelIface *iface);
static void gitg_repository_tree_model_iface_init(GtkTreeModelIface *iface);
G_DEFINE_TYPE_EXTENDED (GitgRvModel, gitg_rv_model, GTK_TYPE_LIST_STORE, 0,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, gitg_rv_model_tree_model_iface_init));
G_DEFINE_TYPE_EXTENDED(GitgRepository, gitg_repository, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL, gitg_repository_tree_model_iface_init));
struct _GitgRvModelPrivate
{
GHashTable *hashtable;
/* Properties */
enum {
PROP_0,
PROP_PATH,
PROP_LOADER
};
enum
@ -22,54 +27,88 @@ enum
N_COLUMNS
};
static GtkTreeModelIface parent_iface = { 0, };
static int
gitg_rv_model_get_n_columns (GtkTreeModel *self)
struct _GitgRepositoryPrivate
{
/* validate our parameters */
g_return_val_if_fail(GITG_RV_MODEL(self), 0);
gchar *path;
GitgRunner *loader;
GHashTable *hashtable;
gint stamp;
GType column_types[N_COLUMNS];
GitgRevision **storage;
gulong size;
gulong allocated;
gint grow_size;
};
inline static gint
gitg_repository_error_quark()
{
static GQuark quark = 0;
if (G_UNLIKELY(quark == 0))
quark = g_quark_from_static_string("GitgRepositoryErrorQuark");
return quark;
}
/* GtkTreeModel implementations */
static GtkTreeModelFlags
tree_model_get_flags(GtkTreeModel *tree_model)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), 0);
return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
}
static gint
tree_model_get_n_columns(GtkTreeModel *tree_model)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), 0);
return N_COLUMNS;
}
static GType
gitg_rv_model_get_column_type(GtkTreeModel *self, int column)
static GType
tree_model_get_column_type(GtkTreeModel *tree_model, gint index)
{
GType types[] = {
GITG_TYPE_REVISION,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_STRING
};
/* validate our parameters */
g_return_val_if_fail(GITG_IS_RV_MODEL(self), G_TYPE_INVALID);
g_return_val_if_fail(column >= 0 && column < N_COLUMNS, G_TYPE_INVALID);
return types[column];
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), G_TYPE_INVALID);
g_return_val_if_fail(index < N_COLUMNS && index >= 0, G_TYPE_INVALID);
}
/* retreive an object from our parent's data storage,
* unref the returned object when done */
static GitgRevision *
gitg_rv_model_get_object(GitgRvModel *self, GtkTreeIter *iter)
static gboolean
tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
{
GValue value = { 0, };
GitgRevision *obj;
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
gint *indices;
gint depth;
/* validate our parameters */
g_return_val_if_fail(GITG_IS_RV_MODEL(self), NULL);
g_return_val_if_fail(iter != NULL, NULL);
indices = gtk_tree_path_get_indices(path);
depth = gtk_tree_path_get_depth(path);
GitgRepository *rp = GITG_REPOSITORY(tree_model);
/* retreive the object using our parent's interface, take our own
* reference to it */
parent_iface.get_value(GTK_TREE_MODEL(self), iter, 0, &value);
obj = GITG_REVISION(g_value_dup_object(&value));
g_return_val_if_fail(depth == 1, FALSE);
if (indices[0] < 0 || indices[0] >= rp->priv->size)
return FALSE;
iter->stamp = rp->priv->stamp;
iter->user_data = GINT_TO_POINTER(indices[0]);
iter->user_data2 = NULL;
iter->user_data3 = NULL;
return TRUE;
}
g_value_unset (&value);
return obj;
static GtkTreePath *
tree_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), NULL);
GitgRepository *rp = GITG_REPOSITORY(tree_model);
g_return_val_if_fail(iter->stamp == rp->priv->stamp, NULL);
return gtk_tree_path_new_from_indices(GPOINTER_TO_INT(iter->user_data), -1);
}
static gchar *
@ -78,74 +117,234 @@ timestamp_to_str(guint64 timestamp)
struct tm *tms = localtime((time_t *)&timestamp);
char buf[255];
strftime(buf, 255, "%Y-%m-%d %H:%M:%S", tms);
strftime(buf, 255, "%c", tms);
return g_strdup(buf);
}
static void
gitg_rv_model_get_value(GtkTreeModel *self, GtkTreeIter *iter, int column,
GValue *value)
static void
tree_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value)
{
GitgRevision *obj;
/* validate our parameters */
g_return_if_fail(GITG_IS_RV_MODEL(self));
g_return_if_fail(iter != NULL);
g_return_if_fail(GITG_IS_REPOSITORY(tree_model));
g_return_if_fail(column >= 0 && column < N_COLUMNS);
g_return_if_fail(value != NULL);
GitgRepository *rp = GITG_REPOSITORY(tree_model);
g_return_if_fail(iter->stamp == rp->priv->stamp);
/* get the object from our parent's storage */
obj = gitg_rv_model_get_object(GITG_RV_MODEL(self), iter);
/* initialise our GValue to the required type */
g_value_init(value, gitg_rv_model_get_column_type(GTK_TREE_MODEL(self), column));
gint index = GPOINTER_TO_INT(iter->user_data);
g_return_if_fail(index >= 0 && index < rp->priv->size);
GitgRevision *rv = rp->priv->storage[index];
g_value_init(value, rp->priv->column_types[column]);
switch (column)
{
case OBJECT_COLUMN:
/* the object itself was requested */
g_value_set_object(value, obj);
break;
case AUTHOR_COLUMN:
g_value_set_string(value, gitg_revision_get_author(obj));
break;
g_value_set_object(value, rv);
break;
case SUBJECT_COLUMN:
g_value_set_string(value, gitg_revision_get_subject(obj));
break;
g_value_set_string(value, gitg_revision_get_subject(rv));
break;
case AUTHOR_COLUMN:
g_value_set_string(value, gitg_revision_get_author(rv));
break;
case DATE_COLUMN:
g_value_take_string(value, timestamp_to_str(gitg_revision_get_timestamp(obj)));
break;
g_value_take_string(value, timestamp_to_str(gitg_revision_get_timestamp(rv)));
break;
default:
g_assert_not_reached();
break;
}
/* release the reference gained from gitg_rv_model _get_object() */
g_object_unref(obj);
}
static void
gitg_rv_model_tree_model_iface_init(GtkTreeModelIface *iface)
static gboolean
tree_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter)
{
parent_iface = *iface;
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
GitgRepository *rp = GITG_REPOSITORY(tree_model);
g_return_val_if_fail(iter->stamp == rp->priv->stamp, FALSE);
iface->get_n_columns = gitg_rv_model_get_n_columns;
iface->get_column_type = gitg_rv_model_get_column_type;
iface->get_value = gitg_rv_model_get_value;
gint next = GPOINTER_TO_INT(iter->user_data) + 1;
if (next >= rp->priv->size)
return FALSE;
iter->user_data = GINT_TO_POINTER(next);
return TRUE;
}
static gboolean
tree_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
// Only root has children, because it's a flat list
if (parent != NULL)
return FALSE;
GitgRepository *rp = GITG_REPOSITORY(tree_model);
iter->stamp = rp->priv->stamp;
iter->user_data = GINT_TO_POINTER(0);
iter->user_data2 = NULL;
iter->user_data3 = NULL;
return TRUE;
}
static gboolean
tree_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
// Only root (NULL) has children
return iter == NULL;
}
static gint
tree_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), 0);
GitgRepository *rp = GITG_REPOSITORY(tree_model);
return iter ? 0 : rp->priv->size;
}
static gboolean
tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
g_return_val_if_fail(n >= 0, FALSE);
if (parent)
return FALSE;
GitgRepository *rp = GITG_REPOSITORY(tree_model);
g_return_val_if_fail(n < rp->priv->size, FALSE);
iter->stamp = rp->priv->stamp;
iter->user_data = GINT_TO_POINTER(n);
iter->user_data2 = NULL;
iter->user_data3 = NULL;
return TRUE;
}
static gboolean
tree_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(tree_model), FALSE);
return FALSE;
}
static GType
gitg_repository_get_column_type(GtkTreeModel *self, int column)
{
/* validate our parameters */
g_return_val_if_fail(GITG_IS_REPOSITORY(self), G_TYPE_INVALID);
g_return_val_if_fail(column >= 0 && column < N_COLUMNS, G_TYPE_INVALID);
return GITG_REPOSITORY(self)->priv->column_types[column];
}
static void
gitg_rv_model_finalize(GObject *object)
gitg_repository_tree_model_iface_init(GtkTreeModelIface *iface)
{
G_OBJECT_CLASS (gitg_rv_model_parent_class)->finalize(object);
iface->get_flags = tree_model_get_flags;
iface->get_n_columns = tree_model_get_n_columns;
iface->get_column_type = tree_model_get_column_type;
iface->get_iter = tree_model_get_iter;
iface->get_path = tree_model_get_path;
iface->get_value = tree_model_get_value;
iface->iter_next = tree_model_iter_next;
iface->iter_children = tree_model_iter_children;
iface->iter_has_child = tree_model_iter_has_child;
iface->iter_n_children = tree_model_iter_n_children;
iface->iter_nth_child = tree_model_iter_nth_child;
iface->iter_parent = tree_model_iter_parent;
}
static void
gitg_repository_finalize(GObject *object)
{
GitgRepository *rp = GITG_REPOSITORY(object);
// Make sure to cancel the loader
gitg_runner_cancel(rp->priv->loader);
g_object_unref(rp->priv->loader);
// Clear the model to remove all revision objects
gitg_repository_clear(rp);
// Free the path
g_free(rp->priv->path);
// Free the hash
g_hash_table_destroy(rp->priv->hashtable);
G_OBJECT_CLASS (gitg_repository_parent_class)->finalize(object);
}
static void
gitg_repository_set_property(GObject *object, guint prop_id, GValue const *value, GParamSpec *pspec)
{
GitgRepository *self = GITG_REPOSITORY(object);
switch (prop_id)
{
case PROP_PATH:
g_free(self->priv->path);
self->priv->path = gitg_utils_find_git(g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
gitg_repository_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GitgRepository *self = GITG_REPOSITORY(object);
switch (prop_id)
{
case PROP_PATH:
g_value_set_string(value, self->priv->path);
break;
case PROP_LOADER:
g_value_set_object(value, self->priv->loader);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
gitg_rv_model_class_init(GitgRvModelClass *klass)
gitg_repository_class_init(GitgRepositoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gitg_rv_model_finalize;
object_class->finalize = gitg_repository_finalize;
g_type_class_add_private(object_class, sizeof(GitgRvModelPrivate));
object_class->set_property = gitg_repository_set_property;
object_class->get_property = gitg_repository_get_property;
g_object_class_install_property(object_class, PROP_PATH,
g_param_spec_string ("path",
"PATH",
"The repository path",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property(object_class, PROP_LOADER,
g_param_spec_object ("loader",
"LOADER",
"The repository loader",
GITG_TYPE_RUNNER,
G_PARAM_READABLE));
g_type_class_add_private(object_class, sizeof(GitgRepositoryPrivate));
}
static guint
@ -169,46 +368,186 @@ hash_equal(gconstpointer a, gconstpointer b)
}
static void
gitg_rv_model_init(GitgRvModel *object)
on_loader_update(GitgRunner *object, gchar **buffer, GitgRepository *self)
{
object->priv = GITG_RV_MODEL_GET_PRIVATE(object);
gchar *line;
while ((line = *buffer++))
{
// New line is read
gchar **components = g_strsplit(line, "\01", 0);
if (g_strv_length(components) < 5)
{
g_strfreev(components);
continue;
}
// components -> [hash, author, subject, parents ([1 2 3]), timestamp]
gint64 timestamp = g_ascii_strtoll(components[4], NULL, 0);
GitgRevision *rv = gitg_revision_new(components[0], components[1], components[2], components[3], timestamp);
gitg_repository_add(self, rv, NULL);
g_object_unref(rv);
g_strfreev(components);
}
}
static void
gitg_repository_init(GitgRepository *object)
{
object->priv = GITG_REPOSITORY_GET_PRIVATE(object);
object->priv->hashtable = g_hash_table_new_full(hash_hash, hash_equal, NULL, NULL);
GType types[] = { GITG_TYPE_REVISION };
gtk_list_store_set_column_types(GTK_LIST_STORE(object), 1, types);
object->priv->column_types[0] = GITG_TYPE_REVISION;
object->priv->column_types[1] = G_TYPE_STRING;
object->priv->column_types[2] = G_TYPE_STRING;
object->priv->column_types[3] = G_TYPE_STRING;
object->priv->grow_size = 1000;
object->priv->stamp = g_random_int();
object->priv->loader = gitg_runner_new(1000);
g_signal_connect(object->priv->loader, "update", G_CALLBACK(on_loader_update), object);
}
static void
grow_storage(GitgRepository *repository, gint size)
{
if (repository->priv->size + size <= repository->priv->allocated)
return;
gulong prevallocated = repository->priv->allocated;
repository->priv->allocated += repository->priv->grow_size;
GitgRevision **newstorage = g_slice_alloc(sizeof(GitgRevision *) * repository->priv->allocated);
int i;
for (i = 0; i < repository->priv->size; ++i)
newstorage[i] = repository->priv->storage[i];
if (repository->priv->storage)
g_slice_free1(sizeof(GitgRevision *) * prevallocated, repository->priv->storage);
repository->priv->storage = newstorage;
}
GitgRepository *
gitg_repository_new(gchar const *path)
{
return g_object_new(GITG_TYPE_REPOSITORY, "path", path, NULL);
}
gchar const *
gitg_repository_get_path(GitgRepository *self)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(self), NULL);
return self->priv->path;
}
GitgRunner *
gitg_repository_get_loader(GitgRepository *self)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(self), NULL);
return GITG_RUNNER(g_object_ref(self->priv->loader));
}
gboolean
gitg_repository_load(GitgRepository *self, GError **error)
{
g_return_val_if_fail(GITG_IS_REPOSITORY(self), FALSE);
if (self->priv->path == NULL)
{
if (error)
*error = g_error_new_literal(gitg_repository_error_quark(), GITG_REPOSITORY_ERROR_NOT_FOUND, _("Not a valid git repository"));
return FALSE;
}
gitg_runner_cancel(self->priv->loader);
gitg_repository_clear(self);
gchar *argv[] = {
"git",
"--git-dir",
gitg_utils_dot_git_path(self->priv->path),
"log",
"--encoding=UTF-8",
"--topo-order",
"--pretty=format:%H\01%an\01%s\01%P\01%at",
"HEAD",
NULL
};
gboolean ret = gitg_runner_run(self->priv->loader, argv, error);
g_free(argv[2]);
return ret;
}
void
gitg_rv_model_add(GitgRvModel *self, GitgRevision *obj, GtkTreeIter *iter)
gitg_repository_add(GitgRepository *self, GitgRevision *obj, GtkTreeIter *iter)
{
static guint num = 0;
GtkTreeIter iter1;
/* validate our parameters */
g_return_if_fail(GITG_IS_RV_MODEL(self));
g_return_if_fail(GITG_IS_REPOSITORY(self));
g_return_if_fail(GITG_IS_REVISION(obj));
grow_storage(self, 1);
/* put this object in our data storage */
gtk_list_store_append(GTK_LIST_STORE(self), &iter1);
gtk_list_store_set(GTK_LIST_STORE(self), &iter1, 0, obj, -1);
self->priv->storage[self->priv->size++] = g_object_ref(obj);
g_hash_table_insert(self->priv->hashtable, (gpointer)gitg_revision_get_hash(obj), GUINT_TO_POINTER(num++));
g_hash_table_insert(self->priv->hashtable, (gpointer)gitg_revision_get_hash(obj), GUINT_TO_POINTER(self->priv->size - 1));
iter1.stamp = self->priv->stamp;
iter1.user_data = GINT_TO_POINTER(self->priv->size - 1);
iter1.user_data2 = NULL;
iter1.user_data3 = NULL;
GtkTreePath *path = gtk_tree_path_new_from_indices(self->priv->size - 1, -1);
gtk_tree_model_row_inserted(GTK_TREE_MODEL(self), path, &iter1);
gtk_tree_path_free(path);
/* return the iter if the user cares */
if (iter)
*iter = iter1;
}
GitgRvModel *
gitg_rv_model_new()
void
gitg_repository_clear(GitgRepository *repository)
{
return g_object_new(GITG_TYPE_RV_MODEL, NULL);
int i;
GtkTreePath *path = gtk_tree_path_new_from_indices(repository->priv->size - 1, -1);
for (i = repository->priv->size - 1; i >= 0; --i)
{
GtkTreePath *dup = gtk_tree_path_copy(path);
gtk_tree_model_row_deleted(GTK_TREE_MODEL(repository), dup);
gtk_tree_path_free(dup);
gtk_tree_path_prev(path);
g_object_unref(repository->priv->storage[i]);
}
gtk_tree_path_free(path);
if (repository->priv->storage)
g_slice_free1(sizeof(GitgRevision *) * repository->priv->size, repository->priv->storage);
repository->priv->storage = NULL;
repository->priv->size = 0;
repository->priv->allocated = 0;
}
gboolean
gitg_rv_model_find_by_hash(GitgRvModel *store, gchar const *hash, GtkTreeIter *iter)
gitg_repository_find_by_hash(GitgRepository *store, gchar const *hash, GtkTreeIter *iter)
{
g_return_val_if_fail(GITG_IS_RV_MODEL(store), FALSE);
g_return_val_if_fail(GITG_IS_REPOSITORY(store), FALSE);
gpointer result = g_hash_table_lookup(store->priv->hashtable, hash);
@ -223,42 +562,10 @@ gitg_rv_model_find_by_hash(GitgRvModel *store, gchar const *hash, GtkTreeIter *i
}
gboolean
gitg_rv_model_find(GitgRvModel *store, GitgRevision *revision, GtkTreeIter *iter)
gitg_repository_find(GitgRepository *store, GitgRevision *revision, GtkTreeIter *iter)
{
g_return_val_if_fail(GITG_IS_REVISION(revision), FALSE);
return gitg_rv_model_find_by_hash(store, gitg_revision_get_hash(revision), iter);
return gitg_repository_find_by_hash(store, gitg_revision_get_hash(revision), iter);
}
gint gitg_rv_model_compare(GitgRvModel *store, GtkTreeIter *a, GtkTreeIter *b, gint col)
{
GitgRevision *rv1;
GitgRevision *rv2;
rv1 = gitg_rv_model_get_object(store, a);
rv2 = gitg_rv_model_get_object(store, b);
gint ret;
int i1;
int i2;
switch (col)
{
case SUBJECT_COLUMN:
ret = g_utf8_collate(gitg_revision_get_subject(rv1), gitg_revision_get_subject(rv2));
break;
case AUTHOR_COLUMN:
ret = g_utf8_collate(gitg_revision_get_author(rv1), gitg_revision_get_author(rv2));
break;
case DATE_COLUMN:
i1 = gitg_revision_get_timestamp(rv1);
i2 = gitg_revision_get_timestamp(rv2);
ret = i1 < i2 ? -1 : (i1 > i2 ? 1 : 0);
break;
}
g_object_unref(rv1);
g_object_unref(rv2);
return ret;
}

View file

@ -1,43 +1,56 @@
#ifndef __GITG_RV_MODEL_H__
#define __GITG_RV_MODEL_H__
#ifndef __GITG_REPOSITORY_H__
#define __GITG_REPOSITORY_H__
#include <gtk/gtkliststore.h>
#include <gtk/gtktreemodel.h>
#include "gitg-revision.h"
#include "gitg-runner.h"
G_BEGIN_DECLS
#define GITG_TYPE_RV_MODEL (gitg_rv_model_get_type ())
#define GITG_RV_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RV_MODEL, GitgRvModel))
#define GITG_RV_MODEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RV_MODEL, GitgRvModel const))
#define GITG_RV_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_RV_MODEL, GitgRvModelClass))
#define GITG_IS_RV_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_RV_MODEL))
#define GITG_IS_RV_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_RV_MODEL))
#define GITG_RV_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_RV_MODEL, GitgRvModelClass))
#define GITG_TYPE_REPOSITORY (gitg_repository_get_type ())
#define GITG_REPOSITORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REPOSITORY, GitgRepository))
#define GITG_REPOSITORY_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REPOSITORY, GitgRepository const))
#define GITG_REPOSITORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REPOSITORY, GitgRepositoryClass))
#define GITG_IS_REPOSITORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REPOSITORY))
#define GITG_IS_REPOSITORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REPOSITORY))
#define GITG_REPOSITORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REPOSITORY, GitgRepositoryClass))
typedef struct _GitgRvModel GitgRvModel;
typedef struct _GitgRvModelClass GitgRvModelClass;
typedef struct _GitgRvModelPrivate GitgRvModelPrivate;
typedef struct _GitgRepository GitgRepository;
typedef struct _GitgRepositoryClass GitgRepositoryClass;
typedef struct _GitgRepositoryPrivate GitgRepositoryPrivate;
struct _GitgRvModel {
GtkListStore parent;
typedef enum
{
GITG_REPOSITORY_NO_ERROR = 0,
GITG_REPOSITORY_ERROR_NOT_FOUND
} GitgRepositoryError;
struct _GitgRepository
{
GObject parent;
GitgRvModelPrivate *priv;
GitgRepositoryPrivate *priv;
};
struct _GitgRvModelClass {
GtkListStoreClass parent_class;
struct _GitgRepositoryClass
{
GObjectClass parent_class;
};
GType gitg_rv_model_get_type (void) G_GNUC_CONST;
GitgRvModel *gitg_rv_model_new(void);
GType gitg_repository_get_type (void) G_GNUC_CONST;
GitgRepository *gitg_repository_new(gchar const *path);
gchar const *gitg_repository_get_path(GitgRepository *repository);
GitgRunner *gitg_repository_get_loader(GitgRepository *repository);
void gitg_rv_model_add(GitgRvModel *self, GitgRevision *obj, GtkTreeIter *iter);
gboolean gitg_rv_model_find_by_hash(GitgRvModel *self, gchar const *hash, GtkTreeIter *iter);
gboolean gitg_rv_model_find(GitgRvModel *store, GitgRevision *revision, GtkTreeIter *iter);
gboolean gitg_repository_load(GitgRepository *repository, GError **error);
gint gitg_rv_model_compare(GitgRvModel *store, GtkTreeIter *a, GtkTreeIter *b, gint col);
void gitg_repository_add(GitgRepository *repository, GitgRevision *revision, GtkTreeIter *iter);
void gitg_repository_clear(GitgRepository *repository);
gboolean gitg_repository_find_by_hash(GitgRepository *self, gchar const *hash, GtkTreeIter *iter);
gboolean gitg_repository_find(GitgRepository *store, GitgRevision *revision, GtkTreeIter *iter);
G_END_DECLS
#endif /* __GITG_RV_MODEL_H__ */
#endif /* __GITG_REPOSITORY_H__ */

View file

@ -1,3 +1,6 @@
#include <string.h>
#include <glib.h>
#include "gitg-utils.h"
inline static guint8
@ -52,3 +55,51 @@ gitg_utils_sha1_to_hash_new(gchar const *sha1)
return ret;
}
static gchar *
find_dot_git(gchar *path)
{
while (strcmp(path, ".") != 0)
{
gchar *res = g_build_filename(path, ".git", NULL);
if (g_file_test(res, G_FILE_TEST_IS_DIR))
{
g_free(res);
return path;
}
gchar *tmp = g_path_get_dirname(path);
g_free(path);
path = tmp;
g_free(res);
}
return NULL;
}
gchar *
gitg_utils_find_git(gchar const *path)
{
gchar const *find = G_DIR_SEPARATOR_S ".git";
gchar *dir;
if (strstr(path, find) == path + strlen(path) - strlen(find))
dir = g_strndup(path, strlen(path) - strlen(find));
else
dir = g_strdup(path);
return find_dot_git(dir);
}
gchar *
gitg_utils_dot_git_path(gchar const *path)
{
gchar const *find = G_DIR_SEPARATOR_S ".git";
if (strstr(path, find) == path + strlen(path) - strlen(find))
return g_strdup(path);
else
return g_build_filename(path, ".git", NULL);
}

View file

@ -9,4 +9,7 @@ void gitg_utils_hash_to_sha1(gchar const *hash, gchar *sha);
gchar *gitg_utils_sha1_to_hash_new(gchar const *sha);
gchar *gitg_utils_hash_to_sha1_new(gchar const *hash);
gchar *gitg_utils_find_git(gchar const *path);
gchar *gitg_utils_dot_git_path(gchar const *path);
#endif /* __GITG_UTILS_H__ */

View file

@ -7,9 +7,9 @@
#include <gtksourceview/gtksourcelanguagemanager.h>
#include <gdk/gdkkeysyms.h>
#include "gitg-rv-model.h"
#include "gitg-repository.h"
#include "gitg-utils.h"
#include "gitg-loader.h"
#include "gitg-runner.h"
#include "sexy-icon-entry.h"
#include "config.h"
@ -21,12 +21,12 @@ static GOptionEntry entries[] =
static GtkWindow *window;
static GtkBuilder *builder;
static GtkTreeView *tree_view;
static GitgRvModel *store;
static GtkStatusbar *statusbar;
static GitgRunner *diff_runner;
static GtkSourceView *diff_view;
static gchar *gitdir;
static GtkWidget *search_popup;
static GitgRepository *repository;
void
parse_options(int *argc, char ***argv)
@ -59,7 +59,7 @@ on_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer userdata)
static gint
string_compare(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
{
return gitg_rv_model_compare(store, a, b, GPOINTER_TO_INT(userdata));
return 0; //gitg_rv_model_compare(store, a, b, GPOINTER_TO_INT(userdata));
}
static gchar *
@ -165,7 +165,7 @@ on_parent_clicked(GtkWidget *ev, GdkEventButton *event, gpointer userdata)
return FALSE;
GtkTreeIter iter;
if (gitg_rv_model_find_by_hash(store, (gchar *)userdata, &iter))
if (gitg_repository_find_by_hash(repository, (gchar *)userdata, &iter))
gtk_tree_selection_select_iter(gtk_tree_view_get_selection(tree_view), &iter);
return TRUE;
@ -254,7 +254,7 @@ on_update_diff(GtkTreeSelection *selection, GtkVBox *container)
gchar *argv[] = {
"git",
"--git-dir",
gitdir,
gitg_utils_dot_git_path(gitg_repository_get_path(repository)),
"show",
"--pretty=format:%s%n%n%b",
"--encoding=UTF-8",
@ -265,13 +265,15 @@ on_update_diff(GtkTreeSelection *selection, GtkVBox *container)
gitg_runner_run(diff_runner, argv, NULL);
g_object_unref(rv);
g_free(hash);
g_free(argv[2]);
}
static void
build_tree_view()
{
tree_view = GTK_TREE_VIEW(gtk_builder_get_object(builder, "tree_view_rv"));
store = gitg_rv_model_new();
gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(repository));
gtk_tree_view_insert_column_with_attributes(tree_view,
0, _("Subject"), gtk_cell_renderer_text_new(), "text", 1, NULL);
@ -295,7 +297,7 @@ build_tree_view()
gtk_tree_view_column_set_fixed_width(column, cw[i]);
gtk_tree_view_column_set_sort_column_id(column, i + 1);
gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), i + 1, string_compare, GINT_TO_POINTER(i + 1), NULL);
//gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), i + 1, string_compare, GINT_TO_POINTER(i + 1), NULL);
}
GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
@ -520,7 +522,7 @@ on_diff_update(GitgRunner *runner, gchar **buffer, gpointer userdata)
}
static void
on_begin_loading(GitgLoader *loader, gpointer userdata)
on_begin_loading(GitgRunner *loader, gpointer userdata)
{
GdkCursor *cursor = gdk_cursor_new(GDK_WATCH);
gdk_window_set_cursor(GTK_WIDGET(tree_view)->window, cursor);
@ -530,67 +532,32 @@ on_begin_loading(GitgLoader *loader, gpointer userdata)
}
static void
on_end_loading(GitgLoader *loader, gpointer userdata)
on_end_loading(GitgRunner *loader, gpointer userdata)
{
gchar *msg = g_strdup_printf(_("Loaded %d revisions"), gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL));
gchar *msg = g_strdup_printf(_("Loaded %d revisions"), gtk_tree_model_iter_n_children(GTK_TREE_MODEL(repository), NULL));
gtk_statusbar_push(statusbar, 0, msg);
g_free(msg);
gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(store));
gdk_window_set_cursor(GTK_WIDGET(tree_view)->window, NULL);
}
static void
on_update(GitgLoader *loader, GitgRevision **revisions)
on_update(GitgRunner *loader, gchar **revisions, gpointer userdata)
{
GitgRevision *rv;
gtk_tree_view_set_model(tree_view, NULL);
while ((rv = *revisions++))
gitg_rv_model_add(store, rv, NULL);
gchar *msg = g_strdup_printf(_("Loading %d revisions..."), gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL));
gchar *msg = g_strdup_printf(_("Loading %d revisions..."), gtk_tree_model_iter_n_children(GTK_TREE_MODEL(repository), NULL));
gtk_statusbar_push(statusbar, 0, msg);
g_free(msg);
//gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(store));
}
static gchar *
find_dot_git(gchar *path)
{
while (strcmp(path, ".") != 0)
{
gchar *res = g_build_filename(path, ".git", NULL);
if (g_file_test(res, G_FILE_TEST_IS_DIR))
{
g_free(path);
return res;
}
gchar *tmp = g_path_get_dirname(path);
g_free(path);
path = tmp;
g_free(res);
}
return NULL;
}
static gboolean
handle_no_gitdir(gpointer userdata)
{
if (gitdir)
if (gitg_repository_get_path(repository))
return FALSE;
GtkWidget *dlg = gtk_message_dialog_new(window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("No .git directory found"));
GtkWidget *dlg = gtk_message_dialog_new(window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Gitg repository could not be found"));
gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_destroy(dlg);
@ -610,27 +577,28 @@ main(int argc, char **argv)
gtk_init(&argc, &argv);
parse_options(&argc, &argv);
gitdir = find_dot_git(argc > 1 ? g_strdup(argv[1]) : g_get_current_dir());
gchar *gitdir = argc > 1 ? g_strdup(argv[1]) : g_get_current_dir();
repository = gitg_repository_new(gitdir);
g_free(gitdir);
build_ui();
GitgLoader *loader = gitg_loader_new(store);
diff_runner = gitg_runner_new(2000);
g_signal_connect(diff_runner, "begin-loading", G_CALLBACK(on_diff_begin_loading), NULL);
g_signal_connect(diff_runner, "update", G_CALLBACK(on_diff_update), NULL);
g_signal_connect(diff_runner, "end-loading", G_CALLBACK(on_diff_end_loading), NULL);
g_signal_connect(loader, "begin-loading", G_CALLBACK(on_begin_loading), NULL);
g_signal_connect(loader, "revisions-added", G_CALLBACK(on_update), NULL);
g_signal_connect(loader, "end-loading", G_CALLBACK(on_end_loading), NULL);
if (gitdir != NULL)
gitg_loader_load(loader, gitdir, NULL);
GitgRunner *loader = gitg_repository_get_loader(repository);
g_signal_connect(loader, "begin-loading", G_CALLBACK(on_begin_loading), NULL);
g_signal_connect(loader, "end-loading", G_CALLBACK(on_end_loading), NULL);
g_signal_connect(loader, "update", G_CALLBACK(on_update), NULL);
g_object_unref(loader);
gitg_repository_load(repository, NULL);
g_idle_add(handle_no_gitdir, NULL);
gtk_main();
g_free(gitdir);
return 0;
}