Implemented basic preferences

The lane collapse preference works, search filter not yet. Also, colors for the diff were implemented, but due to a limitation in gtksourceview this does not work (and is not yet committed).
This commit is contained in:
Jesse van den Kieboom 2009-02-08 13:07:17 +01:00
parent d4a1a2e987
commit bf6012d548
21 changed files with 1549 additions and 127 deletions

View file

@ -23,6 +23,7 @@ AM_INIT_AUTOMAKE([1.8 dist-bzip2 no-dist-gzip])
AM_MAINTAINER_MODE
AC_CONFIG_HEADERS(config.h)
AC_PATH_PROG(GCONFTOOL, gconftool-2)
IT_PROG_INTLTOOL([0.35.0])
AC_PROG_LIBTOOL
@ -57,6 +58,12 @@ AC_SUBST(PACKAGE_LIBS)
AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
dnl ================================================================
dnl GConf related settings
dnl ================================================================
AM_GCONF_SOURCE_2
AC_CONFIG_FILES([
Makefile
gitg/Makefile

View file

@ -5,6 +5,11 @@ desktop_in_files = gitg.desktop.in
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_DESKTOP_RULE@
schemasdir = $(GCONF_SCHEMA_FILE_DIR)
schemas_in_files = gitg.schemas.in
schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
@INTLTOOL_SCHEMAS_RULE@
man_MANS = gitg.1
gitglangsdir = $(datadir)/gitg/language-specs
@ -13,12 +18,25 @@ gitglangs_DATA = gitgdiff.lang
gitgstylesdir = $(datadir)/gitg/styles
gitgstyles_DATA = gitgstyle.xml
if GCONF_SCHEMAS_INSTALL
install-data-local:
if test -z "$(DESTDIR)" ; then \
for p in $(schemas_DATA) ; do \
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$$p ; \
done \
fi
else
install-data-local:
endif
EXTRA_DIST = \
$(desktop_in_files) \
$(schemas_in_files) \
$(gitglangs_DATA) \
$(gitgstyles_DATA) \
$(man_MANS)
CLEANFILES = \
$(desktop_DATA)
$(desktop_DATA) \
$(schemas_DATA)

29
data/gitg.schemas.in Normal file
View file

@ -0,0 +1,29 @@
<gconfschemafile>
<schemalist>
<schema>
<key>/schemas/apps/gitg/preferences/view/history/search-filter</key>
<applyto>/apps/gitg/preferences/view/history/search-filter</applyto>
<owner>gitg</owner>
<type>bool</type>
<default>FALSE</default>
<locale name="C">
<short>Filter Revisions When Searching</short>
<long>Whether searching filters the revisions in the history view
instead of jumping to the first match.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/gitg/preferences/view/history/collapse-inactive-lanes</key>
<applyto>/apps/gitg/preferences/view/history/collapse-inactive-lanes</applyto>
<owner>gitg</owner>
<type>int</type>
<default>2</default>
<locale name="C">
<short>When to Collapse Inactive Lanes</short>
<long>Setting that indicates when an inactive lane should be collapsed.
Valid values are 0 - 4, where 0 indicates 'early' and 4 indicates 'late'.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

View file

@ -27,20 +27,18 @@
</metadata>
<styles>
<style id="added-line" _name="Added line" map-to="diff:added-line"/> <!--Others 2-->
<style id="removed-line" _name="Removed line" map-to="diff:removed-line"/> <!--Others 3-->
<style id="changed-line" _name="Changed line" map-to="diff:changed-line"/> <!--Preprocessor-->
<style id="special-case" _name="Special case" map-to="diff:special-case"/> <!--String-->
<style id="hunk" _name="Hunk" map-to="diff:location"/> <!--Keyword-->
<style id="ignore" _name="Ignore" map-to="def:comment"/>
<style id="diff-file" _name="" map-to="diff:diff-file"/> <!--Data Type-->
<style id="added-line" _name="Added line"/>
<style id="removed-line" _name="Removed line"/>
<style id="changed-line" _name="Changed line"/>
<style id="hunk" _name="Hunk"/>
<style id="header" _name="Diff file"/>
<style id="trailing-spaces" _name="Trailing spaces"/>
</styles>
<definitions>
<context id="gitgdiff">
<include>
<context id="diff-file" style-ref="diff-file">
<context id="header" style-ref="header">
<start>^diff --git</start>
<end>\+\+\+ .*$</end>
</context>
@ -79,21 +77,6 @@
<context ref="def:escape"/>
</include>
</context>
<context id="special-case" style-ref="special-case">
<prefix>^</prefix>
<suffix>\b</suffix>
<keyword>Only in .*</keyword>
<keyword>Files .* and .* are identical$</keyword>
<keyword>Files .* and .* differ$</keyword>
<keyword>Binary files .* and .* differ$</keyword>
<keyword>File .* is a .* while file .* is a .*</keyword>
<keyword>No newline at end of file .*</keyword>
</context>
<context id="ignore" style-ref="ignore" end-at-line-end="true">
<start>^\S</start>
</context>
</include>
</context>
</definitions>

View file

@ -42,6 +42,7 @@
<color name="plum1" value="#ad7fa8"/>
<color name="plum2" value="#75507b"/>
<color name="plum3" value="#5c3566"/>
<color name="chocolate0" value="#f1d09e"/>
<color name="chocolate1" value="#e9b96e"/>
<color name="chocolate2" value="#c17d11"/>
<color name="chocolate3" value="#8f5902"/>
@ -56,67 +57,21 @@
<color name="aluminium5" value="#555753"/>
<color name="aluminium6" value="#2e3436"/>
<!-- legacy styles for old lang files: do NOT use them in lang files -->
<style name="Others" foreground="chameleon3" bold="true"/>
<style name="Others 2" foreground="chameleon3"/>
<style name="Others 3" foreground="plum3"/>
<!-- Bracket Matching -->
<style name="bracket-match" foreground="aluminium1" background="aluminium3" bold="true"/>
<style name="bracket-mismatch" foreground="aluminium1" background="scarletred3" bold="true"/>
<!-- Default -->
<style name="gitgdiff:text" foreground="skyblue3" background="aluminium1"/>
<style name="text" use-style="gitgdiff:text"/>
<!-- Right Margin -->
<style name="right-margin" foreground="aluminium5" background="aluminium4"/>
<style name="line-numbers" foreground="aluminium4" background="aluminium1"/>
<!-- Search Matching -->
<style name="search-match" background="butter1"/>
<!-- Comments -->
<style name="def:comment" foreground="skyblue3"/>
<style name="def:shebang" foreground="skyblue3" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="plum1"/>
<style name="def:special-char" foreground="plum3"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="skyblue1"/>
<!-- Statements -->
<style name="def:statement" foreground="scarletred3" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="chameleon3" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="chocolate3"/>
<style name="def:error" background="scarletred2" bold="true"/>
<style name="def:note" background="orange1" bold="true"/>
<style name="def:underlined" italic="true" underline="true"/>
<!-- Language specific -->
<style name="diff:added-line" foreground="chameleon3" line-background="chameleon0"/>
<style name="diff:removed-line" foreground="scarletred1" line-background="scarletred0"/>
<style name="diff:changed-line" use-style="def:preprocessor"/>
<style name="diff:diff-file" foreground="aluminium2" line-background="orange3"/>
<style name="diff:location" foreground="aluminium1" line-background="skyblue2"/>
<style name="diff:special-case" use-style="def:constant"/>
<style name="gitgdiff:trailing-spaces" background="scarletred2"/>
<style name="xml:tags" foreground="chameleon3"/>
<style name="xml:namespace" bold="true"/>
<style name="js:object" foreground="chameleon3" bold="true"/>
<style name="js:constructors" foreground="chameleon3"/>
<style name="latex:display-math" foreground="plum3"/>
<style name="latex:command" foreground="chameleon3" bold="true"/>
<style name="latex:include" use-style="def:preprocessor"/>
<style name="sh:variable" foreground="plum3"/>
<style name="sh:variable-definition" foreground="chameleon3"/>
<style name="search-match" background="butter1"/>
<style name="gitgdiff:added-line" foreground="chameleon3" line-background="chameleon0"/>
<style name="gitgdiff:removed-line" foreground="scarletred1" line-background="scarletred0"/>
<style name="gitgdiff:changed-line" foreground="chocolate3" line-background="chocolate0"/>
<style name="gitgdiff:header" foreground="aluminium2" line-background="orange3"/>
<style name="gitgdiff:hunk" foreground="aluminium1" line-background="skyblue2"/>
<style name="gitgdiff:trailing-spaces" background="scarletred2"/>
</style-scheme>

View file

@ -24,11 +24,14 @@ gitg_SOURCES = \
gitg-color.c \
gitg-commit.c \
gitg-commit-view.c \
gitg-data-binding.c \
gitg-debug.c \
gitg-diff-view.c \
gitg-label-renderer.c \
gitg-lane.c \
gitg-lanes.c \
gitg-preferences.c \
gitg-preferences-dialog.c \
gitg-ref.c \
gitg-repository.c \
gitg-revision.c \
@ -48,7 +51,10 @@ gitg_LDADD = $(PACKAGE_LIBS)
gitg_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*"
uidir = $(datadir)/gitg/ui/
ui_DATA = gitg-ui.xml gitg-menus.xml
ui_DATA = \
gitg-ui.xml \
gitg-menus.xml \
gitg-preferences.xml
gitg-enum-types.h: gitg-enum-types.h.template $(ENUM_H_FILES) $(GLIB_MKENUMS)
(cd $(srcdir) && $(GLIB_MKENUMS) --template gitg-enum-types.h.template $(ENUM_H_FILES)) > $@

240
gitg/gitg-data-binding.c Normal file
View file

@ -0,0 +1,240 @@
#include "gitg-data-binding.h"
#include <gdk/gdk.h>
typedef struct
{
GObject *object;
gchar *property;
GType type;
guint notify_id;
GitgDataBindingConversion conversion;
gpointer userdata;
} Binding;
typedef enum
{
GITG_DATA_BINDING_NONE = 0,
GITG_DATA_BINDING_MUTUAL = 1 << 0
} GitgDataBindingFlags;
struct _GitgDataBinding
{
Binding source;
Binding dest;
GitgDataBindingFlags flags;
};
static void on_data_binding_destroy(GitgDataBinding *binding, GObject *source);
static void gitg_data_binding_finalize(GitgDataBinding *binding);
static void on_data_binding_changed(GObject *source, GParamSpec *spec, GitgDataBinding *binding);
static void
binding_connect(GitgDataBinding *binding, Binding *bd)
{
gchar *nid = g_strconcat("notify::", bd->property, NULL);
bd->notify_id = g_signal_connect_after(bd->object, nid, G_CALLBACK(on_data_binding_changed), binding);
g_free(nid);
}
static void
binding_fill(Binding *binding, gpointer object, gchar const *property, GType type, GitgDataBindingConversion conversion, gpointer userdata)
{
binding->object = G_OBJECT(object);
binding->property = g_strdup(property);
binding->type = type;
binding->conversion = conversion ? conversion : (GitgDataBindingConversion)g_value_transform;
binding->userdata = userdata;
}
GitgDataBinding *
gitg_data_binding_create(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property,
GitgDataBindingConversion source_to_dest,
GitgDataBindingConversion dest_to_source,
gpointer userdata,
GitgDataBindingFlags flags)
{
g_return_val_if_fail(G_IS_OBJECT(source), NULL);
g_return_val_if_fail(G_IS_OBJECT(dest), NULL);
GObjectClass *sclass = G_OBJECT_GET_CLASS(source);
GObjectClass *dclass = G_OBJECT_GET_CLASS(dest);
GParamSpec *sspec = g_object_class_find_property(sclass, source_property);
if (!sspec)
{
g_warning("No such source property found: %s", source_property);
return NULL;
}
GParamSpec *dspec = g_object_class_find_property(dclass, dest_property);
if (!dspec)
{
g_warning("No such dest property found: %s", dest_property);
return NULL;
}
GitgDataBinding *binding = g_slice_new0(GitgDataBinding);
binding->flags = flags;
binding_fill(&binding->source, source, source_property, G_PARAM_SPEC_VALUE_TYPE(sspec), source_to_dest, userdata);
binding_fill(&binding->dest, dest, dest_property, G_PARAM_SPEC_VALUE_TYPE(dspec), dest_to_source, userdata);
binding_connect(binding, &binding->source);
if (flags & GITG_DATA_BINDING_MUTUAL)
binding_connect(binding, &binding->dest);
g_object_weak_ref(binding->source.object, (GWeakNotify)on_data_binding_destroy, binding);
g_object_weak_ref(binding->dest.object, (GWeakNotify)on_data_binding_destroy, binding);
/* initial value */
on_data_binding_changed(binding->source.object, NULL, binding);
return binding;
}
GitgDataBinding *
gitg_data_binding_new_full(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property,
GitgDataBindingConversion conversion,
gpointer userdata)
{
return gitg_data_binding_create(source, source_property,
dest, dest_property,
conversion, NULL,
userdata,
GITG_DATA_BINDING_NONE);
}
GitgDataBinding *
gitg_data_binding_new(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property)
{
return gitg_data_binding_new_full(source, source_property,
dest, dest_property,
NULL, NULL);
}
GitgDataBinding *
gitg_data_binding_new_mutual_full(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property,
GitgDataBindingConversion source_to_dest,
GitgDataBindingConversion dest_to_source,
gpointer userdata)
{
return gitg_data_binding_create(source, source_property,
dest, dest_property,
source_to_dest, dest_to_source,
userdata,
GITG_DATA_BINDING_MUTUAL);
}
GitgDataBinding *
gitg_data_binding_new_mutual(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property)
{
return gitg_data_binding_new_mutual_full(source, source_property,
dest, dest_property,
NULL, NULL,
NULL);
}
static void
gitg_data_binding_finalize(GitgDataBinding *binding)
{
g_free(binding->source.property);
g_free(binding->dest.property);
g_slice_free(GitgDataBinding, binding);
}
void
gitg_data_binding_free(GitgDataBinding *binding)
{
if (binding->source.notify_id)
g_signal_handler_disconnect(binding->source.object, binding->source.notify_id);
if (binding->dest.notify_id)
g_signal_handler_disconnect(binding->dest.object, binding->dest.notify_id);
g_object_weak_unref(binding->source.object, (GWeakNotify)on_data_binding_destroy, binding);
g_object_weak_unref(binding->dest.object, (GWeakNotify)on_data_binding_destroy, binding);
gitg_data_binding_finalize(binding);
}
static void
on_data_binding_destroy(GitgDataBinding *binding, GObject *object)
{
Binding *bd = binding->source.object == object ? &binding->dest : &binding->source;
/* disconnect notify handler */
if (bd->notify_id)
g_signal_handler_disconnect(bd->object, bd->notify_id);
/* remove weak ref */
g_object_weak_unref(bd->object, (GWeakNotify)on_data_binding_destroy, binding);
/* finalize binding */
gitg_data_binding_finalize(binding);
}
static void
on_data_binding_changed(GObject *object, GParamSpec *spec, GitgDataBinding *binding)
{
Binding *source = binding->source.object == object ? &binding->source : &binding->dest;
Binding *dest = binding->source.object == object ? &binding->dest : &binding->source;
/* Transmit to dest */
GValue value = { 0, };
g_value_init(&value, dest->type);
GValue svalue = { 0, };
g_value_init(&svalue, source->type);
g_object_get_property(source->object, source->property, &svalue);
g_object_get_property(dest->object, dest->property, &value);
if (source->conversion(&svalue, &value, source->userdata))
{
if (dest->notify_id)
g_signal_handler_block(dest->object, dest->notify_id);
g_object_set_property(dest->object, dest->property, &value);
if (dest->notify_id)
g_signal_handler_unblock(dest->object, dest->notify_id);
}
g_value_unset(&value);
g_value_unset(&svalue);
}
/* conversion utilities */
gboolean
gitg_data_binding_color_to_string(GValue const *color, GValue *string, gpointer userdata)
{
GdkColor *clr = g_value_get_boxed(color);
gchar *s = gdk_color_to_string(clr);
g_value_take_string(string, s);
return TRUE;
}
gboolean
gitg_data_binding_string_to_color(GValue const *string, GValue *color, gpointer userdata)
{
gchar const *s = g_value_get_string(string);
GdkColor clr;
gdk_color_parse(s, &clr);
g_value_set_boxed(color, &clr);
return TRUE;
}

34
gitg/gitg-data-binding.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef __GITG_DATA_BINDING_H__
#define __GITG_DATA_BINDING_H__
#include <glib-object.h>
typedef struct _GitgDataBinding GitgDataBinding;
typedef gboolean (*GitgDataBindingConversion)(GValue const *source, GValue *dest, gpointer userdata);
GitgDataBinding *gitg_data_binding_new(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property);
GitgDataBinding *gitg_data_binding_new_full(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property,
GitgDataBindingConversion conversion,
gpointer userdata);
GitgDataBinding *gitg_data_binding_new_mutual(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property);
GitgDataBinding *gitg_data_binding_new_mutual_full(gpointer source, gchar const *source_property,
gpointer dest, gchar const *dest_property,
GitgDataBindingConversion source_to_dest,
GitgDataBindingConversion dest_to_source,
gpointer userdata);
void gitg_data_binding_free(GitgDataBinding *binding);
/* conversion utilities */
gboolean gitg_data_binding_color_to_string(GValue const *color, GValue *string, gpointer userdata);
gboolean gitg_data_binding_string_to_color(GValue const *string, GValue *color, gpointer userdata);
#endif /* __GITG_DATA_BINDING_H__ */

View file

@ -4,9 +4,13 @@
#define GITG_LANES_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_LANES, GitgLanesPrivate))
#define INACTIVE_MAX 30
#define INACTIVE_COLLAPSE 10
#define INACTIVE_GAP 10
enum
{
PROP_0,
PROP_INACTIVE_MAX,
PROP_INACTIVE_COLLAPSE,
PROP_INACTIVE_GAP
};
typedef struct
{
@ -37,6 +41,10 @@ struct _GitgLanesPrivate
/* hash table of rev hash -> CollapsedLane where rev hash is the hash
to be expected on the lane */
GHashTable *collapsed;
gint inactive_max;
gint inactive_collapse;
gint inactive_gap;
};
G_DEFINE_TYPE(GitgLanes, gitg_lanes, G_TYPE_OBJECT)
@ -114,13 +122,86 @@ gitg_lanes_finalize(GObject *object)
G_OBJECT_CLASS(gitg_lanes_parent_class)->finalize(object);
}
static void
gitg_lanes_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GitgLanes *self = GITG_LANES(object);
switch (prop_id)
{
case PROP_INACTIVE_MAX:
self->priv->inactive_max = g_value_get_int(value);
break;
case PROP_INACTIVE_COLLAPSE:
self->priv->inactive_collapse = g_value_get_int(value);
break;
case PROP_INACTIVE_GAP:
self->priv->inactive_gap = g_value_get_int(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
gitg_lanes_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GitgLanes *self = GITG_LANES(object);
switch (prop_id)
{
case PROP_INACTIVE_MAX:
g_value_set_int(value, self->priv->inactive_max);
break;
case PROP_INACTIVE_COLLAPSE:
g_value_set_int(value, self->priv->inactive_collapse);
break;
case PROP_INACTIVE_GAP:
g_value_set_int(value, self->priv->inactive_gap);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}
static void
gitg_lanes_class_init(GitgLanesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gitg_lanes_finalize;
object_class->set_property = gitg_lanes_set_property;
object_class->get_property = gitg_lanes_get_property;
g_object_class_install_property(object_class, PROP_INACTIVE_MAX,
g_param_spec_int("inactive-max",
"INACTIVE_MAX",
"Maximum inactivity on a lane before collapsing",
1,
G_MAXINT,
30,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property(object_class, PROP_INACTIVE_COLLAPSE,
g_param_spec_int("inactive-collapse",
"INACTIVE_COLLAPSE",
"Number of revisions to collapse",
1,
G_MAXINT,
10,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property(object_class, PROP_INACTIVE_GAP,
g_param_spec_int("inactive-gap",
"INACTIVE_GAP",
"Minimum of revisions to leave between collapse and expand",
1,
G_MAXINT,
10,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_type_class_add_private(object_class, sizeof(GitgLanesPrivate));
}
@ -236,7 +317,7 @@ add_collapsed(GitgLanes *lanes, LaneContainer *container, gint8 index)
static void
collapse_lane(GitgLanes *lanes, LaneContainer *container, gint8 index)
{
/* backtrack for INACTIVE_COLLAPSE revisions and remove this container from
/* backtrack for inactive-collapse revisions and remove this container from
those revisions, appropriately updating merge indices etc */
GSList *item;
@ -301,7 +382,7 @@ collapse_lanes(GitgLanes *lanes)
{
LaneContainer *container = (LaneContainer *)item->data;
if (container->inactive != INACTIVE_MAX + INACTIVE_GAP)
if (container->inactive != lanes->priv->inactive_max + lanes->priv->inactive_gap)
{
item = g_slist_next(item);
++index;
@ -359,14 +440,14 @@ expand_lane(GitgLanes *lanes, CollapsedLane *lane)
{
GitgRevision *revision = GITG_REVISION(item->data);
if (cnt == INACTIVE_COLLAPSE)
if (cnt == lanes->priv->inactive_collapse)
break;
/* insert new lane at the index */
GitgLane *copy = gitg_lane_copy(ln);
GSList *lns = gitg_revision_get_lanes(revision);
if (!item->next || cnt + 1 == INACTIVE_COLLAPSE)
if (!item->next || cnt + 1 == lanes->priv->inactive_collapse)
{
GitgLaneBoundary *boundary = gitg_lane_convert_boundary(copy, GITG_LANE_TYPE_START);
@ -507,7 +588,7 @@ prepare_lanes(GitgLanes *lanes, GitgRevision *next, gint8 *pos)
}
/* Store new revision in our track list */
if (g_slist_length(lanes->priv->previous) == INACTIVE_COLLAPSE + INACTIVE_GAP + 1)
if (g_slist_length(lanes->priv->previous) == lanes->priv->inactive_collapse + lanes->priv->inactive_gap + 1)
{
GSList *last = g_slist_last(lanes->priv->previous);
gitg_revision_unref(GITG_REVISION(last->data));

View file

@ -0,0 +1,146 @@
#include "gitg-preferences-dialog.h"
#include "gitg-preferences.h"
#include "gitg-data-binding.h"
#include <stdlib.h>
#include <glib/gi18n.h>
enum
{
COLUMN_NAME,
COLUMN_PROPERTY,
N_COLUMNS
};
#define GITG_PREFERENCES_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialogPrivate))
static GitgPreferencesDialog *preferences_dialog;
struct _GitgPreferencesDialogPrivate
{
GtkCheckButton *history_search_filter;
GtkAdjustment *collapse_inactive_lanes;
gint prev_value;
};
G_DEFINE_TYPE(GitgPreferencesDialog, gitg_preferences_dialog, GTK_TYPE_DIALOG)
static gint
round_val(gdouble val)
{
gint ival = (gint)val;
return ival + (val - ival > 0.5);
}
static void
gitg_preferences_dialog_finalize(GObject *object)
{
GitgPreferencesDialog *dialog = GITG_PREFERENCES_DIALOG(object);
G_OBJECT_CLASS(gitg_preferences_dialog_parent_class)->finalize(object);
}
static void
gitg_preferences_dialog_class_init(GitgPreferencesDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gitg_preferences_dialog_finalize;
g_type_class_add_private(object_class, sizeof(GitgPreferencesDialogPrivate));
}
static void
gitg_preferences_dialog_init(GitgPreferencesDialog *self)
{
self->priv = GITG_PREFERENCES_DIALOG_GET_PRIVATE(self);
}
static void
on_response(GtkWidget *dialog, gint response, gpointer data)
{
gtk_widget_destroy(dialog);
}
static gboolean
convert_collapsed(GValue const *source, GValue *dest, gpointer userdata)
{
GitgPreferencesDialog *dialog = GITG_PREFERENCES_DIALOG(userdata);
gint val = round_val(g_value_get_double(source));
if (val == dialog->priv->prev_value)
return FALSE;
dialog->priv->prev_value = val;
return g_value_transform(source, dest);
}
static void
initialize_view(GitgPreferencesDialog *dialog)
{
GitgPreferences *preferences = gitg_preferences_get_default();
gitg_data_binding_new_mutual(preferences, "history-search-filter",
dialog->priv->history_search_filter, "active");
gitg_data_binding_new_mutual_full(preferences, "history-collapse-inactive-lanes",
dialog->priv->collapse_inactive_lanes, "value",
(GitgDataBindingConversion)g_value_transform,
convert_collapsed,
dialog);
}
static void
create_preferences_dialog()
{
GtkBuilder *b = gtk_builder_new();
GError *error = NULL;
if (!gtk_builder_add_from_file(b, GITG_UI_DIR "/gitg-preferences.xml", &error))
{
g_critical("Could not open UI file: %s (%s)", GITG_UI_DIR "/gitg-preferences.xml", error->message);
g_error_free(error);
exit(1);
}
preferences_dialog = GITG_PREFERENCES_DIALOG(gtk_builder_get_object(b, "dialog_preferences"));
g_object_add_weak_pointer(G_OBJECT(preferences_dialog), (gpointer *)&preferences_dialog);
GitgPreferencesDialogPrivate *priv = preferences_dialog->priv;
priv->history_search_filter = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_history_search_filter"));
priv->collapse_inactive_lanes = GTK_ADJUSTMENT(gtk_builder_get_object(b, "adjustment_collapse_inactive_lanes"));
priv->prev_value = (gint)gtk_adjustment_get_value(priv->collapse_inactive_lanes);
g_signal_connect(preferences_dialog, "response", G_CALLBACK(on_response), NULL);
initialize_view(preferences_dialog);
gtk_builder_connect_signals(b, preferences_dialog);
g_object_unref(b);
}
GitgPreferencesDialog *
gitg_preferences_dialog_present(GtkWindow *window)
{
if (!preferences_dialog)
create_preferences_dialog();
gtk_window_set_transient_for(GTK_WINDOW(preferences_dialog), window);
gtk_window_present(GTK_WINDOW(preferences_dialog));
return preferences_dialog;
}
void
on_collapse_inactive_lanes_changed(GtkAdjustment *adjustment, GParamSpec *spec, GitgPreferencesDialog *dialog)
{
gint val = round_val(gtk_adjustment_get_value(adjustment));
g_signal_handlers_block_by_func(adjustment, G_CALLBACK(on_collapse_inactive_lanes_changed), dialog);
gtk_adjustment_set_value(adjustment, val);
g_signal_handlers_unblock_by_func(adjustment, G_CALLBACK(on_collapse_inactive_lanes_changed), dialog);
}

View file

@ -0,0 +1,35 @@
#ifndef __GITG_PREFERENCES_DIALOG_H__
#define __GITG_PREFERENCES_DIALOG_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GITG_TYPE_PREFERENCES_DIALOG (gitg_preferences_dialog_get_type ())
#define GITG_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialog))
#define GITG_PREFERENCES_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialog const))
#define GITG_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialogClass))
#define GITG_IS_PREFERENCES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_PREFERENCES_DIALOG))
#define GITG_IS_PREFERENCES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_PREFERENCES_DIALOG))
#define GITG_PREFERENCES_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialogClass))
typedef struct _GitgPreferencesDialog GitgPreferencesDialog;
typedef struct _GitgPreferencesDialogClass GitgPreferencesDialogClass;
typedef struct _GitgPreferencesDialogPrivate GitgPreferencesDialogPrivate;
struct _GitgPreferencesDialog {
GtkDialog parent;
GitgPreferencesDialogPrivate *priv;
};
struct _GitgPreferencesDialogClass {
GtkDialogClass parent_class;
};
GType gitg_preferences_dialog_get_type(void) G_GNUC_CONST;
GitgPreferencesDialog *gitg_preferences_dialog_present(GtkWindow *window);
G_END_DECLS
#endif /* __GITG_PREFERENCES_DIALOG_H__ */

431
gitg/gitg-preferences.c Normal file
View file

@ -0,0 +1,431 @@
#include "gitg-preferences.h"
#include <gtksourceview/gtksourcestyleschememanager.h>
#include <gconf/gconf-client.h>
#include <string.h>
#define GITG_PREFERENCES_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_PREFERENCES, GitgPreferencesPrivate))
#define KEY_ROOT "/apps/gitg/preferences"
/* Properties */
enum
{
PROP_0,
PROP_HISTORY_SEARCH_FILTER,
PROP_HISTORY_COLLAPSE_INACTIVE_LANES,
PROP_STYLE_TEXT_FOREGROUND,
PROP_STYLE_TEXT_BACKGROUND,
PROP_STYLE_TEXT_STYLE,
PROP_STYLE_ADDED_LINE_FOREGROUND,
PROP_STYLE_ADDED_LINE_BACKGROUND,
PROP_STYLE_ADDED_LINE_STYLE,
PROP_STYLE_REMOVED_LINE_FOREGROUND,
PROP_STYLE_REMOVED_LINE_BACKGROUND,
PROP_STYLE_REMOVED_LINE_STYLE,
PROP_STYLE_CHANGED_LINE_FOREGROUND,
PROP_STYLE_CHANGED_LINE_BACKGROUND,
PROP_STYLE_CHANGED_LINE_STYLE,
PROP_STYLE_HEADER_FOREGROUND,
PROP_STYLE_HEADER_BACKGROUND,
PROP_STYLE_HEADER_STYLE,
PROP_STYLE_HUNK_FOREGROUND,
PROP_STYLE_HUNK_BACKGROUND,
PROP_STYLE_HUNK_STYLE,
PROP_STYLE_TRAILING_SPACES_FOREGROUND,
PROP_STYLE_TRAILING_SPACES_BACKGROUND,
PROP_STYLE_TRAILING_SPACES_STYLE,
PROP_LAST
};
typedef struct _Binding Binding;
typedef void (*WrapGet)(GitgPreferences *preferences, Binding *binding, GValue *value);
typedef gboolean (*WrapSet)(GitgPreferences *preferences, Binding *binding, GValue const *value);
static void on_preference_changed(GConfClient *client, guint id, GConfEntry *entry, GitgPreferences *preferences);
struct _Binding
{
gchar key[PATH_MAX];
gchar property[PATH_MAX];
WrapGet wrap_get;
WrapSet wrap_set;
};
struct _GitgPreferencesPrivate
{
GConfClient *client;
guint notify_id;
gboolean block_notify[PROP_LAST];
};
G_DEFINE_TYPE(GitgPreferences, gitg_preferences, G_TYPE_OBJECT)
static Binding property_bindings[PROP_LAST];
static gboolean
wrap_set_boolean(GitgPreferences *preferences, Binding *binding, GValue const *value)
{
gboolean val = g_value_get_boolean(value);
return gconf_client_set_bool(preferences->priv->client, binding->key, val, NULL);
}
static void
wrap_get_boolean(GitgPreferences *preferences, Binding *binding, GValue *value)
{
gboolean val = gconf_client_get_bool(preferences->priv->client, binding->key, NULL);
g_value_set_boolean(value, val);
}
static gboolean
wrap_set_int(GitgPreferences *preferences, Binding *binding, GValue const *value)
{
gint val = g_value_get_int(value);
return gconf_client_set_int(preferences->priv->client, binding->key, val, NULL);
}
static void
wrap_get_int(GitgPreferences *preferences, Binding *binding, GValue *value)
{
gint val = gconf_client_get_int(preferences->priv->client, binding->key, NULL);
g_value_set_int(value, val);
}
static gboolean
wrap_set_double(GitgPreferences *preferences, Binding *binding, GValue const *value)
{
gdouble val = g_value_get_double(value);
return gconf_client_set_double(preferences->priv->client, binding->key, val, NULL);
}
static void
wrap_get_double(GitgPreferences *preferences, Binding *binding, GValue *value)
{
gdouble val = gconf_client_get_double(preferences->priv->client, binding->key, NULL);
g_value_set_double(value, val);
}
static gboolean
wrap_set_string(GitgPreferences *preferences, Binding *binding, GValue const *value)
{
gchar const *val = g_value_get_string(value);
return gconf_client_set_string(preferences->priv->client, binding->key, val ? val : "", NULL);
}
static void
wrap_get_string(GitgPreferences *preferences, Binding *binding, GValue *value)
{
gchar *val = gconf_client_get_string(preferences->priv->client, binding->key, NULL);
g_value_take_string(value, val);
}
static void
finalize_notify(GitgPreferences *preferences)
{
gconf_client_remove_dir(preferences->priv->client, KEY_ROOT, NULL);
gconf_client_notify_remove(preferences->priv->client, preferences->priv->notify_id);
}
static void
gitg_preferences_finalize(GObject *object)
{
GitgPreferences *preferences = GITG_PREFERENCES(object);
finalize_notify(preferences);
g_object_unref(preferences->priv->client);
G_OBJECT_CLASS(gitg_preferences_parent_class)->finalize(object);
}
static void
gitg_preferences_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GitgPreferences *self = GITG_PREFERENCES(object);
if (prop_id > PROP_0 && prop_id < PROP_LAST)
{
Binding *b = &property_bindings[prop_id];
self->priv->block_notify[prop_id] = b->wrap_set(self, b, value);
}
else
{
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
gitg_preferences_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GitgPreferences *self = GITG_PREFERENCES(object);
if (prop_id > PROP_0 && prop_id < PROP_LAST)
{
Binding *b = &property_bindings[prop_id];
b->wrap_get(self, b, value);
}
else
{
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
install_property_binding(guint prop_id, gchar const *group, gchar const *name, WrapGet wrap_get, WrapSet wrap_set)
{
Binding *b = &property_bindings[prop_id];
g_snprintf(b->key, PATH_MAX, "%s/%s/%s", KEY_ROOT, group, name);
gchar const *prefix = g_utf8_strrchr(group, -1, '/') + 1;
g_snprintf(b->property, PATH_MAX, "%s-%s", prefix, name);
b->wrap_get = wrap_get;
b->wrap_set = wrap_set;
}
static void
install_style_properties(GObjectClass *object_class, guint prop_start, gchar const *name)
{
gchar *group = g_strconcat("style/", name, NULL);
/* install bindings */
install_property_binding(prop_start + 0,
group,
"foreground",
wrap_get_string,
wrap_set_string);
install_property_binding(prop_start + 1,
group,
"background",
wrap_get_string,
wrap_set_string);
install_property_binding(prop_start + 2,
group,
"style",
wrap_get_int,
wrap_set_int);
g_free(group);
gchar *stylename = g_strconcat("gitgdiff:", name, NULL);
GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default();
GtkSourceStyleScheme *scheme = gtk_source_style_scheme_manager_get_scheme(manager, "gitg");
GtkSourceStyle *style = gtk_source_style_scheme_get_style(scheme, stylename);
g_free(stylename);
gchar *foreground = NULL;
gchar *background = NULL;
gboolean line_background;
group = g_strconcat(name, "-foreground", NULL);
g_object_get(G_OBJECT(style), "line-background-set", &line_background, NULL);
g_object_get(G_OBJECT(style), "foreground", &foreground, line_background ? "line-background" : "background", &background, NULL);
/* install foreground property */
g_object_class_install_property(object_class, prop_start + 0,
g_param_spec_string(group,
NULL,
NULL,
foreground,
G_PARAM_READWRITE));
g_free(group);
group = g_strconcat(name, "-background", NULL);
/* install background property */
g_object_class_install_property(object_class, prop_start + 1,
g_param_spec_string(group,
NULL,
NULL,
background,
G_PARAM_READWRITE));
g_free(group);
group = g_strconcat(name, "-style", NULL);
gboolean bold;
gboolean italic;
gboolean underline;
g_object_get(G_OBJECT(style), "bold", &bold, "italic", &italic, "underline", &underline, NULL);
/* install style property */
g_object_class_install_property(object_class, prop_start + 2,
g_param_spec_int(group,
NULL,
NULL,
0,
G_MAXINT,
bold << 0 | italic << 1 | underline << 2 | line_background << 3,
G_PARAM_READWRITE));
g_free(group);
g_free(foreground);
g_free(background);
}
static void
gitg_preferences_class_init(GitgPreferencesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->finalize = gitg_preferences_finalize;
object_class->set_property = gitg_preferences_set_property;
object_class->get_property = gitg_preferences_get_property;
install_property_binding(PROP_HISTORY_SEARCH_FILTER,
"view/history",
"search-filter",
wrap_get_boolean,
wrap_set_boolean);
g_object_class_install_property(object_class, PROP_HISTORY_SEARCH_FILTER,
g_param_spec_boolean("history-search-filter",
"HISTORY_SEARCH_FILTER",
"Filter revisions when searching",
FALSE,
G_PARAM_READWRITE));
install_property_binding(PROP_HISTORY_COLLAPSE_INACTIVE_LANES,
"view/history",
"collapse-inactive-lanes",
wrap_get_int,
wrap_set_int);
g_object_class_install_property(object_class, PROP_HISTORY_COLLAPSE_INACTIVE_LANES,
g_param_spec_int("history-collapse-inactive-lanes",
"HISTORY_COLLAPSE_INACTIVE_LANES",
"Rule for collapsing inactive lanes",
0,
5,
2,
G_PARAM_READWRITE));
install_style_properties(object_class, PROP_STYLE_TEXT_FOREGROUND, "text");
install_style_properties(object_class, PROP_STYLE_ADDED_LINE_FOREGROUND, "added-line");
install_style_properties(object_class, PROP_STYLE_REMOVED_LINE_FOREGROUND, "removed-line");
install_style_properties(object_class, PROP_STYLE_CHANGED_LINE_FOREGROUND, "changed-line");
install_style_properties(object_class, PROP_STYLE_HEADER_FOREGROUND, "header");
install_style_properties(object_class, PROP_STYLE_HUNK_FOREGROUND, "hunk");
install_style_properties(object_class, PROP_STYLE_TRAILING_SPACES_FOREGROUND, "trailing-spaces");
g_type_class_add_private(object_class, sizeof(GitgPreferencesPrivate));
}
static void
initialize_notify(GitgPreferences *preferences)
{
gconf_client_add_dir(preferences->priv->client,
KEY_ROOT,
GCONF_CLIENT_PRELOAD_NONE,
NULL);
gconf_client_notify_add(preferences->priv->client,
KEY_ROOT,
(GConfClientNotifyFunc)on_preference_changed,
preferences,
NULL,
NULL);
}
static void
initialize_default_values(GitgPreferences *preferences)
{
guint i;
GObjectClass *class = G_OBJECT_GET_CLASS(G_OBJECT(preferences));
for (i = PROP_0 + 1; i < PROP_LAST; ++i)
{
Binding *binding = &property_bindings[i];
GConfValue *v = gconf_client_get_without_default(preferences->priv->client, binding->key, NULL);
if (v)
{
gconf_value_free(v);
continue;
}
GParamSpec *spec = g_object_class_find_property(class, binding->property);
GValue value = {0,};
/* Get default value */
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(spec));
g_param_value_set_default(spec, &value);
/* Set it */
g_object_set_property(G_OBJECT(preferences), binding->property, &value);
g_value_unset(&value);
}
}
static void
gitg_preferences_init(GitgPreferences *self)
{
self->priv = GITG_PREFERENCES_GET_PRIVATE(self);
self->priv->client = gconf_client_get_default();
initialize_notify(self);
/* Set initial values for properties that have defaults and do not exist
yet */
initialize_default_values(self);
}
GitgPreferences *
gitg_preferences_get_default()
{
static GitgPreferences *preferences = NULL;
if (!preferences)
{
preferences = g_object_new(GITG_TYPE_PREFERENCES, NULL);
g_object_add_weak_pointer(G_OBJECT(preferences), (gpointer *)&preferences);
}
return preferences;
}
/* Callbacks */
static void
on_preference_changed(GConfClient *client, guint id, GConfEntry *entry, GitgPreferences *preferences)
{
gchar const *key = gconf_entry_get_key(entry);
/* Find corresponding property */
guint i;
for (i = PROP_0 + 1; i < PROP_LAST; ++i)
{
Binding *b = &property_bindings[i];
if (strcmp(key, b->key) == 0)
{
/* Property match, emit notify */
if (!preferences->priv->block_notify[i])
g_object_notify(G_OBJECT(preferences), b->property);
preferences->priv->block_notify[i] = FALSE;
break;
}
}
}

44
gitg/gitg-preferences.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef __GITG_PREFERENCES_H__
#define __GITG_PREFERENCES_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define GITG_TYPE_PREFERENCES (gitg_preferences_get_type ())
#define GITG_PREFERENCES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_PREFERENCES, GitgPreferences))
#define GITG_PREFERENCES_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_PREFERENCES, GitgPreferences const))
#define GITG_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_PREFERENCES, GitgPreferencesClass))
#define GITG_IS_PREFERENCES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_PREFERENCES))
#define GITG_IS_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_PREFERENCES))
#define GITG_PREFERENCES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_PREFERENCES, GitgPreferencesClass))
typedef enum
{
GITG_PREFERENCES_STYLE_NONE = 0,
GITG_PREFERENCES_STYLE_BOLD = 1 << 0,
GITG_PREFERENCES_STYLE_ITALIC = 1 << 1,
GITG_PREFERENCES_STYLE_UNDERLINE = 1 << 2,
GITG_PREFERENCES_STYLE_LINE_BACKGROUND = 1 << 3,
} GitgPreferencesStyleFlags;
typedef struct _GitgPreferences GitgPreferences;
typedef struct _GitgPreferencesClass GitgPreferencesClass;
typedef struct _GitgPreferencesPrivate GitgPreferencesPrivate;
struct _GitgPreferences {
GObject parent;
GitgPreferencesPrivate *priv;
};
struct _GitgPreferencesClass {
GObjectClass parent_class;
};
GType gitg_preferences_get_type(void) G_GNUC_CONST;
GitgPreferences *gitg_preferences_get_default();
G_END_DECLS
#endif /* __GITG_PREFERENCES_H__ */

225
gitg/gitg-preferences.xml Normal file
View file

@ -0,0 +1,225 @@
<?xml version="1.0"?>
<interface>
<object class="GtkAdjustment" id="adjustment_collapse_inactive_lanes">
<property name="value">2</property>
<property name="lower">0</property>
<property name="upper">5</property>
<property name="step_increment">1</property>
<property name="page_increment">1</property>
<property name="page_size">1</property>
<signal after="false" name="notify::value" handler="on_collapse_inactive_lanes_changed"/>
</object>
<object class="GitgPreferencesDialog" id="dialog_preferences">
<property name="border_width">5</property>
<property name="title" translatable="yes">Preferences</property>
<property name="default_width">400</property>
<property name="default_height">500</property>
<property name="type_hint">normal</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
<object class="GtkVBox" id="dialog_vbox_main">
<property name="visible">True</property>
<property name="spacing">2</property>
<child>
<object class="GtkNotebook" id="notebook1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="spacing">18</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label10">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;History&lt;/b&gt;</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox5">
<property name="visible">True</property>
<child>
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="check_button_history_search_filter">
<property name="label" translatable="yes">Search filters revisions in the history view</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Collapse inactive lanes:</property>
</object>
<packing>
<property name="x_options">GTK_SHRINK | GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkHScale" id="hscale_collapse_inactive_lanes">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment_collapse_inactive_lanes</property>
<property name="draw_value">False</property>
<property name="digits">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Early</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label18">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Late</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label_view">
<property name="visible">True</property>
<property name="label" translatable="yes">View</property>
</object>
<packing>
<property name="tab_fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkHButtonBox" id="dialog_action_area">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_close">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-7">button_close</action-widget>
</action-widgets>
</object>
<object class="GtkImage" id="image_bold">
<property name="visible">True</property>
<property name="stock">gtk-bold</property>
<property name="icon-size">1</property>
</object>
<object class="GtkImage" id="image_italic">
<property name="visible">True</property>
<property name="stock">gtk-italic</property>
<property name="icon-size">1</property>
</object>
<object class="GtkImage" id="image_underline">
<property name="visible">True</property>
<property name="stock">gtk-underline</property>
<property name="icon-size">1</property>
</object>
</interface>

View file

@ -3,6 +3,7 @@
#include "gitg-lanes.h"
#include "gitg-ref.h"
#include "gitg-types.h"
#include "gitg-preferences.h"
#include <gio/gio.h>
#include <glib/gi18n.h>
@ -59,6 +60,7 @@ struct _GitgRepositoryPrivate
gint grow_size;
gchar **last_args;
guint idle_relane_id;
};
inline static gint
@ -96,6 +98,13 @@ tree_model_get_column_type(GtkTreeModel *tree_model, gint index)
return GITG_REPOSITORY(tree_model)->priv->column_types[index];
}
static void
fill_iter(GitgRepository *repository, gint index, GtkTreeIter *iter)
{
iter->stamp = repository->priv->stamp;
iter->user_data = GINT_TO_POINTER(index);
}
static gboolean
tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path)
{
@ -113,11 +122,8 @@ tree_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *pa
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;
fill_iter(rp, indices[0], iter);
return TRUE;
}
@ -208,10 +214,7 @@ tree_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIte
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;
fill_iter(rp, 0, iter);
return TRUE;
}
@ -246,10 +249,7 @@ tree_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIt
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;
fill_iter(rp, n, iter);
return TRUE;
}
@ -334,6 +334,9 @@ gitg_repository_finalize(GObject *object)
/* Free cached args */
g_strfreev(rp->priv->last_args);
if (rp->priv->idle_relane_id)
g_source_remove(rp->priv->idle_relane_id);
G_OBJECT_CLASS (gitg_repository_parent_class)->finalize(object);
}
@ -442,7 +445,6 @@ on_loader_update(GitgRunner *object, gchar **buffer, GitgRepository *self)
gitg_lanes_reset(self->priv->lanes);
lanes = gitg_lanes_next(self->priv->lanes, rv, &mylane);
gitg_revision_set_lanes(rv, lanes, mylane);
gitg_repository_add(self, rv, NULL);
@ -459,6 +461,103 @@ free_refs(GSList *refs)
g_slist_free(refs);
}
static gboolean
repository_relane(GitgRepository *repository)
{
repository->priv->idle_relane_id = 0;
gitg_lanes_reset(repository->priv->lanes);
guint i;
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_first();
for (i = 0; i < repository->priv->size; ++i)
{
guint8 mylane;
GitgRevision *revision = repository->priv->storage[i];
GSList *lanes = gitg_lanes_next(repository->priv->lanes, revision, &mylane);
gitg_revision_set_lanes(revision, lanes, mylane);
fill_iter(repository, i, &iter);
gtk_tree_model_row_changed(GTK_TREE_MODEL(repository), path, &iter);
gtk_tree_path_next(path);
}
gtk_tree_path_free(path);
return FALSE;
}
static void
prepare_relane(GitgRepository *repository)
{
if (!repository->priv->idle_relane_id)
repository->priv->idle_relane_id = g_idle_add((GSourceFunc)repository_relane, repository);
}
static gboolean
convert_setting_to_inactive_max(GValue const *setting, GValue *value, gpointer userdata)
{
g_return_val_if_fail(G_VALUE_HOLDS(setting, G_TYPE_INT), FALSE);
g_return_val_if_fail(G_VALUE_HOLDS(value, G_TYPE_INT), FALSE);
gint s = g_value_get_int(setting);
g_value_set_int(value, 2 + s * 8);
prepare_relane(GITG_REPOSITORY(userdata));
return TRUE;
}
static gboolean
convert_setting_to_inactive_collapse(GValue const *setting, GValue *value, gpointer userdata)
{
g_return_val_if_fail(G_VALUE_HOLDS(setting, G_TYPE_INT), FALSE);
g_return_val_if_fail(G_VALUE_HOLDS(value, G_TYPE_INT), FALSE);
gint s = g_value_get_int(setting);
g_value_set_int(value, 1 + s * 3);
prepare_relane(GITG_REPOSITORY(userdata));
return TRUE;
}
static gboolean
convert_setting_to_inactive_gap(GValue const *setting, GValue *value, gpointer userdata)
{
g_return_val_if_fail(G_VALUE_HOLDS(setting, G_TYPE_INT), FALSE);
g_return_val_if_fail(G_VALUE_HOLDS(value, G_TYPE_INT), FALSE);
g_value_set_int(value, 10);
prepare_relane(GITG_REPOSITORY(userdata));
return TRUE;
}
static void
initialize_lanes_bindings(GitgRepository *repository)
{
GitgPreferences *preferences = gitg_preferences_get_default();
gitg_data_binding_new_full(preferences, "history-collapse-inactive-lanes",
repository->priv->lanes, "inactive-max",
convert_setting_to_inactive_max,
repository);
gitg_data_binding_new_full(preferences, "history-collapse-inactive-lanes",
repository->priv->lanes, "inactive-collapse",
convert_setting_to_inactive_collapse,
repository);
gitg_data_binding_new_full(preferences, "history-collapse-inactive-lanes",
repository->priv->lanes, "inactive-gap",
convert_setting_to_inactive_gap,
repository);
}
static void
gitg_repository_init(GitgRepository *object)
{
@ -477,6 +576,8 @@ gitg_repository_init(GitgRepository *object)
object->priv->loader = gitg_runner_new(10000);
g_signal_connect(object->priv->loader, "update", G_CALLBACK(on_loader_update), object);
initialize_lanes_bindings(object);
}
static void
@ -548,6 +649,7 @@ static gboolean
reload_revisions(GitgRepository *repository, GError **error)
{
g_signal_emit(repository, repository_signals[LOAD], 0);
return gitg_repository_run_command(repository, repository->priv->loader, (gchar const **)repository->priv->last_args, error);
}

View file

@ -73,6 +73,12 @@
<signal name="activate" handler="on_edit_paste"/>
</object>
</child>
<child>
<object class="GtkAction" id="EditPreferencesAction">
<property name="stock-id">gtk-preferences</property>
<signal name="activate" handler="on_edit_preferences"/>
</object>
</child>
</object>
</child>
<child>
@ -132,6 +138,8 @@
<menuitem action="EditCutAction"/>
<menuitem action="EditCopyAction"/>
<menuitem action="EditPasteAction"/>
<separator/>
<menuitem action="EditPreferencesAction"/>
</menu>
<menu action="ViewAction">
<menuitem action="ViewRefreshAction"/>

View file

@ -15,6 +15,7 @@
#include "gitg-cell-renderer-path.h"
#include "gitg-commit-view.h"
#include "gitg-settings.h"
#include "gitg-preferences-dialog.h"
#define GITG_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_WINDOW, GitgWindowPrivate))
@ -1010,3 +1011,9 @@ on_tree_view_button_release(GtkTreeView *treeview, GdkEventButton *event, GitgWi
goto_hash(window, hash);
return TRUE;
}
void
on_edit_preferences(GtkAction *action, GitgWindow *window)
{
gitg_preferences_dialog_present(GTK_WINDOW(window));
}

View file

@ -132,15 +132,17 @@ set_icons()
int
main(int argc, char **argv)
{
g_thread_init(NULL);
gitg_debug_init();
bindtextdomain(GETTEXT_PACKAGE, GITG_LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
g_thread_init(NULL);
gitg_debug_init();
g_set_prgname("gitg");
/* Translators: this is the application name as in g_set_application_name */
g_set_application_name(_("gitg"));
gtk_init(&argc, &argv);

View file

@ -54,16 +54,16 @@ GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDA
ALL_LINGUAS = @ALL_LINGUAS@
PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; fi)
PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi)
USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep ^$$lang$$ $(srcdir)/LINGUAS`" -o -n "`echo $$ALINGUAS|grep ' ?$$lang ?'`"; then printf "$$lang "; fi; done; fi)
USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep ^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep ^$$lang$$`"; then printf "$$lang "; fi; done; fi)
USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done)
USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done)
POFILES=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done)
POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done)
DISTFILES = ChangeLog Makefile.in.in POTFILES.in $(POFILES)
EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS
DISTFILES = Makefile.in.in POTFILES.in $(POFILES)
EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS
POTFILES = \
# This comment gets stripped out
@ -101,7 +101,6 @@ install: install-data
install-data: install-data-@USE_NLS@
install-data-no: all
install-data-yes: all
$(mkdir_p) $(DESTDIR)$(itlocaledir)
linguas="$(USE_LINGUAS)"; \
for lang in $$linguas; do \
dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \

View file

@ -1,6 +1,7 @@
# List of source files containing translatable strings.
[encoding: UTF-8]
data/gitg.desktop.in.in
data/gitg.schemas.in
gitg/gitg.c
gitg/gitg-commit-view.c
gitg/gitg-repository.c
@ -8,3 +9,4 @@ gitg/gitg-revision-tree-view.c
gitg/gitg-window.c
[type: gettext/glade]gitg/gitg-ui.xml
[type: gettext/glade]gitg/gitg-menus.xml
[type: gettext/glade]gitg/gitg-preferences.xml

View file

@ -2,16 +2,41 @@
msgid "Git repository browser"
msgstr "Git repository bekijker"
#: ../data/gitg.desktop.in.in.h:2 ../gitg/gitg.c:144 ../gitg/gitg-window.c:718
#: ../gitg/gitg-window.c:733 ../gitg/gitg-ui.xml.h:30
#. Translators: this is the application name as in g_set_application_name
#: ../data/gitg.desktop.in.in.h:2 ../gitg/gitg.c:148 ../gitg/gitg-window.c:720
#: ../gitg/gitg-window.c:735 ../gitg/gitg-ui.xml.h:30
msgid "gitg"
msgstr "gitg"
#: ../gitg/gitg.c:19
#: ../data/gitg.schemas.in.h:1
msgid "Filter Revisions When Searching"
msgstr "Filter revisies bij zoeken"
#: ../data/gitg.schemas.in.h:2
msgid ""
"Setting that indicates when an inactive lane should be collapsed. Valid "
"values are 0 - 4, where 0 indicates 'early' and 4 indicates 'late'."
msgstr ""
"Instelling die aangeeft wanneer een inactieve baan ingebouwd moet worden. "
"Geldige waarden zijn 0 - 4, waarbij 0 'vroeg' en 4 'laat' betekent."
#: ../data/gitg.schemas.in.h:3
msgid "When to Collapse Inactive Lanes"
msgstr "Wannneer inactieve lanen ingevouwd moeten worden"
#: ../data/gitg.schemas.in.h:4
msgid ""
"Whether searching filters the revisions in the history view instead of "
"jumping to the first match."
msgstr ""
"Of zoeken de revisies in de geschiedenis filtert in plaats van naar het "
"eerste resultaat te springen."
#: ../gitg/gitg.c:21
msgid "Start gitg in commit mode"
msgstr "Open gitg in commit mode"
#: ../gitg/gitg.c:29
#: ../gitg/gitg.c:31
msgid "- git repository viewer"
msgstr "- git repository bekijker"
@ -44,7 +69,7 @@ msgid "Reverting changes is permanent and cannot be undone"
msgstr ""
"Wijzigingen terugdraaien is permanent en kan niet ongedaan gemaakt worden"
#: ../gitg/gitg-repository.c:637
#: ../gitg/gitg-repository.c:739
msgid "Not a valid git repository"
msgstr "Geen geldige git repository"
@ -52,37 +77,37 @@ msgstr "Geen geldige git repository"
msgid "(Empty)"
msgstr "(Leeg)"
#: ../gitg/gitg-window.c:301
#: ../gitg/gitg-window.c:303
msgid "Select branch"
msgstr "Selecteer tak"
#: ../gitg/gitg-window.c:465
#: ../gitg/gitg-window.c:467
msgid "Begin loading repository"
msgstr "Begin laden van repository"
#: ../gitg/gitg-window.c:474
#: ../gitg/gitg-window.c:476
#, c-format
msgid "Loaded %d revisions in %.2fs"
msgstr "%d revisies ingeladen in %.2fs"
#: ../gitg/gitg-window.c:485
#: ../gitg/gitg-window.c:487
#, c-format
msgid "Loading %d revisions..."
msgstr "Laden van %d revisies..."
#: ../gitg/gitg-window.c:494
#: ../gitg/gitg-window.c:496
msgid "Could not find git repository"
msgstr "Kon git repository niet vinden"
#: ../gitg/gitg-window.c:630
#: ../gitg/gitg-window.c:632
msgid "All branches"
msgstr "Alle takken"
#: ../gitg/gitg-window.c:789
#: ../gitg/gitg-window.c:791
msgid "Open git repository"
msgstr "Open git repository"
#: ../gitg/gitg-window.c:893
#: ../gitg/gitg-window.c:895
msgid "gitg is a git repository viewer for gtk+/GNOME"
msgstr "gitg is een repository bekijker voor gtk+/GNOME"
@ -217,3 +242,46 @@ msgstr "_Hash"
#: ../gitg/gitg-menus.xml.h:4
msgid "_Subject"
msgstr "_Onderwerp"
#: ../gitg/gitg-preferences.xml.h:1
msgid "<b>History</b>"
msgstr "<b>Geschiedenis</b>"
#: ../gitg/gitg-preferences.xml.h:2
msgid "Collapse inactive lanes:"
msgstr "Invouwen van inactieve banen:"
#: ../gitg/gitg-preferences.xml.h:3
msgid "Early"
msgstr "Vroeg"
#: ../gitg/gitg-preferences.xml.h:4
msgid "Late"
msgstr "Laat"
#: ../gitg/gitg-preferences.xml.h:5
msgid "Preferences"
msgstr "Voorkeuren"
#: ../gitg/gitg-preferences.xml.h:6
msgid "Search filters revisions in the history view"
msgstr "Zoeken filtert revisies in de geschiedenis"
#: ../gitg/gitg-preferences.xml.h:7
msgid "View"
msgstr "Beeld"
#~ msgid "<b>Diff view</b>"
#~ msgstr "<b>Diff veld</b>"
#~ msgid "Background:"
#~ msgstr "Achtergrond:"
#~ msgid "Colors and styles"
#~ msgstr "Kleuren en stijlen"
#~ msgid "Fill entire line"
#~ msgstr "Vul volledige regel"
#~ msgid "Foreground:"
#~ msgstr "Voorgrond:"