From a74c5661a672712ddb96bd70d51fadea23dda933 Mon Sep 17 00:00:00 2001 From: Jesse van den Kieboom Date: Sat, 14 Apr 2012 13:46:39 +0200 Subject: [PATCH] Initial porting to vala --- .gitmodules | 6 + Makefile.am | 6 +- configure.ac | 172 +- data/gitg-glade.xml | 7 - gitg/Makefile.am | 116 +- gitg/gitg-activatable.c | 70 - gitg/gitg-activatable.h | 55 - gitg/gitg-application.vala | 343 ++ gitg/gitg-avatar-cache.c | 416 -- gitg/gitg-avatar-cache.h | 73 - gitg/gitg-blame-renderer.c | 454 --- gitg/gitg-blame-renderer.h | 61 - gitg/gitg-branch-actions.c | 2108 ---------- gitg/gitg-branch-actions.h | 53 - gitg/gitg-cell-renderer-path.c | 639 --- gitg/gitg-cell-renderer-path.h | 69 - gitg/gitg-commit-menu.ui | 54 - gitg/gitg-commit-view.c | 3216 --------------- gitg/gitg-commit-view.h | 61 - gitg/gitg-diff-line-renderer.c | 379 -- gitg/gitg-diff-line-renderer.h | 60 - gitg/gitg-diff-view.c | 1633 -------- gitg/gitg-diff-view.h | 106 - gitg/gitg-dirs.c | 78 - gitg/gitg-dirs.h | 32 - gitg/gitg-dirs.vala | 64 + gitg/gitg-dnd.c | 1090 ----- gitg/gitg-dnd.h | 45 - gitg/gitg-label-renderer.c | 349 -- gitg/gitg-label-renderer.h | 52 - gitg/gitg-menus.xml | 168 - gitg/gitg-new-branch.ui | 106 - gitg/gitg-plugins-engine.vala | 67 + gitg/gitg-preferences-dialog.c | 431 -- gitg/gitg-preferences-dialog.h | 57 - gitg/gitg-preferences.ui | 810 ---- gitg/gitg-repository-dialog.c | 906 ----- gitg/gitg-repository-dialog.h | 62 - gitg/gitg-repository.ui | 320 -- gitg/gitg-resource.vala | 62 + gitg/gitg-revision-changes-panel.c | 1048 ----- gitg/gitg-revision-changes-panel.h | 34 - gitg/gitg-revision-changes-panel.ui | 79 - gitg/gitg-revision-details-panel.c | 936 ----- gitg/gitg-revision-details-panel.h | 58 - gitg/gitg-revision-details-panel.ui | 270 -- gitg/gitg-revision-files-panel.c | 1524 ------- gitg/gitg-revision-files-panel.h | 61 - gitg/gitg-revision-files-panel.ui | 96 - gitg/gitg-revision-panel.c | 124 - gitg/gitg-revision-panel.h | 70 - gitg/gitg-stat-view.c | 500 --- gitg/gitg-stat-view.h | 37 - gitg/gitg-tag.ui | 158 - gitg/gitg-ui.xml | 136 - gitg/gitg-uri.c | 103 - gitg/gitg-uri.h | 17 - gitg/gitg-utils.c | 466 --- gitg/gitg-utils.h | 61 - gitg/gitg-window.c | 3584 ----------------- gitg/gitg-window.h | 87 - gitg/gitg-window.ui | 576 --- gitg/gitg-window.vala | 457 +++ gitg/gitg.c | 207 - gitg/gitg.vala | 25 + gitg/resources/gitg-resources.xml | 10 + gitg/resources/ui/gitg-menus.ui | 33 + gitg/resources/ui/gitg-window.ui | 138 + gitg/resources/ui/style.css | 56 + libgit2 | 1 + libgit2-glib | 1 + libgitg-ext/GitgExt.py | 38 + libgitg-ext/Makefile.am | 100 + libgitg-ext/gitg-ext-application.vala | 19 + libgitg-ext/gitg-ext-message-bus.vala | 294 ++ libgitg-ext/gitg-ext-message-id.vala | 75 + libgitg-ext/gitg-ext-message.vala | 40 + .../gitg-ext-navigation-tree-view.vala | 476 +++ libgitg-ext/gitg-ext-navigation.vala | 22 + libgitg-ext/gitg-ext-panel.vala | 18 + libgitg-ext/gitg-ext-view.vala | 112 + libgitg-ext/libgitg-ext-1.0.pc.in | 11 + libgitg-ext/resources/resources.xml | 7 + libgitg/Makefile.am | 119 +- libgitg/gitg-changed-file.c | 343 -- libgitg/gitg-changed-file.h | 90 - libgitg/gitg-color.c | 139 - libgitg/gitg-color.h | 51 - libgitg/gitg-color.vala | 85 + libgitg/gitg-command.c | 513 --- libgitg/gitg-command.h | 98 - libgitg/gitg-commit-model.vala | 246 ++ libgitg/gitg-commit.c | 1484 ------- libgitg/gitg-commit.h | 108 - libgitg/gitg-commit.vala | 90 + libgitg/gitg-config.c | 529 --- libgitg/gitg-config.h | 75 - libgitg/gitg-convert.c | 118 - libgitg/gitg-convert.h | 34 - libgitg/gitg-debug.c | 74 - libgitg/gitg-debug.h | 59 - libgitg/gitg-encodings.c | 570 --- libgitg/gitg-encodings.h | 72 - libgitg/gitg-enum-types.c.template | 40 - libgitg/gitg-enum-types.h.template | 28 - libgitg/gitg-hash.c | 147 - libgitg/gitg-hash.h | 50 - libgitg/gitg-i18n.c | 52 - libgitg/gitg-i18n.h | 71 - libgitg/gitg-init.vala | 20 + libgitg/gitg-io.c | 507 --- libgitg/gitg-io.h | 106 - libgitg/gitg-lane.c | 86 - libgitg/gitg-lane.h | 69 - libgitg/gitg-lane.vala | 63 + libgitg/gitg-lanes.c | 750 ---- libgitg/gitg-lanes.h | 64 - libgitg/gitg-lanes.vala | 466 +++ libgitg/gitg-line-parser.c | 479 --- libgitg/gitg-line-parser.h | 67 - libgitg/gitg-ref.c | 248 -- libgitg/gitg-ref.h | 86 - libgitg/gitg-ref.vala | 275 ++ libgitg/gitg-repository.c | 2081 ---------- libgitg/gitg-repository.h | 113 - libgitg/gitg-repository.vala | 38 + libgitg/gitg-revision.c | 413 -- libgitg/gitg-revision.h | 88 - libgitg/gitg-runner.c | 646 --- libgitg/gitg-runner.h | 76 - libgitg/gitg-shell.c | 1045 ----- libgitg/gitg-shell.h | 159 - libgitg/gitg-smart-charset-converter.c | 438 -- libgitg/gitg-smart-charset-converter.h | 76 - libgitg/libgitg-1.0.pc.in | 11 + plugins/Makefile.am | 3 + plugins/dash/Makefile.am | 52 + plugins/dash/dash.plugin | 11 + plugins/dash/gitg-dash-navigation.vala | 93 + plugins/dash/gitg-dash.vala | 285 ++ plugins/dash/resources/resources.xml | 10 + plugins/dash/resources/view-create.ui | 91 + plugins/dash/resources/view-open.ui | 91 + plugins/dash/resources/view-recent.ui | 173 + plugins/history/Makefile.am | 52 + plugins/history/gitg-history-navigation.vala | 123 + plugins/history/gitg-history.vala | 103 + plugins/history/history.plugin | 11 + plugins/history/resources/resources.xml | 8 + plugins/history/resources/view-history.ui | 13 + vapi/config.vapi | 13 + vapi/gobject-introspection-1.0.vapi | 31 + 152 files changed, 5163 insertions(+), 36776 deletions(-) create mode 100644 .gitmodules delete mode 100644 gitg/gitg-activatable.c delete mode 100644 gitg/gitg-activatable.h create mode 100644 gitg/gitg-application.vala delete mode 100644 gitg/gitg-avatar-cache.c delete mode 100644 gitg/gitg-avatar-cache.h delete mode 100644 gitg/gitg-blame-renderer.c delete mode 100644 gitg/gitg-blame-renderer.h delete mode 100644 gitg/gitg-branch-actions.c delete mode 100644 gitg/gitg-branch-actions.h delete mode 100644 gitg/gitg-cell-renderer-path.c delete mode 100644 gitg/gitg-cell-renderer-path.h delete mode 100644 gitg/gitg-commit-menu.ui delete mode 100644 gitg/gitg-commit-view.c delete mode 100644 gitg/gitg-commit-view.h delete mode 100644 gitg/gitg-diff-line-renderer.c delete mode 100644 gitg/gitg-diff-line-renderer.h delete mode 100644 gitg/gitg-diff-view.c delete mode 100644 gitg/gitg-diff-view.h delete mode 100644 gitg/gitg-dirs.c delete mode 100644 gitg/gitg-dirs.h create mode 100644 gitg/gitg-dirs.vala delete mode 100644 gitg/gitg-dnd.c delete mode 100644 gitg/gitg-dnd.h delete mode 100644 gitg/gitg-label-renderer.c delete mode 100644 gitg/gitg-label-renderer.h delete mode 100644 gitg/gitg-menus.xml delete mode 100644 gitg/gitg-new-branch.ui create mode 100644 gitg/gitg-plugins-engine.vala delete mode 100644 gitg/gitg-preferences-dialog.c delete mode 100644 gitg/gitg-preferences-dialog.h delete mode 100644 gitg/gitg-preferences.ui delete mode 100644 gitg/gitg-repository-dialog.c delete mode 100644 gitg/gitg-repository-dialog.h delete mode 100644 gitg/gitg-repository.ui create mode 100644 gitg/gitg-resource.vala delete mode 100644 gitg/gitg-revision-changes-panel.c delete mode 100644 gitg/gitg-revision-changes-panel.h delete mode 100644 gitg/gitg-revision-changes-panel.ui delete mode 100644 gitg/gitg-revision-details-panel.c delete mode 100644 gitg/gitg-revision-details-panel.h delete mode 100644 gitg/gitg-revision-details-panel.ui delete mode 100644 gitg/gitg-revision-files-panel.c delete mode 100644 gitg/gitg-revision-files-panel.h delete mode 100644 gitg/gitg-revision-files-panel.ui delete mode 100644 gitg/gitg-revision-panel.c delete mode 100644 gitg/gitg-revision-panel.h delete mode 100644 gitg/gitg-stat-view.c delete mode 100644 gitg/gitg-stat-view.h delete mode 100644 gitg/gitg-tag.ui delete mode 100644 gitg/gitg-ui.xml delete mode 100644 gitg/gitg-uri.c delete mode 100644 gitg/gitg-uri.h delete mode 100644 gitg/gitg-utils.c delete mode 100644 gitg/gitg-utils.h delete mode 100644 gitg/gitg-window.c delete mode 100644 gitg/gitg-window.h delete mode 100644 gitg/gitg-window.ui create mode 100644 gitg/gitg-window.vala delete mode 100644 gitg/gitg.c create mode 100644 gitg/gitg.vala create mode 100644 gitg/resources/gitg-resources.xml create mode 100644 gitg/resources/ui/gitg-menus.ui create mode 100644 gitg/resources/ui/gitg-window.ui create mode 100644 gitg/resources/ui/style.css create mode 160000 libgit2 create mode 160000 libgit2-glib create mode 100644 libgitg-ext/GitgExt.py create mode 100644 libgitg-ext/Makefile.am create mode 100644 libgitg-ext/gitg-ext-application.vala create mode 100644 libgitg-ext/gitg-ext-message-bus.vala create mode 100644 libgitg-ext/gitg-ext-message-id.vala create mode 100644 libgitg-ext/gitg-ext-message.vala create mode 100644 libgitg-ext/gitg-ext-navigation-tree-view.vala create mode 100644 libgitg-ext/gitg-ext-navigation.vala create mode 100644 libgitg-ext/gitg-ext-panel.vala create mode 100644 libgitg-ext/gitg-ext-view.vala create mode 100644 libgitg-ext/libgitg-ext-1.0.pc.in create mode 100644 libgitg-ext/resources/resources.xml delete mode 100644 libgitg/gitg-changed-file.c delete mode 100644 libgitg/gitg-changed-file.h delete mode 100644 libgitg/gitg-color.c delete mode 100644 libgitg/gitg-color.h create mode 100644 libgitg/gitg-color.vala delete mode 100644 libgitg/gitg-command.c delete mode 100644 libgitg/gitg-command.h create mode 100644 libgitg/gitg-commit-model.vala delete mode 100644 libgitg/gitg-commit.c delete mode 100644 libgitg/gitg-commit.h create mode 100644 libgitg/gitg-commit.vala delete mode 100644 libgitg/gitg-config.c delete mode 100644 libgitg/gitg-config.h delete mode 100644 libgitg/gitg-convert.c delete mode 100644 libgitg/gitg-convert.h delete mode 100644 libgitg/gitg-debug.c delete mode 100644 libgitg/gitg-debug.h delete mode 100644 libgitg/gitg-encodings.c delete mode 100644 libgitg/gitg-encodings.h delete mode 100644 libgitg/gitg-enum-types.c.template delete mode 100644 libgitg/gitg-enum-types.h.template delete mode 100644 libgitg/gitg-hash.c delete mode 100644 libgitg/gitg-hash.h delete mode 100644 libgitg/gitg-i18n.c delete mode 100644 libgitg/gitg-i18n.h create mode 100644 libgitg/gitg-init.vala delete mode 100644 libgitg/gitg-io.c delete mode 100644 libgitg/gitg-io.h delete mode 100644 libgitg/gitg-lane.c delete mode 100644 libgitg/gitg-lane.h create mode 100644 libgitg/gitg-lane.vala delete mode 100644 libgitg/gitg-lanes.c delete mode 100644 libgitg/gitg-lanes.h create mode 100644 libgitg/gitg-lanes.vala delete mode 100644 libgitg/gitg-line-parser.c delete mode 100644 libgitg/gitg-line-parser.h delete mode 100644 libgitg/gitg-ref.c delete mode 100644 libgitg/gitg-ref.h create mode 100644 libgitg/gitg-ref.vala delete mode 100644 libgitg/gitg-repository.c delete mode 100644 libgitg/gitg-repository.h create mode 100644 libgitg/gitg-repository.vala delete mode 100644 libgitg/gitg-revision.c delete mode 100644 libgitg/gitg-revision.h delete mode 100644 libgitg/gitg-runner.c delete mode 100644 libgitg/gitg-runner.h delete mode 100644 libgitg/gitg-shell.c delete mode 100644 libgitg/gitg-shell.h delete mode 100644 libgitg/gitg-smart-charset-converter.c delete mode 100644 libgitg/gitg-smart-charset-converter.h create mode 100644 libgitg/libgitg-1.0.pc.in create mode 100644 plugins/Makefile.am create mode 100644 plugins/dash/Makefile.am create mode 100644 plugins/dash/dash.plugin create mode 100644 plugins/dash/gitg-dash-navigation.vala create mode 100644 plugins/dash/gitg-dash.vala create mode 100644 plugins/dash/resources/resources.xml create mode 100644 plugins/dash/resources/view-create.ui create mode 100644 plugins/dash/resources/view-open.ui create mode 100644 plugins/dash/resources/view-recent.ui create mode 100644 plugins/history/Makefile.am create mode 100644 plugins/history/gitg-history-navigation.vala create mode 100644 plugins/history/gitg-history.vala create mode 100644 plugins/history/history.plugin create mode 100644 plugins/history/resources/resources.xml create mode 100644 plugins/history/resources/view-history.ui create mode 100644 vapi/config.vapi create mode 100644 vapi/gobject-introspection-1.0.vapi diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..4798a696 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "libgit2"] + path = libgit2 + url = https://github.com/libgit2/libgit2.git +[submodule "libgit2-glib"] + path = libgit2-glib + url = git@github.com:nacho/libgit2-glib.git diff --git a/Makefile.am b/Makefile.am index 8a1de3d5..9ef7d1b4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,9 +4,6 @@ ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} SUBDIRS = libgitg gitg data po tests tools -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libgitg-1.0.pc - DISTCLEANFILES = \ intltool-extract \ intltool-merge \ @@ -17,8 +14,7 @@ EXTRA_DIST = \ MAINTAINERS \ intltool-extract.in \ intltool-merge.in \ - intltool-update.in \ - libgitg-1.0.pc.in + intltool-update.in MAINTAINERCLEANFILES = \ aclocal.m4 \ diff --git a/configure.ac b/configure.ac index 22350102..77625638 100644 --- a/configure.ac +++ b/configure.ac @@ -14,7 +14,7 @@ AC_INIT([gitg], [http://live.gnome.org/Gitg]) AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_SRCDIR([gitg/gitg.c]) +AC_CONFIG_SRCDIR([gitg/gitg.vala]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) @@ -36,11 +36,15 @@ AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PATH_PROG(GZIP, gzip) +AM_PATH_PYTHON +AM_PROG_VALAC + AC_PATH_PROG(GLIB_MKENUMS, glib-mkenums) +AC_PATH_PROG(GLIB_COMPILE_RESOURCES, glib-compile-resources) # Initialize libtool LT_PREREQ([2.2]) -LT_INIT +LT_INIT(disable-static) # i18n stuff IT_PROG_INTLTOOL([0.40.0]) @@ -49,47 +53,64 @@ AM_GNU_GETTEXT_VERSION([0.17]) AM_GNU_GETTEXT([external]) GETTEXT_PACKAGE=gitg + +dnl adl_RECURSIVE_EVAL(VALUE, RESULT) +dnl ================================= +dnl Interpolate the VALUE in loop until it doesn't change, +dnl and set the result to $RESULT. +dnl WARNING: It's easy to get an infinite loop with some unsane input. +AC_DEFUN([adl_RECURSIVE_EVAL], +[_lcl_receval="$1" +$2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" + _lcl_receval_old='' + while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do + _lcl_receval_old="[$]_lcl_receval" + eval _lcl_receval="\"[$]_lcl_receval\"" + done + echo "[$]_lcl_receval")`]) + +adl_RECURSIVE_EVAL("$datadir/gitg", [GITG_DATADIR]) +adl_RECURSIVE_EVAL("$datadir/locale", [GITG_LOCALEDIR]) +adl_RECURSIVE_EVAL("$libdir/gitg", [GITG_LIBDIR]) + AC_SUBST(GETTEXT_PACKAGE) + AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package]) +AC_DEFINE_UNQUOTED(GITG_DATADIR,"$GITG_DATADIR", [data dir]) +AC_DEFINE_UNQUOTED(GITG_LOCALEDIR,"$GITG_LOCALEDIR", [locale dir]) +AC_DEFINE_UNQUOTED(GITG_LIBDIR,"$GITG_LIBDIR", [lib dir]) AC_CHECK_LIB([m], [sinf]) GLIB_REQUIRED_VERSION=2.26 GTK_REQUIRED_VERSION=3.0.0 GTKSOURCEVIEW_REQUIRED_VERSION=3.1.3 +INTROSPECTION_REQUIRED=0.10.1 -PKG_CHECK_MODULES(GITG, [ - gtk+-3.0 >= $GTK_REQUIRED_VERSION +PKG_CHECK_MODULES(LIBGITG, [ gthread-2.0 >= $GLIB_REQUIRED_VERSION glib-2.0 >= $GLIB_REQUIRED_VERSION gobject-2.0 >= $GLIB_REQUIRED_VERSION gmodule-2.0 >= $GLIB_REQUIRED_VERSION gio-2.0 >= $GLIB_REQUIRED_VERSION gio-unix-2.0 >= $GLIB_REQUIRED_VERSION + gobject-introspection-1.0 >= $INTROSPECTION_REQUIRED + libgit2-glib-1.0 ]) -PKG_CHECK_MODULES(PACKAGE, [ - gtksourceview-3.0 >= $GTKSOURCEVIEW_REQUIRED_VERSION - gsettings-desktop-schemas -]) - -AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal) - -GNOME_COMPILE_WARNINGS([maximum]) - -if test "x$USE_MAINTAINER_MODE" = "xyes"; then -PACKAGE_CFLAGS="$PACKAGE_CFLAGS -Wall -Werror -Wuninitialized -Wmissing-declarations" -enable_deprecations="yes" -fi - - AC_ARG_ENABLE(deprecations, [AS_HELP_STRING([--enable-deprecations], [warn about deprecated usages [default=no]])], [enable_deprecations=$enableval]) +if test "x$USE_MAINTAINER_MODE" = "xyes"; then +LIBGITG_CFLAGS="$LIBGITG_CFLAGS -Wall -Werror -Wuninitialized -Wmissing-declarations" +enable_deprecations="yes" +fi + if test "$enable_deprecations" = "yes"; then - DISABLE_DEPRECATED_CFLAGS="\ + LIBGITG_CFLAGS="$LIBGITG_CFLAGS \ -DG_DISABLE_DEPRECATED \ -DGDK_DISABLE_DEPRECATED \ -DGTK_DISABLE_DEPRECATED \ @@ -98,36 +119,56 @@ if test "$enable_deprecations" = "yes"; then -DGSEAL_ENABLE" fi -PACKAGE_LIBS="$PACKAGE_LIBS -lm" - - AC_ARG_ENABLE(debug, [AS_HELP_STRING([--disable-debug], [disable debug information [default=yes]])], [enable_debug=$enableval], [enable_debug=yes]) if test "x$enable_debug" = "xyes"; then - PACKAGE_CFLAGS="$PACKAGE_CFLAGS -g" + LIBGITG_CFLAGS="$LIBGITG_CFLAGS -g -O0" AC_DEFINE([ENABLE_DEBUG],[1],[Whether debugging support is enabled]) fi -AM_CONDITIONAL([ENABLE_DEBUG], [test "$enable_debug" = "yes"]) +AC_SUBST(LIBGITG_CFLAGS) +AC_SUBST(LIBGITG_LIBS) +PKG_CHECK_MODULES(LIBGITG_GTK, [ + gtk+-3.0 >= $GTK_REQUIRED_VERSION +]) -AC_ARG_ENABLE(debug, - [AS_HELP_STRING([--disable-debug], - [disable debug information [default=yes]])], - [enable_debug=$enableval], [enable_debug=yes]) +LIBGITG_GTK_CFLAGS="$LIBGITG_CFLAGS $LIBGITG_GTK_CFLAGS" +LIBGITG_GTK_LIBS="$LIBGITG_LIBS $LIBGITG_GTK_LIBS" -if test "x$enable_debug" = "xyes"; then - PACKAGE_CFLAGS="$PACKAGE_CFLAGS -g" - AC_DEFINE([ENABLE_DEBUG],[1],[Whether debugging support is enabled]) -fi +AC_SUBST(LIBGITG_GTK_CFLAGS) +AC_SUBST(LIBGITG_GTK_LIBS) -AM_CONDITIONAL([ENABLE_DEBUG], [test "$enable_debug" = "yes"]) +LIBGITG_EXT_CFLAGS="$LIBGITG_GTK_CFLAGS" +LIBGITG_EXT_LIBS="$LIBGITG_GTK_LIBS" -AC_SUBST(PACKAGE_CFLAGS) -AC_SUBST(PACKAGE_LIBS) +AC_SUBST(LIBGITG_EXT_CFLAGS) +AC_SUBST(LIBGITG_EXT_LIBS) + +LIBPEAS_REQUIRED_VERSION=1.2.0 +LIBPEAS_GTK_REQUIRED_VERSION=1.2.0 + +PKG_CHECK_MODULES(GITG, [ + gtksourceview-3.0 >= $GTKSOURCEVIEW_REQUIRED_VERSION + gsettings-desktop-schemas + libpeas-1.0 >= $LIBPEAS_REQUIRED_VERSION + libpeas-gtk-1.0 >= $LIBPEAS_GTK_REQUIRED_VERSION + gee-1.0 +]) + +GITG_CFLAGS="$LIBGITG_GTK_CFLAGS $GITG_CFLAGS" +GITG_LIBS="$LIBGITG_GTK_LIBS $GITG_LIBS -lm" + +AC_SUBST(GITG_CFLAGS) +AC_SUBST(GITG_LIBS) + +GOBJECT_INTROSPECTION_REQUIRE($INTROSPECTION_REQUIRED) +AC_SUBST(INTROSPECTION_REQUIRED) + +GNOME_COMPILE_WARNINGS([maximum]) GLIB_GSETTINGS @@ -148,10 +189,63 @@ AS_IF([ test "$glade_catalog" = "yes" ], AC_MSG_RESULT([$GLADE_CATALOG_DIR]) AC_SUBST(GLADE_CATALOG_DIR)]) +GITG_PLUGIN_DATADIR="$datadir/gitg/plugins" +AC_SUBST(GITG_PLUGIN_DATADIR) + +GITG_PLUGIN_LIBDIR="$libdir/gitg/plugins" +AC_SUBST(GITG_PLUGIN_LIBDIR) + +GITG_PLUGIN_CFLAGS="$GITG_CFLAGS" +GITG_PLUGIN_LIBS="$GITG_LIBS" + +AC_SUBST(GITG_PLUGIN_CFLAGS) +AC_SUBST(GITG_PLUGIN_LIBS) + +GITG_PLUGIN_LIBTOOL_FLAGS="-module -avoid-version" +AC_SUBST(GITG_PLUGIN_LIBTOOL_FLAGS) + +GITG_PLUGIN_VALAFLAGS="--pkg GitgExt-1.0 \ + --pkg Ggit-1.0 \ + --pkg Gitg-1.0 \ + --pkg gio-2.0 \ + --pkg gtk+-3.0 \ + --pkg libpeas-1.0 \ + --pkg gee-1.0 \ + --vapidir \$(top_srcdir)/vapi \ + --pkg config" + +AC_SUBST(GITG_PLUGIN_VALAFLAGS) + +dnl =========================================================================== +dnl Check for python +dnl =========================================================================== +PYGOBJECT_REQUIRED=3.0.0 + +AC_ARG_ENABLE([python], + AS_HELP_STRING([--enable-python[=@<:@no/auto/yes@:>@]],[Build with python support]), + [enable_python=$enableval], + [enable_python="auto"]) + +if test "x$enable_python" = "xauto"; then + PKG_CHECK_EXISTS([pygobject-3.0 >= $PYGOBJECT_REQUIRED], + [enable_python=yes],[enable_python=no]) +fi + +if test "x$enable_python" = "xyes"; then + PKG_CHECK_MODULES(PYTHON, [pygobject-3.0 >= $PYGOBJECT_REQUIRED]) + + pyoverridesdir=`$PYTHON -c "import gi; print(gi._overridesdir)"` + AC_SUBST(pyoverridesdir) +fi + +AM_CONDITIONAL(ENABLE_PYTHON, test x"$enable_python" = "xyes") + AC_CONFIG_FILES([ Makefile -libgitg-1.0.pc libgitg/Makefile +libgitg/libgitg-1.0.pc +libgitg-ext/Makefile +libgitg-ext/libgitg-ext-1.0.pc gitg/Makefile data/Makefile data/gitg.desktop.in @@ -160,6 +254,9 @@ data/org.gnome.gitg.gschema.xml.in po/Makefile.in tests/Makefile tools/Makefile +plugins/Makefile +plugins/dash/Makefile +plugins/history/Makefile ]) AC_OUTPUT @@ -172,4 +269,5 @@ Configuration: Compiler: ${CC} Glade catalog: ${glade_catalog} Debug enabled: ${enable_debug} + Python support: ${enable_python} " diff --git a/data/gitg-glade.xml b/data/gitg-glade.xml index 0b22393c..66664ce4 100644 --- a/data/gitg-glade.xml +++ b/data/gitg-glade.xml @@ -3,15 +3,8 @@ - - - - - - - diff --git a/gitg/Makefile.am b/gitg/Makefile.am index e74617fb..1b06d971 100644 --- a/gitg/Makefile.am +++ b/gitg/Makefile.am @@ -4,85 +4,67 @@ AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(srcdir) \ $(GITG_CFLAGS) \ - $(PACKAGE_CFLAGS) \ $(WARN_CFLAGS) \ - $(DISABLE_DEPRECATED_CFLAGS) \ -DDATADIR=\""$(datadir)"\" \ -DGITG_DATADIR=\""$(datadir)/gitg"\" \ -DGITG_LOCALEDIR=\""$(datadir)/locale"\" -NOINST_H_FILES = \ - gitg-activatable.h \ - gitg-avatar-cache.h \ - gitg-blame-renderer.h \ - gitg-branch-actions.h \ - gitg-cell-renderer-path.h \ - gitg-commit-view.h \ - gitg-diff-line-renderer.h \ - gitg-diff-view.h \ - gitg-dirs.h \ - gitg-dnd.h \ - gitg-label-renderer.h \ - gitg-preferences-dialog.h \ - gitg-repository-dialog.h \ - gitg-revision-panel.h \ - gitg-revision-details-panel.h \ - gitg-revision-files-panel.h \ - gitg-revision-changes-panel.h \ - gitg-stat-view.h \ - gitg-uri.h \ - gitg-utils.h \ - gitg-window.h +VALAFLAGS = \ + --vapidir $(top_srcdir)/vapi \ + --pkg config \ + --pkg Ggit-1.0 \ + --pkg Gitg-1.0 \ + --pkg GitgExt-1.0 \ + --pkg gtk+-3.0 \ + --pkg gio-2.0 \ + --pkg libpeas-1.0 \ + --pkg gobject-introspection-1.0 -gitg_SOURCES = \ - $(BUILT_SOURCES) \ - gitg.c \ - gitg-activatable.c \ - gitg-avatar-cache.c \ - gitg-blame-renderer.c \ - gitg-branch-actions.c \ - gitg-cell-renderer-path.c \ - gitg-commit-view.c \ - gitg-diff-line-renderer.c \ - gitg-diff-view.c \ - gitg-dirs.c \ - gitg-dnd.c \ - gitg-label-renderer.c \ - gitg-preferences-dialog.c \ - gitg-repository-dialog.c \ - gitg-revision-panel.c \ - gitg-revision-details-panel.c \ - gitg-revision-files-panel.c \ - gitg-revision-changes-panel.c \ - gitg-stat-view.c \ - gitg-uri.c \ - gitg-utils.c \ - gitg-window.c \ - $(NOINST_H_FILES) +VALASOURCES = \ + gitg.vala \ + gitg-dirs.vala \ + gitg-window.vala \ + gitg-resource.vala \ + gitg-application.vala \ + gitg-plugins-engine.vala -gitg_LDADD = \ - $(GITG_LIBS) \ - $(PACKAGE_LIBS) \ - $(top_builddir)/libgitg/libgitg-1.0.la +BUILT_SOURCES = \ + gitg-resources.c \ + gitg-resources.h + +gitg_SOURCES = \ + $(VALASOURCES) \ + gitg-resources.c + +gitg_LDADD = \ + $(GITG_LIBS) \ + $(PACKAGE_LIBS) \ + $(top_builddir)/libgitg/libgitg-1.0.la \ + $(top_builddir)/libgitg-ext/libgitg-ext-1.0.la gitg_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*" -uidir = $(datadir)/gitg/ui/ -ui_DATA = \ - gitg-window.ui \ - gitg-commit-menu.ui \ - gitg-ui.xml \ - gitg-menus.xml \ - gitg-preferences.ui \ - gitg-new-branch.ui \ - gitg-tag.ui \ - gitg-repository.ui \ - gitg-revision-details-panel.ui \ - gitg-revision-changes-panel.ui \ - gitg-revision-files-panel.ui +gitg-resources.c: resources/gitg-resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/gitg-resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-source \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +gitg-resources.h: resources/gitg-resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/gitg-resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-header \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +# Ignore all warnings for vala code... +gitg_CFLAGS = \ + -w EXTRA_DIST = \ - $(ui_DATA) + resources/gitg-resources.xml \ + $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/gitg-resources.xml) + +CLEANFILES = \ + $(VALASOURCES:.vala=.c) \ + $(BUILT_SOURCES) -include $(top_srcdir)/git.mk diff --git a/gitg/gitg-activatable.c b/gitg/gitg-activatable.c deleted file mode 100644 index 07fb2674..00000000 --- a/gitg/gitg-activatable.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * gitg-activatable.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-activatable.h" - -G_DEFINE_INTERFACE(GitgActivatable, gitg_activatable, G_TYPE_OBJECT) - -/* Default implementation */ -static gchar * -gitg_activatable_get_id_default (GitgActivatable *panel) -{ - g_return_val_if_reached (NULL); -} - -static gboolean -gitg_activatable_activate_default (GitgActivatable *panel, - gchar const *cmd) -{ - return FALSE; -} - -static void -gitg_activatable_default_init (GitgActivatableInterface *iface) -{ - static gboolean initialized = FALSE; - - iface->get_id = gitg_activatable_get_id_default; - iface->activate = gitg_activatable_activate_default; - - if (!initialized) - { - initialized = TRUE; - } -} - -gchar * -gitg_activatable_get_id (GitgActivatable *panel) -{ - g_return_val_if_fail (GITG_IS_ACTIVATABLE (panel), NULL); - - return GITG_ACTIVATABLE_GET_INTERFACE (panel)->get_id (panel); -} - -gboolean -gitg_activatable_activate (GitgActivatable *panel, - gchar const *action) -{ - g_return_val_if_fail (GITG_IS_ACTIVATABLE (panel), FALSE); - - return GITG_ACTIVATABLE_GET_INTERFACE (panel)->activate (panel, action); -} diff --git a/gitg/gitg-activatable.h b/gitg/gitg-activatable.h deleted file mode 100644 index e83189b5..00000000 --- a/gitg/gitg-activatable.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * gitg-activatable.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_ACTIVATABLE_H__ -#define __GITG_ACTIVATABLE_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_ACTIVATABLE (gitg_activatable_get_type ()) -#define GITG_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_ACTIVATABLE, GitgActivatable)) -#define GITG_IS_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_ACTIVATABLE)) -#define GITG_ACTIVATABLE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GITG_TYPE_ACTIVATABLE, GitgActivatableInterface)) - -typedef struct _GitgActivatable GitgActivatable; -typedef struct _GitgActivatableInterface GitgActivatableInterface; - -struct _GitgActivatableInterface -{ - GTypeInterface parent; - - gchar *(*get_id) (GitgActivatable *panel); - gboolean (*activate) (GitgActivatable *panel, - gchar const *cmd); -}; - -GType gitg_activatable_get_type (void) G_GNUC_CONST; - -gchar *gitg_activatable_get_id (GitgActivatable *panel); -gboolean gitg_activatable_activate (GitgActivatable *panel, - gchar const *action); - -G_END_DECLS - -#endif /* __GITG_ACTIVATABLE_H__ */ diff --git a/gitg/gitg-application.vala b/gitg/gitg-application.vala new file mode 100644 index 00000000..d5a57efe --- /dev/null +++ b/gitg/gitg-application.vala @@ -0,0 +1,343 @@ +namespace Gitg +{ + +public class Application : Gtk.Application +{ + public Application() + { + Object(application_id: "org.gnome.gitg", + flags: ApplicationFlags.HANDLES_OPEN | + ApplicationFlags.HANDLES_COMMAND_LINE | + ApplicationFlags.SEND_ENVIRONMENT); + } + + private struct Options + { + public static bool quit = false; + public static bool commit = false; + public static string? select = null; + public static bool startup = false; + public static bool no_wd = false; + public static ApplicationCommandLine command_line; + + public static const OptionEntry[] entries = { + {"version", 'v', OptionFlags.NO_ARG, OptionArg.CALLBACK, + (void *)show_version_and_quit, N_("Show the application's version"), null}, + {"commit", 'c', 0, OptionArg.NONE, + ref commit, N_("Start gitg in commit mode"), null}, + {"select", 's', 0, OptionArg.STRING, ref select, N_("Select commit after loading the repository"), null}, + {"no-wd", 0, 0, OptionArg.NONE, + ref no_wd, N_("Do not try to load a repository from the current working directory"), null}, + {null} + }; + } + + private static Options options; + + private static void show_version_and_quit() + { + stdout.printf("%s %s\n", + Environment.get_application_name(), + Config.VERSION); + + options.quit = true; + } + + private void parse_command_line(ref unowned string[] argv) throws OptionError + { + var ctx = new OptionContext(_("- git repository viewer")); + + ctx.add_main_entries(options.entries, Config.GETTEXT_PACKAGE); + ctx.add_group(Gtk.get_option_group(true)); + + ctx.parse(ref argv); + } + + protected override bool local_command_line ([CCode (array_length = false, array_null_terminated = true)] ref unowned string[] arguments, out int exit_status) + { + // Parse command line just for -v and -h + string[] cp = arguments; + unowned string[] argv = cp; + + try + { + parse_command_line(ref argv); + } + catch (Error e) + { + exit_status = 1; + return true; + } + + if (options.quit) + { + exit_status = 0; + return true; + } + + return base.local_command_line(ref arguments, out exit_status); + } + + protected override int command_line(ApplicationCommandLine cmd) + { + string[] arguments = cmd.get_arguments(); + unowned string[] argv = arguments; + + try + { + parse_command_line(ref argv); + } + catch (Error e) + { + cmd.printerr("option parsing failed: %s\n", e.message); + return 1; + } + + if (options.quit) + { + return 0; + } + + options.command_line = cmd; + + if (options.startup) + { + app_init(); + options.startup = false; + } + + if (argv.length > 1) + { + File[] files = new File[argv.length - 1]; + files.length = 0; + + foreach (string arg in argv[1:argv.length]) + { + files += File.new_for_commandline_arg(arg); + } + + open(files, open_hint_from_options); + } + else + { + activate(); + } + + return 1; + } + + private string open_hint_from_options + { + get { return options.commit ? "commit" : "history"; } + } + + private void on_app_new_window_activated() + { + } + + private void on_app_help_activated() + { + + } + + private void on_app_about_activated() + { + + } + + private void on_app_quit_activated() + { + foreach (var window in get_windows()) + { + window.destroy(); + } + } + + private static const ActionEntry[] app_entries = { + {"new", on_app_new_window_activated}, + {"help", on_app_help_activated}, + {"about", on_app_about_activated}, + {"quit", on_app_quit_activated} + }; + + private void setup_menus() + { + add_action_entries(app_entries, this); + + MenuModel[] menus = Resource.load_objects("ui/gitg-menus.ui", {"app-menu", "win-menu"}); + + set_app_menu(menus[0]); + set_menubar(menus[1]); + } + + protected override void startup() + { + options.startup = true; + base.startup(); + + setup_menus(); + } + + protected override void activate() + { + /* Application gets activated when no command line arguments have + * been provided. However, gitg does something special in the case + * that it has been launched from the terminal. It will try to open + * the cwd as a repository. However, when not launched from the terminal + * this is undesired, and a --no-wd allows gitg to be launched without + * the implicit working directory opening of the repository. In the + * end, the following happens: + * + * 1) --no-wd: present the window + * 2) Get cwd from the commandline: open + */ + if (options.no_wd) + { + present_window(); + } + else + { + // Otherwise open repository from current dir + string? wd = options.command_line.get_cwd(); + + open(new File[] { File.new_for_path(wd) }, + open_hint_from_options); + } + + base.activate(); + } + + private Window? find_window_for_file(File file) + { + foreach (Gtk.Window window in get_windows()) + { + Window wnd = window as Window; + + if (wnd.repository == null) + { + continue; + } + + if (wnd.repository.get_location().equal(file)) + { + return wnd; + } + } + + return null; + } + + protected override void open(File[] files, string hint) + { + if (files.length == 0) + { + return; + } + + bool opened = false; + + // Set of files are potential git repositories + foreach (File f in files) + { + // See if the repository is already open somewhere + Window? window = find_window_for_file(f); + + if (window != null) + { + // Present the window with this repository open + window.present_with_time(Gdk.CURRENT_TIME); + continue; + } + + File? resolved; + + // Try to open a repository at this location + try + { + resolved = Ggit.Repository.discover(f); + } + catch { continue; } + + // Open the repository + Repository? repo; + + try + { + repo = new Repository(resolved, null); + } + catch { continue; } + + // Finally, create a window for the repository + new_window(repo, hint); + opened = true; + } + + if (!opened) + { + // still open a window + present_window(); + } + } + + private void app_init() + { + PluginsEngine.initialize(); + + Gtk.CssProvider? provider = Resource.load_css("style.css"); + + if (provider != null) + { + Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), + provider, + 600); + } + } + + private GitgExt.ViewAction get_action_from_hint(string? hint) + { + if (hint == null) + { + return GitgExt.ViewAction.DEFAULT; + } + + EnumClass klass = (EnumClass)typeof(GitgExt.ViewAction).class_ref(); + EnumValue? val = klass.get_value_by_nick(hint); + + if (val == null) + { + return GitgExt.ViewAction.DEFAULT; + } + else + { + return (GitgExt.ViewAction)val.value; + } + } + + private void new_window(Repository? repo = null, string? hint = null) + { + + add_window(Window.create_new(this, repo, get_action_from_hint(hint))); + present_window(); + } + + private void present_window() + { + /* Present the first window in the windows registered on the + * application. If there are no windows, then create a new empty + * window. + */ + unowned List windows = get_windows(); + + if (windows == null) + { + new_window(); + return; + } + + windows.data.present_with_time(Gdk.CURRENT_TIME); + } +} + +} + +// ex:set ts=4 noet diff --git a/gitg/gitg-avatar-cache.c b/gitg/gitg-avatar-cache.c deleted file mode 100644 index 93170525..00000000 --- a/gitg/gitg-avatar-cache.c +++ /dev/null @@ -1,416 +0,0 @@ -/* -*- 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 -#include -#include - -#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 -cached_pixbuf_unref0 (gpointer pixbuf) -{ - if (pixbuf != NULL) - { - g_object_unref (pixbuf); - } -} - -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, - cached_pixbuf_unref0); - } - - if (pixbuf != NULL) - { - g_object_ref (pixbuf); - } - - g_hash_table_insert (priv->pixbuf_table, g_strdup (uri), 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 - { - /* At the moment G_IO_ERROR_NOT_FOUND is not being returned - * and instead an error code of 404 is. This is HTTP's - * File Not Found error. - */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || - (error != NULL && error->code == 404)) - { - avatar_cache_insert (loader->cache, loader->uri, NULL); - } - else if (!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; - gboolean found = FALSE; - 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) - { - found = g_hash_table_lookup_extended (priv->pixbuf_table, uri, - NULL, (gpointer *) &pixbuf); - } - - if (found) - { - if (pixbuf == NULL) - { - g_simple_async_result_set_error (result, G_IO_ERROR, - G_IO_ERROR_NOT_FOUND, - "Not Found"); - } - else - { - 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; - gssize len; - gchar *lowercase_id; - - 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); - } - - len = strlen (gravatar_id); - lowercase_id = g_ascii_strdown (gravatar_id, len); - - g_checksum_update (priv->checksum, (gpointer) lowercase_id, len); - - g_free (lowercase_id); - - /* d=404 will return a File Not Found if the avatar does not exist */ - return g_strdup_printf ("http://www.gravatar.com/avatar/%s?d=404&s=%d", - g_checksum_get_string (priv->checksum), - AVATAR_SIZE); -} diff --git a/gitg/gitg-avatar-cache.h b/gitg/gitg-avatar-cache.h deleted file mode 100644 index dca9a347..00000000 --- a/gitg/gitg-avatar-cache.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- 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 -#include - -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-blame-renderer.c b/gitg/gitg-blame-renderer.c deleted file mode 100644 index 630c284a..00000000 --- a/gitg/gitg-blame-renderer.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * gitg-blame-renderer.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2011 - Ignacio Casal Quinteiro - * - * 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 "gitg-blame-renderer.h" - -#include -#include -#include - -#define GITG_BLAME_RENDERER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_BLAME_RENDERER, GitgBlameRendererPrivate)) - -/* Properties */ -enum -{ - PROP_0, - PROP_REVISION, - PROP_SHOW, - PROP_GROUP_START -}; - -struct _GitgBlameRendererPrivate -{ - GitgRevision *revision; - gint max_line; - gboolean group_start; - gboolean show; - - gchar *line_number; - - PangoLayout *cached_layout; - PangoLayout *line_layout; -}; - -G_DEFINE_TYPE (GitgBlameRenderer, gitg_blame_renderer, GTK_SOURCE_TYPE_GUTTER_RENDERER) - -static void -gitg_blame_renderer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgBlameRenderer *self = GITG_BLAME_RENDERER (object); - - switch (prop_id) - { - case PROP_REVISION: - self->priv->revision = g_value_get_boxed (value); - break; - case PROP_SHOW: - self->priv->show = g_value_get_boolean (value); - break; - case PROP_GROUP_START: - self->priv->group_start = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_blame_renderer_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgBlameRenderer *self = GITG_BLAME_RENDERER (object); - - switch (prop_id) - { - case PROP_REVISION: - g_value_set_boxed (value, self->priv->revision); - break; - case PROP_SHOW: - g_value_set_boolean (value, self->priv->show); - break; - case PROP_GROUP_START: - g_value_set_boolean (value, self->priv->group_start); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_blame_renderer_finalize (GObject *object) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (object); - - g_free (br->priv->line_number); - - G_OBJECT_CLASS (gitg_blame_renderer_parent_class)->finalize (object); -} - -static void -gitg_blame_renderer_begin (GtkSourceGutterRenderer *renderer, - cairo_t *cr, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - - br->priv->cached_layout = gtk_widget_create_pango_layout (GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer)), - NULL); - br->priv->line_layout = gtk_widget_create_pango_layout (GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer)), - NULL); -} - -static void -render_blame (GtkSourceGutterRenderer *renderer, - cairo_t *ctx, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState renderer_state) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - gchar *text; - PangoLayout *layout; - GtkWidget *widget; - GtkStyleContext *style_context; - gchar *sha1; - gchar short_sha1[9]; - - widget = GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer)); - layout = br->priv->cached_layout; - - pango_layout_set_width (layout, -1); - - sha1 = gitg_revision_get_sha1 (br->priv->revision); - strncpy (short_sha1, sha1, 8); - short_sha1[8] = '\0'; - g_free (sha1); - - text = g_strdup_printf ("%s %s", short_sha1, - gitg_revision_get_author (br->priv->revision)); - - pango_layout_set_markup (layout, text, -1); - g_free (text); - style_context = gtk_widget_get_style_context (widget); - - if (br->priv->group_start) - { - GdkRGBA bg_color; - - gtk_style_context_get_background_color (style_context, GTK_STATE_INSENSITIVE, &bg_color); - gdk_cairo_set_source_rgba (ctx, &bg_color); - - cairo_save (ctx); - cairo_move_to (ctx, background_area->x, background_area->y); - cairo_line_to (ctx, background_area->x + background_area->width, - cell_area->y); - cairo_stroke (ctx); - cairo_restore (ctx); - } - - gtk_render_layout (style_context, - ctx, - cell_area->x, - cell_area->y, - layout); -} - -static void -render_line (GtkSourceGutterRenderer *renderer, - cairo_t *ctx, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState renderer_state) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - PangoLayout *layout; - GtkWidget *widget; - GtkStyleContext *style_context; - gint width, height; - - widget = GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer)); - layout = br->priv->line_layout; - - pango_layout_set_markup (layout, br->priv->line_number, -1); - pango_layout_get_size (layout, &width, &height); - - style_context = gtk_widget_get_style_context (widget); - - width /= PANGO_SCALE; - - gtk_render_layout (style_context, - ctx, - cell_area->x + cell_area->width - width - 5, - cell_area->y, - layout); -} - -static void -gitg_blame_renderer_draw (GtkSourceGutterRenderer *renderer, - cairo_t *ctx, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState renderer_state) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - - /* Chain up to draw background */ - GTK_SOURCE_GUTTER_RENDERER_CLASS ( - gitg_blame_renderer_parent_class)->draw (renderer, - ctx, - background_area, - cell_area, - start, - end, - renderer_state); - - if (br->priv->show && br->priv->revision != NULL) - { - render_blame (renderer, - ctx, - background_area, - cell_area, - start, - end, - renderer_state); - } - - render_line (renderer, - ctx, - background_area, - cell_area, - start, - end, - renderer_state); -} - -static void -gitg_blame_renderer_end (GtkSourceGutterRenderer *renderer) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - - g_object_unref (br->priv->cached_layout); - br->priv->cached_layout = NULL; - - g_object_unref (br->priv->line_layout); - br->priv->line_layout = NULL; -} - -static void -gutter_renderer_query_data (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state) -{ - GitgBlameRenderer *br = GITG_BLAME_RENDERER (renderer); - gchar *text; - gint line; - gboolean current_line; - - line = gtk_text_iter_get_line (start) + 1; - - current_line = (state & GTK_SOURCE_GUTTER_RENDERER_STATE_CURSOR) && - gtk_text_view_get_cursor_visible (gtk_source_gutter_renderer_get_view (renderer)); - - if (current_line) - { - text = g_strdup_printf ("%d", line); - } - else - { - text = g_strdup_printf ("%d", line); - } - - g_free (br->priv->line_number); - br->priv->line_number = text; -} - -static void -measure_text (GitgBlameRenderer *br, - const gchar *markup, - gint *width) -{ - PangoLayout *layout; - gint w; - gint h; - GtkSourceGutterRenderer *r; - GtkTextView *view; - - r = GTK_SOURCE_GUTTER_RENDERER (br); - view = gtk_source_gutter_renderer_get_view (r); - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL); - - pango_layout_set_markup (layout, - markup, - -1); - - pango_layout_get_size (layout, &w, &h); - - if (width) - { - *width = w / PANGO_SCALE; - } - - g_object_unref (layout); -} - -static GtkTextBuffer * -get_buffer (GitgBlameRenderer *renderer) -{ - GtkTextView *view; - - view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer)); - - return gtk_text_view_get_buffer (view); -} - -static void -recalculate_size (GitgBlameRenderer *br) -{ - GtkTextBuffer *buffer; - gchar *markup; - gint size; - gchar *text; - gint num, num_digits, i; - - buffer = get_buffer (br); - - num = gtk_text_buffer_get_line_count (buffer); - num_digits = 0; - - while (num > 0) - { - num /= 10; - ++num_digits; - } - - num_digits = MAX (num_digits, 2); - - text = g_new (gchar, br->priv->max_line + num_digits + 1); - for (i = 0; i < br->priv->max_line + num_digits; i++) - { - text[i] = '0'; - } - text[br->priv->max_line + num_digits] = '\0'; - - markup = g_strdup_printf ("%s", text); - g_free (text); - - measure_text (br, markup, &size); - g_free (markup); - - gtk_source_gutter_renderer_set_size (GTK_SOURCE_GUTTER_RENDERER (br), - size); -} - -static void -update_num_digits (GitgBlameRenderer *renderer, - gint max_line) -{ - max_line = MAX (max_line, 2); - - if (max_line != renderer->priv->max_line) - { - renderer->priv->max_line = max_line; - recalculate_size (renderer); - } -} - -static void -gitg_blame_renderer_class_init (GitgBlameRendererClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass); - - renderer_class->begin = gitg_blame_renderer_begin; - renderer_class->draw = gitg_blame_renderer_draw; - renderer_class->end= gitg_blame_renderer_end; - renderer_class->query_data = gutter_renderer_query_data; - - object_class->set_property = gitg_blame_renderer_set_property; - object_class->get_property = gitg_blame_renderer_get_property; - object_class->finalize = gitg_blame_renderer_finalize; - - g_object_class_install_property (object_class, - PROP_REVISION, - g_param_spec_boxed ("revision", - "Revision", - "Revision", - GITG_TYPE_REVISION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_SHOW, - g_param_spec_boolean ("show", - "Show", - "Show", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_GROUP_START, - g_param_spec_boolean ("group-start", - "Group Start", - "Group start", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_type_class_add_private (object_class, sizeof (GitgBlameRendererPrivate)); -} - -static void -gitg_blame_renderer_init (GitgBlameRenderer *self) -{ - self->priv = GITG_BLAME_RENDERER_GET_PRIVATE (self); -} - -GitgBlameRenderer * -gitg_blame_renderer_new (void) -{ - return g_object_new (GITG_TYPE_BLAME_RENDERER, NULL); -} - -void -gitg_blame_renderer_set_max_line_count (GitgBlameRenderer *renderer, - gint max_line) -{ - g_return_if_fail (GITG_IS_BLAME_RENDERER (renderer)); - - update_num_digits (renderer, max_line); -} diff --git a/gitg/gitg-blame-renderer.h b/gitg/gitg-blame-renderer.h deleted file mode 100644 index 412ac900..00000000 --- a/gitg/gitg-blame-renderer.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * gitg-blame-renderer.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2011 - Ignacio Casal Quinteiro - * - * 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_BLAME_RENDERER_H__ -#define __GITG_BLAME_RENDERER_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_BLAME_RENDERER (gitg_blame_renderer_get_type ()) -#define GITG_BLAME_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_BLAME_RENDERER, GitgBlameRenderer)) -#define GITG_BLAME_RENDERER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_BLAME_RENDERER, GitgBlameRenderer const)) -#define GITG_BLAME_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_BLAME_RENDERER, GitgBlameRendererClass)) -#define GITG_IS_BLAME_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_BLAME_RENDERER)) -#define GITG_IS_BLAME_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_BLAME_RENDERER)) -#define GITG_BLAME_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_BLAME_RENDERER, GitgBlameRendererClass)) - -typedef struct _GitgBlameRenderer GitgBlameRenderer; -typedef struct _GitgBlameRendererClass GitgBlameRendererClass; -typedef struct _GitgBlameRendererPrivate GitgBlameRendererPrivate; - -struct _GitgBlameRenderer { - GtkSourceGutterRenderer parent; - - GitgBlameRendererPrivate *priv; -}; - -struct _GitgBlameRendererClass { - GtkSourceGutterRendererClass parent_class; -}; - -GType gitg_blame_renderer_get_type (void) G_GNUC_CONST; - -GitgBlameRenderer *gitg_blame_renderer_new (void); - -void gitg_blame_renderer_set_max_line_count (GitgBlameRenderer *renderer, - gint max_line_count); - -G_END_DECLS - -#endif /* __GITG_BLAME_RENDERER_H__ */ diff --git a/gitg/gitg-branch-actions.c b/gitg/gitg-branch-actions.c deleted file mode 100644 index 4281602a..00000000 --- a/gitg/gitg-branch-actions.c +++ /dev/null @@ -1,2108 +0,0 @@ -/* - * gitg-branch-actions.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include - -#include "gitg-branch-actions.h" - -typedef enum -{ - GITG_PROGRESS_SUCCESS, - GITG_PROGRESS_ERROR, - GITG_PROGRESS_CANCELLED -} GitgProgress; - -typedef void (*ProgressCallback) (GitgWindow *window, GitgProgress progress, gpointer data); - -typedef struct -{ - GitgWindow *window; - GitgShell *shell; - - ProgressCallback callback; - gpointer callback_data; - - guint timeout_id; - - GtkDialog *dialog; - GtkProgressBar *progress; -} ProgressInfo; - -static void -free_progress_info (ProgressInfo *info) -{ - if (info->timeout_id) - { - g_source_remove (info->timeout_id); - } - - gtk_widget_destroy (GTK_WIDGET (info->dialog)); - - g_object_unref (info->shell); - g_slice_free (ProgressInfo, info); -} - -static gchar const ** -parse_valist (va_list ap) -{ - gchar const *a; - gchar const **ret; - guint num = 0; - - ret = g_new (gchar const *, 1); - - while ( (a = va_arg (ap, gchar const *)) != NULL) - { - ret = g_realloc (ret, sizeof (gchar const *) * (++num + 1)); - ret[num - 1] = a; - } - - ret[num] = NULL; - return ret; -} - -static void -on_progress_end (GitgShell *shell, gboolean cancelled, ProgressInfo *info) -{ - GitgProgress progress; - - if (cancelled) - { - progress = GITG_PROGRESS_CANCELLED; - } - else if (gitg_io_get_exit_status (GITG_IO (shell)) != 0) - { - progress = GITG_PROGRESS_ERROR; - } - else - { - progress = GITG_PROGRESS_SUCCESS; - } - - GitgWindow *window = info->window; - ProgressCallback callback = info->callback; - gpointer data = info->callback_data; - free_progress_info (info); - - callback (window, progress, data); -} - -static void -on_progress_response (GtkDialog *dialog, GtkResponseType response, ProgressInfo *info) -{ - gitg_io_cancel (GITG_IO (info->shell)); -} - -static gboolean -on_progress_timeout (ProgressInfo *info) -{ - gtk_progress_bar_pulse (info->progress); - return TRUE; -} - -static GitgShell * -run_progress (GitgWindow *window, - gchar const *title, - gchar const *message, - ProgressCallback callback, - gpointer callback_data, - ...) -{ - va_list ap; - - va_start (ap, callback_data); - - GitgShell *shell = gitg_shell_new (1000); - gchar const **argv = parse_valist (ap); - - GitgCommand *cmd = gitg_command_newv (gitg_window_get_repository (window), - (gchar const * const *)argv); - - if (!gitg_shell_run (shell, cmd, NULL)) - { - g_free (argv); - g_object_unref (shell); - - callback (window, GITG_PROGRESS_ERROR, callback_data); - - return NULL; - } - - g_free (argv); - - // Create dialog to show progress - GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; - GtkWidget *dlg; - - dlg = gtk_message_dialog_new (GTK_WINDOW (window), - flags, - GTK_MESSAGE_INFO, - GTK_BUTTONS_CANCEL, - "%s", - title); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", - message); - - gtk_window_set_title (GTK_WINDOW (dlg), _ ("gitg")); - - // Add progress bar - GtkWidget *area = gtk_dialog_get_content_area (GTK_DIALOG (dlg)); - GtkWidget *progress = gtk_progress_bar_new (); - gtk_widget_show (progress); - - gtk_box_pack_start (GTK_BOX (area), progress, FALSE, FALSE, 0); - - gtk_widget_show (dlg); - - ProgressInfo *info = g_slice_new0 (ProgressInfo); - - info->dialog = GTK_DIALOG (dlg); - info->progress = GTK_PROGRESS_BAR (progress); - info->callback = callback; - info->callback_data = callback_data; - info->window = window; - info->shell = g_object_ref (shell); - - info->timeout_id = g_timeout_add (100, (GSourceFunc)on_progress_timeout, info); - - g_signal_connect (dlg, "response", G_CALLBACK (on_progress_response), info); - g_signal_connect (shell, "end", G_CALLBACK (on_progress_end), info); - - return shell; -} - -static gint -message_dialog (GitgWindow *window, - GtkMessageType type, - gchar const *primary, - gchar const *secondary, - gchar const *accept, - ...) -{ - GtkWidget *dlg; - va_list ap; - - va_start (ap, accept); - gchar *prim = g_strdup_vprintf (primary, ap); - va_end (ap); - - GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; - dlg = gtk_message_dialog_new (GTK_WINDOW (window), - flags, - type, - GTK_BUTTONS_NONE, - "%s", - prim); - - g_free (prim); - - gtk_window_set_title (GTK_WINDOW (dlg), _ ("gitg")); - - if (secondary) - { - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", - secondary); - } - - GtkWidget *button; - - button = gtk_button_new_from_stock (accept ? GTK_STOCK_CANCEL : GTK_STOCK_OK); - gtk_widget_show (button); - - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - accept ? GTK_RESPONSE_CANCEL : GTK_RESPONSE_ACCEPT); - - if (accept) - { - button = gtk_button_new_with_label (accept); - gtk_widget_show (button); - - GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_OK, - GTK_ICON_SIZE_BUTTON); - gtk_widget_show (image); - - gtk_button_set_image (GTK_BUTTON (button), image); - gtk_dialog_add_action_widget (GTK_DIALOG (dlg), - button, - GTK_RESPONSE_ACCEPT); - } - - gint ret = gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); - - return ret; -} - -static GitgShell * -remove_local_branch (GitgWindow *window, - GitgRef *ref) -{ - gchar const *name = gitg_ref_get_shortname (ref); - GitgRepository *repository = gitg_window_get_repository (window); - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "branch", - "-d", - name, - NULL), - NULL)) - { - gint ret = message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Branch <%s> could not be removed"), - _ ("This usually means that the branch is not fully merged in HEAD. Do you want to forcefully remove the branch?"), - _ ("Force remove"), - name); - - if (ret == GTK_RESPONSE_ACCEPT) - { - if (!gitg_shell_run_sync (gitg_command_new (repository, - "branch", - "-D", - name, - NULL), - NULL)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Branch <%s> could not be forcefully removed"), - NULL, - NULL, - name); - - return NULL; - } - else - { - gitg_repository_reload (repository); - return NULL; - } - } - } - else - { - gitg_repository_reload (repository); - - return NULL; - } - - return NULL; -} - -static void -on_remove_remote_result (GitgWindow *window, GitgProgress progress, gpointer data) -{ - GitgRef *ref = (GitgRef *)data; - - if (progress == GITG_PROGRESS_ERROR) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to remove remote branch <%s>."), - NULL, - NULL, - gitg_ref_get_shortname (ref)); - } - else if (progress == GITG_PROGRESS_SUCCESS) - { - gitg_repository_reload (gitg_window_get_repository (window)); - } - - gitg_ref_free (ref); -} - -static GitgShell * -remove_remote_branch (GitgWindow *window, - GitgRef *ref) -{ - gchar const *name = gitg_ref_get_shortname (ref); - - gint r = message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Are you sure you want to remove the remote branch <%s>?"), - _ ("This permanently removes the remote branch."), - _ ("Remove remote branch"), - name); - - if (r != GTK_RESPONSE_ACCEPT) - { - return NULL; - } - - gchar const *local = gitg_ref_get_local_name (ref); - gchar *rm = g_strconcat (":", local, NULL); - - GitgShell *ret; - gchar *message = g_strdup_printf ("Removing remote branch `%s'", name); - - ret = run_progress (window, - _ ("Remove branch"), - message, - on_remove_remote_result, - gitg_ref_copy (ref), - "push", - gitg_ref_get_prefix (ref), - rm, - NULL); - g_free (message); - - return ret; -} - -static gchar * -get_stash_refspec (GitgRepository *repository, GitgRef *stash) -{ - gchar **out; - gboolean retval; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (repository, - "log", - "--no-color", - "--pretty=oneline", - "-g", - "refs/stash", - NULL), - FALSE, - &out, - NULL); - - gchar **ptr = out; - gchar *sha1 = gitg_hash_hash_to_sha1_new (gitg_ref_get_hash (stash)); - gchar *ret = NULL; - - while (retval && ptr && *ptr) - { - if (g_str_has_prefix (*ptr, sha1)) - { - gchar *start = *ptr + GITG_HASH_SHA_SIZE + 1; - gchar *end = strchr (start, ':'); - - if (end) - { - ret = g_strndup (start, end - start); - } - break; - } - ptr++; - } - - g_strfreev (out); - g_free (sha1); - - return ret; -} - -static GitgShell * -remove_stash (GitgWindow *window, GitgRef *ref) -{ - gint r = message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Are you sure you want to remove this stash item?"), - _ ("This permanently removes the stash item"), - _ ("Remove stash")); - - if (r != GTK_RESPONSE_ACCEPT) - { - return NULL; - } - - GitgRepository *repository = gitg_window_get_repository (window); - gchar *spec = get_stash_refspec (repository, ref); - - if (!spec) - { - return NULL; - } - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "reflog", - "delete", - "--updateref", - "--rewrite", - spec, - NULL), - NULL)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to remove stash"), - _ ("The stash item could not be successfully removed"), - NULL); - } - else - { - if (!gitg_shell_run_sync (gitg_command_new (repository, - "rev-parse", - "--verify", - "refs/stash@{0}", - NULL), - NULL)) - { - gitg_shell_run_sync (gitg_command_new (repository, - "update-ref", - "-d", - "refs/stash", - NULL), - NULL); - } - - gitg_repository_reload (repository); - } - - g_free (spec); - return NULL; -} - -static GitgShell * -remove_tag (GitgWindow *window, GitgRef *ref) -{ - gchar const *name = gitg_ref_get_shortname (ref); - gchar *message = g_strdup_printf (_ ("Are you sure you want to remove the tag <%s>?"), - name); - gint r = message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Remove tag"), - message, - _ ("Remove tag")); - g_free (message); - - if (r != GTK_RESPONSE_ACCEPT) - { - return NULL; - } - - GitgRepository *repository = gitg_window_get_repository (window); - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "tag", - "-d", - name, - NULL), - NULL)) - { - message = g_strdup_printf (_ ("The tag <%s> could not be successfully removed"), - name); - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to remove tag"), - message, - NULL); - g_free (message); - return NULL; - } - else - { - gitg_repository_reload (repository); - return NULL; - } -} - -GitgShell * -gitg_branch_actions_remove (GitgWindow *window, - GitgRef *ref) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (ref != NULL, NULL); - - GitgRef *cp = gitg_ref_copy (ref); - GitgShell *ret = NULL; - - switch (gitg_ref_get_ref_type (cp)) - { - case GITG_REF_TYPE_BRANCH: - ret = remove_local_branch (window, cp); - break; - case GITG_REF_TYPE_REMOTE: - ret = remove_remote_branch (window, cp); - break; - case GITG_REF_TYPE_STASH: - ret = remove_stash (window, cp); - break; - case GITG_REF_TYPE_TAG: - ret = remove_tag (window, cp); - break; - default: - break; - } - - gitg_ref_free (cp); - return ret; -} - -static GitgShell * -rename_branch (GitgWindow *window, - GitgRef *ref, - const gchar *newname) -{ - gchar const *oldname = gitg_ref_get_shortname (ref); - GitgRepository *repository = gitg_window_get_repository (window); - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "branch", - "-m", - oldname, - newname, - NULL), - NULL)) - { - gint ret = message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Branch <%s> could not be renamed to <%s>"), - _ ("This usually means that a branch with that name already exists. Do you want to overwrite the branch?"), - _ ("Force rename"), - oldname, newname); - - if (ret == GTK_RESPONSE_ACCEPT) - { - if (!gitg_shell_run_sync (gitg_command_new (repository, - "branch", - "-M", - oldname, - newname, - NULL), - NULL)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Branch <%s> could not be forcefully renamed"), - NULL, - NULL, - oldname); - - return NULL; - } - else - { - gitg_repository_reload (repository); - return NULL; - } - } - } - else - { - gitg_repository_reload (repository); - - return NULL; - } - - return NULL; -} - -static gchar * -rename_dialog (GitgWindow *window, const gchar *oldname) -{ - GtkWidget *dlg; - - GtkDialogFlags flags = GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; - dlg = gtk_dialog_new_with_buttons ("gitg", - GTK_WINDOW (window), - flags, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - "_Rename", GTK_RESPONSE_OK, - NULL); - - gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK); - - GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); - GtkWidget *label = gtk_label_new (_("Name:")); - GtkWidget *entry = gtk_entry_new (); - - gtk_entry_set_text (GTK_ENTRY (entry), oldname); - gtk_entry_set_width_chars (GTK_ENTRY (entry), 25); - gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); - - gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX (box), entry, TRUE, TRUE, 0); - gtk_widget_show_all (box); - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, TRUE, TRUE, 12); - gint ret = gtk_dialog_run (GTK_DIALOG (dlg)); - - gchar *newname = NULL; - if (ret == GTK_RESPONSE_OK) - { - const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry)); - if (*text != '\0' && strcmp (text, oldname)) - { - newname = g_strdup (text); - } - } - - gtk_widget_destroy (dlg); - - return newname; -} - -GitgShell * -gitg_branch_actions_rename (GitgWindow *window, - GitgRef *ref) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (ref != NULL, NULL); - - if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH) - { - gchar *newname = rename_dialog (window, gitg_ref_get_shortname (ref)); - - if (newname) - { - GitgRef *cp = gitg_ref_copy (ref); - GitgShell *ret = NULL; - ret = rename_branch (window, cp, newname); - gitg_ref_free (cp); - g_free (newname); - return ret; - } - } - - return NULL; -} - -static void -reset_buffer (GitgShell *shell, GString *buffer) -{ - g_string_erase (buffer, 0, -1); -} - -static void -update_buffer (GitgShell *shell, gchar **lines, GString *buffer) -{ - gchar **ptr = lines; - - while (ptr && *ptr) - { - if (buffer->len != 0) - { - g_string_append_c (buffer, '\n'); - } - - g_string_append (buffer, *ptr); - ++ptr; - } -} - -static gboolean -no_changes (GitgRepository *repository) -{ - return gitg_shell_run_sync (gitg_command_new (repository, - "update-index", - "--refresh", - NULL), - NULL) && - gitg_shell_run_sync (gitg_command_new (repository, - "diff-files", - "--no-ext-diff", - "--quiet", - NULL), - NULL) && - gitg_shell_run_sync (gitg_command_new (repository, - "diff-index", - "--no-ext-diff", - "--cached", - "--quiet", - "HEAD", - "--", - NULL), - NULL); -} - -static gboolean -stash_changes_real (GitgWindow *window, gchar **ref, gboolean storeref) -{ - GitgRepository *repository = gitg_window_get_repository (window); - gboolean ret; - gchar *tree = NULL; - gchar *commit = NULL; - gchar *head = NULL; - gchar *msg = NULL; - gboolean showerror = FALSE; - - GitgShell *shell = gitg_shell_new_synchronized (1000); - GString *buffer = g_string_new (""); - - g_signal_connect (shell, "begin", G_CALLBACK (reset_buffer), buffer); - g_signal_connect (shell, "update", G_CALLBACK (update_buffer), buffer); - - gchar const *secondary; - - if (storeref) - { - secondary = _ ("Do you want to temporarily stash these changes?"); - } - else - { - secondary = _ ("Do you want to stash and reapply these changes?"); - } - - gint r = message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("You have uncommited changes in your current working tree"), - secondary, - _ ("Stash changes")); - - if (r != GTK_RESPONSE_ACCEPT) - { - ret = FALSE; - goto cleanup; - } - - gitg_shell_run (shell, - gitg_command_new (repository, - "log", - "--no-color", - "--abbrev-commit", - "--pretty=oneline", - "-n", - "1", - "HEAD", - NULL), - NULL); - - GitgRef *working = gitg_repository_get_current_working_ref (repository); - - if (working) - { - msg = g_strconcat (gitg_ref_get_shortname (working), ": ", buffer->str, NULL); - } - else - { - msg = g_strconcat (" (no branch): ", buffer->str, NULL); - } - - // Create tree object of the current index - gitg_shell_run (shell, - gitg_command_new (repository, - "write-tree", - NULL), - NULL); - - if (buffer->len == 0) - { - ret = FALSE; - showerror = TRUE; - - goto cleanup; - } - - tree = g_strndup (buffer->str, buffer->len); - head = gitg_repository_parse_head (repository); - - gchar *idxmsg = g_strconcat ("index on ", msg, NULL); - - GInputStream *inp = g_memory_input_stream_new_from_data (idxmsg, -1, NULL); - gitg_io_set_input (GITG_IO (shell), inp); - g_object_unref (inp); - - gitg_shell_run (shell, - gitg_command_new (repository, - "commit-tree", - tree, - "-p", - head, - NULL), - NULL); - - g_free (idxmsg); - gitg_io_set_input (GITG_IO (shell), NULL); - - if (buffer->len == 0) - { - ret = FALSE; - showerror = TRUE; - - goto cleanup; - } - - commit = g_strndup (buffer->str, buffer->len); - - // Working tree - gchar *tmpname = NULL; - gint fd = g_file_open_tmp ("gitg-temp-index-XXXXXX", &tmpname, NULL); - - if (fd == -1) - { - ret = FALSE; - showerror = TRUE; - - goto cleanup; - } - - GFile *customindex = g_file_new_for_path (tmpname); - - close (fd); - - GFile *git_dir = gitg_repository_get_git_dir (repository); - GFile *index_ = g_file_get_child (git_dir, "index"); - - gboolean copied = g_file_copy (index_, customindex, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, NULL); - - g_object_unref (index_); - g_object_unref (git_dir); - - if (!copied) - { - g_object_unref (customindex); - - ret = FALSE; - showerror = TRUE; - goto cleanup; - } - - tmpname = g_file_get_path (customindex); - - GitgCommand *cmd_read_tree = gitg_command_new (repository, - "read-tree", - "-m", - tree, - NULL); - - gitg_command_add_environment (cmd_read_tree, - "GIT_INDEX_FILE", - tmpname, - NULL); - - GitgCommand *cmd_add = gitg_command_new (repository, - "add", - "-u", - NULL); - - gitg_command_add_environment (cmd_add, - "GIT_INDEX_FILE", - tmpname, - NULL); - - GitgCommand *cmd_write_tree = gitg_command_new (repository, - "write-tree", - NULL); - - gitg_command_add_environment (cmd_write_tree, - "GIT_INDEX_FILE", - tmpname, - NULL); - - g_free (tmpname); - - gboolean writestash; - - writestash = gitg_shell_run (shell, cmd_read_tree, NULL) && - gitg_shell_run (shell, cmd_add, NULL) && - gitg_shell_run (shell, cmd_write_tree, NULL); - - g_file_delete (customindex, NULL, NULL); - g_object_unref (customindex); - - if (!writestash) - { - ret = FALSE; - showerror = TRUE; - - goto cleanup; - } - - gchar *stashtree = g_strndup (buffer->str, buffer->len); - gchar *reason = g_strconcat ("gitg auto stash: ", msg, NULL); - - inp = g_memory_input_stream_new_from_data (reason, -1, NULL); - gitg_io_set_input (GITG_IO (shell), inp); - g_object_unref (inp); - - gitg_shell_run (shell, - gitg_command_new (repository, - "commit-tree", - stashtree, - "-p", - head, - "-p", - commit, - NULL), - NULL); - - gitg_io_set_input (GITG_IO (shell), NULL); - - g_free (stashtree); - - if (buffer->len == 0) - { - g_free (reason); - - ret = FALSE; - showerror = TRUE; - - goto cleanup; - } - - gchar *rref = g_strndup (buffer->str, buffer->len); - - if (ref) - { - *ref = g_strdup (rref); - } - - git_dir = gitg_repository_get_git_dir (repository); - gchar *git_path = g_file_get_path (git_dir); - - gchar *path = g_build_filename (git_path, - "logs", - "refs", - "stash", - NULL); - - g_object_unref (git_dir); - g_free (git_path); - - GFile *reflog = g_file_new_for_path (path); - GFileOutputStream *stream = g_file_create (reflog, G_FILE_CREATE_NONE, NULL, NULL); - - g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL); - - g_object_unref (stream); - g_object_unref (reflog); - - g_free (path); - - gitg_shell_run (shell, - gitg_command_new (repository, - "update-ref", - "-m", - reason, - "refs/stash", - rref, - NULL), - NULL); - - g_free (rref); - - gitg_shell_run (shell, - gitg_command_new (repository, - "reset", - "--hard", - NULL), - NULL); - - ret = TRUE; - -cleanup: - g_string_free (buffer, TRUE); - g_object_unref (shell); - g_free (commit); - g_free (tree); - g_free (head); - g_free (msg); - - if (showerror) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to save current index state"), - NULL, - NULL); - } - - return ret; -} - -static gboolean -stash_changes (GitgWindow *window, gchar **ref, gboolean storeref) -{ - if (no_changes (gitg_window_get_repository (window))) - { - if (ref) - { - *ref = NULL; - } - - return TRUE; - } - - return stash_changes_real (window, ref, storeref); -} - -static gboolean -checkout_local_branch_real (GitgWindow *window, GitgRef *ref) -{ - GitgRepository *repository = gitg_window_get_repository (window); - - return gitg_shell_run_sync (gitg_command_new (repository, - "checkout", - gitg_ref_get_shortname (ref), - NULL), - NULL); -} - -static gboolean -checkout_local_branch (GitgWindow *window, - GitgRef *ref) -{ - if (!stash_changes (window, NULL, TRUE)) - { - return FALSE; - } - - gchar const *name = gitg_ref_get_shortname (ref); - - if (!checkout_local_branch_real (window, ref)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout local branch <%s>"), - NULL, - NULL, - name); - return FALSE; - } - else - { - gitg_repository_load (gitg_window_get_repository (window), 1, (gchar const **)&name, NULL); - return TRUE; - } -} - -static gboolean -checkout_remote_branch (GitgWindow *window, - GitgRef *ref) -{ - if (!stash_changes (window, NULL, TRUE)) - { - return FALSE; - } - - GitgRepository *repository = gitg_window_get_repository (window); - gchar const *name = gitg_ref_get_shortname (ref); - gchar const *local = gitg_ref_get_local_name (ref); - gboolean ret; - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "checkout", - "--track", - "-b", - local, - name, - NULL), - NULL)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout remote branch <%s> to local branch <%s>"), - NULL, - NULL, - name, - local); - ret = FALSE; - } - else - { - gitg_repository_load (repository, 1, (gchar const **)&local, NULL); - ret = TRUE; - } - - return ret; -} - -static gboolean -checkout_tag (GitgWindow *window, - GitgRef *ref) -{ - if (!stash_changes (window, NULL, TRUE)) - { - return FALSE; - } - - GitgRepository *repository = gitg_window_get_repository (window); - gchar const *name = gitg_ref_get_shortname (ref); - gboolean ret; - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "checkout", - "-b", - name, - name, - NULL), - NULL)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout tag <%s> to local branch <%s>"), - NULL, - NULL, - name, - name); - ret = FALSE; - } - else - { - gitg_repository_load (repository, 1, (gchar const **)&name, NULL); - ret = TRUE; - } - - return ret; -} - -gboolean -gitg_branch_actions_checkout (GitgWindow *window, - GitgRef *ref) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - - GitgRef *cp = gitg_ref_copy (ref); - gboolean ret = FALSE; - - switch (gitg_ref_get_ref_type (cp)) - { - case GITG_REF_TYPE_BRANCH: - ret = checkout_local_branch (window, cp); - break; - case GITG_REF_TYPE_REMOTE: - ret = checkout_remote_branch (window, cp); - break; - case GITG_REF_TYPE_TAG: - ret = checkout_tag (window, cp); - break; - default: - break; - } - - gitg_ref_free (cp); - return ret; -} - -typedef struct -{ - gboolean rebase; - - GitgRef *source; - GitgRef *dest; - - gchar *stashcommit; - GitgRef *head; -} RefInfo; - -static RefInfo * -ref_info_new (GitgRef *source, GitgRef *dest) -{ - RefInfo *ret = g_slice_new0 (RefInfo); - - ret->source = gitg_ref_copy (source); - ret->dest = gitg_ref_copy (dest); - - return ret; -} - -static void -ref_info_free (RefInfo *info) -{ - gitg_ref_free (info->source); - gitg_ref_free (info->dest); - - g_free (info->stashcommit); - gitg_ref_free (info->head); - - g_slice_free (RefInfo, info); -} - -static void -on_merge_rebase_result (GitgWindow *window, - GitgProgress progress, - gpointer data) -{ - RefInfo *info = (RefInfo *)data; - - if (progress == GITG_PROGRESS_ERROR) - { - gchar const *message; - - if (info->rebase) - { - message = _ ("Failed to rebase %s branch <%s> onto %s branch <%s>"); - } - else - { - message = _ ("Failed to merge %s branch <%s> with %s branch <%s>"); - } - - message_dialog (window, - GTK_MESSAGE_ERROR, - message, - NULL, - NULL, - gitg_ref_get_ref_type (info->source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (info->source), - gitg_ref_get_ref_type (info->dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (info->dest)); - } - else if (progress == GITG_PROGRESS_SUCCESS) - { - GitgRepository *repository = gitg_window_get_repository (window); - - // Checkout head - if (!checkout_local_branch_real (window, info->head)) - { - gchar const *message = NULL; - - if (info->stashcommit) - { - gitg_shell_run_sync (gitg_command_new (repository, - "update-ref", - "-m", - "gitg autosave stash", - "refs/stash", - info->stashcommit, - NULL), - NULL); - - message = _ ("The stashed changes have been stored to be reapplied manually"); - } - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout previously checked out branch"), - message, - NULL); - } - else if (info->stashcommit) - { - // Reapply stash - if (!gitg_shell_run_sync (gitg_command_new (gitg_window_get_repository (window), - "stash", - "apply", - "--index", - info->stashcommit, - NULL), - NULL)) - { - gitg_shell_run_sync (gitg_command_new (repository, - "update-ref", - "-m", - "gitg autosave stash", - "refs/stash", - info->stashcommit, - NULL), - NULL); - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to reapply stash correctly"), - _ ("There might be unresolved conflicts in the working tree or index which you need to resolve manually"), - NULL); - } - } - - gitg_repository_reload (gitg_window_get_repository (window)); - } - - ref_info_free (info); -} - -GitgShell * -gitg_branch_actions_merge (GitgWindow *window, - GitgRef *source, - GitgRef *dest) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (dest != NULL, NULL); - g_return_val_if_fail (source != NULL, NULL); - g_return_val_if_fail (gitg_ref_get_ref_type (dest) != GITG_REF_TYPE_REMOTE, NULL); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to merge %s branch <%s> onto %s branch <%s>?"), - gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (source), - gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (dest)); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Merge"), - message, - _ ("Merge")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return NULL; - } - - g_free (message); - GitgRepository *repository = gitg_window_get_repository (window); - gchar *stashcommit = NULL; - - if (!stash_changes (window, &stashcommit, FALSE)) - { - return NULL; - } - - GitgRef *head = gitg_repository_get_current_working_ref (repository); - - // First checkout the correct branch on which to merge, e.g. dest - if (!gitg_shell_run_sync (gitg_command_new (repository, - "checkout", - gitg_ref_get_shortname (dest), - NULL), - NULL)) - { - g_free (stashcommit); - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout local branch <%s>"), - _ ("The branch on which to merge could not be checked out"), - NULL, - gitg_ref_get_shortname (dest)); - return NULL; - } - - message = g_strdup_printf (_ ("Merging %s branch <%s> onto %s branch <%s>"), - gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (source), - gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (dest)); - - GitgShell *ret; - RefInfo *info = ref_info_new (source, dest); - info->stashcommit = stashcommit; - info->head = gitg_ref_copy (head); - info->rebase = FALSE; - - ret = run_progress (window, - _ ("Merge"), - message, - on_merge_rebase_result, - info, - "merge", - gitg_ref_get_shortname (source), - NULL); - - g_free (message); - - return ret; -} - -GitgShell * -gitg_branch_actions_rebase (GitgWindow *window, - GitgRef *source, - GitgRef *dest) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (dest != NULL, NULL); - g_return_val_if_fail (source != NULL, NULL); - g_return_val_if_fail (gitg_ref_get_ref_type (source) != GITG_REF_TYPE_REMOTE, NULL); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to rebase %s branch <%s> onto %s branch <%s>?"), - gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (source), - gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (dest)); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Rebase"), - message, - _ ("Rebase")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return NULL; - } - - g_free (message); - GitgRepository *repository = gitg_window_get_repository (window); - gchar *stashcommit = NULL; - - if (!no_changes (repository)) - { - // Check if destination is current HEAD - gchar *head = gitg_repository_parse_head (repository); - GitgHash hash; - - gitg_hash_sha1_to_hash (head, hash); - g_free (head); - - if (gitg_hash_hash_equal (hash, gitg_ref_get_hash (dest))) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Unable to rebase"), - _ ("There are still uncommitted changes in your working tree and you are trying to rebase a branch onto the currently checked out branch. Either remove, stash or commit your changes first and try again"), - NULL); - return NULL; - } - - if (!stash_changes_real (window, &stashcommit, FALSE)) - { - return NULL; - } - } - - gchar *merge_head = gitg_hash_hash_to_sha1_new (gitg_ref_get_hash (dest)); - - message = g_strdup_printf (_ ("Rebasing %s branch <%s> onto %s branch <%s>"), - gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (source), - gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_BRANCH ? _ ("local") : _ ("remote"), - gitg_ref_get_shortname (dest)); - - GitgShell *ret; - RefInfo *info = ref_info_new (source, dest); - info->stashcommit = stashcommit; - info->head = gitg_ref_copy (gitg_repository_get_current_working_ref (repository)); - info->rebase = TRUE; - - ret = run_progress (window, - _ ("Rebase"), - message, - on_merge_rebase_result, - info, - "rebase", - merge_head, - gitg_ref_get_shortname (source), - NULL); - - g_free (message); - g_free (merge_head); - - return ret; -} - -static void -on_push_result (GitgWindow *window, - GitgProgress progress, - gpointer data) -{ - RefInfo *info = (RefInfo *)data; - - if (progress == GITG_PROGRESS_ERROR) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to push local branch <%s> to remote <%s>"), - _ ("This usually means that the remote branch could not be fast-forwarded. Try fetching the latest changes."), - NULL, - gitg_ref_get_shortname (info->source), - gitg_ref_get_shortname (info->dest)); - } - else if (progress == GITG_PROGRESS_SUCCESS) - { - gitg_repository_reload (gitg_window_get_repository (window)); - } - - ref_info_free (info); -} - -GitgShell * -gitg_branch_actions_push (GitgWindow *window, - GitgRef *source, - GitgRef *dest) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (dest != NULL, NULL); - g_return_val_if_fail (source != NULL, NULL); - g_return_val_if_fail (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH, NULL); - g_return_val_if_fail (gitg_ref_get_ref_type (dest) == GITG_REF_TYPE_REMOTE, NULL); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to push <%s> to <%s>?"), - gitg_ref_get_shortname (source), - gitg_ref_get_shortname (dest)); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Push"), - message, - _ ("Push")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return NULL; - } - - g_free (message); - - gchar const *prefix = gitg_ref_get_prefix (dest); - gchar const *local = gitg_ref_get_local_name (dest); - gchar const *name = gitg_ref_get_shortname (source); - - gchar *spec = g_strconcat (name, ":", local, NULL); - message = g_strdup_printf (_ ("Pushing local branch <%s> to remote branch <%s>"), - gitg_ref_get_shortname (source), - gitg_ref_get_shortname (dest)); - - GitgShell *ret; - RefInfo *info = ref_info_new (source, dest); - - ret = run_progress (window, - _ ("Push"), - message, - on_push_result, - info, - "push", - prefix, - spec, - NULL); - - g_free (message); - g_free (spec); - - return ret; -} - -GitgShell * -gitg_branch_actions_push_remote (GitgWindow *window, - GitgRef *source, - gchar const *remote, - gchar const *branch) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (remote != NULL, NULL); - g_return_val_if_fail (source != NULL, NULL); - g_return_val_if_fail (gitg_ref_get_ref_type (source) == GITG_REF_TYPE_BRANCH, NULL); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to push <%s> to remote <%s/%s>?"), - gitg_ref_get_shortname (source), - remote, branch); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Push"), - message, - _ ("Push")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return NULL; - } - - g_free (message); - - gchar const *name = gitg_ref_get_shortname (source); - gchar *spec = g_strconcat (name, ":", branch, NULL); - message = g_strdup_printf (_ ("Pushing local branch <%s> to remote branch <%s/%s>"), - gitg_ref_get_shortname (source), - remote, branch); - - GitgShell *ret; - gchar *rr = g_strconcat ("refs/remotes/", remote, "/", branch, NULL); - GitgRef *rmref = gitg_ref_new ("0000000000000000000000000000000000000000", rr); - g_free (rr); - - RefInfo *info = ref_info_new (source, rmref); - gitg_ref_free (rmref); - - ret = run_progress (window, - _ ("Push"), - message, - on_push_result, - info, - "push", - remote, - spec, - NULL); - - g_free (message); - g_free (spec); - - return ret; -} - -gboolean -gitg_branch_actions_apply_stash (GitgWindow *window, - GitgRef *stash, - GitgRef *branch) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - g_return_val_if_fail (gitg_ref_get_ref_type (stash) == GITG_REF_TYPE_STASH, FALSE); - g_return_val_if_fail (gitg_ref_get_ref_type (branch) == GITG_REF_TYPE_BRANCH, FALSE); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to apply the stash item to local branch <%s>?"), - gitg_ref_get_shortname (branch)); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Apply stash"), - message, - _ ("Apply stash")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return FALSE; - } - - GitgRepository *repository = gitg_window_get_repository (window); - GitgRef *current = gitg_repository_get_current_working_ref (repository); - - if (!gitg_ref_equal (branch, current)) - { - if (!stash_changes (window, NULL, TRUE)) - { - return FALSE; - } - - if (!checkout_local_branch_real (window, branch)) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout local branch <%s>"), - NULL, - NULL, - gitg_ref_get_shortname (branch)); - return FALSE; - } - } - - gchar *sha1 = gitg_hash_hash_to_sha1_new (gitg_ref_get_hash (stash)); - gboolean ret; - - if (!gitg_shell_run_sync (gitg_command_new (repository, - "stash", - "apply", - "--index", - sha1, - NULL), - NULL)) - { - message = g_strdup_printf (_ ("The stash could not be applied to local branch <%s>"), - gitg_ref_get_shortname (branch)); - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to apply stash"), - message, - NULL); - g_free (message); - ret = FALSE; - - if (!gitg_ref_equal (current, branch) && no_changes (repository)) - { - checkout_local_branch_real (window, current); - } - } - else - { - ret = TRUE; - gitg_repository_reload (repository); - } - - return ret; -} - -gboolean -gitg_branch_actions_create (GitgWindow *window, gchar const *sha1, gchar const *name) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - g_return_val_if_fail (sha1 != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - GitgRepository *repository; - gboolean result = FALSE; - - repository = gitg_window_get_repository (window); - - result = gitg_shell_run_sync (gitg_command_new (repository, - "branch", - name, - sha1, - NULL), - NULL); - - if (!result) - { - gchar const *message; - - message = _ ("The branch could not be successfully created"); - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to create a branch"), - message, - NULL); - return FALSE; - } - else - { - gitg_repository_reload (repository); - return TRUE; - } -} - -gboolean -gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *name, gchar const *message, gboolean sign) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - g_return_val_if_fail (sha1 != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - GitgRepository *repository; - gboolean result = FALSE; - - repository = gitg_window_get_repository (window); - - if (message != NULL && message[0] != '\0') - { - result = gitg_shell_run_sync (gitg_command_new (repository, - "tag", - "-m", - message, - sign ? "-s" : "-a", - name, - sha1, - NULL), - NULL); - } - else - { - result = gitg_shell_run_sync (gitg_command_new (repository, - "tag", - name, - sha1, - NULL), - NULL); - } - - if (!result) - { - gchar const *secondary; - - if (sign) - { - secondary = _ ("The tag object could not be successfully created. Please make sure you have a GPG key and the key is unlocked"); - } - else - { - secondary = _ ("The tag object could not be successfully created"); - } - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to create tag"), - secondary, - NULL); - return FALSE; - } - else - { - gitg_repository_reload (repository); - return TRUE; - } -} - -typedef struct -{ - GitgRevision *revision; - GitgRef *dest; - - gchar *stashcommit; - GitgRef *head; -} CherryPickInfo; - -static CherryPickInfo * -cherry_pick_info_new (GitgRevision *revision, GitgRef *dest) -{ - CherryPickInfo *ret = g_slice_new0 (CherryPickInfo); - - ret->revision = gitg_revision_ref (revision); - ret->dest = gitg_ref_copy (dest); - - return ret; -} - -static void -cherry_pick_info_free (CherryPickInfo *info) -{ - gitg_revision_unref (info->revision); - gitg_ref_free (info->dest); - - g_free (info->stashcommit); - gitg_ref_free (info->head); - - g_slice_free (CherryPickInfo, info); -} - -static void -on_cherry_pick_result (GitgWindow *window, - GitgProgress progress, - gpointer data) -{ - CherryPickInfo *info = (CherryPickInfo *)data; - - if (progress == GITG_PROGRESS_ERROR) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to cherry-pick on <%s>"), - NULL, - NULL, - gitg_ref_get_shortname (info->dest)); - } - else if (progress == GITG_PROGRESS_SUCCESS) - { - GitgRepository *repository = gitg_window_get_repository (window); - - // Checkout head - if (!checkout_local_branch_real (window, info->head)) - { - gchar const *message = NULL; - - if (info->stashcommit) - { - gitg_shell_run_sync (gitg_command_new (repository, - "update-ref", - "-m", - "gitg autosave stash", - "refs/stash", - info->stashcommit, - NULL), - NULL); - - message = _ ("The stashed changes have been stored to be reapplied manually"); - } - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout previously checked out branch"), - message, - NULL); - } - else if (info->stashcommit) - { - // Reapply stash - if (!gitg_shell_run_sync (gitg_command_new (gitg_window_get_repository (window), - "stash", - "apply", - "--index", - info->stashcommit, - NULL), - NULL)) - { - gitg_shell_run_sync (gitg_command_new (repository, - "update-ref", - "-m", - "gitg autosave stash", - "refs/stash", - info->stashcommit, - NULL), - NULL); - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to reapply stash correctly"), - _ ("There might be unresolved conflicts in the working tree or index which you need to resolve manually"), - NULL); - } - } - - gitg_repository_reload (gitg_window_get_repository (window)); - } - - cherry_pick_info_free (info); -} - -GitgShell * -gitg_branch_actions_cherry_pick (GitgWindow *window, - GitgRevision *revision, - GitgRef *dest) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (revision != NULL, NULL); - g_return_val_if_fail (dest != NULL, NULL); - - gchar *message = g_strdup_printf (_ ("Are you sure you want to cherry-pick that revision on <%s>?"), - gitg_ref_get_shortname (dest)); - - if (message_dialog (window, - GTK_MESSAGE_QUESTION, - _ ("Cherry-pick"), - message, - _ ("Cherry-pick")) != GTK_RESPONSE_ACCEPT) - { - g_free (message); - return NULL; - } - - gchar *stashcommit; - - if (!stash_changes (window, &stashcommit, FALSE)) - { - return NULL; - } - - GitgRepository *repository = gitg_window_get_repository (window); - GitgRef *head = gitg_repository_get_current_working_ref (repository); - - // First checkout the correct branch on which to cherry-pick - if (!gitg_shell_run_sync (gitg_command_new (repository, - "checkout", - gitg_ref_get_shortname (dest), - NULL), - NULL)) - { - g_free (stashcommit); - - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to checkout local branch <%s>"), - _ ("The branch on which to cherry-pick could not be checked out"), - NULL, - gitg_ref_get_shortname (dest)); - - return NULL; - } - - message = g_strdup_printf (_ ("Cherry-picking on <%s>"), - gitg_ref_get_shortname (dest)); - - GitgShell *ret; - - CherryPickInfo *info = cherry_pick_info_new (revision, dest); - - info->stashcommit = stashcommit; - info->head = gitg_ref_copy (head); - - gchar *sha1 = gitg_revision_get_sha1 (revision); - - ret = run_progress (window, - _ ("Cherry-pick"), - message, - on_cherry_pick_result, - info, - "cherry-pick", - sha1, - NULL); - - g_free (message); - g_free (sha1); - - return ret; -} - -typedef struct -{ - GitgRevision *revision; - gchar *destination; - GOutputStream *stream; -} FormatPatchInfo; - -static FormatPatchInfo * -format_patch_info_new (GitgRevision *revision, gchar const *destination, GOutputStream *stream) -{ - FormatPatchInfo *ret = g_slice_new0 (FormatPatchInfo); - - ret->revision = gitg_revision_ref (revision); - ret->destination = g_strdup (destination); - ret->stream = stream; - - return ret; -} - -static void -format_patch_info_free (FormatPatchInfo *info) -{ - gitg_revision_unref (info->revision); - g_free (info->destination); - - g_object_unref (info->stream); - - g_slice_free (FormatPatchInfo, info); -} - -static void -on_format_patch_result (GitgWindow *window, - GitgProgress progress, - gpointer data) -{ - FormatPatchInfo *info = (FormatPatchInfo *)data; - - if (progress == GITG_PROGRESS_ERROR) - { - message_dialog (window, - GTK_MESSAGE_ERROR, - _ ("Failed to generate format-patch"), - NULL, - NULL, - NULL); - } - - format_patch_info_free (info); -} - -static void -on_format_patch_update (GitgShell *shell, - gchar **lines, - FormatPatchInfo *info) -{ - while (lines && *lines) - { - g_output_stream_write_all (info->stream, *lines, strlen (*lines), NULL, NULL, NULL); - g_output_stream_write_all (info->stream, "\n", 1, NULL, NULL, NULL); - ++lines; - } -} - -GitgShell * -gitg_branch_actions_format_patch (GitgWindow *window, - GitgRevision *revision, - gchar const *destination) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), NULL); - g_return_val_if_fail (revision != NULL, NULL); - g_return_val_if_fail (destination != NULL, NULL); - - GitgShell *ret; - - GFile *file = g_file_new_for_uri (destination); - GFileOutputStream *stream = g_file_replace (file, - NULL, - FALSE, - G_FILE_CREATE_REPLACE_DESTINATION, - NULL, - NULL); - g_object_unref (file); - - if (!stream) - { - return NULL; - } - - gchar *sha1 = gitg_revision_get_sha1 (revision); - gchar *message; - - message = g_strdup_printf (_ ("Generating format-patch for <%s>"), - gitg_revision_get_subject (revision)); - - FormatPatchInfo *info = format_patch_info_new (revision, - destination, - G_OUTPUT_STREAM (stream)); - - ret = run_progress (window, - _ ("Format patch"), - message, - on_format_patch_result, - info, - "format-patch", - "-1", - "--stdout", - sha1, - NULL); - - if (ret) - { - g_signal_connect (ret, "update", G_CALLBACK (on_format_patch_update), info); - } - - g_free (sha1); - g_free (message); - - return ret; -} diff --git a/gitg/gitg-branch-actions.h b/gitg/gitg-branch-actions.h deleted file mode 100644 index 88fac6ab..00000000 --- a/gitg/gitg-branch-actions.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * gitg-branch-actions.h - * This file is part of gitg - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_BRANCH_ACTIONS_H__ -#define __GITG_BRANCH_ACTIONS_H__ - -#include -#include - -G_BEGIN_DECLS - -gboolean gitg_branch_actions_create (GitgWindow *window, gchar const *sha1, gchar const *name); -GitgShell *gitg_branch_actions_remove (GitgWindow *window, GitgRef *ref); -GitgShell *gitg_branch_actions_rename (GitgWindow *window, GitgRef *ref); -gboolean gitg_branch_actions_checkout (GitgWindow *window, GitgRef *ref); - -GitgShell *gitg_branch_actions_merge (GitgWindow *window, GitgRef *source, GitgRef *dest); -GitgShell *gitg_branch_actions_rebase (GitgWindow *window, GitgRef *source, GitgRef *dest); - -GitgShell *gitg_branch_actions_push (GitgWindow *window, GitgRef *source, GitgRef *dest); -GitgShell *gitg_branch_actions_push_remote (GitgWindow *window, GitgRef *source, gchar const *remote, gchar const *branch); - -gboolean gitg_branch_actions_apply_stash (GitgWindow *window, GitgRef *stash, GitgRef *branch); - -gboolean gitg_branch_actions_tag (GitgWindow *window, gchar const *sha1, gchar const *name, gchar const *message, gboolean sign); - -GitgShell *gitg_branch_actions_cherry_pick (GitgWindow *window, GitgRevision *revision, GitgRef *dest); - -GitgShell *gitg_branch_actions_format_patch (GitgWindow *window, GitgRevision *revision, gchar const *destination); - -G_END_DECLS - -#endif /* __GITG_BRANCH_ACTIONS_H__ */ - diff --git a/gitg/gitg-cell-renderer-path.c b/gitg/gitg-cell-renderer-path.c deleted file mode 100644 index 97902ee8..00000000 --- a/gitg/gitg-cell-renderer-path.c +++ /dev/null @@ -1,639 +0,0 @@ -/* - * gitg-cell-renderer-path.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include - -#include "gitg-cell-renderer-path.h" -#include "gitg-label-renderer.h" - -#define GITG_CELL_RENDERER_PATH_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_CELL_RENDERER_PATH, GitgCellRendererPathPrivate)) - -#define DEFAULT_DOT_WIDTH 10 -#define DEFAULT_TRIANGLE_WIDTH 8 - -#define DEFAULT_LANE_WIDTH (DEFAULT_DOT_WIDTH + 6) - -/* Properties */ -enum -{ - PROP_0, - - PROP_REVISION, - PROP_NEXT_REVISION, - PROP_LANE_WIDTH, - PROP_DOT_WIDTH, - PROP_TRIANGLE_WIDTH, - PROP_LABELS -}; - -struct _GitgCellRendererPathPrivate -{ - GitgRevision *revision; - GitgRevision *next_revision; - GSList *labels; - guint lane_width; - guint triangle_width; - guint dot_width; - - gint last_height; -}; - -static GtkCellRendererTextClass *parent_class = NULL; - -G_DEFINE_TYPE (GitgCellRendererPath, gitg_cell_renderer_path, GTK_TYPE_CELL_RENDERER_TEXT) - -static gint -num_lanes (GitgCellRendererPath *self) -{ - return g_slist_length (gitg_revision_get_lanes (self->priv->revision)); -} - -static gboolean -is_dummy (GitgRevision *revision) -{ - switch (gitg_revision_get_sign (revision)) - { - case 's': - case 't': - case 'u': - return TRUE; - default: - return FALSE; - } -} - -static gint -total_width (GitgCellRendererPath *self, - GtkWidget *widget) -{ - PangoFontDescription *font; - g_object_get (self, "font-desc", &font, NULL); - - gint offset = 0; - - if (is_dummy (self->priv->revision)) - { - offset = self->priv->lane_width; - } - - return num_lanes (self) * self->priv->lane_width + - gitg_label_renderer_width (widget, font, self->priv->labels) + - offset; -} - -static void -gitg_cell_renderer_path_finalize (GObject *object) -{ - GitgCellRendererPath *self = GITG_CELL_RENDERER_PATH (object); - - gitg_revision_unref (self->priv->revision); - gitg_revision_unref (self->priv->next_revision); - - g_slist_free (self->priv->labels); - - G_OBJECT_CLASS (gitg_cell_renderer_path_parent_class)->finalize (object); -} - -static void -renderer_get_size (GtkCellRenderer *renderer, - GtkWidget *widget, - const GdkRectangle *area, - gint *xoffset, - gint *yoffset, - gint *width, - gint *height) -{ - GitgCellRendererPath *self = GITG_CELL_RENDERER_PATH (renderer); - - if (xoffset) - { - *xoffset = 0; - } - - if (yoffset) - { - *yoffset = 0; - } - - if (width) - { - *width = total_width (self, widget); - } - - if (height) - { - *height = area ? area->height : 1; - } -} - -static void -draw_arrow (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area, - gint8 laneidx, - gboolean top) -{ - gdouble cw = self->priv->lane_width; - gdouble xpos = area->x + laneidx * cw + cw / 2.0; - gdouble df = (top ? -1 : 1) * 0.25 * area->height; - gdouble ypos = area->y + area->height / 2.0 + df; - gdouble q = cw / 4.0; - - cairo_move_to (cr, xpos - q, ypos + (top ? q : -q)); - cairo_line_to (cr, xpos, ypos); - cairo_line_to (cr, xpos + q, ypos + (top ? q : -q)); - cairo_stroke (cr); - - cairo_move_to (cr, xpos, ypos); - cairo_line_to (cr, xpos, ypos - df); - cairo_stroke (cr); - - //cairo_move_to (cr, xpos, ypos); - //cairo_line_to (cr, xpos, ypos + (top ? 1 : -1) * area->height / 2.0); - //cairo_stroke (cr); -} - -static void -draw_paths_real (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area, - GitgRevision *revision, - gdouble yoffset) -{ - if (!revision) - { - return; - } - - GSList *lanes = gitg_revision_get_lanes (revision); - gint8 to = 0; - gdouble cw = self->priv->lane_width; - gdouble ch = area->height / 2.0; - GitgLane *lane; - - while (lanes) - { - GSList *item; - - lane = (GitgLane *) (lanes->data); - gitg_color_set_cairo_source (lane->color, cr); - - for (item = lane->from; item; item = item->next) - { - gint8 from = (gint8)GPOINTER_TO_INT (item->data); - - cairo_move_to (cr, area->x + from * cw + cw / 2.0, - area->y + yoffset * ch); - - cairo_curve_to (cr, area->x + from * cw + cw / 2.0, - area->y + (yoffset + 1) * ch, - area->x + to * cw + cw / 2.0, area->y + (yoffset + 1) * ch, - area->x + to * cw + cw / 2.0, area->y + (yoffset + 2) * ch); - - cairo_stroke (cr); - } - - ++to; - lanes = lanes->next; - } -} - -static void -draw_top_paths (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area) -{ - draw_paths_real (self, cr, area, self->priv->revision, -1); -} - -static void -draw_bottom_paths (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area) -{ - draw_paths_real (self, cr, area, self->priv->next_revision, 1); -} - -static void -draw_arrows (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area) -{ - GSList *item; - gint8 to = 0; - - for (item = gitg_revision_get_lanes (self->priv->revision); item; item = item->next) - { - GitgLane *lane = (GitgLane *)item->data; - gitg_color_set_cairo_source (lane->color, cr); - - if (lane->type & GITG_LANE_TYPE_START) - { - draw_arrow (self, cr, area, to, TRUE); - } - else if (lane->type & GITG_LANE_TYPE_END) - { - draw_arrow (self, cr, area, to, FALSE); - } - - ++to; - } -} - -static void -draw_paths (GitgCellRendererPath *self, - cairo_t *cr, - const GdkRectangle *area) -{ - cairo_set_line_width (cr, 2); - //cairo_set_source_rgb (cr, 0.45, 0.6, 0.74); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - - draw_top_paths (self, cr, area); - draw_bottom_paths (self, cr, area); - draw_arrows (self, cr, area); -} - -static void -draw_labels (GitgCellRendererPath *self, - GtkWidget *widget, - cairo_t *context, - const GdkRectangle *area) -{ - gint offset = num_lanes (self) * self->priv->lane_width; - PangoFontDescription *font; - - if (is_dummy (self->priv->revision)) - { - offset += self->priv->lane_width; - } - - g_object_get (self, "font-desc", &font, NULL); - - cairo_translate (context, offset, 0.0); - gitg_label_renderer_draw (widget, font, context, self->priv->labels, area); -} - -static void -draw_indicator_triangle (GitgCellRendererPath *self, - GitgLane *lane, - cairo_t *context, - const GdkRectangle *area) -{ - gdouble offset = gitg_revision_get_mylane (self->priv->revision) * self->priv->lane_width + (self->priv->lane_width - self->priv->triangle_width) / 2.0; - gdouble radius = self->priv->triangle_width / 2.0; - gdouble xs; - int xd; - - if (lane->type & GITG_LANE_SIGN_LEFT) - { - xs = radius; - xd = -1; - } - else - { - xs = -radius; - xd = 1; - } - - cairo_set_line_width (context, 2.0); - - cairo_move_to (context, - area->x + offset + radius + xs, - area->y + (area->height - self->priv->triangle_width) / 2); - - cairo_rel_line_to (context, 0, self->priv->triangle_width); - cairo_rel_line_to (context, - xd * self->priv->triangle_width, - -self->priv->triangle_width / 2); - - cairo_close_path (context); - - cairo_set_source_rgb (context, 0, 0, 0); - cairo_stroke_preserve (context); - - gitg_color_set_cairo_source (lane->color, context); - cairo_fill (context); -} - -static void -draw_indicator_circle (GitgCellRendererPath *self, - GitgLane *lane, - cairo_t *context, - const GdkRectangle *area) -{ - gdouble offset = gitg_revision_get_mylane (self->priv->revision) * self->priv->lane_width + (self->priv->lane_width - self->priv->dot_width) / 2.0; - gdouble radius = self->priv->dot_width / 2.0; - - if (is_dummy (self->priv->revision)) - { - offset += self->priv->lane_width; - } - - cairo_set_line_width (context, 2.0); - cairo_arc (context, area->x + offset + radius, area->y + area->height / 2.0, radius, 0, 2 * M_PI); - cairo_set_source_rgb (context, 0, 0, 0); - - if (is_dummy (self->priv->revision)) - { - cairo_stroke (context); - } - else - { - cairo_stroke_preserve (context); - gitg_color_set_cairo_source (lane->color, context); - - cairo_fill (context); - } -} - -static void -draw_indicator (GitgCellRendererPath *self, - cairo_t *context, - const GdkRectangle *area) -{ - GitgLane *lane = gitg_revision_get_lane (self->priv->revision); - - if (lane->type & GITG_LANE_SIGN_LEFT || lane->type & GITG_LANE_SIGN_RIGHT) - { - draw_indicator_triangle (self, lane, context, area); - } - else - { - draw_indicator_circle (self, lane, context, area); - } -} - -static void -renderer_render (GtkCellRenderer *renderer, - cairo_t *cr, - GtkWidget *widget, - const GdkRectangle *area, - const GdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GitgCellRendererPath *self; - GdkRectangle narea; - GdkRectangle ncell_area; - - self = GITG_CELL_RENDERER_PATH (renderer); - - self->priv->last_height = area->height; - - cairo_save (cr); - - gdk_cairo_rectangle (cr, area); - cairo_clip (cr); - - draw_paths (self, cr, area); - - /* draw indicator */ - draw_indicator (self, cr, area); - - /* draw labels */ - draw_labels (self, widget, cr, area); - - narea = *area; - ncell_area = *cell_area; - - narea.x += total_width (self, widget); - ncell_area.x += total_width (self, widget); - - cairo_restore (cr); - - if (GTK_CELL_RENDERER_CLASS (parent_class)->render) - { - GTK_CELL_RENDERER_CLASS (parent_class)->render (renderer, - cr, - widget, - &narea, - &ncell_area, - flags); - } -} - -static void -gitg_cell_renderer_path_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgCellRendererPath *self = GITG_CELL_RENDERER_PATH (object); - - switch (prop_id) - { - case PROP_REVISION: - g_value_set_boxed (value, self->priv->revision); - break; - case PROP_NEXT_REVISION: - g_value_set_boxed (value, self->priv->next_revision); - break; - case PROP_LANE_WIDTH: - g_value_set_uint (value, self->priv->lane_width); - break; - case PROP_DOT_WIDTH: - g_value_set_uint (value, self->priv->dot_width); - break; - case PROP_TRIANGLE_WIDTH: - g_value_set_uint (value, self->priv->triangle_width); - break; - case PROP_LABELS: - g_value_set_pointer (value, self->priv->labels); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_cell_renderer_path_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgCellRendererPath *self = GITG_CELL_RENDERER_PATH (object); - - switch (prop_id) - { - case PROP_REVISION: - gitg_revision_unref (self->priv->revision); - self->priv->revision = g_value_dup_boxed (value); - break; - case PROP_NEXT_REVISION: - gitg_revision_unref (self->priv->next_revision); - self->priv->next_revision = g_value_dup_boxed (value); - break; - case PROP_LANE_WIDTH: - self->priv->lane_width = g_value_get_uint (value); - break; - case PROP_DOT_WIDTH: - self->priv->dot_width = g_value_get_uint (value); - break; - case PROP_TRIANGLE_WIDTH: - self->priv->triangle_width = g_value_get_uint (value); - break; - case PROP_LABELS: - g_slist_free (self->priv->labels); - self->priv->labels = (GSList *)g_value_get_pointer (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_cell_renderer_path_class_init (GitgCellRendererPathClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkCellRendererClass *renderer_class = GTK_CELL_RENDERER_CLASS (klass); - - object_class->finalize = gitg_cell_renderer_path_finalize; - object_class->get_property = gitg_cell_renderer_path_get_property; - object_class->set_property = gitg_cell_renderer_path_set_property; - - renderer_class->get_size = renderer_get_size; - renderer_class->render = renderer_render; - - parent_class = g_type_class_peek_parent (klass); - - g_object_class_install_property (object_class, - PROP_REVISION, - g_param_spec_boxed ("revision", - "REVISION", - "The revision", - GITG_TYPE_REVISION, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_NEXT_REVISION, - g_param_spec_boxed ("next-revision", - "NEXT_REVISION", - "The next revision", - GITG_TYPE_REVISION, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_LANE_WIDTH, - g_param_spec_uint ("lane-width", - "LANE WIDTH", - "The lane width", - 0, - G_MAXUINT, - DEFAULT_LANE_WIDTH, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_DOT_WIDTH, - g_param_spec_uint ("dot-width", - "DOT WIDTH", - "The dot width", - 0, - G_MAXUINT, - DEFAULT_DOT_WIDTH, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_TRIANGLE_WIDTH, - g_param_spec_uint ("triangle-width", - "TRIANGLE WIDTH", - "The triangle width", - 0, - G_MAXUINT, - DEFAULT_TRIANGLE_WIDTH, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_LABELS, - g_param_spec_pointer ("labels", - "LABELS", - "Labels", - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GitgCellRendererPathPrivate)); -} - -static void -gitg_cell_renderer_path_init (GitgCellRendererPath *self) -{ - self->priv = GITG_CELL_RENDERER_PATH_GET_PRIVATE (self); - - self->priv->lane_width = DEFAULT_LANE_WIDTH; - self->priv->dot_width = DEFAULT_DOT_WIDTH; - self->priv->triangle_width = DEFAULT_TRIANGLE_WIDTH; -} - -GtkCellRenderer * -gitg_cell_renderer_path_new () -{ - return GTK_CELL_RENDERER (g_object_new (GITG_TYPE_CELL_RENDERER_PATH, NULL)); -} - -GitgRef * -gitg_cell_renderer_path_get_ref_at_pos (GtkWidget *widget, - GitgCellRendererPath *renderer, - gint x, - gint *hot_x) -{ - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GITG_IS_CELL_RENDERER_PATH (renderer), NULL); - - PangoFontDescription *font; - g_object_get (renderer, "font-desc", &font, NULL); - - gint offset = 0; - - if (is_dummy (renderer->priv->revision)) - { - offset = renderer->priv->lane_width; - } - - x -= num_lanes (renderer) * renderer->priv->lane_width + offset; - - return gitg_label_renderer_get_ref_at_pos (widget, - font, - renderer->priv->labels, - x, - hot_x); -} - -GdkPixbuf * -gitg_cell_renderer_path_render_ref (GtkWidget *widget, - GitgCellRendererPath *renderer, - GitgRef *ref, - gint minwidth) -{ - g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); - g_return_val_if_fail (GITG_IS_CELL_RENDERER_PATH (renderer), NULL); - - PangoFontDescription *font; - g_object_get (renderer, "font-desc", &font, NULL); - - return gitg_label_renderer_render_ref (widget, - font, - ref, - renderer->priv->last_height, - minwidth); -} diff --git a/gitg/gitg-cell-renderer-path.h b/gitg/gitg-cell-renderer-path.h deleted file mode 100644 index 8ab7c99c..00000000 --- a/gitg/gitg-cell-renderer-path.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * gitg-cell-renderer-path.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_CELL_RENDERER_PATH_H__ -#define __GITG_CELL_RENDERER_PATH_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_CELL_RENDERER_PATH (gitg_cell_renderer_path_get_type ()) -#define GITG_CELL_RENDERER_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CELL_RENDERER_PATH, GitgCellRendererPath)) -#define GITG_CELL_RENDERER_PATH_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CELL_RENDERER_PATH, GitgCellRendererPath const)) -#define GITG_CELL_RENDERER_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_CELL_RENDERER_PATH, GitgCellRendererPathClass)) -#define GITG_IS_CELL_RENDERER_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_CELL_RENDERER_PATH)) -#define GITG_IS_CELL_RENDERER_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_CELL_RENDERER_PATH)) -#define GITG_CELL_RENDERER_PATH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_CELL_RENDERER_PATH, GitgCellRendererPathClass)) - -typedef struct _GitgCellRendererPath GitgCellRendererPath; -typedef struct _GitgCellRendererPathClass GitgCellRendererPathClass; -typedef struct _GitgCellRendererPathPrivate GitgCellRendererPathPrivate; - -struct _GitgCellRendererPath -{ - GtkCellRendererText parent; - - GitgCellRendererPathPrivate *priv; -}; - -struct _GitgCellRendererPathClass -{ - GtkCellRendererTextClass parent_class; -}; - -GType gitg_cell_renderer_path_get_type (void) G_GNUC_CONST; -GtkCellRenderer *gitg_cell_renderer_path_new (void); - -GitgRef *gitg_cell_renderer_path_get_ref_at_pos (GtkWidget *widget, - GitgCellRendererPath *renderer, - gint x, - gint *hot_x); -GdkPixbuf *gitg_cell_renderer_path_render_ref (GtkWidget *widget, - GitgCellRendererPath *renderer, - GitgRef *ref, - gint minwidth); - -G_END_DECLS - -#endif /* __GITG_CELL_RENDERER_PATH_H__ */ diff --git a/gitg/gitg-commit-menu.ui b/gitg/gitg-commit-menu.ui deleted file mode 100644 index 90ad8e80..00000000 --- a/gitg/gitg-commit-menu.ui +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - Stage - - - - - Unstage - - - - - Revert - - - - - Ignore - - - - - gtk-edit - - - - - gtk-delete - - - - - - - - - - - - - - - - - - - - - diff --git a/gitg/gitg-commit-view.c b/gitg/gitg-commit-view.c deleted file mode 100644 index bda199e5..00000000 --- a/gitg/gitg-commit-view.c +++ /dev/null @@ -1,3216 +0,0 @@ -/* - * gitg-commit-view.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "gitg-commit-view.h" -#include "gitg-diff-view.h" -#include "gitg-utils.h" - -#define GITG_COMMIT_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GITG_TYPE_COMMIT_VIEW, GitgCommitViewPrivate)) - -#define CATEGORY_UNSTAGE_HUNK "CategoryUnstageHunk" -#define CATEGORY_STAGE_HUNK "CategoryStageHunk" - -/* Properties */ -enum -{ - PROP_0, - PROP_REPOSITORY, - PROP_CONTEXT_SIZE -}; - -enum -{ - COLUMN_NAME = 0, - COLUMN_FILE, - N_COLUMNS -}; - -typedef enum -{ - CONTEXT_TYPE_FILE, - CONTEXT_TYPE_HUNK -} ContextType; - -struct _GitgCommitViewPrivate -{ - GitgCommit *commit; - GitgRepository *repository; - - GtkListStore *store_unstaged; - GtkListStore *store_staged; - - GtkTreeView *tree_view_staged; - GtkTreeView *tree_view_unstaged; - - GtkSourceView *changes_view; - GtkTextView *comment_view; - GtkSourceGutterRenderer *pixbuf_renderer; - GtkCheckButton *check_button_signed_off_by; - GtkCheckButton *check_button_amend; - - GtkHScale *hscale_context; - gint context_size; - - GitgShell *shell; - guint update_id; - gboolean is_diff; - - GdkCursor *hand; - GitgChangedFile *current_file; - GitgChangedFileChanges current_changes; - - GtkUIManager *ui_manager; - ContextType context_type; - GtkTextIter context_iter; - - GtkActionGroup *group_context; - GtkTextMark *highlight_mark; - GtkTextTag *highlight_tag; - - GSettings *message_settings; - GSettings *diff_settings; -}; - -static void gitg_commit_view_buildable_iface_init (GtkBuildableIface *iface); - -G_DEFINE_TYPE_EXTENDED (GitgCommitView, gitg_commit_view, GTK_TYPE_VPANED, 0, - G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gitg_commit_view_buildable_iface_init)); - -static GtkBuildableIface parent_iface; - -static void on_commit_file_inserted (GitgCommit *commit, - GitgChangedFile *file, - GitgCommitView *view); -static void on_commit_file_removed (GitgCommit *commit, - GitgChangedFile *file, - GitgCommitView *view); - -static void on_staged_button_press (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view); -static void on_unstaged_button_press (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view); -static gboolean on_staged_unstaged_button_press_before (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view); -static void on_unstaged_tree_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GitgCommitView *view); -static void on_staged_tree_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GitgCommitView *view); - -static gboolean popup_unstaged_menu (GitgCommitView *view, - GdkEventButton *event); -static gboolean popup_staged_menu (GitgCommitView *view, - GdkEventButton *event); - -static gboolean on_staged_popup_menu (GtkWidget *widget, - GitgCommitView *view); -static gboolean on_unstaged_popup_menu (GtkWidget *widget, - GitgCommitView *view); - -static gboolean on_staged_motion (GtkWidget *widget, - GdkEventMotion *event, - GitgCommitView *view); -static gboolean on_unstaged_motion (GtkWidget *widget, - GdkEventMotion *event, - GitgCommitView *view); - -static void on_commit_clicked (GtkButton *button, - GitgCommitView *view); -static void on_context_value_changed (GtkHScale *scale, - GitgCommitView *view); - -static void on_changes_view_popup_menu (GtkTextView *textview, - GtkMenu *menu, - GitgCommitView *view); - -static void on_stage_changes (GtkAction *action, - GitgCommitView *view); -static void on_revert_changes (GtkAction *action, - GitgCommitView *view); -static void on_ignore_file (GtkAction *action, - GitgCommitView *view); -static void on_unstage_changes (GtkAction *action, - GitgCommitView *view); -static void on_edit_file (GtkAction *action, - GitgCommitView *view); -static void on_delete_file (GtkAction *action, - GitgCommitView *view); - -static void on_check_button_amend_toggled (GtkToggleButton *button, - GitgCommitView *view); - -static void pixbuf_renderer_query_data_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state, - GitgCommitView *view); -static gboolean pixbuf_renderer_query_activatable_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *iter, - GdkRectangle *area, - GdkEvent *event, - GitgCommitView *view); -static void pixbuf_renderer_activate_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *iter, - GdkRectangle *area, - GdkEvent *event, - GitgCommitView *view); - -static void -gitg_commit_view_finalize (GObject *object) -{ - GitgCommitView *view = GITG_COMMIT_VIEW (object); - - if (view->priv->update_id) - { - g_signal_handler_disconnect (view->priv->shell, view->priv->update_id); - } - - gitg_io_cancel (GITG_IO (view->priv->shell)); - g_object_unref (view->priv->shell); - g_object_unref (view->priv->ui_manager); - - g_object_unref (view->priv->hand); - - G_OBJECT_CLASS (gitg_commit_view_parent_class)->finalize (object); -} - -static void -icon_data_func (GtkTreeViewColumn *column, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgCommitView *view) -{ - GitgChangedFile *file; - - gtk_tree_model_get (model, iter, COLUMN_FILE, &file, -1); - GitgChangedFileStatus status = gitg_changed_file_get_status (file); - - gboolean staged = (model == GTK_TREE_MODEL (view->priv->store_staged)); - - switch (status) - { - case GITG_CHANGED_FILE_STATUS_NEW: - g_object_set (renderer, - "stock-id", - staged ? GTK_STOCK_ADD : GTK_STOCK_NEW, - NULL); - break; - case GITG_CHANGED_FILE_STATUS_MODIFIED: - g_object_set (renderer, - "stock-id", - staged ? GTK_STOCK_APPLY : GTK_STOCK_EDIT, - NULL); - break; - case GITG_CHANGED_FILE_STATUS_DELETED: - g_object_set (renderer, - "stock-id", - staged ? GTK_STOCK_REMOVE : GTK_STOCK_DELETE, - NULL); - break; - default: - break; - } - - g_object_unref (file); -} - -static void -set_icon_data_func (GitgCommitView *view, - GtkTreeView *treeview, - GtkCellRenderer *renderer) -{ - GtkTreeViewColumn *column = gtk_tree_view_get_column (treeview, 0); - - gtk_tree_view_column_set_cell_data_func (column, - renderer, - (GtkTreeCellDataFunc)icon_data_func, - view, - NULL); -} - -static void -set_language (GitgCommitView *view, - GtkSourceLanguage *language) -{ - GtkTextView *text_view; - GtkSourceBuffer *buffer; - - text_view = GTK_TEXT_VIEW (view->priv->changes_view); - buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (text_view)); - - gtk_source_buffer_set_language (buffer, language); - gitg_diff_view_set_diff_enabled (GITG_DIFF_VIEW (view->priv->changes_view), - FALSE); -} - -static void -set_diff_language (GitgCommitView *view) -{ - GtkSourceLanguageManager *manager = gtk_source_language_manager_get_default (); - GtkSourceLanguage *language = gtk_source_language_manager_get_language (manager, "gitgdiff"); - - set_language (view, language); - gitg_diff_view_set_diff_enabled (GITG_DIFF_VIEW (view->priv->changes_view), TRUE); - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), TRUE); -} - -static void -show_binary_information (GitgCommitView *view) -{ - set_language (view, NULL); - - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), FALSE); - - gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view)), - _("Cannot display file content as text"), - -1); -} - -static void -on_changes_update (GitgShell *shell, - gchar **buffer, - GitgCommitView *view) -{ - gchar *line; - GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view)); - GtkTextIter iter; - - gtk_text_buffer_get_end_iter (buf, &iter); - - while ((line = *(buffer++))) - { - if (view->priv->is_diff && g_str_has_prefix (line, "@@")) - { - if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED) - { - gtk_source_buffer_create_source_mark (GTK_SOURCE_BUFFER (buf), - NULL, - CATEGORY_STAGE_HUNK, - &iter); - } - else - { - gtk_source_buffer_create_source_mark (GTK_SOURCE_BUFFER (buf), - NULL, - CATEGORY_UNSTAGE_HUNK, - &iter); - } - } - - gtk_text_buffer_insert (buf, &iter, line, -1); - } - - if (gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buf)) == NULL) - { - gchar *content_type = gitg_utils_guess_content_type (GTK_TEXT_BUFFER (buf)); - - if (content_type && !gitg_utils_can_display_content_type (content_type)) - { - gitg_io_cancel (GITG_IO (shell)); - show_binary_information (view); - } - else if (content_type) - { - GtkSourceLanguage *language = gitg_utils_get_language (NULL, content_type); - set_language (view, language); - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), FALSE); - } - - g_free (content_type); - } - - while (gtk_events_pending ()) - { - gtk_main_iteration (); - } -} - -static void -connect_update (GitgCommitView *view) -{ - view->priv->update_id = g_signal_connect (view->priv->shell, - "update", - G_CALLBACK (on_changes_update), - view); -} - -static void -set_current_file (GitgCommitView *view, - GitgChangedFile *file, - GitgChangedFileChanges changes) -{ - if (view->priv->current_file != NULL) - { - g_object_unref (view->priv->current_file); - } - - view->priv->current_file = file ? g_object_ref (file) : NULL; - view->priv->current_changes = changes; -} - -static gboolean -get_selected_files (GtkTreeView *tree_view, - GList **files, - GList **paths, - GitgChangedFileChanges *changes, - GitgChangedFileStatus *status) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view); - - if (files == NULL && changes == NULL && status == NULL && paths == NULL) - { - return gtk_tree_selection_count_selected_rows (selection) != 0; - } - - GtkTreeModel *model; - GList *items = gtk_tree_selection_get_selected_rows (selection, &model); - - if (files) - { - *files = NULL; - } - - if (paths) - { - *paths = NULL; - } - - if (!items) - { - return FALSE; - } - - if (changes) - { - *changes = ~0; - } - - if (status) - { - *status = -1; - } - - GList *item; - GitgChangedFile *file; - - for (item = items; item; item = g_list_next (item)) - { - GtkTreeIter iter; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)item->data); - gtk_tree_model_get (model, &iter, COLUMN_FILE, &file, -1); - - if (changes) - { - *changes &= gitg_changed_file_get_status (file); - } - - GitgChangedFileStatus s = gitg_changed_file_get_status (file); - - if (status) - { - if (*status != -1 && *status != s) - { - *status = GITG_CHANGED_FILE_STATUS_NONE; - } - else - *status = s; - } - - if (files) - { - *files = g_list_prepend (*files, file); - } - else - { - g_object_unref (file); - } - } - - if (paths) - { - *paths = items; - } - else - { - g_list_free_full (items, (GDestroyNotify)gtk_tree_path_free); - } - - if (files) - { - *files = g_list_reverse (*files); - } - - return TRUE; -} - -static gboolean -check_selection (GtkTreeView *tree_view, - GtkTreeIter *iter, - GitgCommitView *view) -{ - if (view->priv->update_id) - { - g_signal_handler_disconnect (view->priv->shell, view->priv->update_id); - } - - gitg_io_cancel (GITG_IO (view->priv->shell)); - view->priv->update_id = 0; - - GtkTextView *tv = GTK_TEXT_VIEW (view->priv->changes_view); - GtkTextBuffer *buffer = gtk_text_view_get_buffer (tv); - GtkTextIter start; - GtkTextIter end; - - gtk_text_buffer_get_bounds (buffer, &start, &end); - - gtk_source_buffer_remove_source_marks (GTK_SOURCE_BUFFER (buffer), - &start, - &end, - CATEGORY_UNSTAGE_HUNK); - - gtk_source_buffer_remove_source_marks (GTK_SOURCE_BUFFER (buffer), - &start, - &end, - CATEGORY_STAGE_HUNK); - - gtk_text_buffer_set_text (gtk_text_view_get_buffer (tv), "", -1); - - GList *paths; - gboolean ret; - get_selected_files (tree_view, NULL, &paths, NULL, NULL); - - if (g_list_length (paths) != 1) - { - set_current_file (view, NULL, GITG_CHANGED_FILE_CHANGES_NONE); - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), - FALSE); - ret = FALSE; - } - else - { - if (iter) - { - gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view), - iter, - (GtkTreePath *)paths->data); - } - - ret = TRUE; - } - - g_list_free_full (paths, (GDestroyNotify)gtk_tree_path_free); - return ret; -} - -static void -unselect_tree_view (GtkTreeView *view) -{ - gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (view)); -} - -static void -unstaged_selection_changed (GtkTreeSelection *selection, - GitgCommitView *view) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - if (!check_selection (view->priv->tree_view_unstaged, &iter, view)) - { - return; - } - - model = gtk_tree_view_get_model (view->priv->tree_view_unstaged); - unselect_tree_view (view->priv->tree_view_staged); - - GitgChangedFile *file; - - gtk_tree_model_get (model, &iter, COLUMN_FILE, &file, -1); - GitgChangedFileStatus status = gitg_changed_file_get_status (file); - GFile *f = gitg_changed_file_get_file (file); - - if (status == GITG_CHANGED_FILE_STATUS_NEW) - { - gchar *content_type = gitg_utils_get_content_type (f); - - if (!gitg_utils_can_display_content_type (content_type)) - { - show_binary_information (view); - } - else - { - GInputStream *stream = G_INPUT_STREAM (g_file_read (f, NULL, NULL)); - - if (!stream) - { - show_binary_information (view); - } - else - { - gchar *basename = g_file_get_basename (f); - GtkSourceLanguage *language; - - language = gitg_utils_get_language (basename, - content_type); - g_free (basename); - - set_language (view, language); - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), - FALSE); - - view->priv->is_diff = FALSE; - connect_update (view); - - gitg_shell_run_stream (view->priv->shell, - stream, - NULL); - - g_object_unref (stream); - } - } - - g_free (content_type); - } - else - { - gboolean allow_external; - - set_diff_language (view); - view->priv->is_diff = TRUE; - connect_update (view); - - gchar *path = gitg_repository_relative (view->priv->repository, f); - - gchar ct[10]; - g_snprintf (ct, sizeof (ct), "-U%d", view->priv->context_size); - - allow_external = g_settings_get_boolean (view->priv->diff_settings, - "external"); - - gitg_shell_run (view->priv->shell, - gitg_command_new (view->priv->repository, - "diff", - allow_external ? "--ext-diff" : "--no-ext-diff", - "--no-color", - ct, - "--", - path, - NULL), - NULL); - - g_free (path); - } - - set_current_file (view, file, GITG_CHANGED_FILE_CHANGES_UNSTAGED); - - g_object_unref (file); - g_object_unref (f); -} - -static void -staged_selection_changed (GtkTreeSelection *selection, - GitgCommitView *view) -{ - GtkTreeModel *model; - GtkTreeIter iter; - - if (!check_selection (view->priv->tree_view_staged, &iter, view)) - { - return; - } - - model = gtk_tree_view_get_model (view->priv->tree_view_staged); - unselect_tree_view (view->priv->tree_view_unstaged); - - GitgChangedFile *file; - - gtk_tree_model_get (model, &iter, COLUMN_FILE, &file, -1); - GitgChangedFileStatus status = gitg_changed_file_get_status (file); - - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (view->priv->repository, f); - - if (status == GITG_CHANGED_FILE_STATUS_NEW) - { - view->priv->is_diff = FALSE; - - gchar *content_type = gitg_utils_get_content_type (f); - - if (!gitg_utils_can_display_content_type (content_type)) - { - show_binary_information (view); - } - else - { - gtk_widget_set_sensitive (GTK_WIDGET (view->priv->hscale_context), - FALSE); - - connect_update (view); - - gchar *indexpath = g_strconcat (":0:", path, NULL); - gitg_shell_run (view->priv->shell, - gitg_command_new (view->priv->repository, - "show", - "--encoding=UTF-8", - "--no-color", - indexpath, - NULL), - NULL); - - g_free (indexpath); - } - - g_free (content_type); - } - else - { - gboolean allow_external; - - view->priv->is_diff = TRUE; - set_diff_language (view); - connect_update (view); - - gchar *head = gitg_repository_parse_head (view->priv->repository); - gchar ct[10]; - g_snprintf (ct, sizeof (ct), "-U%d", view->priv->context_size); - - allow_external = g_settings_get_boolean (view->priv->diff_settings, - "external"); - - gitg_shell_run (view->priv->shell, - gitg_command_new (view->priv->repository, - "diff-index", - allow_external ? "--ext-diff" : "--no-ext-diff", - ct, - "--cached", - "--no-color", - head, - "--", - path, - NULL), - NULL); - - g_free (head); - } - - g_object_unref (f); - g_free (path); - - set_current_file (view, file, GITG_CHANGED_FILE_CHANGES_CACHED); - g_object_unref (file); -} - -static gint -compare_by_name (GtkTreeModel *model, - GtkTreeIter *a, - GtkTreeIter *b, - gpointer userdata) -{ - gchar *s1; - gchar *s2; - - gtk_tree_model_get (model, a, COLUMN_NAME, &s1, -1); - gtk_tree_model_get (model, b, COLUMN_NAME, &s2, -1); - - gint ret = gitg_utils_sort_names (s1, s2); - - g_free (s1); - g_free (s2); - - return ret; -} - -static void -set_sort_func (GtkListStore *store) -{ - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), - 0, - GTK_SORT_ASCENDING); - - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store), - 0, - compare_by_name, - NULL, - NULL); -} - -static gboolean -has_hunk_mark (GtkSourceBuffer *buffer, - GtkTextIter *iter) -{ - GSList *m1; - gboolean has_mark; - - m1 = gtk_source_buffer_get_source_marks_at_iter (buffer, - iter, - CATEGORY_UNSTAGE_HUNK); - - has_mark = (m1 != NULL); - g_slist_free (m1); - - if (has_mark) - { - return TRUE; - } - - m1 = gtk_source_buffer_get_source_marks_at_iter (buffer, - iter, - CATEGORY_STAGE_HUNK); - - has_mark = (m1 != NULL); - g_slist_free (m1); - - return has_mark; -} - -static gchar * -get_patch_header (GitgCommitView *view, - GtkTextBuffer *buffer, - GtkTextIter const *iter) -{ - GtkTextIter begin; - GtkTextIter end; - GitgDiffIter diff_iter; - - if (!gitg_diff_view_get_header_at_iter (GITG_DIFF_VIEW (view->priv->changes_view), - iter, - &diff_iter)) - { - return NULL; - } - - gitg_diff_iter_get_bounds (&diff_iter, &begin, &end); - - return gtk_text_buffer_get_text (buffer, &begin, &end, TRUE); -} - -static gchar * -get_patch_contents (GitgCommitView *view, - GtkTextBuffer *buffer, - GtkTextIter const *iter) -{ - GtkTextIter begin; - GtkTextIter end; - GitgDiffIter diff_iter; - - if (!gitg_diff_view_get_hunk_at_iter (GITG_DIFF_VIEW (view->priv->changes_view), - iter, - &diff_iter)) - { - return NULL; - } - - gitg_diff_iter_get_bounds (&diff_iter, &begin, &end); - - return gtk_text_buffer_get_text (buffer, &begin, &end, FALSE); -} - -static gchar * -get_hunk_patch (GitgCommitView *view, - GtkTextIter *iter) -{ - /* Get patch header */ - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view)); - gchar *header = get_patch_header (view, buffer, iter); - - if (!header) - { - return NULL; - } - - /* Get patch contents */ - gchar *contents = get_patch_contents (view, buffer, iter); - - if (!contents) - { - g_free (header); - return NULL; - } - - return g_strconcat (header, contents, NULL); -} - -static gchar * -line_patch_contents (GitgCommitView *view, - GtkTextIter const *iter, - GitgDiffLineType old_type, - GitgDiffLineType new_type) -{ - GtkTextIter start; - GtkTextIter end; - GtkTextIter patch_iter = *iter; - GitgDiffView *diff_view = GITG_DIFF_VIEW (view->priv->changes_view); - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (diff_view)); - GitgDiffIter diff_iter; - - gtk_text_iter_set_line_offset (&patch_iter, 0); - - if (!gitg_diff_view_get_hunk_at_iter (diff_view, &patch_iter, &diff_iter)) - { - return NULL; - } - - gitg_diff_iter_get_bounds (&diff_iter, &start, &end); - GtkTextIter begin = start; - - GString *patch = g_string_new (""); - gchar *header = NULL; - gint count_old = 0; - gint count_new = 0; - - while (gtk_text_iter_compare (&start, &end) < 0) - { - GitgDiffLineType line_type; - gboolean is_patch_line; - - line_type = gitg_diff_view_get_line_type (diff_view, &start); - - is_patch_line = gtk_text_iter_equal (&start, &patch_iter); - - gchar *text; - GtkTextIter line_end = start; - gtk_text_iter_forward_to_line_end (&line_end); - - if (gtk_text_iter_equal (&start, &begin)) - { - header = gtk_text_buffer_get_text (buffer, &start, &line_end, TRUE); - } - else - { - if (line_type == old_type && !is_patch_line) - { - /* Take over like it was context */ - g_string_append_c (patch, ' '); - - if (!gtk_text_iter_ends_line (&start)) - { - gtk_text_iter_forward_char (&start); - } - } - - if (line_type == GITG_DIFF_LINE_TYPE_NONE || - line_type == old_type || is_patch_line) - { - /* copy context */ - gtk_text_iter_forward_line (&line_end); - text = gtk_text_buffer_get_text (buffer, &start, &line_end, TRUE); - - g_string_append (patch, text); - - if (!is_patch_line || line_type == GITG_DIFF_LINE_TYPE_REMOVE) - { - ++count_old; - } - - if (!is_patch_line || line_type == GITG_DIFF_LINE_TYPE_ADD) - { - ++count_new; - } - - g_free (text); - } - } - - if (!gtk_text_iter_forward_line (&start)) - { - break; - } - } - - gchar *head = gitg_utils_rewrite_hunk_counters (header, count_old, count_new); - g_free (header); - gchar *ret = NULL; - - if (head) - { - gchar *contents = g_string_free (patch, FALSE); - ret = g_strconcat (head, "\n", contents, NULL); - - g_free (contents); - g_free (head); - } - - return ret; -} - -static gboolean -stage_unstage_hunk (GitgCommitView *view, - gchar const *hunk, - GError **error) -{ - gboolean ret; - gboolean unstage = view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED; - - if (unstage) - { - ret = gitg_commit_stage (view->priv->commit, - view->priv->current_file, - hunk, - error); - } - else - { - ret = gitg_commit_unstage (view->priv->commit, - view->priv->current_file, - hunk, - error); - } - - return ret; -} - -static gboolean -handle_stage_unstage_line (GitgCommitView *view, - GtkTextIter const *iter) -{ - GitgDiffView *diff_view = GITG_DIFF_VIEW (view->priv->changes_view); - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view)); - gchar *header = get_patch_header (view, buffer, iter); - GitgDiffLineType old_type; - GitgDiffLineType new_type; - - if (!header) - { - return FALSE; - } - - GitgDiffIter diff_iter; - - if (!gitg_diff_view_get_header_at_iter (diff_view, iter, &diff_iter)) - { - g_free (header); - return FALSE; - } - - if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED) - { - old_type = GITG_DIFF_LINE_TYPE_REMOVE; - new_type = GITG_DIFF_LINE_TYPE_ADD; - } - else - { - old_type = GITG_DIFF_LINE_TYPE_ADD; - new_type = GITG_DIFF_LINE_TYPE_REMOVE; - } - - gchar *contents = line_patch_contents (view, iter, old_type, new_type); - - if (!contents) - { - g_free (header); - return FALSE; - } - - gboolean ret; - GitgChangedFile *file = g_object_ref (view->priv->current_file); - GError *error = NULL; - gchar *hunk = g_strconcat (header, contents, NULL); - - g_free (contents); - g_free (header); - - ret = stage_unstage_hunk (view, hunk, &error); - - if (ret && file == view->priv->current_file) - { - gitg_diff_view_clear_line (GITG_DIFF_VIEW (view->priv->changes_view), - iter, - old_type, - new_type); - } - else if (!ret) - { - g_warning ("Could not stage/unstage: %s", error->message); - g_error_free (error); - } - - g_free (hunk); - g_object_unref (file); - - return ret; -} - -static gboolean -handle_stage_unstage (GitgCommitView *view, - GtkTextIter *iter) -{ - gchar *hunk = get_hunk_patch (view, iter); - - if (!hunk) - { - return FALSE; - } - - gboolean ret; - GitgChangedFile *file = g_object_ref (view->priv->current_file); - GError *error = NULL; - - ret = stage_unstage_hunk (view, hunk, &error); - - if (ret && file == view->priv->current_file) - { - /* remove hunk from text view */ - gitg_diff_view_remove_hunk (GITG_DIFF_VIEW (view->priv->changes_view), iter); - } - else if (!ret) - { - g_warning ("Could not stage/unstage: %s", error->message); - g_error_free (error); - } - - g_object_unref (file); - g_free (hunk); - - return ret; -} - -static gboolean -get_info_at_pointer (GitgCommitView *view, - GtkTextIter *iter, - gboolean *is_hunk, - gchar **hunk, - GitgDiffLineType *line_type) -{ - GtkTextView *textview = GTK_TEXT_VIEW (view->priv->changes_view); - gint x; - gint y; - gint width; - gint height; - gint buf_x; - gint buf_y; - - /* Get where the pointer really is. */ - GdkWindow *win = gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_TEXT); - - gdk_window_get_pointer (win, &x, &y, NULL); - - width = gdk_window_get_width (win); - height = gdk_window_get_height (win); - - if (x < 0 || y < 0 || x > width || y > height) - { - return FALSE; - } - - /* Get the iter where the cursor is at */ - gtk_text_view_window_to_buffer_coords (textview, GTK_TEXT_WINDOW_TEXT, x, y, &buf_x, &buf_y); - gtk_text_view_get_iter_at_location (textview, iter, buf_x, buf_y); - - gtk_text_iter_set_line_offset (iter, 0); - - GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (textview)); - - if (is_hunk) - { - *is_hunk = has_hunk_mark (buffer, iter); - - if (*is_hunk && hunk) - { - *hunk = get_hunk_patch (view, iter); - } - } - - if (line_type) - { - *line_type = gitg_diff_view_get_line_type (GITG_DIFF_VIEW (view->priv->changes_view), - iter); - } - - return TRUE; -} - -static void -unset_highlight (GitgCommitView *view) -{ - if (!view->priv->highlight_mark) - { - return; - } - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view)); - GtkTextIter start; - GtkTextIter end; - - gtk_text_buffer_get_iter_at_mark (buffer, &start, view->priv->highlight_mark); - end = start; - - gtk_text_iter_forward_to_line_end (&end); - - gtk_text_buffer_remove_tag (buffer, view->priv->highlight_tag, &start, &end); - - gtk_text_buffer_delete_mark (buffer, view->priv->highlight_mark); - view->priv->highlight_mark = NULL; -} - -static void -set_highlight (GitgCommitView *view, - GtkTextIter *iter) -{ - if (!view->priv->highlight_tag) - { - return; - } - - GtkTextIter start = *iter; - GtkTextBuffer *buffer = gtk_text_iter_get_buffer (iter); - - gtk_text_iter_set_line_offset (&start, 0); - - if (view->priv->highlight_mark != NULL) - { - GtkTextIter mark_iter; - gtk_text_buffer_get_iter_at_mark (buffer, - &mark_iter, - view->priv->highlight_mark); - - if (gtk_text_iter_equal (&start, &mark_iter)) - { - return; - } - - unset_highlight (view); - } - - view->priv->highlight_mark = gtk_text_buffer_create_mark (buffer, - NULL, - &start, - TRUE); - - GtkTextIter end = start; - gtk_text_iter_forward_to_line_end (&end); - - gtk_text_buffer_apply_tag (buffer, - view->priv->highlight_tag, - &start, - &end); -} - -static gboolean -gutter_event (GtkWidget *widget, - GdkEventAny *event, - GitgCommitView *view) -{ - GtkTextView *textview = GTK_TEXT_VIEW (view->priv->changes_view); - gint x; - gint y; - gint width; - gint height; - gint buf_x; - gint buf_y; - GtkTextIter iter; - GitgDiffLineType line_type; - GtkSourceGutter *gutter; - GtkSourceGutterRenderer *renderer_at_pos; - - /* Get where the pointer really is. */ - GdkWindow *win = gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_LEFT); - - gdk_window_get_pointer (win, &x, &y, NULL); - - width = gdk_window_get_width (win); - height = gdk_window_get_height (win); - - if (x < 0 || y < 0 || x > width || y > height) - { - unset_highlight (view); - gdk_window_set_cursor (event->window, NULL); - return FALSE; - } - - /* Get the iter where the cursor is at */ - gtk_text_view_window_to_buffer_coords (textview, GTK_TEXT_WINDOW_LEFT, x, y, &buf_x, &buf_y); - gtk_text_view_get_iter_at_location (textview, &iter, buf_x, buf_y); - - gtk_text_iter_set_line_offset (&iter, 0); - - line_type = gitg_diff_view_get_line_type (GITG_DIFF_VIEW (view->priv->changes_view), - &iter); - - gutter = gtk_source_view_get_gutter (view->priv->changes_view, - GTK_TEXT_WINDOW_LEFT); - renderer_at_pos = gtk_source_gutter_get_renderer_at_pos (gutter, x, y); - - if (renderer_at_pos == view->priv->pixbuf_renderer && - (line_type == GITG_DIFF_LINE_TYPE_ADD || - line_type == GITG_DIFF_LINE_TYPE_REMOVE)) - { - set_highlight (view, &iter); - gdk_window_set_cursor (event->window, view->priv->hand); - } - else - { - unset_highlight (view); - gdk_window_set_cursor (event->window, NULL); - } - - return FALSE; -} - -static gboolean -view_event (GtkWidget *widget, - GdkEventAny *event, - GitgCommitView *view) -{ - GtkTextWindowType type; - GtkTextBuffer *buffer; - GtkTextIter iter; - gboolean is_hunk = FALSE; - - type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (widget), event->window); - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget)); - - if (type == GTK_TEXT_WINDOW_LEFT) - { - return gutter_event (widget, event, view); - } - - if (type == GTK_TEXT_WINDOW_TEXT && event->type == GDK_LEAVE_NOTIFY) - { - unset_highlight (view); - gdk_window_set_cursor (event->window, NULL); - return FALSE; - } - - get_info_at_pointer (view, &iter, &is_hunk, NULL, NULL); - - if (event->type == GDK_LEAVE_NOTIFY || - event->type == GDK_MOTION_NOTIFY || - event->type == GDK_BUTTON_PRESS || - event->type == GDK_BUTTON_RELEASE || - event->type == GDK_ENTER_NOTIFY) - { - if (is_hunk) - { - set_highlight (view, &iter); - gdk_window_set_cursor (event->window, view->priv->hand); - } - else - { - unset_highlight (view); - gdk_window_set_cursor (event->window, NULL); - } - } - - if (type == GTK_TEXT_WINDOW_TEXT &&event->type == GDK_BUTTON_RELEASE && - ((GdkEventButton *) event)->button == 1 && is_hunk && - !gtk_text_buffer_get_has_selection (buffer)) - { - if (handle_stage_unstage (view, &iter)) - { - unset_highlight (view); - gdk_window_set_cursor (event->window, NULL); - } - } - - return FALSE; -} - -static GtkTextBuffer * -initialize_buffer (GitgCommitView *view) -{ - GtkTextBuffer *buffer = GTK_TEXT_BUFFER (gtk_source_buffer_new (NULL)); - - GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default (); - GtkSourceStyleScheme *scheme = gtk_source_style_scheme_manager_get_scheme (manager, "gitg"); - gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (buffer), scheme); - - return buffer; -} - -static GtkTargetEntry dnd_entries[] = { - {"text/uri-list", 0, 1} -}; - -static void -on_tree_view_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection, - guint info, - guint time, - GitgCommitView *view) -{ - GList *selected; - GList *item; - gchar **uris; - guint i = 0; - - get_selected_files (GTK_TREE_VIEW (widget), &selected, NULL, NULL, NULL); - uris = g_new (gchar *, g_list_length (selected) + 1); - - for (item = selected; item; item = g_list_next (item)) - { - GitgChangedFile *file = GITG_CHANGED_FILE (item->data); - GFile *gf = gitg_changed_file_get_file (file); - - uris[i++] = g_file_get_uri (gf); - g_object_unref (gf); - } - - uris[i] = NULL; - gtk_selection_data_set_uris (selection, uris); - - g_strfreev (uris); - - g_list_free_full (selected, g_object_unref); -} - -static void -on_tree_view_staged_drag_data_received (GtkWidget *widget, - GdkDragContext *drag_context, - gint x, - gint y, - GtkSelectionData *data, - guint info, - guint time, - GitgCommitView *view) -{ - /* Stage all the files dropped on this */ - gchar **uris = gtk_selection_data_get_uris (data); - gchar **uri; - - for (uri = uris; *uri; ++uri) - { - GFile *file = g_file_new_for_uri (*uri); - GitgChangedFile *f; - - f = gitg_commit_find_changed_file (view->priv->commit, file); - - if (f && (gitg_changed_file_get_changes (f) & GITG_CHANGED_FILE_CHANGES_UNSTAGED)) - { - gitg_commit_stage (view->priv->commit, f, NULL, NULL); - } - - g_object_unref (f); - g_object_unref (file); - } -} - -static void -on_tree_view_unstaged_drag_data_received (GtkWidget *widget, - GdkDragContext *drag_context, - gint x, - gint y, - GtkSelectionData *data, - guint info, - guint time, - GitgCommitView *view) -{ - /* Unstage all the files dropped on this */ - gchar **uris = gtk_selection_data_get_uris (data); - gchar **uri; - - for (uri = uris; *uri; ++uri) - { - GFile *file = g_file_new_for_uri (*uri); - GitgChangedFile *f; - - f = gitg_commit_find_changed_file (view->priv->commit, file); - - if (f && (gitg_changed_file_get_changes (f) & GITG_CHANGED_FILE_CHANGES_CACHED)) - { - gitg_commit_unstage (view->priv->commit, f, NULL, NULL); - } - - g_object_unref (f); - g_object_unref (file); - } -} - -static void -initialize_dnd (GitgCommitView *view, - GtkTreeView *tree_view, - GCallback drag_data_received) -{ - gtk_tree_view_enable_model_drag_dest (tree_view, - dnd_entries, - G_N_ELEMENTS (dnd_entries), - GDK_ACTION_COPY); - - gtk_tree_view_enable_model_drag_source (tree_view, - GDK_BUTTON1_MASK, - dnd_entries, - G_N_ELEMENTS (dnd_entries), - GDK_ACTION_COPY); - - g_signal_connect (tree_view, - "drag-data-get", - G_CALLBACK (on_tree_view_drag_data_get), - view); - - g_signal_connect (tree_view, - "drag-data-received", - G_CALLBACK (drag_data_received), - view); -} - -static void -initialize_dnd_staged (GitgCommitView *view) -{ - initialize_dnd (view, - view->priv->tree_view_staged, - G_CALLBACK (on_tree_view_staged_drag_data_received)); -} - -static void -initialize_dnd_unstaged (GitgCommitView *view) -{ - initialize_dnd (view, - view->priv->tree_view_unstaged, - G_CALLBACK (on_tree_view_unstaged_drag_data_received)); -} - -static void -on_tag_added (GtkTextTagTable *table, - GtkTextTag *tag, - GitgCommitView *view) -{ - gtk_text_tag_set_priority (view->priv->highlight_tag, - gtk_text_tag_table_get_size (table) - 1); -} - -/* Copied from GtkSourceView's gtksourceviewgutterrenderermarks.c */ -static int -measure_line_height (GtkSourceView *view) -{ - PangoLayout *layout; - gint height = 12; - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), "QWERTY"); - - if (layout) - { - pango_layout_get_pixel_size (layout, NULL, &height); - g_object_unref (layout); - } - - return height - 2; -} - -static void -gitg_commit_view_parser_finished (GtkBuildable *buildable, - GtkBuilder *builder) -{ - GtkSourceMarkAttributes *attrs; - GtkSourceGutter *gutter; - - if (parent_iface.parser_finished) - { - parent_iface.parser_finished (buildable, builder); - } - - /* Store widgets */ - GitgCommitView *self = GITG_COMMIT_VIEW (buildable); - - GtkBuilder *b = gitg_utils_new_builder ("gitg-commit-menu.ui"); - self->priv->ui_manager = g_object_ref (gtk_builder_get_object (b, "uiman")); - - g_signal_connect (gtk_builder_get_object (b, "StageChangesAction"), - "activate", - G_CALLBACK (on_stage_changes), - self); - - g_signal_connect (gtk_builder_get_object (b, "RevertChangesAction"), - "activate", - G_CALLBACK (on_revert_changes), - self); - - g_signal_connect (gtk_builder_get_object (b, "IgnoreFileAction"), - "activate", - G_CALLBACK (on_ignore_file), - self); - - g_signal_connect (gtk_builder_get_object (b, "UnstageChangesAction"), - "activate", - G_CALLBACK (on_unstage_changes), - self); - - g_signal_connect (gtk_builder_get_object (b, "EditFileAction"), - "activate", - G_CALLBACK (on_edit_file), - self); - - g_signal_connect (gtk_builder_get_object (b, "DeleteFileAction"), - "activate", - G_CALLBACK (on_delete_file), - self); - - self->priv->group_context = GTK_ACTION_GROUP (gtk_builder_get_object (b, "action_group_commit_context")); - - g_object_unref (b); - - self->priv->tree_view_unstaged = GTK_TREE_VIEW (gtk_builder_get_object (builder, "tree_view_unstaged")); - self->priv->tree_view_staged = GTK_TREE_VIEW (gtk_builder_get_object (builder, "tree_view_staged")); - - self->priv->store_unstaged = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GITG_TYPE_CHANGED_FILE); - self->priv->store_staged = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, GITG_TYPE_CHANGED_FILE); - - set_sort_func (self->priv->store_unstaged); - set_sort_func (self->priv->store_staged); - - self->priv->changes_view = GTK_SOURCE_VIEW (gtk_builder_get_object (builder, "source_view_changes")); - - gtk_widget_add_events (GTK_WIDGET (self->priv->changes_view), - GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK); - - self->priv->comment_view = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "text_view_comment")); - self->priv->check_button_signed_off_by = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "check_button_signed_off_by")); - self->priv->check_button_amend = GTK_CHECK_BUTTON (gtk_builder_get_object (builder, "check_button_amend")); - - g_settings_bind (self->priv->message_settings, - "show-right-margin", - self->priv->comment_view, - "show-right-margin", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (self->priv->message_settings, - "right-margin-at", - self->priv->comment_view, - "right-margin-position", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - self->priv->hscale_context = GTK_HSCALE (gtk_builder_get_object (builder, "hscale_context")); - gtk_range_set_value (GTK_RANGE (self->priv->hscale_context), 3); - - initialize_dnd_staged (self); - initialize_dnd_unstaged (self); - - GtkIconTheme *theme = gtk_icon_theme_get_default (); - GdkPixbuf *pixbuf = gtk_icon_theme_load_icon (theme, GTK_STOCK_ADD, 12, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - - if (pixbuf) - { - attrs = gtk_source_mark_attributes_new (); - gtk_source_mark_attributes_set_pixbuf (attrs, pixbuf); - - gtk_source_view_set_mark_attributes (self->priv->changes_view, - CATEGORY_STAGE_HUNK, - attrs, 1); - - g_object_unref (pixbuf); - g_object_unref (attrs); - } - - pixbuf = gtk_icon_theme_load_icon (theme, GTK_STOCK_REMOVE, 12, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - - if (pixbuf) - { - attrs = gtk_source_mark_attributes_new (); - gtk_source_mark_attributes_set_pixbuf (attrs, pixbuf); - - gtk_source_view_set_mark_attributes (self->priv->changes_view, - CATEGORY_UNSTAGE_HUNK, - attrs, 2); - - g_object_unref (pixbuf); - g_object_unref (attrs); - } - - gitg_utils_set_monospace_font (GTK_WIDGET (self->priv->changes_view)); - - GtkTextBuffer *buffer = initialize_buffer (self); - gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->priv->changes_view), buffer); - g_signal_connect (self->priv->changes_view, "event", G_CALLBACK (view_event), self); - - gtk_tree_view_set_model (self->priv->tree_view_unstaged, GTK_TREE_MODEL (self->priv->store_unstaged)); - gtk_tree_view_set_model (self->priv->tree_view_staged, GTK_TREE_MODEL (self->priv->store_staged)); - - set_icon_data_func (self, self->priv->tree_view_unstaged, GTK_CELL_RENDERER (gtk_builder_get_object (builder, "unstaged_cell_renderer_icon"))); - set_icon_data_func (self, self->priv->tree_view_staged, GTK_CELL_RENDERER (gtk_builder_get_object (builder, "staged_cell_renderer_icon"))); - - GtkSourceStyleScheme *scheme; - GtkSourceStyle *style; - - scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer)); - style = gtk_source_style_scheme_get_style (scheme, "current-line"); - - gchar *background = NULL; - gboolean background_set = FALSE; - - gchar *foreground = NULL; - gboolean foreground_set = FALSE; - - if (style) - { - g_object_get (style, - "line-background", - &background, - "line-background-set", - &background_set, - "foreground", - &foreground, - "foreground-set", - &foreground_set, - NULL); - - if (!background_set) - { - g_object_get (style, - "background", - &background, - "background-set", - &background_set, - NULL); - } - } - - if (background_set) - { - self->priv->highlight_tag = gtk_text_buffer_create_tag (buffer, - NULL, - "paragraph-background", - background, - "foreground", - foreground, - "foreground-set", - foreground_set, - NULL); - - gtk_text_tag_set_priority (self->priv->highlight_tag, - gtk_text_tag_table_get_size (gtk_text_buffer_get_tag_table (buffer)) - 1); - - g_signal_connect (gtk_text_buffer_get_tag_table (buffer), - "tag-added", - G_CALLBACK (on_tag_added), - self); - } - - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (self->priv->tree_view_unstaged); - - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - g_signal_connect (selection, "changed", G_CALLBACK (unstaged_selection_changed), self); - - selection = gtk_tree_view_get_selection (self->priv->tree_view_staged); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - g_signal_connect (selection, "changed", G_CALLBACK (staged_selection_changed), self); - - g_signal_connect (self->priv->tree_view_unstaged, - "event-after", - G_CALLBACK (on_unstaged_button_press), - self); - - g_signal_connect (self->priv->tree_view_staged, - "event-after", - G_CALLBACK (on_staged_button_press), - self); - - g_signal_connect (self->priv->tree_view_unstaged, - "button-press-event", - G_CALLBACK (on_staged_unstaged_button_press_before), - self); - - g_signal_connect (self->priv->tree_view_staged, - "button-press-event", - G_CALLBACK (on_staged_unstaged_button_press_before), - self); - - g_signal_connect (self->priv->tree_view_unstaged, - "row-activated", - G_CALLBACK (on_unstaged_tree_view_row_activated), - self); - g_signal_connect (self->priv->tree_view_staged, - "row-activated", - G_CALLBACK (on_staged_tree_view_row_activated), - self); - - g_signal_connect (self->priv->tree_view_unstaged, - "popup-menu", - G_CALLBACK (on_unstaged_popup_menu), - self); - - g_signal_connect (self->priv->tree_view_staged, - "popup-menu", - G_CALLBACK (on_staged_popup_menu), - self); - - g_signal_connect (self->priv->changes_view, - "populate-popup", - G_CALLBACK (on_changes_view_popup_menu), - self); - - g_signal_connect (self->priv->tree_view_unstaged, - "motion-notify-event", - G_CALLBACK (on_unstaged_motion), - self); - - g_signal_connect (self->priv->tree_view_staged, - "motion-notify-event", - G_CALLBACK (on_staged_motion), - self); - - g_signal_connect (gtk_builder_get_object (builder, "button_commit"), - "clicked", - G_CALLBACK (on_commit_clicked), - self); - - g_signal_connect (self->priv->hscale_context, - "value-changed", - G_CALLBACK (on_context_value_changed), - self); - - g_signal_connect (self->priv->check_button_amend, - "toggled", - G_CALLBACK (on_check_button_amend_toggled), - self); - - gutter = gtk_source_view_get_gutter (self->priv->changes_view, - GTK_TEXT_WINDOW_LEFT); - - self->priv->pixbuf_renderer = gtk_source_gutter_renderer_pixbuf_new (); - g_object_set (self->priv->pixbuf_renderer, "xpad", 4, NULL); - - gtk_source_gutter_insert (gutter, self->priv->pixbuf_renderer, 1); - gtk_source_gutter_renderer_set_size (self->priv->pixbuf_renderer, - measure_line_height (GTK_SOURCE_VIEW (self->priv->changes_view))); - - g_signal_connect (self->priv->pixbuf_renderer, - "query-data", - G_CALLBACK (pixbuf_renderer_query_data_cb), - self); - g_signal_connect (self->priv->pixbuf_renderer, - "query-activatable", - G_CALLBACK (pixbuf_renderer_query_activatable_cb), - self); - g_signal_connect (self->priv->pixbuf_renderer, - "activate", - G_CALLBACK (pixbuf_renderer_activate_cb), - self); -} - -static void -gitg_commit_view_buildable_iface_init (GtkBuildableIface *iface) -{ - parent_iface = *iface; - - iface->parser_finished = gitg_commit_view_parser_finished; -} - -static void -gitg_commit_view_dispose (GObject *object) -{ - GitgCommitView *self = GITG_COMMIT_VIEW (object); - - if (self->priv->message_settings) - { - g_object_unref (self->priv->message_settings); - self->priv->message_settings = NULL; - } - - if (self->priv->diff_settings) - { - g_object_unref (self->priv->diff_settings); - self->priv->diff_settings = NULL; - } - - if (self->priv->repository) - { - g_object_unref (self->priv->repository); - self->priv->repository = NULL; - } - - if (self->priv->commit) - { - g_signal_handlers_disconnect_by_func (self->priv->commit, - on_commit_file_inserted, - self); - - g_signal_handlers_disconnect_by_func (self->priv->commit, - on_commit_file_removed, - self); - - g_object_unref (self->priv->commit); - self->priv->commit = NULL; - } - - if (self->priv->pixbuf_renderer != NULL) - { - g_object_unref (self->priv->pixbuf_renderer); - self->priv->pixbuf_renderer = NULL; - } -} - -static void -gitg_commit_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgCommitView *self = GITG_COMMIT_VIEW (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - g_value_set_object (value, self->priv->repository); - break; - case PROP_CONTEXT_SIZE: - g_value_set_int (value, self->priv->context_size); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_commit_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgCommitView *self = GITG_COMMIT_VIEW (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - self->priv->repository = g_value_dup_object (value); - break; - case PROP_CONTEXT_SIZE: - self->priv->context_size = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -initialize_commit (GitgCommitView *self) -{ - if (self->priv->commit) - { - return; - } - - self->priv->commit = gitg_commit_new (self->priv->repository); - - g_signal_connect (self->priv->commit, - "inserted", - G_CALLBACK (on_commit_file_inserted), - self); - - g_signal_connect (self->priv->commit, - "removed", - G_CALLBACK (on_commit_file_removed), - self); - - gitg_commit_refresh (self->priv->commit); -} - -static void -gitg_commit_view_map (GtkWidget *widget) -{ - GitgCommitView *self = GITG_COMMIT_VIEW (widget); - - GTK_WIDGET_CLASS (gitg_commit_view_parent_class)->map (widget); - - if (!self->priv->repository) - { - return; - } - - initialize_commit (self); -} - -static void -gitg_commit_view_class_init (GitgCommitViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = gitg_commit_view_finalize; - object_class->dispose = gitg_commit_view_dispose; - - widget_class->map = gitg_commit_view_map; - - object_class->set_property = gitg_commit_view_set_property; - object_class->get_property = gitg_commit_view_get_property; - - g_object_class_install_property (object_class, - PROP_REPOSITORY, - g_param_spec_object ("repository", - "REPOSITORY", - "Repository", - GITG_TYPE_REPOSITORY, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_CONTEXT_SIZE, - g_param_spec_int ("context-size", - "CONTEXT_SIZE", - "Diff context size", - 1, - G_MAXINT, - 3, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); - - g_type_class_add_private (object_class, sizeof (GitgCommitViewPrivate)); -} - -static void -gitg_commit_view_init (GitgCommitView *self) -{ - self->priv = GITG_COMMIT_VIEW_GET_PRIVATE (self); - - self->priv->message_settings = - g_settings_new ("org.gnome.gitg.preferences.commit.message"); - - self->priv->diff_settings = - g_settings_new ("org.gnome.gitg.preferences.diff"); - - self->priv->shell = gitg_shell_new (10000); - gitg_shell_set_preserve_line_endings (self->priv->shell, TRUE); - - self->priv->hand = gdk_cursor_new (GDK_HAND1); -} - -void -gitg_commit_view_set_repository (GitgCommitView *view, - GitgRepository *repository) -{ - g_return_if_fail (GITG_IS_COMMIT_VIEW (view)); - g_return_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository)); - - if (view->priv->repository) - { - g_object_unref (view->priv->repository); - view->priv->repository = NULL; - } - - if (view->priv->commit) - { - g_object_unref (view->priv->commit); - view->priv->commit = NULL; - } - - gtk_list_store_clear (view->priv->store_unstaged); - gtk_list_store_clear (view->priv->store_staged); - - if (repository) - { - view->priv->repository = g_object_ref (repository); - } - - if (gtk_widget_get_mapped (GTK_WIDGET (view))) - { - initialize_commit (view); - } - - g_object_notify (G_OBJECT (view), "repository"); -} - -static void -append_file (GtkListStore *store, - GitgChangedFile *file, - GitgCommitView *view) -{ - GFile *f = gitg_changed_file_get_file (file); - gchar *rel = gitg_repository_relative (view->priv->repository, f); - - GtkTreeIter iter; - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, - &iter, - COLUMN_NAME, - rel, - COLUMN_FILE, - file, - -1); - - g_free (rel); - g_object_unref (f); -} - -/* Callbacks */ -static gboolean -find_file_in_store (GtkListStore *store, - GitgChangedFile *file, - GtkTreeIter *iter) -{ - GtkTreeModel *model = GTK_TREE_MODEL (store); - - if (!gtk_tree_model_get_iter_first (model, iter)) - { - return FALSE; - } - - do - { - GitgChangedFile *other; - gtk_tree_model_get (model, iter, COLUMN_FILE, &other, -1); - gboolean ret = (other == file); - - g_object_unref (other); - - if (ret) - { - return TRUE; - } - } while (gtk_tree_model_iter_next (model, iter)); - - return FALSE; -} - -static void -model_row_changed (GtkListStore *store, - GtkTreeIter *iter) -{ - GtkTreePath *path; - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter); - - if (!path) - { - return; - } - - gtk_tree_model_row_changed (GTK_TREE_MODEL (store), path, iter); - gtk_tree_path_free (path); -} - -static void -on_commit_file_changed (GitgChangedFile *file, - GParamSpec *spec, - GitgCommitView *view) -{ - GtkTreeIter staged; - GtkTreeIter unstaged; - gboolean isstaged; - gboolean isunstaged; - - isstaged = find_file_in_store (view->priv->store_staged, - file, - &staged); - - isunstaged = find_file_in_store (view->priv->store_unstaged, - file, - &unstaged); - - if (isstaged) - { - model_row_changed (view->priv->store_staged, &staged); - } - - if (isunstaged) - { - model_row_changed (view->priv->store_unstaged, &unstaged); - } - - GitgChangedFileChanges changes = gitg_changed_file_get_changes (file); - - if (changes & GITG_CHANGED_FILE_CHANGES_CACHED) - { - if (!isstaged) - { - append_file (view->priv->store_staged, file, view); - } - } - else - { - if (isstaged) - { - gtk_list_store_remove (view->priv->store_staged, &staged); - } - } - - if (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED) - { - if (!isunstaged) - { - append_file (view->priv->store_unstaged, file, view); - } - } - else - { - if (isunstaged) - { - gtk_list_store_remove (view->priv->store_unstaged, - &unstaged); - } - } -} - -static void -on_commit_file_inserted (GitgCommit *commit, - GitgChangedFile *file, - GitgCommitView *view) -{ - GitgChangedFileChanges changes; - - changes = gitg_changed_file_get_changes (file); - - if (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED) - { - append_file (view->priv->store_unstaged, file, view); - } - - if (changes & GITG_CHANGED_FILE_CHANGES_CACHED) - { - append_file (view->priv->store_staged, file, view); - } - - g_signal_connect (file, - "notify::changes", - G_CALLBACK (on_commit_file_changed), - view); - - g_signal_connect (file, - "notify::status", - G_CALLBACK (on_commit_file_changed), - view); -} - -static void -on_commit_file_removed (GitgCommit *commit, - GitgChangedFile *file, - GitgCommitView *view) -{ - GtkTreeIter iter; - - if (find_file_in_store (view->priv->store_staged, file, &iter)) - { - gtk_list_store_remove (view->priv->store_staged, &iter); - } - - if (find_file_in_store (view->priv->store_unstaged, file, &iter)) - { - gtk_list_store_remove (view->priv->store_unstaged, &iter); - } -} - -static gboolean -column_icon_test (GtkTreeView *view, - gdouble ex, - gdouble ey, - GitgChangedFile **file) -{ - GtkTreeViewColumn *column; - gint x; - gint y; - GtkTreePath *path; - - gtk_tree_view_convert_widget_to_bin_window_coords (view, - (gint)ex, - (gint)ey, - &x, - &y); - - if (!gtk_tree_view_get_path_at_pos (view, - x, - y, - &path, - &column, - NULL, - NULL)) - { - return FALSE; - } - - if (column != gtk_tree_view_get_column (view, 0)) - { - gtk_tree_path_free (path); - return FALSE; - } - - if (file) - { - GtkTreeModel *model = gtk_tree_view_get_model (view); - GtkTreeIter iter; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, COLUMN_FILE, file, -1); - } - - gtk_tree_path_free (path); - - return TRUE; -} - -static gboolean -on_staged_unstaged_button_press_before (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view) -{ - if (event->button == 1 && - column_icon_test (GTK_TREE_VIEW (widget), - event->x, - event->y, - NULL)) - { - /* Block selection by treeview when clicking on the icon */ - return TRUE; - } - - if (event->button != 3) - { - return FALSE; - } - - /* Check if it is important to keep the selection here */ - GtkTreeView *treeview = GTK_TREE_VIEW (widget); - GtkTreePath *path; - - if (gtk_tree_view_get_path_at_pos (treeview, - (gint)event->x, - (gint)event->y, - &path, - NULL, - NULL, - NULL)) - { - GtkTreeSelection *selection = - gtk_tree_view_get_selection (treeview); - - if (gtk_tree_selection_path_is_selected (selection, path)) - { - /* Block normal treeview behavior to unselect potential - multiselection */ - return TRUE; - } - } - - return FALSE; -} - -static void -on_unstaged_tree_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GitgCommitView *view) -{ - GList *files = NULL; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - gitg_commit_stage (view->priv->commit, files->data, NULL, NULL); - g_list_free_full (files, (GDestroyNotify)g_object_unref); -} - -static void -on_staged_tree_view_row_activated (GtkTreeView *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column, - GitgCommitView *view) -{ - GList *files = NULL; - - get_selected_files (view->priv->tree_view_staged, - &files, - NULL, - NULL, - NULL); - - gitg_commit_unstage (view->priv->commit, files->data, NULL, NULL); - g_list_free_full (files, (GDestroyNotify)g_object_unref); -} - -static void -on_unstaged_button_press (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view) -{ - GitgChangedFile *file; - - if (event->type != GDK_BUTTON_PRESS) - { - return; - } - - if (event->button == 1 && - column_icon_test (view->priv->tree_view_unstaged, - event->x, - event->y, - &file)) - { - GList *files = NULL; - - gitg_commit_stage (view->priv->commit, file, NULL, NULL); - - /* If the file is currently selected in the 'staged' tree, - then refresh the diff */ - get_selected_files (view->priv->tree_view_staged, - &files, - NULL, - NULL, - NULL); - - if (files && !files->next) - { - GFile *f; - - f = gitg_changed_file_get_file (files->data); - - if (gitg_changed_file_equal (file, f)) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection ( - view->priv->tree_view_staged); - - staged_selection_changed (selection, view); - } - - g_object_unref (f); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - g_object_unref (file); - } - else if (event->button == 3) - { - view->priv->context_type = CONTEXT_TYPE_FILE; - popup_unstaged_menu (view, event); - } -} - -static void -on_staged_button_press (GtkWidget *widget, - GdkEventButton *event, - GitgCommitView *view) -{ - GitgChangedFile *file; - - if (event->type != GDK_BUTTON_PRESS) - { - return; - } - - if (event->button == 1 && - column_icon_test (view->priv->tree_view_staged, - event->x, - event->y, - &file)) - { - GList *files = NULL; - - gitg_commit_unstage (view->priv->commit, file, NULL, NULL); - - /* If the file is currently selected in the 'unstaged' tree, - then refresh the diff */ - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - if (files && !files->next) - { - GFile *f; - - f = gitg_changed_file_get_file (files->data); - - if (gitg_changed_file_equal (file, f)) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection ( - view->priv->tree_view_unstaged); - - unstaged_selection_changed (selection, view); - } - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - g_object_unref (file); - } - else if (event->button == 3) - { - view->priv->context_type = CONTEXT_TYPE_FILE; - popup_staged_menu (view, event); - } -} - -static gboolean -on_unstaged_motion (GtkWidget *widget, - GdkEventMotion *event, - GitgCommitView *view) -{ - if (column_icon_test (view->priv->tree_view_unstaged, - event->x, - event->y, - NULL)) - { - gdk_window_set_cursor (gtk_widget_get_window (widget), - view->priv->hand); - } - else - { - gdk_window_set_cursor (gtk_widget_get_window (widget), NULL); - } - - return FALSE; -} - -static gboolean -on_staged_motion (GtkWidget *widget, - GdkEventMotion *event, - GitgCommitView *view) -{ - if (column_icon_test (view->priv->tree_view_staged, - event->x, - event->y, - NULL)) - { - gdk_window_set_cursor (gtk_widget_get_window (widget), - view->priv->hand); - } - else - { - gdk_window_set_cursor (gtk_widget_get_window (widget), NULL); - } - - return FALSE; -} - -static gchar * -get_comment (GitgCommitView *view) -{ - GtkTextBuffer *buffer; - GtkTextIter start; - GtkTextIter end; - - buffer = gtk_text_view_get_buffer (view->priv->comment_view); - - gtk_text_buffer_get_bounds (buffer, &start, &end); - gchar *text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE); - gchar *ptr; - - for (ptr = text; *ptr; ptr = g_utf8_next_char (ptr)) - if (!g_unichar_isspace (g_utf8_get_char (ptr))) - { - return text; - } - - g_free (text); - return NULL; -} - -static void -show_error (GitgCommitView *view, - gchar const *error) -{ - GtkWidget *dlg; - - dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - "%s", - error); - - gtk_dialog_run (GTK_DIALOG (dlg)); - gtk_widget_destroy (dlg); -} - -static void -on_commit_clicked (GtkButton *button, - GitgCommitView *view) -{ - gchar *comment; - gboolean signoff; - gboolean amend; - - if (!gitg_commit_has_changes (view->priv->commit)) - { - show_error (view, _("You must first stage some changes before committing")); - return; - } - - comment = get_comment (view); - - if (!comment) - { - show_error (view, _("Please enter a commit message before committing")); - return; - } - - signoff = gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (view->priv->check_button_signed_off_by)); - - amend = gtk_toggle_button_get_active ( - GTK_TOGGLE_BUTTON (view->priv->check_button_amend)); - - GError *error = NULL; - - if (!gitg_commit_commit (view->priv->commit, - comment, - signoff, - amend, - &error)) - { - if (error && - error->domain == GITG_COMMIT_ERROR && - error->code == GITG_COMMIT_ERROR_SIGNOFF) - { - show_error (view, _("Your user name or email could not be retrieved for use in the sign off message")); - } - else - { - gchar *msg; - - msg = g_strconcat (_("Something went wrong while trying to commit"), - ":\n\n", - error->message, - NULL); - - show_error (view, msg); - g_free (msg); - } - - if (error) - { - g_error_free (error); - } - } - else - { - gtk_text_buffer_set_text ( - gtk_text_view_get_buffer (view->priv->comment_view), - "", - -1); - - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON (view->priv->check_button_amend), - FALSE); - - gtk_toggle_button_set_active ( - GTK_TOGGLE_BUTTON (view->priv->check_button_signed_off_by), - FALSE); - } - - g_free (comment); -} - -static void -on_context_value_changed (GtkHScale *scale, - GitgCommitView *view) -{ - view->priv->context_size = (gint)gtk_range_get_value (GTK_RANGE (scale)); - - if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED) - { - unstaged_selection_changed ( - gtk_tree_view_get_selection (view->priv->tree_view_unstaged), - view); - } - else if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_CACHED) - { - staged_selection_changed ( - gtk_tree_view_get_selection (view->priv->tree_view_staged), - view); - } -} - -static gboolean -set_unstaged_popup_status (GitgCommitView *view) -{ - GitgChangedFileChanges changes; - GitgChangedFileStatus status; - GtkAction *revert; - GtkAction *ignore; - GtkAction *edit; - GtkAction *delete; - - if (!get_selected_files (view->priv->tree_view_unstaged, - NULL, - NULL, - &changes, - &status)) - { - return FALSE; - } - - revert = gtk_ui_manager_get_action (view->priv->ui_manager, - "/ui/popup_commit_stage/RevertChangesAction"); - - ignore = gtk_ui_manager_get_action (view->priv->ui_manager, - "/ui/popup_commit_stage/IgnoreFileAction"); - - edit = gtk_ui_manager_get_action (view->priv->ui_manager, - "/ui/popup_commit_stage/EditFileAction"); - - delete = gtk_ui_manager_get_action (view->priv->ui_manager, - "/ui/popup_commit_stage/DeleteFileAction"); - - gtk_action_set_visible (revert, status == GITG_CHANGED_FILE_STATUS_MODIFIED || - status == GITG_CHANGED_FILE_STATUS_DELETED); - gtk_action_set_visible (ignore, status == GITG_CHANGED_FILE_STATUS_NEW); - - gtk_action_set_visible (edit, status != GITG_CHANGED_FILE_STATUS_DELETED); - gtk_action_set_visible (delete, status == GITG_CHANGED_FILE_STATUS_NEW); - - return TRUE; -} - -static gboolean -set_staged_popup_status (GitgCommitView *view) -{ - GitgChangedFileStatus status; - GtkAction *edit; - - if (!get_selected_files (view->priv->tree_view_staged, - NULL, - NULL, - NULL, - &status)) - { - return FALSE; - } - - edit = gtk_ui_manager_get_action (view->priv->ui_manager, - "/ui/popup_commit_stage/EditFileAction"); - - gtk_action_set_visible (edit, status != GITG_CHANGED_FILE_STATUS_DELETED); - - return TRUE; -} - -static gboolean -popup_unstaged_menu (GitgCommitView *view, - GdkEventButton *event) -{ - GtkWidget *wd; - - if (!set_unstaged_popup_status (view)) - { - return FALSE; - } - - wd = gtk_ui_manager_get_widget (view->priv->ui_manager, - "/ui/popup_commit_stage"); - - view->priv->context_type = CONTEXT_TYPE_FILE; - - if (event) - { - gtk_menu_popup (GTK_MENU (wd), - NULL, - NULL, - NULL, - NULL, - event->button, - event->time); - } - else - { - gtk_menu_popup (GTK_MENU (wd), - NULL, - NULL, - gitg_utils_menu_position_under_tree_view, - view->priv->tree_view_staged, - 0, - gtk_get_current_event_time ()); - } - - return TRUE; -} - -static gboolean -popup_staged_menu (GitgCommitView *view, - GdkEventButton *event) -{ - GtkWidget *wd; - - if (!set_staged_popup_status (view)) - { - return FALSE; - } - - wd = gtk_ui_manager_get_widget (view->priv->ui_manager, - "/ui/popup_commit_unstage"); - - view->priv->context_type = CONTEXT_TYPE_FILE; - - if (event) - { - gtk_menu_popup (GTK_MENU (wd), - NULL, - NULL, - NULL, - NULL, - event->button, - event->time); - } - else - { - gtk_menu_popup (GTK_MENU (wd), - NULL, - NULL, - gitg_utils_menu_position_under_tree_view, - view->priv->tree_view_unstaged, - 0, - gtk_get_current_event_time ()); - } - - return TRUE; -} - - -static gboolean -on_unstaged_popup_menu (GtkWidget *widget, - GitgCommitView *view) -{ - return popup_unstaged_menu (view, NULL); -} - -static gboolean -on_staged_popup_menu (GtkWidget *widget, - GitgCommitView *view) -{ - return popup_staged_menu (view, NULL); -} - -static void -on_stage_changes (GtkAction *action, - GitgCommitView *view) -{ - if (view->priv->context_type == CONTEXT_TYPE_FILE) - { - GList *files = NULL; - GList *item; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - gitg_commit_stage (view->priv->commit, - GITG_CHANGED_FILE (item->data), - NULL, - NULL); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - } - else - { - handle_stage_unstage (view, &view->priv->context_iter); - } -} - -static void -do_revert_changes (GitgCommitView *view) -{ - gboolean ret = TRUE; - - if (view->priv->context_type == CONTEXT_TYPE_FILE) - { - GList *files = NULL; - GList *item; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - ret &= gitg_commit_undo (view->priv->commit, - GITG_CHANGED_FILE (item->data), - NULL, - NULL); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - } - else - { - GitgChangedFile *file; - gchar *hunk; - - file = g_object_ref (view->priv->current_file); - - hunk = get_hunk_patch (view, &view->priv->context_iter); - - ret = gitg_commit_undo (view->priv->commit, - view->priv->current_file, - hunk, - NULL); - - g_free (hunk); - - if (ret && view->priv->current_file == file) - { - gitg_diff_view_remove_hunk (GITG_DIFF_VIEW (view->priv->changes_view), - &view->priv->context_iter); - } - - g_object_unref (file); - } - - if (!ret) - { - show_error (view, _("Revert fail")); - } -} - -static void -on_revert_changes (GtkAction *action, - GitgCommitView *view) -{ - GtkWidget *dialog; - gint response; - - dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), - GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", - _("Are you sure you want to revert these changes?")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", - _("Reverting changes is permanent and cannot be undone")); - - response = gtk_dialog_run (GTK_DIALOG (dialog)); - - if (response == GTK_RESPONSE_YES) - { - do_revert_changes (view); - } - - gtk_widget_destroy (dialog); -} - -static void -on_edit_file (GtkAction *action, - GitgCommitView *view) -{ - GList *files = NULL; - GList *item; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - GitgChangedFile *file = item->data; - - if (gitg_changed_file_get_status (file) == - GITG_CHANGED_FILE_STATUS_DELETED) - { - continue; - } - - GFile *location = gitg_changed_file_get_file (file); - gchar *uri = g_file_get_uri (location); - - gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (view)), - uri, - GDK_CURRENT_TIME, - NULL); - - g_free (uri); - g_object_unref (location); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); -} - -static void -do_delete_file (GitgCommitView *view) -{ - GList *files = NULL; - GList *item; - gboolean success = TRUE; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - GitgChangedFile *file = item->data; - GFile *location = gitg_changed_file_get_file (file); - - success &= g_file_delete (location, NULL, NULL); - - g_object_unref (location); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - - gitg_commit_refresh (view->priv->commit); - - if (!success) - { - show_error (view, _("Delete Failed")); - } -} - -static void -on_delete_file (GtkAction *action, - GitgCommitView *view) -{ - GtkWidget *toplevel; - GtkWidget *dialog; - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view)); - - dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel), - GTK_DIALOG_MODAL, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_YES_NO, - "%s", - _("Are you sure you want to delete these files?")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", - _("Deleting files is permanent " - "and cannot be undone")); - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) - { - do_delete_file (view); - } - - gtk_widget_destroy (dialog); -} - -static void -on_ignore_file (GtkAction *action, - GitgCommitView *view) -{ - GList *files = NULL; - GList *item; - - get_selected_files (view->priv->tree_view_unstaged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - gitg_commit_add_ignore (view->priv->commit, - GITG_CHANGED_FILE (item->data), - NULL); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); -} - -static void -on_unstage_changes (GtkAction *action, - GitgCommitView *view) -{ - if (view->priv->context_type == CONTEXT_TYPE_FILE) - { - GList *files = NULL; - GList *item; - - get_selected_files (view->priv->tree_view_staged, - &files, - NULL, - NULL, - NULL); - - for (item = files; item; item = g_list_next (item)) - { - gitg_commit_unstage (view->priv->commit, - GITG_CHANGED_FILE (item->data), - NULL, - NULL); - } - - g_list_free_full (files, (GDestroyNotify)g_object_unref); - } - else - { - handle_stage_unstage (view, &view->priv->context_iter); - } -} - -static GtkWidget * -create_context_menu_item (GitgCommitView *view, - gchar const *action) -{ - GtkAction *ac; - - ac = gtk_action_group_get_action (view->priv->group_context, action); - - return gtk_action_create_menu_item (ac); -} - -static void -on_changes_view_popup_menu (GtkTextView *textview, - GtkMenu *menu, - GitgCommitView *view) -{ - gboolean is_hunk; - - get_info_at_pointer (view, - &view->priv->context_iter, - &is_hunk, - NULL, - NULL); - - if (!is_hunk) - { - return; - } - - GtkWidget *separator = gtk_separator_menu_item_new (); - gtk_widget_show (separator); - - view->priv->context_type = CONTEXT_TYPE_HUNK; - - gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator); - - if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_CACHED) - { - GtkWidget *unstage; - - unstage = create_context_menu_item (view, "UnstageChangesAction"); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), unstage); - } - else - { - GtkWidget *stage; - GtkWidget *revert; - - stage = create_context_menu_item (view, "StageChangesAction"); - revert = create_context_menu_item (view, "RevertChangesAction"); - - gtk_menu_shell_append (GTK_MENU_SHELL (menu), stage); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), revert); - } -} - -static void -on_check_button_amend_toggled (GtkToggleButton *button, - GitgCommitView *view) -{ - gboolean active; - GtkTextBuffer *buffer; - GtkTextIter start; - GtkTextIter end; - - active = gtk_toggle_button_get_active (button); - buffer = gtk_text_view_get_buffer (view->priv->comment_view); - - gtk_text_buffer_get_bounds (buffer, &start, &end); - - if (active && gtk_text_iter_compare (&start, &end) == 0) - { - // Get last commit message - gchar *message; - - message = gitg_commit_amend_message (view->priv->commit); - - if (message) - { - gtk_text_buffer_set_text (buffer, message, -1); - } - - g_free (message); - } -} - -static void -pixbuf_renderer_query_data_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state, - GitgCommitView *view) -{ - GitgDiffView *diff_view; - const gchar *stock_id; - - diff_view = GITG_DIFF_VIEW (view->priv->changes_view); - - switch (gitg_diff_view_get_line_type (diff_view, start)) - { - case GITG_DIFF_LINE_TYPE_NONE: - stock_id = GTK_STOCK_DISCARD; - break; - case GITG_DIFF_LINE_TYPE_ADD: - stock_id = GTK_STOCK_ADD; - break; - case GITG_DIFF_LINE_TYPE_REMOVE: - stock_id = GTK_STOCK_REMOVE; - break; - default: - g_return_if_reached (); - } - - g_object_set (renderer, - "stock-id", stock_id, - NULL); -} - -static gboolean -pixbuf_renderer_query_activatable_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *iter, - GdkRectangle *area, - GdkEvent *event, - GitgCommitView *view) -{ - GitgDiffView *diff_view = GITG_DIFF_VIEW (view->priv->changes_view); - GitgDiffLineType line_type; - - line_type = gitg_diff_view_get_line_type (diff_view, iter); - - return line_type != GITG_DIFF_LINE_TYPE_NONE && - ((GdkEventButton *) event)->button == 1; -} - -static void -pixbuf_renderer_activate_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *iter, - GdkRectangle *area, - GdkEvent *event, - GitgCommitView *view) -{ - handle_stage_unstage_line (view, iter); -} diff --git a/gitg/gitg-commit-view.h b/gitg/gitg-commit-view.h deleted file mode 100644 index a4cde9dd..00000000 --- a/gitg/gitg-commit-view.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * gitg-commit-view.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_COMMIT_VIEW_H__ -#define __GITG_COMMIT_VIEW_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_COMMIT_VIEW (gitg_commit_view_get_type ()) -#define GITG_COMMIT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMIT_VIEW, GitgCommitView)) -#define GITG_COMMIT_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMIT_VIEW, GitgCommitView const)) -#define GITG_COMMIT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_COMMIT_VIEW, GitgCommitViewClass)) -#define GITG_IS_COMMIT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_COMMIT_VIEW)) -#define GITG_IS_COMMIT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_COMMIT_VIEW)) -#define GITG_COMMIT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_COMMIT_VIEW, GitgCommitViewClass)) - -typedef struct _GitgCommitView GitgCommitView; -typedef struct _GitgCommitViewClass GitgCommitViewClass; -typedef struct _GitgCommitViewPrivate GitgCommitViewPrivate; - -struct _GitgCommitView -{ - GtkVPaned parent; - - GitgCommitViewPrivate *priv; -}; - -struct _GitgCommitViewClass -{ - GtkVPanedClass parent_class; -}; - -GType gitg_commit_view_get_type (void) G_GNUC_CONST; -void gitg_commit_view_set_repository (GitgCommitView *view, - GitgRepository *repository); - -G_END_DECLS - -#endif /* __GITG_COMMIT_VIEW_H__ */ diff --git a/gitg/gitg-diff-line-renderer.c b/gitg/gitg-diff-line-renderer.c deleted file mode 100644 index e28eb8fb..00000000 --- a/gitg/gitg-diff-line-renderer.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * gitg-diff-line-renderer.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-utils.h" -#include "gitg-diff-line-renderer.h" - -#define GITG_DIFF_LINE_RENDERER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRendererPrivate)) - -/* Properties */ -enum -{ - PROP_0, - PROP_LINE_OLD, - PROP_LINE_NEW -}; - -struct _GitgDiffLineRendererPrivate -{ - gint line_old; - gint line_new; - gint num_digits; - - PangoLayout *cached_layout; - PangoAttribute *fg_attr; - PangoAttrList *cached_attr_list; - - glong changed_handler_id; -}; - -G_DEFINE_TYPE (GitgDiffLineRenderer, gitg_diff_line_renderer, GTK_SOURCE_TYPE_GUTTER_RENDERER) - -static void -gitg_diff_line_renderer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgDiffLineRenderer *self = GITG_DIFF_LINE_RENDERER (object); - - switch (prop_id) - { - case PROP_LINE_OLD: - self->priv->line_old = g_value_get_int (value); - break; - case PROP_LINE_NEW: - self->priv->line_new = g_value_get_int (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_diff_line_renderer_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgDiffLineRenderer *self = GITG_DIFF_LINE_RENDERER (object); - - switch (prop_id) - { - case PROP_LINE_OLD: - g_value_set_int (value, self->priv->line_old); - break; - case PROP_LINE_NEW: - g_value_set_int (value, self->priv->line_new); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -create_layout (GitgDiffLineRenderer *renderer, - GtkWidget *widget) -{ - PangoLayout *layout; - PangoAttribute *attr; - GtkStyleContext *context; - GdkRGBA color; - PangoAttrList *attr_list; - - layout = gtk_widget_create_pango_layout (widget, NULL); - - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color); - - attr = pango_attr_foreground_new (color.red * 65535, - color.green * 65535, - color.blue * 65535); - - attr->start_index = 0; - attr->end_index = G_MAXINT; - - attr_list = pango_attr_list_new (); - pango_attr_list_insert (attr_list, attr); - - renderer->priv->fg_attr = attr; - renderer->priv->cached_layout = layout; - renderer->priv->cached_attr_list = attr_list; -} - -static void -gitg_diff_line_renderer_begin (GtkSourceGutterRenderer *renderer, - cairo_t *cr, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end) -{ - GitgDiffLineRenderer *lr = GITG_DIFF_LINE_RENDERER (renderer); - - create_layout (lr, GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer))); -} - -static void -gitg_diff_line_renderer_draw (GtkSourceGutterRenderer *renderer, - cairo_t *ctx, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState renderer_state) -{ - GitgDiffLineRenderer *lr = GITG_DIFF_LINE_RENDERER (renderer); - gchar old_str[16]; - gchar new_str[16]; - PangoLayout *layout; - GtkWidget *widget; - GtkStyleContext *style_context; - guint xpad = 0; - - /* Chain up to draw background */ - GTK_SOURCE_GUTTER_RENDERER_CLASS ( - gitg_diff_line_renderer_parent_class)->draw (renderer, - ctx, - background_area, - cell_area, - start, - end, - renderer_state); - - widget = GTK_WIDGET (gtk_source_gutter_renderer_get_view (renderer)); - layout = lr->priv->cached_layout; - - pango_layout_set_width (layout, cell_area->width / 2); - - pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); - - if (lr->priv->line_old >= 0) - { - g_snprintf (old_str, sizeof (old_str), "%d", lr->priv->line_old); - } - else - { - *old_str = '\0'; - } - - if (lr->priv->line_new >= 0) - { - g_snprintf (new_str, sizeof (old_str), "%d", lr->priv->line_new); - } - else - { - *new_str = '\0'; - } - - g_object_get (renderer, "xpad", &xpad, NULL); - - pango_layout_set_text (layout, old_str, -1); - style_context = gtk_widget_get_style_context (widget); - - gtk_render_layout (style_context, - ctx, - cell_area->x + cell_area->width / 2 - xpad, - cell_area->y, - layout); - - pango_layout_set_text (layout, new_str, -1); - gtk_render_layout (style_context, - ctx, - cell_area->x + cell_area->width, - cell_area->y, - layout); - - gtk_render_line (style_context, - ctx, - background_area->x + background_area->width / 2, - background_area->y - 1, - background_area->x + background_area->width / 2, - background_area->y + background_area->height); -} - -static void -gitg_diff_line_renderer_end (GtkSourceGutterRenderer *renderer) -{ - GitgDiffLineRenderer *lr = GITG_DIFF_LINE_RENDERER (renderer); - - g_object_unref (lr->priv->cached_layout); - lr->priv->cached_layout = NULL; - - pango_attr_list_unref (lr->priv->cached_attr_list); - lr->priv->cached_attr_list = NULL; - - lr->priv->fg_attr = NULL; -} - -static void -measure_text (GitgDiffLineRenderer *lr, - const gchar *markup, - const gchar *text, - gint *width, - gint *height) -{ - PangoLayout *layout; - gint w; - gint h; - GtkSourceGutterRenderer *r; - GtkTextView *view; - - r = GTK_SOURCE_GUTTER_RENDERER (lr); - view = gtk_source_gutter_renderer_get_view (r); - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL); - - if (markup) - { - pango_layout_set_markup (layout, - markup, - -1); - } - else - { - pango_layout_set_text (layout, - text, - -1); - } - - pango_layout_get_size (layout, &w, &h); - - if (width) - { - *width = w / PANGO_SCALE; - } - - if (height) - { - *height = h / PANGO_SCALE; - } - - g_object_unref (layout); -} - -static void -recalculate_size (GitgDiffLineRenderer *lr) -{ - gchar *markup; - gint size; - gint num = 1; - gint i; - - for (i = 1; i < lr->priv->num_digits; ++i) - { - num *= 10; - } - - markup = g_strdup_printf ("%d %d", - num, - num); - - measure_text (lr, markup, NULL, &size, NULL); - g_free (markup); - - gtk_source_gutter_renderer_set_size (GTK_SOURCE_GUTTER_RENDERER (lr), - size); -} - -static void -update_num_digits (GitgDiffLineRenderer *renderer, - guint max_line_count) -{ - /* Get size of this rendering */ - gint num_digits; - - num_digits = 0; - - while (max_line_count > 0) - { - max_line_count /= 10; - ++num_digits; - } - - num_digits = MAX (num_digits, 2); - - if (num_digits != renderer->priv->num_digits) - { - renderer->priv->num_digits = num_digits; - recalculate_size (renderer); - } -} - -static void -gitg_diff_line_renderer_class_init (GitgDiffLineRendererClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkSourceGutterRendererClass *renderer_class = GTK_SOURCE_GUTTER_RENDERER_CLASS (klass); - - renderer_class->begin = gitg_diff_line_renderer_begin; - renderer_class->draw = gitg_diff_line_renderer_draw; - renderer_class->end= gitg_diff_line_renderer_end; - - object_class->set_property = gitg_diff_line_renderer_set_property; - object_class->get_property = gitg_diff_line_renderer_get_property; - - g_object_class_install_property (object_class, - PROP_LINE_OLD, - g_param_spec_int ("line-old", - "Line Old", - "Line Old", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_LINE_NEW, - g_param_spec_int ("line-new", - "Line New", - "Line New", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_type_class_add_private (object_class, sizeof (GitgDiffLineRendererPrivate)); -} - -static void -gitg_diff_line_renderer_init (GitgDiffLineRenderer *self) -{ - self->priv = GITG_DIFF_LINE_RENDERER_GET_PRIVATE (self); -} - -GitgDiffLineRenderer * -gitg_diff_line_renderer_new () -{ - return g_object_new (GITG_TYPE_DIFF_LINE_RENDERER, NULL); -} - -void -gitg_diff_line_renderer_set_max_line_count (GitgDiffLineRenderer *renderer, - guint max_line_count) -{ - g_return_if_fail (GITG_IS_DIFF_LINE_RENDERER (renderer)); - - update_num_digits (renderer, max_line_count); -} diff --git a/gitg/gitg-diff-line-renderer.h b/gitg/gitg-diff-line-renderer.h deleted file mode 100644 index 1ffdad5a..00000000 --- a/gitg/gitg-diff-line-renderer.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * gitg-diff-line-renderer.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_DIFF_LINE_RENDERER_H__ -#define __GITG_DIFF_LINE_RENDERER_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_DIFF_LINE_RENDERER (gitg_diff_line_renderer_get_type ()) -#define GITG_DIFF_LINE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRenderer)) -#define GITG_DIFF_LINE_RENDERER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRenderer const)) -#define GITG_DIFF_LINE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRendererClass)) -#define GITG_IS_DIFF_LINE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_DIFF_LINE_RENDERER)) -#define GITG_IS_DIFF_LINE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_DIFF_LINE_RENDERER)) -#define GITG_DIFF_LINE_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRendererClass)) - -typedef struct _GitgDiffLineRenderer GitgDiffLineRenderer; -typedef struct _GitgDiffLineRendererClass GitgDiffLineRendererClass; -typedef struct _GitgDiffLineRendererPrivate GitgDiffLineRendererPrivate; - -struct _GitgDiffLineRenderer { - GtkSourceGutterRenderer parent; - - GitgDiffLineRendererPrivate *priv; -}; - -struct _GitgDiffLineRendererClass { - GtkSourceGutterRendererClass parent_class; -}; - -GType gitg_diff_line_renderer_get_type (void) G_GNUC_CONST; -GitgDiffLineRenderer *gitg_diff_line_renderer_new (void); - -void gitg_diff_line_renderer_set_max_line_count (GitgDiffLineRenderer *renderer, - guint max_line_count); - -G_END_DECLS - -#endif /* __GITG_DIFF_LINE_RENDERER_H__ */ diff --git a/gitg/gitg-diff-view.c b/gitg/gitg-diff-view.c deleted file mode 100644 index 284a8676..00000000 --- a/gitg/gitg-diff-view.c +++ /dev/null @@ -1,1633 +0,0 @@ -/* - * gitg-diff-view.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-diff-view.h" -#include "gitg-diff-line-renderer.h" -#include "gitg-utils.h" - -#include -#include - -#define GITG_DIFF_VIEW_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_DIFF_VIEW, GitgDiffViewPrivate)) - -#ifndef MAX -#define MAX(a, b) (a > b ? a : b) -#endif - -#ifndef MIN -#define MIN(a, b) (a < b ? a : b) -#endif - -#define IDLE_SCAN_COUNT 30 - -#define GITG_DIFF_ITER_GET_VIEW(iter) ((GitgDiffView *) ((iter)->userdata)) -#define GITG_DIFF_ITER_GET_REGION(iter) ((Region *) ((iter)->userdata2)) - -#define GITG_DIFF_ITER_SET_REGION(iter, region) ((iter)->userdata2 = region) -#define GITG_DIFF_ITER_SET_VIEW(iter, view) ((iter)->userdata = view) - -static void on_buffer_insert_text (GtkTextBuffer *buffer, - GtkTextIter *iter, - gchar const *text, - gint len, - GitgDiffView *view); - -static void on_buffer_delete_range (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GitgDiffView *view); - -/*static void -line_renderer_size_func (GtkSourceGutter *gutter, - GtkCellRenderer *cell, - GitgDiffView *view); -*/ -static void line_renderer_query_data_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state, - GitgDiffView *view); -static void disable_diff_view (GitgDiffView *view); -static void enable_diff_view (GitgDiffView *view); - -static gboolean on_idle_scan (GitgDiffView *view); - -/* Signals */ -enum -{ - HEADER_ADDED, - HUNK_ADDED, - NUM_SIGNALS -}; - -/* Properties */ -enum -{ - PROP_0, - - PROP_DIFF_ENABLED -}; - -typedef struct _Region Region; - -struct _Region -{ - GitgDiffIterType type; - Region *next; - Region *prev; - - guint line; - gboolean visible; -}; - -typedef struct -{ - Region region; - - gchar index_from[GITG_HASH_SHA_SIZE + 1]; - gchar index_to[GITG_HASH_SHA_SIZE + 1]; -} Header; - -typedef struct -{ - Region region; - guint old; - guint new; -} Hunk; - -struct _GitgDiffViewPrivate -{ - guint last_scan_line; - - guint max_line_count; - Region *regions; - Region *last_region; - GSequence *regions_index; - - guint scan_id; - gboolean diff_enabled; - GtkTextBuffer *current_buffer; - GtkTextTag *invisible_tag; - GtkTextTag *subheader_tag; - - GitgDiffLineRenderer *line_renderer; - - Region *lines_current_region; - gint lines_previous_line; - guint lines_counters[2]; - - gboolean ignore_changes; -}; - -G_DEFINE_TYPE (GitgDiffView, gitg_diff_view, GTK_SOURCE_TYPE_VIEW) - -static gboolean gitg_diff_view_draw (GtkWidget *widget, cairo_t *cr); -static guint diff_view_signals[NUM_SIGNALS] = {0,}; - -static void -region_free (Region *region, - gboolean all) -{ - if (!region) - { - return; - } - - if (all) - { - region_free (region->next, all); - } - else - { - if (region->next) - { - region->next->prev = region->prev; - } - - if (region->prev) - { - region->prev->next = region->next; - } - } - - if (region->type == GITG_DIFF_ITER_TYPE_HEADER) - { - g_slice_free (Header, (Header *)region); - } - else - { - g_slice_free (Hunk, (Hunk *)region); - } -} - -static void -set_max_line_count (GitgDiffView *view, - guint max_line_count) -{ - view->priv->max_line_count = max_line_count; - - if (view->priv->line_renderer) - { - gitg_diff_line_renderer_set_max_line_count (view->priv->line_renderer, - max_line_count); - } -} - -static void -regions_free (GitgDiffView *view) -{ - region_free (view->priv->regions, TRUE); - - g_sequence_remove_range (g_sequence_get_begin_iter (view->priv->regions_index), - g_sequence_get_end_iter (view->priv->regions_index)); - - view->priv->regions = NULL; - view->priv->last_region = NULL; - view->priv->last_scan_line = 0; - - set_max_line_count (view, 99); -} - -static void -gitg_diff_view_finalize (GObject *object) -{ - GitgDiffView *view = GITG_DIFF_VIEW (object); - - regions_free (view); - g_sequence_free (view->priv->regions_index); - - G_OBJECT_CLASS (gitg_diff_view_parent_class)->finalize (object); -} - -static void -gitg_diff_view_dispose (GObject *object) -{ - GitgDiffView *view = GITG_DIFF_VIEW (object); - - disable_diff_view (view); - - if (view->priv->line_renderer) - { - g_object_unref (view->priv->line_renderer); - view->priv->line_renderer = NULL; - } - - G_OBJECT_CLASS (gitg_diff_view_parent_class)->dispose (object); -} - -static void -set_diff_enabled (GitgDiffView *view, - gboolean enabled) -{ - if (enabled == view->priv->diff_enabled) - { - return; - } - - if (enabled) - { - enable_diff_view (view); - } - else - { - disable_diff_view (view); - } - - gtk_widget_queue_draw (GTK_WIDGET (view)); -} - -static void -gitg_diff_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgDiffView *self = GITG_DIFF_VIEW (object); - - switch (prop_id) - { - case PROP_DIFF_ENABLED: - set_diff_enabled (self, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_diff_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgDiffView *self = GITG_DIFF_VIEW (object); - - switch (prop_id) - { - case PROP_DIFF_ENABLED: - g_value_set_boolean (value, self->priv->diff_enabled); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_diff_view_constructed (GObject *object) -{ - g_object_set (object, "show-line-numbers", FALSE, NULL); - - G_OBJECT_CLASS (gitg_diff_view_parent_class)->constructed (object); -} - -static void -gitg_diff_view_class_init (GitgDiffViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->finalize = gitg_diff_view_finalize; - object_class->dispose = gitg_diff_view_dispose; - object_class->set_property = gitg_diff_view_set_property; - object_class->get_property = gitg_diff_view_get_property; - - object_class->constructed = gitg_diff_view_constructed; - - widget_class->draw = gitg_diff_view_draw; - - diff_view_signals[HEADER_ADDED] = - g_signal_new ("header-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgDiffViewClass, header_added), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - diff_view_signals[HUNK_ADDED] = - g_signal_new ("hunk-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgDiffViewClass, hunk_added), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - g_object_class_install_property (object_class, PROP_DIFF_ENABLED, - g_param_spec_boolean ("diff-enabled", - "DIFF_ENABLED", - "Enables diff view", - FALSE, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof (GitgDiffViewPrivate)); -} - -static void -disable_diff_view (GitgDiffView *view) -{ - if (!view->priv->diff_enabled) - { - return; - } - - regions_free (view); - - if (view->priv->scan_id) - { - g_source_remove (view->priv->scan_id); - view->priv->scan_id = 0; - } - - if (view->priv->current_buffer) - { - GtkTextTagTable *table; - GtkSourceGutter *gutter; - - table = gtk_text_buffer_get_tag_table (view->priv->current_buffer); - - g_signal_handlers_disconnect_by_func (view->priv->current_buffer, - G_CALLBACK (on_buffer_insert_text), - view); - - g_signal_handlers_disconnect_by_func (view->priv->current_buffer, - G_CALLBACK (on_buffer_delete_range), - view); - - gtk_text_tag_table_remove (table, view->priv->invisible_tag); - gtk_text_tag_table_remove (table, view->priv->subheader_tag); - - g_object_unref (view->priv->current_buffer); - - view->priv->current_buffer = NULL; - view->priv->invisible_tag = NULL; - view->priv->subheader_tag = NULL; - - gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (view), - GTK_TEXT_WINDOW_LEFT); - - gtk_source_gutter_remove (gutter, - GTK_SOURCE_GUTTER_RENDERER (view->priv->line_renderer)); - } - - view->priv->diff_enabled = FALSE; -} - -static void -enable_diff_view (GitgDiffView *view) -{ - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkSourceGutter *gutter; - - if (view->priv->diff_enabled) - { - disable_diff_view (view); - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - view->priv->current_buffer = g_object_ref (buffer); - - g_signal_connect_after (buffer, - "insert-text", - G_CALLBACK (on_buffer_insert_text), - view); - - g_signal_connect_after (buffer, - "delete-range", - G_CALLBACK (on_buffer_delete_range), - view); - - view->priv->scan_id = g_idle_add ( (GSourceFunc)on_idle_scan, view); - - view->priv->invisible_tag = gtk_text_buffer_create_tag (view->priv->current_buffer, - "GitgHunkInvisible", - "invisible", - TRUE, - NULL); - - view->priv->subheader_tag = gtk_text_buffer_create_tag (view->priv->current_buffer, - "GitgHunkSubHeader", - "invisible", - TRUE, - NULL); - - table = gtk_text_buffer_get_tag_table (view->priv->current_buffer); - - gtk_text_tag_set_priority (view->priv->subheader_tag, - gtk_text_tag_table_get_size (table) - 1); - - gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (view), - GTK_TEXT_WINDOW_LEFT); - - gtk_source_gutter_insert (gutter, - GTK_SOURCE_GUTTER_RENDERER (view->priv->line_renderer), - 0); - - g_signal_connect (view->priv->line_renderer, - "query-data", - (GCallback) line_renderer_query_data_cb, - view); - - view->priv->diff_enabled = TRUE; -} - -static void -on_buffer_set (GitgDiffView *self, GParamSpec *spec, gpointer userdata) -{ - if (self->priv->diff_enabled) - { - enable_diff_view (self); - } -} - -static void -gitg_diff_view_init (GitgDiffView *self) -{ - self->priv = GITG_DIFF_VIEW_GET_PRIVATE (self); - - self->priv->regions_index = g_sequence_new (NULL); - self->priv->line_renderer = gitg_diff_line_renderer_new (); - - g_object_ref (self->priv->line_renderer); - g_object_set (self->priv->line_renderer, "xpad", 2, NULL); - - g_signal_connect (self, "notify::buffer", G_CALLBACK (on_buffer_set), NULL); -} - -GitgDiffView * -gitg_diff_view_new () -{ - return g_object_new (GITG_TYPE_DIFF_VIEW, NULL); -} - -static gint -index_compare (gconstpointer a, gconstpointer b, gpointer userdata) -{ - guint la = ( (Region *)a)->line; - guint lb = ( (Region *)b)->line; - - return la < lb ? -1 : (la > lb ? 1 : 0); -} - -static void -ensure_max_line (GitgDiffView *view, Hunk *hunk) -{ - guint num = hunk->region.next ? hunk->region.next->line - hunk->region.line : 0; - guint m = MAX (hunk->new + num, hunk->old + num); - - if (m > view->priv->max_line_count) - { - set_max_line_count (view, m); - - gtk_source_gutter_queue_draw (gtk_source_view_get_gutter (GTK_SOURCE_VIEW (view), GTK_TEXT_WINDOW_LEFT)); - } -} - -static void -hide_header_details (GitgDiffView *view, - Region *region) -{ - /* Just hide the lines 2->n lines from region to region->next */ - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - GtkTextIter startiter; - GtkTextIter enditer; - - gint line = region->line + 2; - - gtk_text_buffer_get_iter_at_line (buffer, &startiter, line); - - enditer = startiter; - - if (region->next) - { - gtk_text_iter_forward_lines (&enditer, region->next->line - line); - } - else - { - gtk_text_iter_forward_line (&enditer); - } - - gtk_text_buffer_apply_tag (buffer, view->priv->subheader_tag, &startiter, &enditer); -} - -static void -region_to_iter (GitgDiffView *view, Region *region, GitgDiffIter *iter) -{ - GITG_DIFF_ITER_SET_VIEW (iter, view); - GITG_DIFF_ITER_SET_REGION (iter, region); -} - -static void -add_region (GitgDiffView *view, Region *region) -{ - if (view->priv->last_region) - { - view->priv->last_region->next = region; - region->prev = view->priv->last_region; - - if (view->priv->last_region->type == GITG_DIFF_ITER_TYPE_HUNK) - { - ensure_max_line (view, (Hunk *)view->priv->last_region); - } - } - else - { - view->priv->regions = region; - region->prev = NULL; - } - - view->priv->last_region = region; - - if (region->prev && region->prev->type == GITG_DIFF_ITER_TYPE_HEADER) - { - /* Hide header details if first hunk is scanned */ - hide_header_details (view, region->prev); - } - - g_sequence_insert_sorted (view->priv->regions_index, region, index_compare, NULL); - - GitgDiffIter iter; - region_to_iter (view, region, &iter); - - if (region->type == GITG_DIFF_ITER_TYPE_HEADER) - { - g_signal_emit (view, diff_view_signals[HEADER_ADDED], 0, &iter); - } - else if (region->type == GITG_DIFF_ITER_TYPE_HUNK) - { - g_signal_emit (view, diff_view_signals[HUNK_ADDED], 0, &iter); - } -} - -static void -parse_hunk_info (Hunk *hunk, GtkTextIter *iter) -{ - GtkTextIter end = *iter; - - gtk_text_iter_forward_to_line_end (&end); - gchar *text = gtk_text_iter_get_text (iter, &end); - - hunk->old = 0; - hunk->new = 0; - - gchar *old = g_utf8_strchr (text, -1, '-'); - gchar *new = g_utf8_strchr (text, -1, '+'); - - if (!old || !new) - { - return; - } - - hunk->old = atoi (old + 1); - hunk->new = atoi (new + 1); - - g_free (text); -} - -static void -ensure_scan (GitgDiffView *view, guint last_line) -{ - /* Scan from last_scan_line, making regions */ - GtkTextIter iter; - GtkTextBuffer *buffer = view->priv->current_buffer; - gtk_text_buffer_get_iter_at_line (buffer, &iter, view->priv->last_scan_line); - - while (view->priv->last_scan_line <= last_line) - { - GtkTextIter start = iter; - GtkTextIter end = iter; - - if (!gtk_text_iter_forward_line (&iter)) - { - break; - } - - ++view->priv->last_scan_line; - - if (!gtk_text_iter_forward_chars (&end, 3)) - { - continue; - } - - gchar *text = gtk_text_iter_get_text (&start, &end); - - if (g_str_has_prefix (text, "@@ ") || g_str_has_prefix (text, "@@@")) - { - /* start new hunk region */ - Hunk *hunk = g_slice_new (Hunk); - hunk->region.type = GITG_DIFF_ITER_TYPE_HUNK; - hunk->region.line = view->priv->last_scan_line - 1; - hunk->region.visible = TRUE; - - parse_hunk_info (hunk, &start); - - add_region (view, (Region *)hunk); - - g_free (text); - continue; - } - - g_free (text); - - if (!gtk_text_iter_forward_chars (&end, 7)) - { - continue; - } - - text = gtk_text_iter_get_text (&start, &end); - - if (g_str_has_prefix (text, "diff --git") || g_str_has_prefix (text, "diff --cc")) - { - /* start new header region */ - Header *header = g_slice_new (Header); - header->region.type = GITG_DIFF_ITER_TYPE_HEADER; - header->region.line = view->priv->last_scan_line - 1; - header->region.visible = TRUE; - - header->index_to[0] = '\0'; - header->index_from[0] = '\0'; - - add_region (view, (Region *)header); - } - - g_free (text); - } - - if (view->priv->last_region && view->priv->last_region->type == GITG_DIFF_ITER_TYPE_HUNK) - { - ensure_max_line (view, (Hunk *)view->priv->last_region); - } -} - -static Region * -find_current_region (GitgDiffView *view, guint line) -{ - GSequenceIter *iter; - Region tmp = {0, NULL, NULL, line}; - - iter = g_sequence_search (view->priv->regions_index, &tmp, index_compare, NULL); - - if (!iter || g_sequence_iter_is_begin (iter)) - { - return NULL; - } - - if (!g_sequence_iter_is_end (iter)) - { - Region *ret = (Region *)g_sequence_get (iter); - - if (ret->line == line) - { - return ret->visible ? ret : NULL; - } - } - - Region *ret = (Region *)g_sequence_get (g_sequence_iter_prev (iter)); - return ret->visible ? ret : NULL; -} - -static gboolean -line_has_prefix (GitgDiffView *view, guint line, gchar const *prefix) -{ - GtkTextIter iter; - - gtk_text_buffer_get_iter_at_line (view->priv->current_buffer, &iter, line); - - GtkTextIter end = iter; - - if (!gtk_text_iter_forward_chars (&end, g_utf8_strlen (prefix, -1))) - { - return FALSE; - } - - gchar *text = gtk_text_iter_get_text (&iter, &end); - gboolean ret = g_str_has_prefix (text, prefix); - g_free (text); - - return ret; -} - -static gboolean -draw_old (GitgDiffView *view, guint line) -{ - return !line_has_prefix (view, line, "+"); -} - -static gboolean -draw_new (GitgDiffView *view, guint line) -{ - return !line_has_prefix (view, line, "-"); -} - -static void -get_initial_counters (GitgDiffView *view, Region *region, guint line, guint counters[2]) -{ - guint i; - - counters[0] = counters[1] = 0; - - for (i = region->line + 1; i < line; ++i) - { - if (draw_old (view, i)) - ++counters[0]; - - if (draw_new (view, i)) - ++counters[1]; - } -} - -static void -line_renderer_query_data_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state, - GitgDiffView *view) -{ - gint line_old = -1; - gint line_new = -1; - gint line_number; - Region **current = &view->priv->lines_current_region; - - line_number = gtk_text_iter_get_line (start) + 1; - - ensure_scan (view, line_number); - - if (!*current || view->priv->lines_previous_line + 1 != line_number) - { - *current = find_current_region (view, line_number); - - if (*current) - { - get_initial_counters (view, - *current, - line_number, - view->priv->lines_counters); - } - } - - view->priv->lines_previous_line = line_number; - - if (*current && - (*current)->type == GITG_DIFF_ITER_TYPE_HUNK && - line_number != (*current)->line) - { - Hunk *hunk = (Hunk *)*current; - - if (draw_old (view, line_number)) - { - line_old = hunk->old + view->priv->lines_counters[0]++; - } - - if (draw_new (view, line_number)) - { - line_new = hunk->new + view->priv->lines_counters[1]++; - } - } - - g_object_set (renderer, "line_old", line_old, "line_new", line_new, NULL); - - if (*current && (*current)->next && line_number == (*current)->next->line - 1) - { - view->priv->lines_counters[0] = view->priv->lines_counters[1] = 0; - *current = (*current)->next->visible ? (*current)->next : NULL; - } -} - -static gint -gitg_diff_view_draw (GtkWidget *widget, - cairo_t *cr) -{ - GitgDiffView *view = GITG_DIFF_VIEW (widget); - - /* Prepare for new round of draw on the line renderer */ - view->priv->lines_current_region = NULL; - view->priv->lines_previous_line = -1; - view->priv->lines_counters[0] = 0; - view->priv->lines_counters[1] = 0; - - if (GTK_WIDGET_CLASS (gitg_diff_view_parent_class)->draw) - { - return GTK_WIDGET_CLASS (gitg_diff_view_parent_class)->draw (widget, cr); - } - else - { - return FALSE; - } -} - -void -gitg_diff_view_set_diff_enabled (GitgDiffView *view, gboolean enabled) -{ - g_return_if_fail (GITG_IS_DIFF_VIEW (view)); - - set_diff_enabled (view, enabled); - - g_object_notify (G_OBJECT (view), "diff-enabled"); -} - -static void -offset_regions (Region *region, - gint offset) -{ - while (region) - { - region->line += offset; - region = region->next; - } -} - -static gint -compare_regions (Region *first, - Region *second, - gpointer user_data) -{ - return first->line < second->line ? -1 : (first->line > second->line ? 1 : 0); -} - -static GSequenceIter * -region_get_iter (GitgDiffView *view, Region *region) -{ - GSequenceIter *iter; - - iter = g_sequence_search (view->priv->regions_index, - region, - (GCompareDataFunc)compare_regions, - NULL); - - if (g_sequence_iter_is_end (iter)) - { - return g_sequence_iter_prev (iter); - } - else - { - Region *reg = g_sequence_get (iter); - - if (reg->line != region->line) - { - return g_sequence_iter_prev (iter); - } - else - { - return iter; - } - } -} - -static void -remove_regions_sequence (GitgDiffView *view, - Region *from, - Region *to) -{ - GSequenceIter *start; - GSequenceIter *end; - - start = region_get_iter (view, from); - - if (to) - { - end = g_sequence_iter_prev (region_get_iter (view, to)); - } - else - { - end = g_sequence_get_end_iter (view->priv->regions_index); - } - - g_sequence_remove_range (start, end); -} - -static void -remove_regions (GitgDiffView *view, Region *from, Region *to) -{ - GtkTextBuffer *buffer; - GtkTextIter start; - GtkTextIter end; - gint offset; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - if (from->prev) - { - if (to) - { - from->prev->next = to; - to->prev = from->prev; - } - else - { - from->prev->next = NULL; - } - } - else - { - if (to) - { - view->priv->regions = to; - to->prev = NULL; - } - else - { - view->priv->regions = NULL; - } - } - - if (!to) - { - view->priv->last_region = from->prev; - } - - remove_regions_sequence (view, from, to); - - gtk_text_buffer_get_iter_at_line (buffer, &start, from->line); - - if (to) - { - gtk_text_buffer_get_iter_at_line (buffer, &end, to->line); - } - else - { - gtk_text_buffer_get_end_iter (buffer, &end); - } - - /* Remove and free from sequence */ - while (from && from != to) - { - Region *next = from->next; - - //region_free (from); - from = next; - } - - offset = gtk_text_iter_get_line (&start) - gtk_text_iter_get_line (&end); - - offset_regions (to, offset); - - view->priv->ignore_changes = TRUE; - gtk_text_buffer_begin_user_action (buffer); - gtk_text_buffer_delete (buffer, &start, &end); - gtk_text_buffer_end_user_action (buffer); - view->priv->ignore_changes = FALSE; -} - -void -gitg_diff_view_remove_hunk (GitgDiffView *view, GtkTextIter *iter) -{ - g_return_if_fail (GITG_IS_DIFF_VIEW (view)); - g_return_if_fail (iter != NULL); - - /* removes hunk at iter and if it was the last hunk of a file, also removes - the file header */ - Region *region = find_current_region (view, - gtk_text_iter_get_line (iter)); - - if (!region) - { - return; - } - - Region *from = region; - Region *to = region->next; - - if (region->prev && region->prev->type == GITG_DIFF_ITER_TYPE_HEADER && - (!to || to->type == GITG_DIFF_ITER_TYPE_HEADER)) - { - /* also remove the header in this case */ - from = region->prev; - } - - remove_regions (view, from, to); -} - -gboolean -gitg_diff_view_get_start_iter (GitgDiffView *view, GitgDiffIter *iter) -{ - g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - if (!view->priv->diff_enabled) - { - return FALSE; - } - - region_to_iter (view, view->priv->regions, iter); - return GITG_DIFF_ITER_GET_REGION (iter) != NULL; -} - -gboolean -gitg_diff_iter_forward (GitgDiffIter *iter) -{ - g_return_val_if_fail (iter != NULL, FALSE); - - if (!GITG_DIFF_ITER_GET_REGION (iter)) - { - return FALSE; - } - - GITG_DIFF_ITER_SET_REGION (iter, GITG_DIFF_ITER_GET_REGION (iter)->next); - - return GITG_DIFF_ITER_GET_REGION (iter) != NULL; -} - -gboolean -gitg_diff_view_get_end_iter (GitgDiffView *view, GitgDiffIter *iter) -{ - g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - region_to_iter (view, view->priv->last_region, iter); - - return GITG_DIFF_ITER_GET_REGION (iter) != NULL; -} - -gboolean -gitg_diff_iter_backward (GitgDiffIter *iter) -{ - g_return_val_if_fail (iter != NULL, FALSE); - - if (!GITG_DIFF_ITER_GET_REGION (iter)) - { - return FALSE; - } - - GITG_DIFF_ITER_SET_REGION (iter, GITG_DIFF_ITER_GET_REGION (iter)->prev); - - return GITG_DIFF_ITER_GET_REGION (iter) != NULL; - -} - -GitgDiffIterType -gitg_diff_iter_get_type (GitgDiffIter *iter) -{ - g_return_val_if_fail (iter != NULL, 0); - g_return_val_if_fail (GITG_IS_DIFF_VIEW (GITG_DIFF_ITER_GET_VIEW (iter)), 0); - g_return_val_if_fail (GITG_DIFF_ITER_GET_REGION (iter) != NULL, 0); - - return GITG_DIFF_ITER_GET_REGION (iter)->type; -} - -static void -region_iter_range (GitgDiffView *view, Region *region, GtkTextIter *start, GtkTextIter *end) -{ - gtk_text_buffer_get_iter_at_line (view->priv->current_buffer, start, region->line); - - Region *next = region->next; - - while (next && next->type != region->type) - next = next->next; - - if (next) - gtk_text_buffer_get_iter_at_line (view->priv->current_buffer, end, next->line); - else - gtk_text_buffer_get_end_iter (view->priv->current_buffer, end); -} - -void -gitg_diff_iter_set_visible (GitgDiffIter *iter, gboolean visible) -{ - g_return_if_fail (iter != NULL); - g_return_if_fail (GITG_IS_DIFF_VIEW (GITG_DIFF_ITER_GET_VIEW (iter))); - g_return_if_fail (GITG_DIFF_ITER_GET_REGION (iter) != NULL); - - GitgDiffView *view = GITG_DIFF_ITER_GET_VIEW (iter); - Region *region = GITG_DIFF_ITER_GET_REGION (iter); - - if (region->visible == visible) - return; - - GtkTextIter start; - GtkTextIter end; - - region_iter_range (view, region, &start, &end); - region->visible = visible; - - /* Propagate visibility to hunks */ - if (region->type == GITG_DIFF_ITER_TYPE_HEADER) - { - Region *next = region->next; - - while (next && next->type != GITG_DIFF_ITER_TYPE_HEADER) - { - next->visible = visible; - next = next->next; - } - } - - if (visible) - { - gtk_text_buffer_remove_tag (view->priv->current_buffer, view->priv->invisible_tag, &start, &end); - - if (region->type == GITG_DIFF_ITER_TYPE_HEADER) - { - hide_header_details (view, region); - } - } - else - { - if (region->type == GITG_DIFF_ITER_TYPE_HEADER) - { - gtk_text_buffer_remove_tag (view->priv->current_buffer, view->priv->subheader_tag, &start, &end); - } - - gtk_text_buffer_apply_tag (view->priv->current_buffer, view->priv->invisible_tag, &start, &end); - } -} - -static gboolean -header_parse_index (GitgDiffView *view, Header *header) -{ - GtkTextIter iter; - GtkTextBuffer *buffer = view->priv->current_buffer; - guint num; - guint i; - - if (header->region.next) - num = header->region.next->line - header->region.line; - else - num = gtk_text_buffer_get_line_count (buffer) - header->region.line; - - gtk_text_buffer_get_iter_at_line (buffer, &iter, header->region.line); - - for (i = 0; i < num; ++i) - { - if (!gtk_text_iter_forward_line (&iter)) - return FALSE; - - GtkTextIter end = iter; - gtk_text_iter_forward_to_line_end (&end); - - /* get line contents */ - gchar *line = gtk_text_iter_get_text (&iter, &end); - gchar match[] = "index "; - - if (g_str_has_prefix (line, match)) - { - gchar *start = line + strlen (match); - gchar *sep = strstr (start, ".."); - gboolean ret; - - if (sep) - { - gchar *last = strstr (sep, " "); - gchar *bet = strstr (start, ","); - - if (!last) - last = line + strlen (line); - - strncpy (header->index_from, start, (bet ? bet : sep) - start); - strncpy (header->index_to, sep + 2, last - (sep + 2)); - - header->index_from[ (bet ? bet : sep) - start] = '\0'; - header->index_to[last - (sep + 2)] = '\0'; - - ret = TRUE; - } - else - { - ret = FALSE; - } - - g_free (line); - return ret; - } - - g_free (line); - } - - return FALSE; -} - -gboolean -gitg_diff_iter_get_index (GitgDiffIter *iter, - gchar **from, - gchar **to) -{ - Region *region = GITG_DIFF_ITER_GET_REGION (iter); - - while (region && region->type != GITG_DIFF_ITER_TYPE_HEADER) - { - region = region->prev; - } - - if (!region) - { - return FALSE; - } - - Header *header = (Header *)region; - gboolean ret = TRUE; - - if (!* (header->index_to)) - { - ret = header_parse_index (GITG_DIFF_ITER_GET_VIEW (iter), header); - } - - if (!ret) - { - return FALSE; - } - - *from = header->index_from; - *to = header->index_to; - - return TRUE; -} - -static gboolean -iter_in_view (GitgDiffView *view, - GtkTextIter *iter) -{ - GtkTextIter start; - GtkTextIter end; - GdkRectangle rect; - GtkTextView *textview = GTK_TEXT_VIEW (view); - - gtk_text_view_get_visible_rect (textview, &rect); - gtk_text_view_get_iter_at_location (textview, &start, rect.x, rect.y); - gtk_text_view_get_iter_at_location (textview, &end, rect.x + rect.width, rect.y + rect.height); - - return gtk_text_iter_in_range (iter, &start, &end) || gtk_text_iter_equal (iter, &end); -} - -static gboolean -try_scan (GitgDiffView *view) -{ - gint lines = gtk_text_buffer_get_line_count (view->priv->current_buffer); - - if (view->priv->last_scan_line > lines) - { - return FALSE; - } - - guint num = MIN (lines - view->priv->last_scan_line, IDLE_SCAN_COUNT); - - if (num == 0) - { - return FALSE; - } - - gchar str[8]; - g_snprintf (str, sizeof (str), "%u", view->priv->max_line_count); - guint max_line = strlen (str); - - guint last = view->priv->last_scan_line; - ensure_scan (view, view->priv->last_scan_line + num); - g_snprintf (str, sizeof (str), "%u", view->priv->max_line_count); - - if (strlen (str) > max_line) - { - gtk_widget_queue_draw (GTK_WIDGET (view)); - } - - return last != view->priv->last_scan_line; -} - -static void -on_buffer_delete_range (GtkTextBuffer *buffer, - GtkTextIter *start, - GtkTextIter *end, - GitgDiffView *view) -{ - if (view->priv->ignore_changes) - { - return; - } - - regions_free (view); - - if (iter_in_view (view, start) || iter_in_view (view, end)) - { - try_scan (view); - } - - if (!view->priv->scan_id) - { - view->priv->scan_id = g_idle_add ( (GSourceFunc)on_idle_scan, - view); - } -} - -static void -on_buffer_insert_text (GtkTextBuffer *buffer, - GtkTextIter *iter, - gchar const *text, - gint len, - GitgDiffView *view) -{ - if (view->priv->ignore_changes) - { - return; - } - - /* if region is in current view and not scanned, issue scan now */ - if (iter_in_view (view, iter)) - { - try_scan (view); - } - - if (!view->priv->scan_id) - { - view->priv->scan_id = g_idle_add ( (GSourceFunc)on_idle_scan, view); - } -} - -static gboolean -on_idle_scan (GitgDiffView *view) -{ - if (try_scan (view)) - { - return TRUE; - } - - view->priv->scan_id = 0; - return FALSE; -} - -gboolean -gitg_diff_view_get_header_at_iter (GitgDiffView *view, - GtkTextIter const *iter, - GitgDiffIter *diff_iter) -{ - g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (diff_iter != NULL, FALSE); - - if (!view->priv->diff_enabled) - { - return FALSE; - } - - ensure_scan (view, gtk_text_iter_get_line (iter)); - - Region *region = find_current_region (view, gtk_text_iter_get_line (iter)); - - while (region && region->type == GITG_DIFF_ITER_TYPE_HUNK) - { - region = region->prev; - } - - region_to_iter (view, region, diff_iter); - return region != NULL && region->type == GITG_DIFF_ITER_TYPE_HEADER; -} - -gboolean -gitg_diff_view_get_hunk_at_iter (GitgDiffView *view, - GtkTextIter const *iter, - GitgDiffIter *diff_iter) -{ - g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (diff_iter != NULL, FALSE); - - if (!view->priv->diff_enabled) - { - return FALSE; - } - - ensure_scan (view, gtk_text_iter_get_line (iter)); - - Region *region = find_current_region (view, gtk_text_iter_get_line (iter)); - - if (region == NULL || region->type != GITG_DIFF_ITER_TYPE_HUNK) - { - return FALSE; - } - - region_to_iter (view, region, diff_iter); - return TRUE; -} - -static void -region_get_bounds (GitgDiffView *view, - Region *region, - GtkTextIter *start, - GtkTextIter *end) -{ - gtk_text_buffer_get_iter_at_line (view->priv->current_buffer, - start, - region->line); - - if (region->next != NULL) - { - gtk_text_buffer_get_iter_at_line (view->priv->current_buffer, - end, - region->next->line); - } - else - { - gtk_text_buffer_get_end_iter (view->priv->current_buffer, - end); - } -} - -void -gitg_diff_iter_get_bounds (GitgDiffIter const *iter, - GtkTextIter *start, - GtkTextIter *end) -{ - g_return_if_fail (iter != NULL); - g_return_if_fail (GITG_IS_DIFF_VIEW (GITG_DIFF_ITER_GET_VIEW (iter))); - g_return_if_fail (GITG_DIFF_ITER_GET_REGION (iter) != NULL); - g_return_if_fail (start != NULL); - g_return_if_fail (end != NULL); - - GitgDiffView *view = GITG_DIFF_ITER_GET_VIEW (iter); - Region *region = GITG_DIFF_ITER_GET_REGION (iter); - - region_get_bounds (view, region, start, end); -} - -GitgDiffLineType -gitg_diff_view_get_line_type (GitgDiffView *view, GtkTextIter const *iter) -{ - g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), GITG_DIFF_LINE_TYPE_NONE); - g_return_val_if_fail (iter != NULL, GITG_DIFF_LINE_TYPE_NONE); - - if (!view->priv->diff_enabled) - { - return GITG_DIFF_LINE_TYPE_NONE; - } - - GitgDiffIter diff_iter; - - if (!gitg_diff_view_get_hunk_at_iter (view, iter, &diff_iter)) - { - return GITG_DIFF_LINE_TYPE_NONE; - } - - GtkTextIter start = *iter; - gtk_text_iter_set_line_offset (&start, 0); - - gunichar ch = gtk_text_iter_get_char (&start); - - switch (ch) - { - case '+': - return GITG_DIFF_LINE_TYPE_ADD; - case '-': - return GITG_DIFF_LINE_TYPE_REMOVE; - default: - return GITG_DIFF_LINE_TYPE_NONE; - } -} - -static void -calculate_hunk_header_counters (GitgDiffView *view, - Region *region) -{ - GtkTextIter start; - GtkTextIter end; - GtkTextIter begin; - - GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - region_get_bounds (view, region, &start, &end); - - begin = start; - - guint new_count = 0; - guint old_count = 0; - - gboolean isempty = TRUE; - - if (gtk_text_iter_forward_line (&start)) - { - while (gtk_text_iter_compare (&start, &end) < 0) - { - GitgDiffLineType line_type; - GtkTextIter line_end = start; - - gtk_text_iter_forward_to_line_end (&line_end); - - line_type = gitg_diff_view_get_line_type (view, &start); - - if (line_type == GITG_DIFF_LINE_TYPE_NONE || - line_type == GITG_DIFF_LINE_TYPE_ADD) - { - ++new_count; - } - - if (line_type == GITG_DIFF_LINE_TYPE_NONE || - line_type == GITG_DIFF_LINE_TYPE_REMOVE) - { - ++old_count; - } - - if (line_type != GITG_DIFF_LINE_TYPE_NONE) - { - isempty = FALSE; - } - - if (!gtk_text_iter_forward_line (&start)) - { - break; - } - } - } - - if (isempty) - { - gitg_diff_view_remove_hunk (view, &begin); - } - else - { - end = begin; - gtk_text_iter_forward_to_line_end (&end); - - gchar *header = gtk_text_buffer_get_text (buffer, &begin, &end, TRUE); - gchar *ret; - - ret = gitg_utils_rewrite_hunk_counters (header, old_count, new_count); - g_free (header); - - gtk_text_buffer_delete (buffer, &begin, &end); - gtk_text_buffer_insert (buffer, &begin, ret, -1); - - g_free (ret); - } -} - -void -gitg_diff_view_clear_line (GitgDiffView *view, - GtkTextIter const *iter, - GitgDiffLineType old_type, - GitgDiffLineType new_type) -{ - g_return_if_fail (GITG_IS_DIFF_VIEW (view)); - g_return_if_fail (iter != NULL); - - GitgDiffLineType line_type; - GitgDiffIter diff_iter; - - line_type = gitg_diff_view_get_line_type (view, iter); - - if (line_type == GITG_DIFF_LINE_TYPE_NONE) - { - return; - } - - gitg_diff_view_get_hunk_at_iter (view, iter, &diff_iter); - - GtkTextIter start = *iter; - GtkTextIter end; - GtkTextBuffer *buffer; - Region *region; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); - - gtk_text_iter_set_line_offset (&start, 0); - end = start; - - gtk_text_buffer_begin_user_action (buffer); - view->priv->ignore_changes = TRUE; - - region = GITG_DIFF_ITER_GET_REGION (&diff_iter); - - if (line_type == new_type) - { - /* means the line now just becomes context */ - gtk_text_iter_forward_char (&end); - gtk_text_buffer_delete (buffer, &start, &end); - gtk_text_buffer_insert (buffer, &start, " ", 1); - } - else - { - /* means the line should be removed */ - if (!gtk_text_iter_forward_line (&end)) - { - gtk_text_iter_forward_to_line_end (&end); - } - - gtk_text_buffer_delete (buffer, &start, &end); - offset_regions (region->next, -1); - } - - calculate_hunk_header_counters (view, region); - - view->priv->ignore_changes = FALSE; - gtk_text_buffer_end_user_action (buffer); -} diff --git a/gitg/gitg-diff-view.h b/gitg/gitg-diff-view.h deleted file mode 100644 index f714b535..00000000 --- a/gitg/gitg-diff-view.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * gitg-diff-view.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_DIFF_VIEW_H__ -#define __GITG_DIFF_VIEW_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_DIFF_VIEW (gitg_diff_view_get_type ()) -#define GITG_DIFF_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_DIFF_VIEW, GitgDiffView)) -#define GITG_DIFF_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_DIFF_VIEW, GitgDiffView const)) -#define GITG_DIFF_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_DIFF_VIEW, GitgDiffViewClass)) -#define GITG_IS_DIFF_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_DIFF_VIEW)) -#define GITG_IS_DIFF_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_DIFF_VIEW)) -#define GITG_DIFF_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_DIFF_VIEW, GitgDiffViewClass)) - -typedef struct _GitgDiffView GitgDiffView; -typedef struct _GitgDiffViewClass GitgDiffViewClass; -typedef struct _GitgDiffViewPrivate GitgDiffViewPrivate; - -typedef struct _GitgDiffIter GitgDiffIter; - -struct _GitgDiffIter -{ - gpointer userdata; - gpointer userdata2; - gpointer userdata3; -}; - -typedef enum -{ - GITG_DIFF_ITER_TYPE_HEADER = 1, - GITG_DIFF_ITER_TYPE_HUNK -} GitgDiffIterType; - -typedef enum -{ - GITG_DIFF_LINE_TYPE_NONE, - GITG_DIFF_LINE_TYPE_ADD, - GITG_DIFF_LINE_TYPE_REMOVE, -} GitgDiffLineType; - -struct _GitgDiffView -{ - GtkSourceView parent; - - GitgDiffViewPrivate *priv; -}; - -struct _GitgDiffViewClass -{ - GtkSourceViewClass parent_class; - - void (*header_added)(GitgDiffView *view, GitgDiffIter *iter); - void (*hunk_added)(GitgDiffView *view, GitgDiffIter *iter); -}; - -GType gitg_diff_view_get_type(void) G_GNUC_CONST; -GitgDiffView *gitg_diff_view_new(void); - -void gitg_diff_view_remove_hunk(GitgDiffView *view, GtkTextIter *iter); -void gitg_diff_view_set_diff_enabled(GitgDiffView *view, gboolean enabled); - -/* Iterator functions */ -gboolean gitg_diff_view_get_start_iter(GitgDiffView *view, GitgDiffIter *iter); -gboolean gitg_diff_iter_forward(GitgDiffIter *iter); - -gboolean gitg_diff_view_get_end_iter(GitgDiffView *view, GitgDiffIter *iter); -gboolean gitg_diff_iter_backward(GitgDiffIter *iter); - -GitgDiffIterType gitg_diff_iter_get_type(GitgDiffIter *iter); -void gitg_diff_iter_set_visible(GitgDiffIter *iter, gboolean visible); -gboolean gitg_diff_iter_get_index(GitgDiffIter *iter, gchar **from, gchar **to); - -gboolean gitg_diff_view_get_header_at_iter (GitgDiffView *view, GtkTextIter const *iter, GitgDiffIter *diff_iter); -gboolean gitg_diff_view_get_hunk_at_iter (GitgDiffView *view, GtkTextIter const *iter, GitgDiffIter *diff_iter); - -void gitg_diff_iter_get_bounds (GitgDiffIter const *iter, GtkTextIter *start, GtkTextIter *end); - -GitgDiffLineType gitg_diff_view_get_line_type (GitgDiffView *view, GtkTextIter const *iter); -void gitg_diff_view_clear_line (GitgDiffView *view, GtkTextIter const *iter, GitgDiffLineType old_type, GitgDiffLineType new_type); - -G_END_DECLS - -#endif /* __GITG_DIFF_VIEW_H__ */ diff --git a/gitg/gitg-dirs.c b/gitg/gitg-dirs.c deleted file mode 100644 index b0e96408..00000000 --- a/gitg/gitg-dirs.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * gitg-dirs.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include "gitg-dirs.h" -#include "config.h" - -gchar const * -gitg_dirs_get_data_dir (void) -{ - static gchar *datadir = NULL; - - if (!datadir) - { - datadir = g_strdup (GITG_DATADIR); - } - - return datadir; -} - -gchar * -gitg_dirs_get_data_filename(gchar const *first, ...) -{ - gchar const *datadir = gitg_dirs_get_data_dir(); - gchar *ret; - - ret = g_build_filename(datadir, first, NULL); - gchar const *item; - - va_list ap; - va_start(ap, first); - - while ((item = va_arg(ap, gchar const *))) - { - gchar *tmp = ret; - ret = g_build_filename(ret, item, NULL); - g_free(tmp); - } - - va_end(ap); - return ret; -} - -void -gitg_dirs_initialize(int argc, char **argv) -{ - gchar *path = g_path_get_dirname(argv[0]); - - if (!g_path_is_absolute(path)) - { - gchar *tmp = path; - gchar *cwd = g_get_current_dir(); - - path = g_build_filename(cwd, tmp, NULL); - g_free(tmp); - g_free(cwd); - } - - g_free(path); -} diff --git a/gitg/gitg-dirs.h b/gitg/gitg-dirs.h deleted file mode 100644 index a6a27553..00000000 --- a/gitg/gitg-dirs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * gitg-dirs.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_DIRS_H__ -#define __GITG_DIRS_H__ - -#include - -gchar const *gitg_dirs_get_data_dir (void); -gchar *gitg_dirs_get_data_filename (gchar const *first, ...) G_GNUC_NULL_TERMINATED; -void gitg_dirs_initialize (int argc, char **argv); - -#endif /* __GITG_DIRS_H__ */ diff --git a/gitg/gitg-dirs.vala b/gitg/gitg-dirs.vala new file mode 100644 index 00000000..bc345e23 --- /dev/null +++ b/gitg/gitg-dirs.vala @@ -0,0 +1,64 @@ +namespace Gitg +{ + +public class Dirs +{ + public static string data_dir + { + get { return Config.GITG_DATADIR; } + } + + public static string locale_dir + { + get { return Config.GITG_LOCALEDIR; } + } + + public static string lib_dir + { + get { return Config.GITG_LIBDIR; } + } + + public static string plugins_dir + { + owned get { return Path.build_filename(lib_dir, "plugins"); } + } + + public static string plugins_data_dir + { + owned get { return Path.build_filename(data_dir, "plugins"); } + } + + public static string user_plugins_dir + { + owned get { return Path.build_filename(Environment.get_user_data_dir(), "gitg", "plugins"); } + } + + public static string user_plugins_data_dir + { + owned get { return user_plugins_dir; } + } + + public static string build_data_file(string part, ...) + { + var l = va_list(); + var ret = Path.build_filename(data_dir, part, null); + + while (true) + { + string? s = l.arg(); + + if (s == null) + { + break; + } + + ret = Path.build_filename(ret, s); + } + + return ret; + } +} + +} + +// ex: ts=4 noet diff --git a/gitg/gitg-dnd.c b/gitg/gitg-dnd.c deleted file mode 100644 index 2b6b91bc..00000000 --- a/gitg/gitg-dnd.c +++ /dev/null @@ -1,1090 +0,0 @@ -/* - * gitg-dnd.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 - -#include "gitg-dnd.h" -#include "gitg-cell-renderer-path.h" -#include "gitg-window.h" -#include "gitg-branch-actions.h" -#include "gitg-utils.h" - -#include - -enum -{ - DRAG_TARGET_REF = 1, - DRAG_TARGET_TREEISH, - DRAG_TARGET_REVISION, - DRAG_TARGET_TEXT, - DRAG_TARGET_URI, - DRAG_TARGET_DIRECT_SAVE -}; - -#define XDS_ATOM gdk_atom_intern ("XdndDirectSave0", FALSE) -#define TEXT_ATOM gdk_atom_intern ("text/plain", FALSE) - -#define MAX_XDS_ATOM_VAL_LEN 4096 - -static GtkTargetEntry target_dest_entries[] = { - {"gitg-ref", GTK_TARGET_SAME_WIDGET, DRAG_TARGET_REF} -}; - -static GtkTargetEntry target_source_entries[] = { - {"x-gitg/treeish-list", GTK_TARGET_OTHER_APP, DRAG_TARGET_TREEISH}, - {"XdndDirectSave0", GTK_TARGET_OTHER_APP, DRAG_TARGET_DIRECT_SAVE} -}; - -typedef struct -{ - GtkTreeView *tree_view; - GitgRef *ref; - GitgRef *target; - GitgRef *cursor_ref; - - GitgDndCallback callback; - GitgDndRevisionCallback revision_callback; - gpointer callback_data; - - gdouble x; - gdouble y; - - gboolean is_drag; - GtkTargetList *target_list; - GtkTargetList *revision_target_list; - GitgRevision *revision; - - guint scroll_timeout; - gchar *xds_destination; - gchar *xds_filename; -} GitgDndData; - -#define GITG_DND_DATA_KEY "GitgDndDataKey" - -#define GITG_DND_GET_DATA(widget) ((GitgDndData *)g_object_get_data(G_OBJECT(widget), GITG_DND_DATA_KEY)) - -static void -remove_scroll_timeout (GitgDndData *data) -{ - if (data->scroll_timeout != 0) - { - g_source_remove (data->scroll_timeout); - data->scroll_timeout = 0; - } -} - - -static GitgDndData * -gitg_dnd_data_new () -{ - GitgDndData *data = g_slice_new0 (GitgDndData); - - data->target_list = gtk_target_list_new (target_dest_entries, - G_N_ELEMENTS (target_dest_entries)); - - data->revision_target_list = gtk_target_list_new (target_source_entries, - G_N_ELEMENTS (target_source_entries)); - - gtk_target_list_add_text_targets (data->revision_target_list, DRAG_TARGET_TEXT); - gtk_target_list_add_uri_targets (data->revision_target_list, DRAG_TARGET_URI); - - return data; -} - -static void -gitg_dnd_data_free (GitgDndData *data) -{ - gtk_target_list_unref (data->target_list); - gtk_target_list_unref (data->revision_target_list); - - remove_scroll_timeout (data); - - g_slice_free (GitgDndData, data); -} - -static GitgRef * -get_ref_at_pos (GtkTreeView *tree_view, - gint x, - gint y, - gint *hot_x, - gint *hot_y, - GitgCellRendererPath **renderer, - GtkTreePath **tp) -{ - gint cell_x; - gint cell_y; - GtkTreePath *path; - GtkTreeViewColumn *column; - - if (!gtk_tree_view_get_path_at_pos (tree_view, - x, - y, - &path, - &column, - &cell_x, - &cell_y)) - { - return NULL; - } - - if (hot_y) - { - *hot_y = cell_y; - } - - GtkCellRenderer *cell = gitg_utils_find_cell_at_pos (tree_view, column, path, cell_x); - - if (!cell || !GITG_IS_CELL_RENDERER_PATH (cell)) - { - return NULL; - } - - if (renderer) - { - *renderer = GITG_CELL_RENDERER_PATH (cell); - } - - GitgRef *ref = gitg_cell_renderer_path_get_ref_at_pos (GTK_WIDGET (tree_view), - GITG_CELL_RENDERER_PATH (cell), - cell_x, - hot_x); - - if (tp) - { - *tp = path; - } - else - { - gtk_tree_path_free (path); - } - - return ref; -} - -static GitgRevision * -get_revision_at_pos (GtkTreeView *tree_view, - gint x, - gint y, - GtkTreePath **tp) -{ - gint cell_x; - gint cell_y; - GtkTreePath *path; - GtkTreeViewColumn *column; - GtkTreeModel *model; - GtkTreeIter iter; - GitgRevision *revision; - - if (!gtk_tree_view_get_path_at_pos (tree_view, - x, - y, - &path, - &column, - &cell_x, - &cell_y)) - { - return NULL; - } - - model = gtk_tree_view_get_model (tree_view); - - if (!gtk_tree_model_get_iter (model, &iter, path)) - { - return NULL; - } - - gtk_tree_model_get (model, &iter, 0, &revision, -1); - - if (revision && tp) - { - *tp = path; - } - else - { - gtk_tree_path_free (path); - } - - return revision; -} - -static gboolean -can_drag (GitgRef *ref) -{ - GitgRefType type = gitg_ref_get_ref_type (ref); - - switch (type) - { - case GITG_REF_TYPE_BRANCH: - case GITG_REF_TYPE_REMOTE: - case GITG_REF_TYPE_STASH: - return TRUE; - break; - default: - return FALSE; - break; - } -} - -static gboolean -can_drop (GitgRef *source, GitgRef *dest) -{ - if (gitg_ref_equal (source, dest)) - { - return FALSE; - } - - GitgRefType source_type = gitg_ref_get_ref_type (source); - GitgRefType dest_type = gitg_ref_get_ref_type (dest); - - if (source_type == GITG_REF_TYPE_BRANCH) - { - return dest_type == GITG_REF_TYPE_BRANCH || dest_type == GITG_REF_TYPE_REMOTE; - } - else if (source_type == GITG_REF_TYPE_REMOTE) - { - return dest_type == GITG_REF_TYPE_BRANCH; - } - else if (source_type == GITG_REF_TYPE_STASH) - { - return dest_type == GITG_REF_TYPE_BRANCH; - } - - return FALSE; -} - -/* Copied from gitg-label-renderer - * TODO: refactor - */ -static inline guint8 -convert_color_channel (guint8 src, - guint8 alpha) -{ - return alpha ? src / (alpha / 255.0) : 0; -} - -static void -convert_bgra_to_rgba (guint8 const *src, - guint8 *dst, - gint width, - gint height) -{ - guint8 const *src_pixel = src; - guint8 * dst_pixel = dst; - int y; - - for (y = 0; y < height; y++) - { - int x; - - for (x = 0; x < width; x++) - { - dst_pixel[0] = convert_color_channel (src_pixel[2], - src_pixel[3]); - dst_pixel[1] = convert_color_channel (src_pixel[1], - src_pixel[3]); - dst_pixel[2] = convert_color_channel (src_pixel[0], - src_pixel[3]); - dst_pixel[3] = src_pixel[3]; - - dst_pixel += 4; - src_pixel += 4; - } - } -} - -static GdkPixbuf * -create_revision_drag_icon (GtkTreeView *tree_view, - GitgRevision *revision) -{ - gchar const *subject = gitg_revision_get_subject (revision); - gchar *sha1 = gitg_revision_get_sha1 (revision); - - /* Only take first 8 characters */ - sha1[8] = '\0'; - - gchar *text = g_strdup_printf ("%s: %s", sha1, subject); - - PangoLayout *layout = gtk_widget_create_pango_layout (GTK_WIDGET (tree_view), text); - gint width; - gint height; - - pango_layout_get_pixel_size (layout, &width, &height); - - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width + 4, height + 4); - cairo_t *context = cairo_create (surface); - - cairo_rectangle (context, 0, 0, width + 4, height + 4); - cairo_set_source_rgb (context, 1, 1, 1); - cairo_fill (context); - - cairo_translate (context, 2, 2); - cairo_set_source_rgb (context, 0, 0, 0); - pango_cairo_show_layout (context, layout); - - guint8 *data = cairo_image_surface_get_data (surface); - GdkPixbuf *ret = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width + 4, height + 4); - guint8 *pixdata = gdk_pixbuf_get_pixels (ret); - - convert_bgra_to_rgba (data, pixdata, width + 4, height + 4); - - cairo_destroy (context); - cairo_surface_destroy (surface); - - g_object_unref (layout); - - g_free (text); - g_free (sha1); - - return ret; -} - -static gchar * -generate_format_patch_filename (GitgRevision *revision) -{ - gchar *name = gitg_revision_get_format_patch_name (revision); - gchar *filename = g_strdup_printf ("0001-%s.patch", name); - - g_free (name); - return filename; -} - -static void -begin_drag (GtkWidget *widget, - GdkEvent *event, - GitgDndData *data) -{ - - GtkTreeView *tree_view = GTK_TREE_VIEW (widget); - gint hot_x; - gint hot_y; - GitgCellRendererPath *cell; - GitgRef *ref = get_ref_at_pos (tree_view, - (gint)data->x, - (gint)data->y, - &hot_x, - &hot_y, - &cell, - NULL); - - if (ref && !can_drag (ref)) - { - return; - } - else if (ref) - { - /* This is a DND operation on a ref */ - data->ref = ref; - gitg_ref_set_state (ref, GITG_REF_STATE_NONE); - - GdkDragContext *context = gtk_drag_begin (widget, - data->target_list, - GDK_ACTION_MOVE, - 1, - event); - - guint minwidth; - guint h; - gdk_display_get_maximal_cursor_size (gtk_widget_get_display (widget), &minwidth, &h); - - GdkPixbuf *pixbuf = gitg_cell_renderer_path_render_ref (GTK_WIDGET (tree_view), - cell, - ref, - minwidth + 1); - - if (pixbuf) - { - gtk_drag_set_icon_pixbuf (context, pixbuf, hot_x, hot_y); - g_object_unref (pixbuf); - } - } - else - { - /* This is a normal DND operation which is just possibly just about - a SHA */ - GitgRevision *revision; - GtkTreePath *path = NULL; - - revision = get_revision_at_pos (tree_view, - (gint)data->x, - (gint)data->y, - &path); - - if (revision && !gitg_revision_get_sign (revision)) - { - /* Make a DND for the revision */ - data->revision = revision; - - GdkDragContext *context = gtk_drag_begin (widget, - data->revision_target_list, - GDK_ACTION_COPY, - 1, - event); - GdkPixbuf *icon; - gchar *filename; - - filename = generate_format_patch_filename (revision); - - gdk_property_change (gtk_widget_get_window (widget), - XDS_ATOM, TEXT_ATOM, - 8, GDK_PROP_MODE_REPLACE, - (guchar *) filename, - strlen (filename)); - - data->xds_filename = filename; - - icon = create_revision_drag_icon (tree_view, revision); - - if (icon) - { - gtk_drag_set_icon_pixbuf (context, icon, 0, 0); - g_object_unref (icon); - } - - gtk_tree_path_free (path); - } - - if (revision) - { - gitg_revision_unref (revision); - } - } -} - -static void -update_highlight (GitgDndData *data, gint x, gint y) -{ - GitgRef *ref = get_ref_at_pos (data->tree_view, - x, - y, - NULL, - NULL, - NULL, - NULL); - - if (ref != data->cursor_ref) - { - if (data->cursor_ref) - { - gitg_ref_set_state (data->cursor_ref, GITG_REF_STATE_NONE); - } - - if (ref && gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_NONE) - { - gitg_ref_set_state (ref, GITG_REF_STATE_PRELIGHT); - - gdk_window_set_cursor (gtk_tree_view_get_bin_window (data->tree_view), - gdk_cursor_new (GDK_HAND2)); - } - else - { - gdk_window_set_cursor (gtk_tree_view_get_bin_window (data->tree_view), - NULL); - } - - data->cursor_ref = ref; - gtk_widget_queue_draw (GTK_WIDGET (data->tree_view)); - } -} - -static gboolean -vertical_autoscroll (GitgDndData *data) -{ - GdkRectangle visible_rect; - gint y; - gint offset; - gfloat value; - - gdk_window_get_pointer (gtk_tree_view_get_bin_window (data->tree_view), NULL, &y, NULL); - gtk_tree_view_convert_bin_window_to_tree_coords (data->tree_view, 0, y, NULL, &y); - - gtk_tree_view_get_visible_rect (data->tree_view, &visible_rect); - - /* see if we are near the edge. */ - offset = y - (visible_rect.y + 2 * 15); - - if (offset > 0) - { - offset = y - (visible_rect.y + visible_rect.height - 2 * 15); - - if (offset < 0) - { - return TRUE; - } - } - - GtkAdjustment *adj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (data->tree_view)); - - value = CLAMP (gtk_adjustment_get_value (adj) + offset, 0.0, - gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj)); - - gtk_adjustment_set_value (adj, value); - return TRUE; -} - -static void -add_scroll_timeout (GitgDndData *data) -{ - if (data->scroll_timeout == 0) - { - data->scroll_timeout = g_timeout_add (50, - (GSourceFunc)vertical_autoscroll, - data); - } -} - - -static gboolean -gitg_drag_source_event_cb (GtkWidget *widget, - GdkEvent *event, - GitgDndData *data) -{ - gboolean retval = FALSE; - - if (event->any.window != gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget))) - { - return FALSE; - } - - switch (event->type) - { - case GDK_BUTTON_PRESS: - if (event->button.button == 1) - { - data->x = event->button.x; - data->y = event->button.y; - - data->is_drag = TRUE; - data->ref = NULL; - data->target = NULL; - } - break; - case GDK_BUTTON_RELEASE: - if (event->button.button == 1) - { - data->is_drag = FALSE; - - if (data->target) - { - gitg_ref_set_state (data->target, GITG_REF_STATE_NONE); - } - - remove_scroll_timeout (data); - } - break; - case GDK_MOTION_NOTIFY: - if (data->is_drag && (event->motion.state & GDK_BUTTON1_MASK)) - { - if (gtk_drag_check_threshold (widget, data->x, data->y, event->motion.x, event->motion.y)) - { - data->is_drag = FALSE; - begin_drag (widget, event, data); - - retval = TRUE; - } - } - else if (!data->is_drag && !(event->motion.state & GDK_BUTTON1_MASK)) - { - update_highlight (data, (gint)event->motion.x, (gint)event->motion.y); - } - break; - default: - break; - } - - return retval; -} - -static gboolean -gitg_drag_source_motion_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time, - GitgDndData *data) -{ - if (!data->ref && !data->revision) - { - return FALSE; - } - - GitgRef *ref; - gint dx; - gint dy; - - gtk_tree_view_convert_widget_to_bin_window_coords (data->tree_view, - x, - y, - &dx, - &dy); - - ref = get_ref_at_pos (GTK_TREE_VIEW (widget), - dx, - dy, - NULL, - NULL, - NULL, - NULL); - - gboolean ret = FALSE; - - if (ref != data->target) - { - if (data->target) - { - gitg_ref_set_state (data->target, GITG_REF_STATE_NONE); - gtk_widget_queue_draw (widget); - } - - if (data->ref && data->callback) - { - data->callback (data->ref, ref, FALSE, data->callback_data); - } - else if (data->revision && data->revision_callback) - { - data->revision_callback (data->revision, ref, FALSE, data->callback_data); - } - } - - if ((data->ref && ref && can_drop (data->ref, ref)) || - (data->revision && ref && gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH)) - { - if (ref != data->target) - { - gitg_ref_set_state (ref, GITG_REF_STATE_SELECTED); - data->target = ref; - - gtk_widget_queue_draw (widget); - } - - gdk_drag_status (context, GDK_ACTION_MOVE, time); - ret = TRUE; - } - else - { - if (data->target) - { - data->target = NULL; - gtk_widget_queue_draw (widget); - } - } - - if (data->ref) - { - add_scroll_timeout (data); - } - - return ret; -} - -static gboolean -gitg_drag_source_drop_cb (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time, - GitgDndData *data) -{ - if (!(data->ref || data->revision) || !data->target) - { - return FALSE; - } - - gboolean ret = FALSE; - - if (data->ref && data->callback) - { - ret = data->callback (data->ref, data->target, TRUE, data->callback_data); - } - else if (data->revision && data->revision_callback) - { - ret = data->revision_callback (data->revision, data->target, TRUE, data->callback_data); - } - - gtk_drag_finish (context, ret, FALSE, time); - return ret; -} - -static gboolean -gitg_drag_source_leave_cb (GtkWidget *widget, - GdkDragContext *context, - guint time, - GitgDndData *data) -{ - remove_scroll_timeout (data); - return FALSE; -} - -static void -remove_trailing_newlines (gchar **lines) -{ - gint lastnewline = -1; - gchar **ptr = lines; - gint i = 0; - - while (ptr && *ptr) - { - if (lastnewline == -1 && **ptr == '\0') - { - lastnewline = i; - } - else if (lastnewline != -1 && **ptr != '\0') - { - lastnewline = -1; - } - - ++i; - ++ptr; - } - - if (lastnewline == -1) - { - return; - } - - while (lines[lastnewline]) - { - g_free (lines[lastnewline]); - lines[lastnewline] = NULL; - - ++lastnewline; - } -} - -static gchar * -revision_to_text (GitgRepository *repository, - GitgRevision *revision) -{ - gchar **lines; - gchar *sha1 = gitg_revision_get_sha1 (revision); - - gitg_shell_run_sync_with_output (gitg_command_new (repository, - "log", - "-1", - "--pretty=format:%h: %s%n%n%b", - sha1, - NULL), - FALSE, - &lines, - NULL); - - remove_trailing_newlines (lines); - gchar *ret = g_strjoinv ("\n", lines); - - g_strfreev (lines); - g_free (sha1); - - return ret; -} - -static gchar * -revision_to_uri (GitgRepository *repository, - GitgRevision *revision) -{ - GFile *work_tree = gitg_repository_get_work_tree (repository); - gchar *sha1 = gitg_revision_get_sha1 (revision); - - gchar *path = g_file_get_path (work_tree); - gchar *ret = g_strdup_printf ("gitg://%s:%s", path, sha1); - - g_free (sha1); - g_free (path); - g_object_unref (work_tree); - - return ret; -} - -static gchar * -revision_to_treeish (GitgRepository *repository, - GitgRevision *revision) -{ - GFile *work_tree = gitg_repository_get_work_tree (repository); - gchar *sha1 = gitg_revision_get_sha1 (revision); - gchar *path = g_file_get_path (work_tree); - - gchar *ret = g_strdup_printf ("%s\n%s", path, sha1); - - g_free (sha1); - g_free (path); - g_object_unref (work_tree); - - return ret; -} - -static gchar * -get_xds_filename (GtkWidget *widget, - GdkDragContext *context) -{ - if (context == NULL || widget == NULL) - { - return NULL; - } - - gint len; - gchar *ret = NULL; - - if (gdk_property_get (gtk_widget_get_window (widget), - XDS_ATOM, TEXT_ATOM, - 0, MAX_XDS_ATOM_VAL_LEN, - FALSE, NULL, NULL, &len, - (unsigned char **) &ret)) - { - gchar *dupped = g_strndup (ret, len); - g_free (ret); - - return dupped; - } - - return NULL; -} - -static gboolean -has_direct_save (GitgDndData *data, - GtkWidget *widget, - GdkDragContext *context) -{ - gboolean ret; - - if (!g_list_find (gdk_drag_context_list_targets (context), XDS_ATOM)) - { - return FALSE; - } - - gchar *filename = get_xds_filename (widget, context); - ret = filename && *filename && g_strcmp0 (data->xds_filename, filename) != 0; - g_free (filename); - - return ret; -} - -static void -gitg_drag_source_data_get_cb (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection, - guint info, - guint time, - GitgDndData *data) -{ - if (!data->revision) - { - return; - } - - GitgRepository *repository = GITG_REPOSITORY (gtk_tree_view_get_model (GTK_TREE_VIEW (widget))); - - if (has_direct_save (data, widget, context)) - { - gchar *destination = get_xds_filename (widget, context); - - if (destination && *destination) - { - data->xds_destination = g_strdup (destination); - - gtk_selection_data_set (selection, - gtk_selection_data_get_target (selection), - 8, - (guchar const *)"S", - 1); - } - else - { - gtk_selection_data_set (selection, - gtk_selection_data_get_target (selection), - 8, - (guchar const *)"E", - 1); - } - - g_free (destination); - return; - } - - switch (info) - { - case DRAG_TARGET_TEXT: - { - gchar *text = revision_to_text (repository, data->revision); - gtk_selection_data_set_text (selection, text, -1); - g_free (text); - } - break; - case DRAG_TARGET_TREEISH: - { - gchar *treeish = revision_to_treeish (repository, - data->revision); - - gtk_selection_data_set (selection, - gtk_selection_data_get_target (selection), - 8, - (guchar const *)treeish, - strlen (treeish)); - - g_free (treeish); - } - break; - case DRAG_TARGET_URI: - { - gchar *uri = revision_to_uri (repository, data->revision); - gchar *uris[] = {uri, NULL}; - - gtk_selection_data_set_uris (selection, uris); - g_free (uri); - } - break; - } -} - -static void -gitg_drag_source_end_cb (GtkTreeView *tree_view, - GdkDragContext *context, - GitgDndData *data) -{ - if (data->revision) - { - gdk_property_delete (gtk_widget_get_window (GTK_WIDGET (tree_view)), XDS_ATOM); - - if (data->xds_destination != NULL) - { - /* Do extract it there then */ - GitgWindow *window = GITG_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (data->tree_view))); - gitg_window_add_branch_action (window, - gitg_branch_actions_format_patch (window, - data->revision, - data->xds_destination)); - - g_free (data->xds_destination); - data->xds_destination = NULL; - } - - if (data->xds_filename != NULL) - { - g_free (data->xds_filename); - data->xds_filename = NULL; - } - } -} - -static void -gitg_drag_source_data_delete_cb (GtkTreeView *tree_view, - GdkDragContext *context, - GitgDndData *data) -{ - g_signal_stop_emission_by_name (tree_view, "drag-data-delete"); -} - -void -gitg_dnd_enable (GtkTreeView *tree_view, - GitgDndCallback callback, - GitgDndRevisionCallback revision_callback, - gpointer callback_data) -{ - if (GITG_DND_GET_DATA (tree_view)) - { - return; - } - - GitgDndData *data = gitg_dnd_data_new (); - - data->tree_view = tree_view; - data->callback = callback; - data->revision_callback = revision_callback; - data->callback_data = callback_data; - - g_object_set_data_full (G_OBJECT (tree_view), - GITG_DND_DATA_KEY, - data, - (GDestroyNotify)gitg_dnd_data_free); - - gtk_widget_add_events (GTK_WIDGET (tree_view), - gtk_widget_get_events (GTK_WIDGET (tree_view)) | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK); - - gtk_drag_dest_set (GTK_WIDGET (tree_view), - 0, - target_dest_entries, - G_N_ELEMENTS (target_dest_entries), - GDK_ACTION_MOVE); - - g_signal_connect (tree_view, - "drag-data-get", - G_CALLBACK (gitg_drag_source_data_get_cb), - data); - - g_signal_connect (tree_view, - "button-press-event", - G_CALLBACK (gitg_drag_source_event_cb), - data); - - g_signal_connect (tree_view, - "button-release-event", - G_CALLBACK (gitg_drag_source_event_cb), - data); - - g_signal_connect (tree_view, - "motion-notify-event", - G_CALLBACK (gitg_drag_source_event_cb), - data); - - g_signal_connect (tree_view, - "drag-motion", - G_CALLBACK (gitg_drag_source_motion_cb), - data); - - g_signal_connect (tree_view, - "drag-drop", - G_CALLBACK (gitg_drag_source_drop_cb), - data); - - g_signal_connect (tree_view, - "drag-leave", - G_CALLBACK (gitg_drag_source_leave_cb), - data); - - g_signal_connect (tree_view, - "drag-end", - G_CALLBACK (gitg_drag_source_end_cb), - data); - - g_signal_connect (tree_view, - "drag-data-delete", - G_CALLBACK (gitg_drag_source_data_delete_cb), - data); -} - -void -gitg_dnd_disable (GtkTreeView *tree_view) -{ - GitgDndData *data = GITG_DND_GET_DATA (tree_view); - - if (data) - { - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_event_cb, data); - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_motion_cb, data); - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_drop_cb, data); - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_leave_cb, data); - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_data_get_cb, data); - g_signal_handlers_disconnect_by_func (tree_view, gitg_drag_source_end_cb, data); - - g_object_set_data (G_OBJECT (tree_view), GITG_DND_DATA_KEY, NULL); - } -} diff --git a/gitg/gitg-dnd.h b/gitg/gitg-dnd.h deleted file mode 100644 index 560dbeaa..00000000 --- a/gitg/gitg-dnd.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * gitg-dnd.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_DND_H__ -#define __GITG_DND_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -typedef gboolean (*GitgDndCallback)(GitgRef *source, GitgRef *dest, gboolean dropped, gpointer callback_data); -typedef gboolean (*GitgDndRevisionCallback)(GitgRevision *source, GitgRef *dest, gboolean dropped, gpointer callback_data); - -void gitg_dnd_enable (GtkTreeView *tree_view, - GitgDndCallback callback, - GitgDndRevisionCallback revision_callback, - gpointer callback_data); - -void gitg_dnd_disable (GtkTreeView *tree_view); - -G_END_DECLS - -#endif /* __GITG_DND_H__ */ - diff --git a/gitg/gitg-label-renderer.c b/gitg/gitg-label-renderer.c deleted file mode 100644 index ba98e831..00000000 --- a/gitg/gitg-label-renderer.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * gitg-label-renderer.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-label-renderer.h" -#include "gitg-utils.h" - -#include -#include - -#define PADDING 4 -#define MARGIN 3 - -static gint -get_label_width (PangoLayout *layout, - GitgRef *ref) -{ - gint w; - gchar *smaller = g_strdup_printf ("%s", - gitg_ref_get_shortname (ref)); - - pango_layout_set_markup (layout, smaller, -1); - - pango_layout_get_pixel_size (layout, &w, NULL); - g_free (smaller); - - return w + PADDING * 2; -} - -gint -gitg_label_renderer_width (GtkWidget *widget, - PangoFontDescription *description, - GSList *labels) -{ - gint width = 0; - GSList *item; - - if (labels == NULL) - return 0; - - PangoContext *ctx = gtk_widget_get_pango_context (widget); - PangoLayout *layout = pango_layout_new (ctx); - pango_layout_set_font_description (layout, description); - - for (item = labels; item; item = item->next) - { - width += get_label_width (layout, GITG_REF (item->data)) + MARGIN; - } - - g_object_unref (layout); - - return width + MARGIN; -} - -static void -get_type_color (GitgRefType type, - gdouble *r, - gdouble *g, - gdouble *b) -{ - switch (type) - { - case GITG_REF_TYPE_NONE: - *r = 1; - *g = 1; - *b = 0.8; - break; - case GITG_REF_TYPE_BRANCH: - *r = 0.8; - *g = 1; - *b = 0.5; - break; - case GITG_REF_TYPE_REMOTE: - *r = 0.5; - *g = 0.8; - *b = 1; - break; - case GITG_REF_TYPE_TAG: - *r = 1; - *g = 1; - *b = 0; - break; - case GITG_REF_TYPE_STASH: - *r = 1; - *g = 0.8; - *b = 0.5; - break; - default: - *r = 1; - *g = 1; - *b = 1; - break; - } -} - -static void -get_ref_color (GitgRef *ref, - gdouble *r, - gdouble *g, - gdouble *b) -{ - if (gitg_ref_get_working (ref)) - { - /* Orange */ - *r = 1; - *g = 0.7; - *b = 0; - } - else - { - get_type_color (gitg_ref_get_ref_type (ref), r, g, b); - } -} - -static void -set_source_for_ref_type (cairo_t *context, - GitgRef *ref, - gboolean use_state) -{ - if (use_state) - { - GitgRefState state = gitg_ref_get_state (ref); - - if (state == GITG_REF_STATE_SELECTED) - { - cairo_set_source_rgb (context, 1, 1, 1); - return; - } - else if (state == GITG_REF_STATE_PRELIGHT) - { - gdouble r, g, b; - get_ref_color (ref, &r, &g, &b); - - cairo_set_source_rgba (context, r, g, b, 0.3); - return; - } - } - - gdouble r, g, b; - get_ref_color (ref, &r, &g, &b); - - cairo_set_source_rgb (context, r, g, b); -} - -static gint -render_label (cairo_t *context, - PangoLayout *layout, - GitgRef *ref, - gint x, - gint y, - gint height, - gboolean use_state) -{ - gint w; - gint h; - gchar *smaller = g_strdup_printf ("%s", - gitg_ref_get_shortname (ref)); - - pango_layout_set_markup (layout, smaller, -1); - pango_layout_get_pixel_size (layout, &w, &h); - - // draw rounded rectangle - gitg_utils_rounded_rectangle (context, x + 0.5, - y + MARGIN + 0.5, - w + PADDING * 2, - height - MARGIN * 2, - 5); - - set_source_for_ref_type (context, ref, use_state); - cairo_fill_preserve (context); - - cairo_set_source_rgb (context, 0, 0, 0); - cairo_stroke (context); - - cairo_save (context); - cairo_translate (context, x + PADDING, y + (height - h) / 2.0 + 0.5); - pango_cairo_show_layout (context, layout); - cairo_restore (context); - - g_free (smaller); - return w; -} - -void -gitg_label_renderer_draw (GtkWidget *widget, - PangoFontDescription *description, - cairo_t *context, - GSList *labels, - const GdkRectangle *area) -{ - GSList *item; - double pos = MARGIN + 0.5; - - cairo_save (context); - cairo_set_line_width (context, 1.0); - - PangoContext *ctx = gtk_widget_get_pango_context (widget); - PangoLayout *layout = pango_layout_new (ctx); - pango_layout_set_font_description (layout, description); - - for (item = labels; item; item = item->next) - { - gint w = render_label (context, - layout, - GITG_REF (item->data), - pos, - area->y, - area->height, - TRUE); - - pos += w + PADDING * 2 + MARGIN; - } - - g_object_unref (layout); - cairo_restore (context); -} - - -GitgRef * -gitg_label_renderer_get_ref_at_pos (GtkWidget *widget, - PangoFontDescription *font, - GSList *labels, - gint x, - gint *hot_x) -{ - if (!labels) - { - return NULL; - } - - PangoContext *ctx = gtk_widget_get_pango_context (widget); - PangoLayout *layout = pango_layout_new (ctx); - pango_layout_set_font_description (layout, font); - - gint start = MARGIN; - GitgRef *ret = NULL; - GSList *item; - - for (item = labels; item; item = item->next) - { - gint width = get_label_width (layout, GITG_REF (item->data)); - - if (x >= start && x <= start + width) - { - ret = GITG_REF (item->data); - - if (hot_x) - { - *hot_x = x - start; - } - - break; - } - - start += width + MARGIN; - } - - g_object_unref (layout); - return ret; -} - -static inline guint8 -convert_color_channel (guint8 src, - guint8 alpha) -{ - return alpha ? src / (alpha / 255.0) : 0; -} - -static void -convert_bgra_to_rgba (guint8 const *src, - guint8 *dst, - gint width, - gint height) -{ - guint8 const *src_pixel = src; - guint8 * dst_pixel = dst; - int y; - - for (y = 0; y < height; y++) - { - int x; - - for (x = 0; x < width; x++) - { - dst_pixel[0] = convert_color_channel (src_pixel[2], - src_pixel[3]); - dst_pixel[1] = convert_color_channel (src_pixel[1], - src_pixel[3]); - dst_pixel[2] = convert_color_channel (src_pixel[0], - src_pixel[3]); - dst_pixel[3] = src_pixel[3]; - - dst_pixel += 4; - src_pixel += 4; - } - } -} - -GdkPixbuf * -gitg_label_renderer_render_ref (GtkWidget *widget, - PangoFontDescription *description, - GitgRef *ref, - gint height, - gint minwidth) -{ - PangoContext *ctx = gtk_widget_get_pango_context (widget); - PangoLayout *layout = pango_layout_new (ctx); - pango_layout_set_font_description (layout, description); - - gint width = MAX (get_label_width (layout, ref), minwidth); - - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width + 2, height + 2); - cairo_t *context = cairo_create (surface); - - cairo_set_line_width (context, 1); - - render_label (context, layout, ref, 1, 1, height, FALSE); - - guint8 *data = cairo_image_surface_get_data (surface); - GdkPixbuf *ret = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width + 2, height + 2); - guint8 *pixdata = gdk_pixbuf_get_pixels (ret); - - convert_bgra_to_rgba (data, pixdata, width + 2, height + 2); - - cairo_destroy (context); - cairo_surface_destroy (surface); - - g_object_unref (layout); - - return ret; -} diff --git a/gitg/gitg-label-renderer.h b/gitg/gitg-label-renderer.h deleted file mode 100644 index e593d6f3..00000000 --- a/gitg/gitg-label-renderer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * gitg-label-renderer.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_LABEL_RENDERER_H__ -#define __GITG_LABEL_RENDERER_H__ - -#include -#include -#include - -gint gitg_label_renderer_width (GtkWidget *widget, - PangoFontDescription *description, - GSList *labels); -void gitg_label_renderer_draw (GtkWidget *widget, - PangoFontDescription *description, - cairo_t *context, - GSList *labels, - const GdkRectangle *area); - -GitgRef *gitg_label_renderer_get_ref_at_pos (GtkWidget *widget, - PangoFontDescription *description, - GSList *labels, - gint x, - gint *hot_x); - -GdkPixbuf *gitg_label_renderer_render_ref (GtkWidget *widget, - PangoFontDescription *description, - GitgRef *ref, - gint height, - gint minwidth); - -#endif /* __GITG_LABEL_RENDERER_H__ */ - diff --git a/gitg/gitg-menus.xml b/gitg/gitg-menus.xml deleted file mode 100644 index 062fc920..00000000 --- a/gitg/gitg-menus.xml +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - _Subject - true - - - - - - _Author - subject - - - - - - _Date - subject - - - - - - _Hash - subject - - - - - - - - - - Checkout branch - - - - - - Remove branch - - - - - - Rename branch - - - - - - Rebase branch onto... - - - - - Merge branch with... - - - - - Push branch to... - - - - - Apply stash to... - - - - - - - - - Merge - - - - - - Rebase - - - - - - - - - - Create branch - - - - - - Create tag - - - - - - Cherry-pick on... - - - - - Format patch - - - - - - Squash revisions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gitg/gitg-new-branch.ui b/gitg/gitg-new-branch.ui deleted file mode 100644 index ae26a809..00000000 --- a/gitg/gitg-new-branch.ui +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - 5 - Create branch - center-always - True - normal - - - True - 2 - vertical - - - True - 2 - 6 - 6 - - - True - 0 - Name: - - - GTK_SHRINK | GTK_FILL - GTK_SHRINK - - - - - True - True - True - - - 1 - 2 - GTK_FILL - - - - - False - False - 0 - - - - - True - end - - - gtk-cancel - True - True - True - True - - - False - False - 0 - - - - - Create branch - True - True - True - True - True - True - True - image_tag - - - False - False - 1 - - - - - False - end - 1 - - - - - - button_cancel - button_branch - - - - True - gtk-apply - - diff --git a/gitg/gitg-plugins-engine.vala b/gitg/gitg-plugins-engine.vala new file mode 100644 index 00000000..925686e5 --- /dev/null +++ b/gitg/gitg-plugins-engine.vala @@ -0,0 +1,67 @@ +namespace Gitg +{ + +public class PluginsEngine : Peas.Engine +{ + private static PluginsEngine s_instance; + + construct + { + enable_loader("python"); + + var repo = Introspection.Repository.get_default(); + + try + { + repo.require("Peas", "1.0", 0); + repo.require("PeasGtk", "1.0", 0); + } + catch (Error e) + { + warning("Could not load repository: %s", e.message); + return; + } + + add_search_path(Dirs.user_plugins_dir, + Dirs.user_plugins_data_dir); + + add_search_path(Dirs.plugins_dir, + Dirs.plugins_data_dir); + + Peas.PluginInfo[] builtins = new Peas.PluginInfo[20]; + builtins.length = 0; + + foreach (var info in get_plugin_list()) + { + if (info.is_builtin()) + { + builtins += info; + } + } + + foreach (var info in builtins) + { + load_plugin(info); + } + } + + public new static PluginsEngine get_default() + { + if (s_instance == null) + { + s_instance = new PluginsEngine(); + s_instance.add_weak_pointer(&s_instance); + } + + return s_instance; + } + + public static void initialize() + { + get_default(); + } +} + +} + +// ex: ts=4 noet diff --git a/gitg/gitg-preferences-dialog.c b/gitg/gitg-preferences-dialog.c deleted file mode 100644 index 60b03767..00000000 --- a/gitg/gitg-preferences-dialog.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * gitg-preferences-dialog.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-preferences-dialog.h" - -#include "gitg-utils.h" - -#include -#include -#include - -enum -{ - COLUMN_NAME, - COLUMN_PROPERTY, - N_COLUMNS -}; - -void on_collapse_inactive_lanes_changed (GtkAdjustment *adjustment, - GParamSpec *spec, - GitgPreferencesDialog *dialog); - -gboolean on_entry_configuration_user_name_focus_out_event (GtkEntry *entry, - GdkEventFocus *event, - GitgPreferencesDialog *dialog); - -gboolean on_entry_configuration_user_email_focus_out_event (GtkEntry *entry, - GdkEventFocus *event, - GitgPreferencesDialog *dialog); - -#define GITG_PREFERENCES_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_PREFERENCES_DIALOG, GitgPreferencesDialogPrivate)) - -static GitgPreferencesDialog *preferences_dialog; - -struct _GitgPreferencesDialogPrivate -{ - GitgConfig *config; - - GtkCheckButton *history_search_filter; - GtkAdjustment *collapse_inactive_lanes; - GtkCheckButton *history_show_virtual_stash; - GtkCheckButton *history_show_virtual_staged; - GtkCheckButton *history_show_virtual_unstaged; - GtkCheckButton *history_topo_order; - GtkCheckButton *check_button_collapse_inactive; - GtkCheckButton *main_layout_vertical; - - GtkCheckButton *check_button_show_right_margin; - GtkLabel *label_right_margin; - GtkSpinButton *spin_button_right_margin; - - GtkCheckButton *check_button_external_diff; - - GtkEntry *entry_configuration_user_name; - GtkEntry *entry_configuration_user_email; - - GtkWidget *table; - - gint prev_value; - - GSettings *history_settings; - GSettings *message_settings; - GSettings *view_settings; - GSettings *diff_settings; -}; - -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_dispose (GObject *object) -{ - GitgPreferencesDialog *dialog = GITG_PREFERENCES_DIALOG (object); - - if (dialog->priv->message_settings) - { - g_object_unref (dialog->priv->message_settings); - dialog->priv->message_settings = NULL; - } - - if (dialog->priv->view_settings) - { - g_object_unref (dialog->priv->view_settings); - dialog->priv->view_settings = NULL; - } - - if (dialog->priv->diff_settings) - { - g_object_unref (dialog->priv->diff_settings); - dialog->priv->diff_settings = NULL; - } - - G_OBJECT_CLASS (gitg_preferences_dialog_parent_class)->dispose (object); -} - -static void -gitg_preferences_dialog_finalize (GObject *object) -{ - GitgPreferencesDialog *dialog = GITG_PREFERENCES_DIALOG (object); - - g_object_unref (dialog->priv->config); - - 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->dispose = gitg_preferences_dialog_dispose; - 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); - - self->priv->config = gitg_config_new (NULL); - self->priv->history_settings = g_settings_new ("org.gnome.gitg.preferences.view.history"); - self->priv->message_settings = g_settings_new ("org.gnome.gitg.preferences.commit.message"); - self->priv->view_settings = g_settings_new ("org.gnome.gitg.preferences.view.main"); - self->priv->diff_settings = g_settings_new ("org.gnome.gitg.preferences.diff"); -} - -static void -on_response(GtkWidget *dialog, gint response, gpointer data) -{ - gtk_widget_destroy(dialog); -} - -static GVariant * -convert_collapsed (const GValue *value, - const GVariantType *expected_type, - gpointer userdata) -{ - GitgPreferencesDialog *dialog = GITG_PREFERENCES_DIALOG (userdata); - gint val = round_val (g_value_get_double (value)); - - if (val == dialog->priv->prev_value) - return NULL; - - dialog->priv->prev_value = val; - - return g_variant_new_int32 (val); -} - -static void -on_collapse_inactive_toggled(GtkToggleButton *button, GitgPreferencesDialog *dialog) -{ - gboolean active = gtk_toggle_button_get_active (button); - gtk_widget_set_sensitive(dialog->priv->table, active); -} - -static void -on_check_button_show_right_margin_toggled(GtkToggleButton *button, GitgPreferencesDialog *dialog) -{ - gboolean active = gtk_toggle_button_get_active (button); - - gtk_widget_set_sensitive(GTK_WIDGET(dialog->priv->label_right_margin), active); - gtk_widget_set_sensitive(GTK_WIDGET(dialog->priv->spin_button_right_margin), active); -} - -static gboolean -orientation_to_layout_vertical (GValue *value, - GVariant *variant, - gpointer user_data) -{ - const gchar *orientation; - gboolean val; - - orientation = g_variant_get_string (variant, NULL); - - if (strcmp (orientation, "vertical") == 0) - { - val = TRUE; - } - else - { - val = FALSE; - } - - g_value_set_boolean (value, val); - - return TRUE; -} - -static GVariant * -layout_vertical_to_orientation (const GValue *value, - const GVariantType *expected_type, - gpointer user_data) -{ - GVariant *orientation; - - if (g_value_get_boolean (value)) - { - orientation = g_variant_new_string ("vertical"); - } - else - { - orientation = g_variant_new_string ("horizontal"); - } - - return orientation; -} - -static void -initialize_view(GitgPreferencesDialog *dialog) -{ - g_signal_connect (dialog->priv->check_button_collapse_inactive, - "toggled", - G_CALLBACK (on_collapse_inactive_toggled), - dialog); - - g_signal_connect (dialog->priv->check_button_show_right_margin, - "toggled", - G_CALLBACK (on_check_button_show_right_margin_toggled), - dialog); - - g_settings_bind (dialog->priv->history_settings, - "search-filter", - dialog->priv->history_search_filter, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind_with_mapping (dialog->priv->history_settings, - "collapse-inactive-lanes", - dialog->priv->collapse_inactive_lanes, - "value", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, - NULL, - convert_collapsed, - dialog, - NULL); - - g_settings_bind (dialog->priv->history_settings, - "collapse-inactive-lanes-active", - dialog->priv->check_button_collapse_inactive, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->history_settings, - "topo-order", - dialog->priv->history_topo_order, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->history_settings, - "show-virtual-stash", - dialog->priv->history_show_virtual_stash, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->history_settings, - "show-virtual-staged", - dialog->priv->history_show_virtual_staged, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->history_settings, - "show-virtual-unstaged", - dialog->priv->history_show_virtual_unstaged, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->message_settings, - "show-right-margin", - dialog->priv->check_button_show_right_margin, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (dialog->priv->message_settings, - "right-margin-at", - dialog->priv->spin_button_right_margin, - "value", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind_with_mapping (dialog->priv->view_settings, - "layout-vertical", - dialog->priv->main_layout_vertical, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, - orientation_to_layout_vertical, - layout_vertical_to_orientation, - NULL, - NULL); - - g_settings_bind (dialog->priv->diff_settings, - "external", - dialog->priv->check_button_external_diff, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); -} - -static void -create_preferences_dialog() -{ - GtkBuilder *b = gitg_utils_new_builder("gitg-preferences.ui"); - - 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->history_show_virtual_stash = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_history_show_virtual_stash")); - priv->history_show_virtual_staged = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_history_show_virtual_staged")); - priv->history_show_virtual_unstaged = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_history_show_virtual_unstaged")); - priv->history_topo_order = GTK_CHECK_BUTTON (gtk_builder_get_object (b, "check_button_history_topo_order")); - - priv->main_layout_vertical = GTK_CHECK_BUTTON (gtk_builder_get_object (b, "check_button_main_layout_vertical")); - - priv->check_button_collapse_inactive = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_collapse_inactive")); - priv->table = GTK_WIDGET(gtk_builder_get_object(b, "table_collapse_inactive_lanes")); - - priv->check_button_show_right_margin = GTK_CHECK_BUTTON(gtk_builder_get_object(b, "check_button_show_right_margin")); - priv->label_right_margin = GTK_LABEL(gtk_builder_get_object(b, "label_right_margin")); - priv->spin_button_right_margin = GTK_SPIN_BUTTON(gtk_builder_get_object(b, "spin_button_right_margin")); - - priv->check_button_external_diff = GTK_CHECK_BUTTON (gtk_builder_get_object (b, "check_button_external_diff")); - - 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); - - priv->entry_configuration_user_name = GTK_ENTRY(gtk_builder_get_object(b, "entry_configuration_user_name")); - priv->entry_configuration_user_email = GTK_ENTRY(gtk_builder_get_object(b, "entry_configuration_user_email")); - - gtk_builder_connect_signals(b, preferences_dialog); - g_object_unref(b); - - gchar *val; - - val = gitg_config_get_value (priv->config, "user.name"); - gtk_entry_set_text (priv->entry_configuration_user_name, val ? val : ""); - g_free (val); - - val = gitg_config_get_value (priv->config, "user.email"); - gtk_entry_set_text (priv->entry_configuration_user_email, val ? val : ""); - g_free (val); -} - -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)); - - if (val > 0) - { - g_signal_handlers_block_by_func (adjustment, - on_collapse_inactive_lanes_changed, - dialog); - - gtk_adjustment_set_value (adjustment, val); - - g_signal_handlers_unblock_by_func (adjustment, - on_collapse_inactive_lanes_changed, - dialog); - } -} - -gboolean -on_entry_configuration_user_name_focus_out_event (GtkEntry *entry, - GdkEventFocus *event, - GitgPreferencesDialog *dialog) -{ - gitg_config_set_value (dialog->priv->config, - "user.name", - gtk_entry_get_text (entry)); - - return FALSE; -} - -gboolean -on_entry_configuration_user_email_focus_out_event (GtkEntry *entry, - GdkEventFocus *event, - GitgPreferencesDialog *dialog) -{ - gitg_config_set_value (dialog->priv->config, - "user.email", - gtk_entry_get_text (entry)); - - return FALSE; -} - diff --git a/gitg/gitg-preferences-dialog.h b/gitg/gitg-preferences-dialog.h deleted file mode 100644 index c1142cbb..00000000 --- a/gitg/gitg-preferences-dialog.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * gitg-preferences-dialog.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_PREFERENCES_DIALOG_H__ -#define __GITG_PREFERENCES_DIALOG_H__ - -#include - -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__ */ diff --git a/gitg/gitg-preferences.ui b/gitg/gitg-preferences.ui deleted file mode 100644 index abf4ffcb..00000000 --- a/gitg/gitg-preferences.ui +++ /dev/null @@ -1,810 +0,0 @@ - - - - - 5 - 2 - 1 - 1 - 1 - - - False - 5 - Preferences - 400 - 500 - normal - - - True - False - vertical - 2 - - - True - False - end - - - gtk-close - True - True - True - False - True - - - False - False - 0 - - - - - False - True - end - 0 - - - - - True - True - True - - - True - False - 12 - vertical - 18 - - - True - False - vertical - 6 - - - True - False - 0 - <b>Interface</b> - True - - - False - True - 0 - - - - - True - False - - - True - False - - - - False - False - 0 - - - - - True - False - vertical - 6 - - - Use vertical layout - True - True - False - False - True - - - False - True - 0 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 0 - - - - - True - False - vertical - 6 - - - True - False - 0 - <b>Revisions</b> - True - - - False - True - 0 - - - - - True - False - - - True - False - - - - False - False - 0 - - - - - True - False - vertical - 6 - - - Search filters revisions in the history view - True - False - False - True - - - False - True - 0 - - - - - Collapse inactive lanes - True - True - False - False - True - True - - - False - True - 1 - - - - - True - False - 2 - 2 - 3 - 3 - - - True - True - adjustment_collapse_inactive_lanes - 0 - False - - - 2 - GTK_FILL - - - - - True - False - 0 - Early - - - 1 - 2 - GTK_FILL - - - - - True - False - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - False - 1 - Late - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - False - True - 2 - - - - - Show stash in history - True - True - False - False - True - - - False - True - 3 - - - - - Show staged changes in history - True - True - False - False - True - - - False - True - 4 - - - - - Show unstaged changes in history - True - True - False - False - True - - - False - True - 5 - - - - - Show history in topological order - True - True - False - False - True - - - False - True - 6 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - - - True - False - Preferences that apply to the history view - History - - - False - - - - - True - False - 12 - vertical - 18 - - - True - False - vertical - 6 - - - True - False - 0 - <b>Commit Message</b> - True - - - False - True - 0 - - - - - True - False - - - True - False - - - - False - False - 0 - - - - - True - False - vertical - 6 - - - Display right _margin - True - True - False - False - True - True - True - - - False - True - 0 - - - - - True - False - 6 - - - True - False - 0 - _Right margin at column: - True - - - False - False - 0 - - - - - True - True - spin_button_right_margin_adjustment - 1 - True - True - - - False - False - 1 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 0 - - - - - 1 - - - - - True - False - Preferences that apply to the commit view - Commit - - - 1 - False - - - - - True - False - 12 - vertical - 18 - - - True - False - vertical - 6 - - - True - False - 0 - <b>Diff Program</b> - True - - - False - True - 0 - - - - - True - False - - - True - False - - - - False - False - 0 - - - - - True - False - vertical - 6 - - - Allow external diff program - True - True - False - False - True - True - True - - - False - True - 0 - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 0 - - - - - 2 - - - - - True - False - Diff - - - 2 - False - - - - - True - False - 12 - vertical - 18 - - - True - False - vertical - 6 - - - True - False - 0 - <b>User</b> - True - - - False - True - 0 - - - - - True - False - - - True - False - - - - False - False - 0 - - - - - True - False - True - 2 - 2 - 6 - 6 - - - True - False - 0 - Name: - - - GTK_SHRINK | GTK_FILL - GTK_FILL - - - - - True - False - 0 - E-mail: - - - 1 - 2 - GTK_SHRINK | GTK_FILL - GTK_FILL - - - - - True - True - True - - True - - - - 1 - 2 - GTK_FILL - - - - - True - True - True - - True - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - False - True - 1 - - - - - False - True - 1 - - - - - False - True - 0 - - - - - 3 - - - - - True - False - Configure global git settings. This corresponds to the settings as stored in ~/.gitconfig. Repository specific settings can be configured at the repository properties. - Configuration - - - 3 - False - - - - - False - True - 1 - - - - - - button_close - - - - True - False - gtk-bold - 1 - - - True - False - gtk-italic - 1 - - - True - False - gtk-underline - 1 - - - 1 - 160 - 72 - 1 - 10 - - diff --git a/gitg/gitg-repository-dialog.c b/gitg/gitg-repository-dialog.c deleted file mode 100644 index b84b46d9..00000000 --- a/gitg/gitg-repository-dialog.c +++ /dev/null @@ -1,906 +0,0 @@ -/* - * gitg-repository-dialog.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 - -#include -#include -#include - -#include "gitg-repository-dialog.h" -#include "gitg-utils.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -void on_button_fetch_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog); - -void on_button_remove_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog); - -void on_button_add_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog); - -gboolean on_entry_repository_user_name_focus_out_event (GtkEntry *entry, - GdkEventFocus *focus, - GitgRepositoryDialog *dialog); - -gboolean on_entry_repository_user_email_focus_out_event (GtkEntry *entry, - GdkEventFocus *focus, - GitgRepositoryDialog *dialog); - -void on_remote_name_edited (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - GitgRepositoryDialog *dialog); - -void on_remote_url_edited (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - GitgRepositoryDialog *dialog); - -#define GITG_REPOSITORY_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REPOSITORY_DIALOG, GitgRepositoryDialogPrivate)) - -static GitgRepositoryDialog *repository_dialog = NULL; - -enum -{ - COLUMN_NAME, - COLUMN_URL, - COLUMN_FETCH, - COLUMN_PULSE, - COLUMN_SPINNER -}; - -struct _GitgRepositoryDialogPrivate -{ - GitgRepository *repository; - GitgConfig *config; - - GtkEntry *entry_repository_user_name; - GtkEntry *entry_repository_user_email; - - GtkTreeView *tree_view_remotes; - GtkListStore *list_store_remotes; - - GtkButton *button_remove_remote; - GtkButton *button_fetch_remote; - GtkImage *image_fetch_remote; - - GList *fetchers; - gboolean show_fetch; -}; - -G_DEFINE_TYPE (GitgRepositoryDialog, gitg_repository_dialog, GTK_TYPE_DIALOG) - -typedef struct -{ - GitgRepositoryDialog *dialog; - GitgShell *shell; - GtkTreeRowReference *reference; - - guint pulse_id; -} FetchInfo; - -static void -fetch_cleanup (FetchInfo *info) -{ - info->dialog->priv->fetchers = g_list_remove (info->dialog->priv->fetchers, info); - - if (gtk_tree_row_reference_valid (info->reference)) - { - GtkTreeIter iter; - GtkTreePath *path = gtk_tree_row_reference_get_path (info->reference); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (info->dialog->priv->list_store_remotes), - &iter, - path); - - gtk_list_store_set (info->dialog->priv->list_store_remotes, - &iter, - COLUMN_FETCH, FALSE, - -1); - - gtk_tree_path_free (path); - } - - g_source_remove (info->pulse_id); - - gtk_tree_row_reference_free (info->reference); - g_object_unref (info->shell); - - g_slice_free (FetchInfo, info); -} - -static void -gitg_repository_dialog_finalize (GObject *object) -{ - GitgRepositoryDialog *dialog = GITG_REPOSITORY_DIALOG (object); - - if (dialog->priv->repository) - { - g_object_unref (dialog->priv->repository); - } - - if (dialog->priv->config) - { - g_object_unref (dialog->priv->config); - } - - GList *copy = g_list_copy (dialog->priv->fetchers); - GList *item; - - for (item = copy; item; item = g_list_next (item)) - { - gitg_io_cancel (GITG_IO (((FetchInfo *)item->data)->shell)); - } - - g_list_free (copy); - g_list_free (dialog->priv->fetchers); - - G_OBJECT_CLASS (gitg_repository_dialog_parent_class)->finalize (object); -} - -static void -gitg_repository_dialog_class_init (GitgRepositoryDialogClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_repository_dialog_finalize; - - g_type_class_add_private (object_class, sizeof(GitgRepositoryDialogPrivate)); -} - -static void -gitg_repository_dialog_init (GitgRepositoryDialog *self) -{ - self->priv = GITG_REPOSITORY_DIALOG_GET_PRIVATE (self); -} - -static void -on_response(GtkWidget *dialog, gint response, gpointer data) -{ - gtk_widget_destroy(dialog); -} - -static void -update_fetch (GitgRepositoryDialog *dialog) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection (dialog->priv->tree_view_remotes); - GList *rows; - GtkTreeModel *model; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - GList *item; - gboolean show_fetch = FALSE; - - for (item = rows; item; item = g_list_next (item)) - { - GtkTreePath *path = (GtkTreePath *)item->data; - GtkTreeIter iter; - - gtk_tree_model_get_iter (model, &iter, path); - - gboolean fetch; - gtk_tree_model_get (model, &iter, COLUMN_FETCH, &fetch, -1); - - if (!fetch) - { - show_fetch = TRUE; - } - } - - if (!rows) - { - show_fetch = TRUE; - } - - if (show_fetch) - { - gtk_image_set_from_stock (dialog->priv->image_fetch_remote, GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON); - gtk_button_set_label (dialog->priv->button_fetch_remote, _("Fetch")); - } - else - { - gtk_image_set_from_stock (dialog->priv->image_fetch_remote, GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON); - gtk_button_set_label (dialog->priv->button_fetch_remote, _("Cancel")); - } - - dialog->priv->show_fetch = show_fetch; - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -static void -update_sensitivity (GitgRepositoryDialog *dialog) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection (dialog->priv->tree_view_remotes); - GList *rows; - GtkTreeModel *model; - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - gtk_widget_set_sensitive (GTK_WIDGET (dialog->priv->button_remove_remote), rows != NULL); - gtk_widget_set_sensitive (GTK_WIDGET (dialog->priv->button_fetch_remote), rows != NULL); - - update_fetch (dialog); - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -static void -add_remote (GitgRepositoryDialog *dialog, gchar const *name, gchar const *url, GtkTreeIter *iter) -{ - GtkTreeIter it; - - gtk_list_store_append (dialog->priv->list_store_remotes, iter ? iter : &it); - gtk_list_store_set (dialog->priv->list_store_remotes, - iter ? iter : &it, - COLUMN_NAME, name, - COLUMN_URL, url, - COLUMN_FETCH, FALSE, - COLUMN_PULSE, 0, - COLUMN_SPINNER, NULL, - -1); -} - -static gboolean -pulse_row (FetchInfo *info) -{ - gint pulse; - gboolean fetch; - GtkTreeIter iter; - GtkTreePath *path = gtk_tree_row_reference_get_path (info->reference); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (info->dialog->priv->list_store_remotes), - &iter, - path); - - gtk_tree_model_get (GTK_TREE_MODEL (info->dialog->priv->list_store_remotes), - &iter, - COLUMN_FETCH, &fetch, - COLUMN_PULSE, &pulse, - -1); - - if (fetch) - { - gtk_list_store_set (info->dialog->priv->list_store_remotes, - &iter, - COLUMN_PULSE, pulse + 1, - -1); - } - - gtk_tree_path_free (path); - - return fetch; -} - -static void -on_fetch_begin_loading (GitgShell *shell, FetchInfo *info) -{ - GtkTreeIter iter; - GtkTreePath *path = gtk_tree_row_reference_get_path (info->reference); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (info->dialog->priv->list_store_remotes), - &iter, - path); - - gtk_list_store_set (info->dialog->priv->list_store_remotes, - &iter, - COLUMN_FETCH, TRUE, - -1); - - /* We can't tell how often we are supposed to pulse so just pulse - * at the interval of the default engine. Yes this is annoying but, - * mclasen said to "blame the engine." - */ - info->pulse_id = g_timeout_add (750 / 12, - (GSourceFunc)pulse_row, - info); - - gtk_tree_path_free (path); - update_fetch (info->dialog); -} - -static void -on_fetch_end_loading (GitgShell *shell, gboolean cancelled, FetchInfo *info) -{ - if (cancelled || !gtk_tree_row_reference_valid (info->reference)) - { - fetch_cleanup (info); - return; - } - - GitgRepositoryDialog *dialog = info->dialog; - - fetch_cleanup (info); - - update_fetch (dialog); - gitg_repository_reload (dialog->priv->repository); -} - -static void -fetch_remote (GitgRepositoryDialog *dialog, GtkTreeIter *iter) -{ - GitgShell *shell = gitg_shell_new (1000); - FetchInfo *info = g_slice_new0 (FetchInfo); - GtkTreeModel *model = GTK_TREE_MODEL (dialog->priv->list_store_remotes); - - GtkTreePath *path = gtk_tree_model_get_path (model, iter); - - info->dialog = dialog; - info->reference = gtk_tree_row_reference_new (model, path); - info->shell = shell; - - gtk_tree_path_free (path); - - g_signal_connect (shell, - "begin", - G_CALLBACK (on_fetch_begin_loading), - info); - - g_signal_connect (shell, - "end", - G_CALLBACK (on_fetch_end_loading), - info); - - dialog->priv->fetchers = g_list_prepend (dialog->priv->fetchers, info); - - gchar *name; - gtk_tree_model_get (model, iter, COLUMN_NAME, &name, -1); - - gitg_shell_run (shell, - gitg_command_new (dialog->priv->repository, - "fetch", - name, - NULL), - NULL); - - g_free (name); -} - -static void -on_selection_changed (GtkTreeSelection *selection, GitgRepositoryDialog *dialog) -{ - update_sensitivity (dialog); -} - -static void -init_remotes(GitgRepositoryDialog *dialog) -{ - gchar *ret = gitg_config_get_value_regex (dialog->priv->config, - "remote\\..*\\.url", - NULL); - - if (!ret) - { - update_sensitivity (dialog); - return; - } - - gchar **lines = g_strsplit(ret, "\n", -1); - gchar **ptr = lines; - - GRegex *regex = g_regex_new ("remote\\.(.+?)\\.url\\s+(.*)", 0, 0, NULL); - - while (*ptr) - { - GMatchInfo *info = NULL; - - if (g_regex_match (regex, *ptr, 0, &info)) - { - gchar *name = g_match_info_fetch (info, 1); - gchar *url = g_match_info_fetch (info, 2); - - add_remote (dialog, name, url, NULL); - - g_free (name); - g_free (url); - } - - g_match_info_free (info); - ++ptr; - } - - g_regex_unref (regex); - g_strfreev (lines); - g_free (ret); - - GtkTreeSelection *selection; - selection = gtk_tree_view_get_selection (dialog->priv->tree_view_remotes); - - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - g_signal_connect (selection, "changed", G_CALLBACK (on_selection_changed), dialog); - - update_sensitivity (dialog); -} - -static void -init_properties(GitgRepositoryDialog *dialog) -{ - gchar *val; - - val = gitg_config_get_value (dialog->priv->config, "user.name"); - gtk_entry_set_text (dialog->priv->entry_repository_user_name, val ? val : ""); - g_free (val); - - val = gitg_config_get_value (dialog->priv->config, "user.email"); - gtk_entry_set_text (dialog->priv->entry_repository_user_email, val ? val : ""); - g_free (val); - - init_remotes(dialog); -} - -static void -fetch_data_spinner_cb (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgRepositoryDialog *dialog) -{ - gboolean fetch; - guint pulse; - - gtk_tree_model_get (model, iter, - COLUMN_FETCH, &fetch, - COLUMN_PULSE, &pulse, - -1); - - g_object_set (G_OBJECT (cell), - "active", fetch, - "visible", fetch, - "pulse", pulse, - NULL); -} - -static void -fetch_data_icon_cb (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgRepositoryDialog *dialog) -{ - gboolean fetch; - - gtk_tree_model_get (model, iter, COLUMN_FETCH, &fetch, -1); - - g_object_set (G_OBJECT (cell), - "visible", !fetch, - NULL); -} - - -static void -create_repository_dialog (GitgWindow *window) -{ - GitgRepository *repository = gitg_window_get_repository (window); - - if (!repository) - { - return; - } - - GtkBuilder *b = gitg_utils_new_builder("gitg-repository.ui"); - - repository_dialog = GITG_REPOSITORY_DIALOG(gtk_builder_get_object(b, "dialog_repository")); - g_object_add_weak_pointer(G_OBJECT(repository_dialog), (gpointer *)&repository_dialog); - - repository_dialog->priv->repository = g_object_ref (repository); - repository_dialog->priv->config = gitg_config_new (repository); - - repository_dialog->priv->entry_repository_user_name = GTK_ENTRY(gtk_builder_get_object(b, "entry_repository_user_name")); - repository_dialog->priv->entry_repository_user_email = GTK_ENTRY(gtk_builder_get_object(b, "entry_repository_user_email")); - - repository_dialog->priv->tree_view_remotes = GTK_TREE_VIEW(gtk_builder_get_object(b, "tree_view_remotes")); - repository_dialog->priv->list_store_remotes = GTK_LIST_STORE(gtk_builder_get_object(b, "list_store_remotes")); - - repository_dialog->priv->button_remove_remote = GTK_BUTTON(gtk_builder_get_object(b, "button_remove_remote")); - repository_dialog->priv->button_fetch_remote = GTK_BUTTON(gtk_builder_get_object(b, "button_fetch_remote")); - repository_dialog->priv->image_fetch_remote = GTK_IMAGE(gtk_builder_get_object(b, "image_fetch_remote")); - - GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (b, "tree_view_remotes_column_name")); - - GtkCellRenderer *spinner_renderer = gtk_cell_renderer_spinner_new (); - g_object_set (spinner_renderer, "visible", FALSE, NULL); - - gtk_tree_view_column_pack_start (column, spinner_renderer, FALSE); - gtk_cell_layout_reorder (GTK_CELL_LAYOUT (column), spinner_renderer, 1); - - gtk_tree_view_column_set_cell_data_func (column, - spinner_renderer, - (GtkTreeCellDataFunc)fetch_data_spinner_cb, - repository_dialog, - NULL); - - GtkCellRenderer *icon_renderer = GTK_CELL_RENDERER (gtk_builder_get_object (b, "tree_view_remotes_renderer_icon")); - gtk_tree_view_column_set_cell_data_func (column, - icon_renderer, - (GtkTreeCellDataFunc)fetch_data_icon_cb, - repository_dialog, - NULL); - - gtk_builder_connect_signals(b, repository_dialog); - g_object_unref (b); - - GFile *work_tree = gitg_repository_get_work_tree (repository); - gchar *basename = g_file_get_basename (work_tree); - g_object_unref (work_tree); - - gchar *title = g_strdup_printf("%s - %s", _("Properties"), basename); - gtk_window_set_title(GTK_WINDOW(repository_dialog), title); - - g_free (title); - g_free (basename); - - g_signal_connect(repository_dialog, "response", G_CALLBACK(on_response), NULL); - - init_properties(repository_dialog); -} - -GitgRepositoryDialog * -gitg_repository_dialog_present (GitgWindow *window) -{ - if (!repository_dialog) - { - create_repository_dialog(window); - } - - gtk_window_set_transient_for(GTK_WINDOW(repository_dialog), GTK_WINDOW (window)); - gtk_window_present(GTK_WINDOW(repository_dialog)); - - return repository_dialog; -} - -void -gitg_repository_dialog_close (void) -{ - if (repository_dialog) - { - gtk_widget_destroy (GTK_WIDGET (repository_dialog)); - } -} - -static void -fetch_remote_cancel (GitgRepositoryDialog *dialog, - GtkTreeIter *iter) -{ - GList *item; - GtkTreePath *orig; - GtkTreeModel *model = GTK_TREE_MODEL (dialog->priv->list_store_remotes); - - orig = gtk_tree_model_get_path (model, iter); - - for (item = dialog->priv->fetchers; item; item = g_list_next (item)) - { - FetchInfo *info = (FetchInfo *)item->data; - GtkTreePath *ref = gtk_tree_row_reference_get_path (info->reference); - gboolean equal = gtk_tree_path_compare (orig, ref) == 0; - - gtk_tree_path_free (ref); - - if (equal) - { - gitg_io_cancel (GITG_IO (info->shell)); - break; - } - } - - gtk_tree_path_free (orig); -} - -void -on_button_fetch_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (dialog->priv->tree_view_remotes); - - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - GList *item; - - for (item = rows; item; item = g_list_next (item)) - { - GtkTreePath *path = (GtkTreePath *)item->data; - GtkTreeIter iter; - gboolean fetch; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, COLUMN_FETCH, &fetch, -1); - - if (!fetch && dialog->priv->show_fetch) - { - fetch_remote (dialog, &iter); - } - else if (fetch && !dialog->priv->show_fetch) - { - fetch_remote_cancel (dialog, &iter); - } - - gtk_tree_path_free (path); - } - - if (rows) - { - update_fetch (dialog); - } - - g_list_free (rows); -} - -static gboolean -remove_remote (GitgRepositoryDialog *dialog, gchar const *name) -{ - return gitg_shell_run_sync (gitg_command_new (dialog->priv->repository, - "remote", - "rm", - name, - NULL), - NULL); -} - -void -on_button_remove_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (dialog->priv->tree_view_remotes); - - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - GList *refs = NULL; - GList *item; - - for (item = rows; item; item = g_list_next (item)) - { - GtkTreeRowReference *ref; - GtkTreePath *path = (GtkTreePath *)item->data; - - ref = gtk_tree_row_reference_new (model, path); - refs = g_list_prepend (refs, ref); - - gtk_tree_path_free (path); - } - - refs = g_list_reverse (refs); - g_list_free (rows); - - for (item = refs; item; item = g_list_next (item)) - { - GtkTreeRowReference *ref = (GtkTreeRowReference *)item->data; - GtkTreePath *path = gtk_tree_row_reference_get_path (ref); - GtkTreeIter iter; - gchar *name; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1); - - gboolean ret = remove_remote (dialog, name); - - if (ret) - { - gtk_list_store_remove (dialog->priv->list_store_remotes, &iter); - } - - gtk_tree_row_reference_free (ref); - gtk_tree_path_free (path); - } - - g_list_free (refs); -} - -void -on_button_add_remote_clicked (GtkButton *button, - GitgRepositoryDialog *dialog) -{ - GtkTreeModel *model = GTK_TREE_MODEL (dialog->priv->list_store_remotes); - GtkTreeIter iter; - - gint num = 0; - - if (gtk_tree_model_get_iter_first (model, &iter)) - { - do - { - gchar *name; - gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1); - - if (g_str_has_prefix (name, "remote")) - { - gint n = atoi (name + 6); - - if (n > num) - { - num = n; - } - } - - g_free (name); - } while (gtk_tree_model_iter_next (model, &iter)); - } - - gchar *name = g_strdup_printf ("remote%d", num + 1); - gchar const url[] = "git://example.com/repository.git"; - - if (gitg_shell_run_sync (gitg_command_new (dialog->priv->repository, - "remote", - "add", - name, - url, - NULL), - NULL)) - { - GtkTreeIter iter; - GtkTreePath *path; - - add_remote (dialog, name, url, &iter); - - path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->priv->list_store_remotes), &iter); - - gtk_tree_view_set_cursor (dialog->priv->tree_view_remotes, - path, - gtk_tree_view_get_column (dialog->priv->tree_view_remotes, COLUMN_NAME), - TRUE); - - gtk_tree_path_free (path); - } - - g_free (name); -} - -gboolean -on_entry_repository_user_name_focus_out_event (GtkEntry *entry, - GdkEventFocus *focus, - GitgRepositoryDialog *dialog) -{ - gchar const *text; - - text = gtk_entry_get_text (entry); - gitg_config_set_value (dialog->priv->config, "user.name", *text ? text : NULL); - - return FALSE; -} - -gboolean -on_entry_repository_user_email_focus_out_event (GtkEntry *entry, - GdkEventFocus *focus, - GitgRepositoryDialog *dialog) -{ - gchar const *text; - - text = gtk_entry_get_text (entry); - gitg_config_set_value (dialog->priv->config, "user.email", *text ? text : NULL); - - return FALSE; -} - -void -on_remote_name_edited (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - GitgRepositoryDialog *dialog) -{ - if (!*new_text) - { - return; - } - - GtkTreePath *tp = gtk_tree_path_new_from_string (path); - GtkTreeIter iter; - - gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->list_store_remotes), - &iter, - tp); - - gchar *oldname; - gchar *url; - - gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->list_store_remotes), - &iter, - COLUMN_NAME, &oldname, - COLUMN_URL, &url, - -1); - - if (gitg_shell_run_sync (gitg_command_new (dialog->priv->repository, - "remote", - "add", - new_text, - url, - NULL), - NULL)) - { - remove_remote (dialog, oldname); - - gtk_list_store_set (dialog->priv->list_store_remotes, - &iter, - COLUMN_NAME, new_text, - -1); - - fetch_remote (dialog, &iter); - } - - g_free (oldname); - g_free (url); - - gtk_tree_path_free (tp); -} - -void -on_remote_url_edited (GtkCellRendererText *renderer, - gchar *path, - gchar *new_text, - GitgRepositoryDialog *dialog) -{ - if (!*new_text) - { - return; - } - - GtkTreePath *tp = gtk_tree_path_new_from_string (path); - GtkTreeIter iter; - - gtk_tree_model_get_iter (GTK_TREE_MODEL (dialog->priv->list_store_remotes), - &iter, - tp); - - gchar *name; - gchar *url; - - gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->list_store_remotes), - &iter, - COLUMN_NAME, &name, - COLUMN_URL, &url, - -1); - - if (g_strcmp0 (url, new_text) == 0) - { - g_free (name); - g_free (url); - - gtk_tree_path_free (tp); - - return; - } - - g_free (url); - - gchar *key = g_strconcat ("remote.", name, ".url", NULL); - g_free (name); - - if (gitg_config_set_value (dialog->priv->config, key, new_text)) - { - gtk_list_store_set (dialog->priv->list_store_remotes, - &iter, - COLUMN_URL, new_text, - -1); - - fetch_remote (dialog, &iter); - } - - g_free (key); - gtk_tree_path_free (tp); -} diff --git a/gitg/gitg-repository-dialog.h b/gitg/gitg-repository-dialog.h deleted file mode 100644 index e712edb8..00000000 --- a/gitg/gitg-repository-dialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * gitg-repository-dialog.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REPOSITORY_DIALOG_H__ -#define __GITG_REPOSITORY_DIALOG_H__ - -#include -#include "gitg-window.h" - -G_BEGIN_DECLS - -#define GITG_TYPE_REPOSITORY_DIALOG (gitg_repository_dialog_get_type ()) -#define GITG_REPOSITORY_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REPOSITORY_DIALOG, GitgRepositoryDialog)) -#define GITG_REPOSITORY_DIALOG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REPOSITORY_DIALOG, GitgRepositoryDialog const)) -#define GITG_REPOSITORY_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REPOSITORY_DIALOG, GitgRepositoryDialogClass)) -#define GITG_IS_REPOSITORY_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REPOSITORY_DIALOG)) -#define GITG_IS_REPOSITORY_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REPOSITORY_DIALOG)) -#define GITG_REPOSITORY_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REPOSITORY_DIALOG, GitgRepositoryDialogClass)) - -typedef struct _GitgRepositoryDialog GitgRepositoryDialog; -typedef struct _GitgRepositoryDialogClass GitgRepositoryDialogClass; -typedef struct _GitgRepositoryDialogPrivate GitgRepositoryDialogPrivate; - -struct _GitgRepositoryDialog -{ - GtkDialog parent; - - GitgRepositoryDialogPrivate *priv; -}; - -struct _GitgRepositoryDialogClass -{ - GtkDialogClass parent_class; -}; - -GType gitg_repository_dialog_get_type (void) G_GNUC_CONST; -GitgRepositoryDialog *gitg_repository_dialog_present(GitgWindow *window); - -void gitg_repository_dialog_close (void); - -G_END_DECLS - -#endif /* __GITG_REPOSITORY_DIALOG_H__ */ diff --git a/gitg/gitg-repository.ui b/gitg/gitg-repository.ui deleted file mode 100644 index f6012e5c..00000000 --- a/gitg/gitg-repository.ui +++ /dev/null @@ -1,320 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - 5 - Properties - 500 - 300 - normal - - - True - 2 - vertical - - - True - True - True - - - True - 12 - vertical - 6 - - - True - True - automatic - automatic - etched-in - - - True - True - list_store_remotes - True - True - - - Name - - - gtk-network - - - - - True - - - - 0 - - - - - - - URL - True - - - True - - - - 1 - - - - - - - - - 0 - - - - - True - horizontal - - - Fetch - True - True - True - image_fetch_remote - - - - False - 0 - - - - - gtk-add - True - True - True - True - - - - False - False - end - 2 - - - - - gtk-remove - True - True - True - True - - - - False - False - end - 1 - - - - - False - 1 - - - - - - - True - Remotes - - - False - - - - - True - 12 - vertical - 6 - - - True - 0 - <b>User</b> - True - - - False - 0 - - - - - True - horizontal - - - True - - - - False - False - 0 - - - - - True - 2 - 2 - 6 - 6 - True - False - - - True - 0 - Name: - - - GTK_SHRINK | GTK_FILL - - - - - True - 0 - E-mail: - - - 1 - 2 - GTK_SHRINK | GTK_FILL - - - - - True - True - - - - - 1 - 2 - - - - - True - True - - - - - 1 - 2 - 1 - 2 - - - - - 1 - - - - - False - 1 - - - - - 1 - - - - - True - Configuration - - - 1 - False - - - - - 1 - - - - - True - end - - - gtk-close - True - True - True - True - - - False - False - 0 - - - - - False - end - 0 - - - - - - button_close - - - - True - gtk-refresh - - diff --git a/gitg/gitg-resource.vala b/gitg/gitg-resource.vala new file mode 100644 index 00000000..4af3c425 --- /dev/null +++ b/gitg/gitg-resource.vala @@ -0,0 +1,62 @@ +namespace Gitg +{ + class Resource + { + public static T[]? load_objects(string id, string[] objects) + { + var builder = new Gtk.Builder(); + + try + { + builder.add_from_resource("/org/gnome/gitg/" + id); + } + catch (Error e) + { + warning("Error while loading resource: %s", e.message); + return null; + } + + T[] ret = new T[objects.length]; + ret.length = 0; + + foreach (string obj in objects) + { + ret += (T)builder.get_object(obj); + } + + return ret; + } + + public static T? load_object(string id, string object) + { + T[]? ret = load_objects(id, new string[] {object}); + + if (ret == null) + { + return null; + } + + return ret[0]; + } + + public static Gtk.CssProvider? load_css(string id) + { + var provider = new Gtk.CssProvider(); + var f = File.new_for_uri("resource:///org/gnome/gitg/ui/" + id); + + try + { + provider.load_from_file(f); + } + catch (Error e) + { + warning("Error while loading resource: %s", e.message); + return null; + } + + return provider; + } + } +} + +// ex: ts=4 noet diff --git a/gitg/gitg-revision-changes-panel.c b/gitg/gitg-revision-changes-panel.c deleted file mode 100644 index 8706e577..00000000 --- a/gitg/gitg-revision-changes-panel.c +++ /dev/null @@ -1,1048 +0,0 @@ -#include "gitg-revision-changes-panel.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include "gitg-diff-view.h" -#include "gitg-utils.h" -#include - - -#include "gitg-revision-panel.h" -#include "gitg-activatable.h" - -#define GITG_REVISION_CHANGES_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelPrivate)) - -struct _GitgRevisionChangesPanelPrivate -{ - GtkWidget *panel_widget; - GtkBuilder *builder; - - GtkSourceView *diff; - GtkTreeView *diff_files; - GtkListStore *list_store_diff_files; - - GitgShell *diff_shell; - GitgShell *diff_files_shell; - - GitgRepository *repository; - GitgRevision *revision; - GSList *cached_headers; - - gchar *selection; - - GSettings *diff_settings; -}; - -typedef enum -{ - DIFF_FILE_STATUS_NONE, - DIFF_FILE_STATUS_NEW, - DIFF_FILE_STATUS_MODIFIED, - DIFF_FILE_STATUS_DELETED -} DiffFileStatus; - -typedef struct -{ - GitgDiffIter iter; -} CachedHeader; - -typedef struct -{ - gint refcount; - - gchar index_from[GITG_HASH_SHA_SIZE + 1]; - gchar index_to[GITG_HASH_SHA_SIZE + 1]; - DiffFileStatus status; - gchar *filename; - - gboolean visible; - GitgDiffIter iter; -} DiffFile; - -static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface); -static void gitg_activatable_iface_init (GitgActivatableInterface *iface); - -static void on_header_added (GitgDiffView *view, GitgDiffIter *iter, GitgRevisionChangesPanel *self); -static void on_diff_files_selection_changed (GtkTreeSelection *selection, GitgRevisionChangesPanel *self); - -static GType diff_file_get_type (void) G_GNUC_CONST; - -G_DEFINE_TYPE_EXTENDED (GitgRevisionChangesPanel, - gitg_revision_changes_panel, - G_TYPE_OBJECT, - 0, - G_IMPLEMENT_INTERFACE (GITG_TYPE_REVISION_PANEL, - gitg_revision_panel_iface_init); - G_IMPLEMENT_INTERFACE (GITG_TYPE_ACTIVATABLE, - gitg_activatable_iface_init)); - -static void set_revision (GitgRevisionChangesPanel *panel, - GitgRepository *repository, - GitgRevision *revision); - -static DiffFile * -diff_file_new (gchar const *from, - gchar *to, - gchar const *status, - gchar const *filename) -{ - DiffFile *f = g_slice_new (DiffFile); - - strncpy (f->index_from, from, GITG_HASH_SHA_SIZE); - strncpy (f->index_to, to, GITG_HASH_SHA_SIZE); - - f->index_from[GITG_HASH_SHA_SIZE] = '\0'; - f->index_to[GITG_HASH_SHA_SIZE] = '\0'; - f->visible = FALSE; - - DiffFileStatus st; - - switch (*status) - { - case 'A': - st = DIFF_FILE_STATUS_NEW; - break; - case 'D': - st = DIFF_FILE_STATUS_DELETED; - break; - default: - st = DIFF_FILE_STATUS_MODIFIED; - break; - } - - f->status = st; - f->filename = g_strdup (filename); - f->refcount = 1; - - return f; -} - -static DiffFile * -diff_file_copy (DiffFile *f) -{ - g_atomic_int_inc (&f->refcount); - return f; -} - -static void -diff_file_unref (DiffFile *f) -{ - if (!g_atomic_int_dec_and_test (&f->refcount)) - { - return; - } - - g_free (f->filename); - g_slice_free (DiffFile, f); -} - -G_DEFINE_BOXED_TYPE (DiffFile, diff_file, diff_file_copy, diff_file_unref) - -static void -revision_files_icon (GtkTreeViewColumn *column, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgRevisionChangesPanel *self) -{ - DiffFile *f; - gtk_tree_model_get (model, iter, 0, &f, -1); - - gchar const *id = NULL; - - switch (f->status) - { - case DIFF_FILE_STATUS_NEW: - id = GTK_STOCK_NEW; - break; - case DIFF_FILE_STATUS_MODIFIED: - id = GTK_STOCK_EDIT; - break; - case DIFF_FILE_STATUS_DELETED: - id = GTK_STOCK_DELETE; - break; - default: - break; - } - - g_object_set (G_OBJECT(renderer), "stock-id", id, NULL); - diff_file_unref (f); -} - -static void -revision_files_name (GtkTreeViewColumn *column, - GtkCellRenderer *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgRevisionChangesPanel *self) -{ - DiffFile *f; - gtk_tree_model_get (model, iter, 0, &f, -1); - - g_object_set (G_OBJECT(renderer), "text", f->filename, NULL); - - diff_file_unref (f); -} - -static gboolean -diff_file_visible (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - DiffFile *f; - gtk_tree_model_get (model, iter, 0, &f, -1); - - if (!f) - { - return FALSE; - } - - gboolean ret = f->visible; - diff_file_unref (f); - - return ret; -} - -static gboolean -on_diff_files_button_press (GtkTreeView *treeview, - GdkEventButton *event, - GitgRevisionChangesPanel *view) -{ - if (event->button != 1) - { - return FALSE; - } - - if (event->window != gtk_tree_view_get_bin_window (treeview)) - { - return FALSE; - } - - GtkTreePath *path; - - if (!gtk_tree_view_get_path_at_pos (treeview, - event->x, - event->y, - &path, - NULL, - NULL, - NULL)) - { - return FALSE; - } - - GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); - gboolean ret = FALSE; - - if (gtk_tree_selection_path_is_selected (selection, path) && - gtk_tree_selection_count_selected_rows (selection) == 1) - { - /* deselect */ - gtk_tree_selection_unselect_path (selection, path); - ret = TRUE; - } - - gtk_tree_path_free (path); - return ret; -} - -static void -gitg_revision_panel_update_impl (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - GitgRevisionChangesPanel *changes_panel; - - changes_panel = GITG_REVISION_CHANGES_PANEL (panel); - - set_revision (changes_panel, repository, revision); -} - -static gchar * -gitg_revision_panel_get_label_impl (GitgRevisionPanel *panel) -{ - return g_strdup (_("Changes")); -} - -static gchar * -revision_panel_get_id (void) -{ - return g_strdup ("changes"); -} - -static gchar * -gitg_revision_panel_get_id_impl (GitgRevisionPanel *panel) -{ - return revision_panel_get_id (); -} - -static gchar * -gitg_activatable_get_id_impl (GitgActivatable *activatable) -{ - return revision_panel_get_id (); -} - -static void -initialize_ui (GitgRevisionChangesPanel *changes_panel) -{ - GitgRevisionChangesPanelPrivate *priv = changes_panel->priv; - - priv->diff = GTK_SOURCE_VIEW (gtk_builder_get_object (priv->builder, - "revision_diff")); - - priv->diff_files = GTK_TREE_VIEW (gtk_builder_get_object (priv->builder, - "tree_view_revision_files")); - - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (priv->diff_files); - - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - - g_signal_connect (selection, - "changed", - G_CALLBACK (on_diff_files_selection_changed), - changes_panel); - - g_signal_connect (priv->diff_files, - "button-press-event", - G_CALLBACK (on_diff_files_button_press), - changes_panel); - - priv->list_store_diff_files = gtk_list_store_new (1, diff_file_get_type ()); - - GtkTreeModel *filter; - - filter = gtk_tree_model_filter_new (GTK_TREE_MODEL(priv->list_store_diff_files), - NULL); - gtk_tree_view_set_model (priv->diff_files, filter); - - gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), - diff_file_visible, - NULL, - NULL); - - GtkTreeViewColumn *column; - - column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (priv->builder, - "revision_files_column_icon")); - - gtk_tree_view_column_set_cell_data_func (column, - GTK_CELL_RENDERER (gtk_builder_get_object (priv->builder, - "revision_files_cell_renderer_icon")), - (GtkTreeCellDataFunc)revision_files_icon, - changes_panel, - NULL); - - column = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (priv->builder, - "revision_files_column_name")); - gtk_tree_view_column_set_cell_data_func (column, - GTK_CELL_RENDERER (gtk_builder_get_object (priv->builder, - "revision_files_cell_renderer_name")), - (GtkTreeCellDataFunc)revision_files_name, - changes_panel, - NULL); - - GtkSourceLanguageManager *manager; - GtkSourceLanguage *language; - GtkSourceBuffer *buffer; - - manager = gtk_source_language_manager_get_default (); - language = gtk_source_language_manager_get_language (manager, "gitgdiff"); - buffer = gtk_source_buffer_new_with_language (language); - - g_object_unref (language); - - GtkSourceStyleSchemeManager *scheme_manager; - GtkSourceStyleScheme *scheme; - - scheme_manager = gtk_source_style_scheme_manager_get_default (); - scheme = gtk_source_style_scheme_manager_get_scheme (scheme_manager, - "gitg"); - gtk_source_buffer_set_style_scheme (buffer, scheme); - - gitg_utils_set_monospace_font (GTK_WIDGET (priv->diff)); - gtk_text_view_set_buffer (GTK_TEXT_VIEW (priv->diff), - GTK_TEXT_BUFFER (buffer)); - - g_signal_connect (priv->diff, - "header-added", - G_CALLBACK (on_header_added), - changes_panel); -} - -static GtkWidget * -gitg_revision_panel_get_panel_impl (GitgRevisionPanel *panel) -{ - GtkBuilder *builder; - GtkWidget *ret; - GitgRevisionChangesPanel *changes_panel; - - changes_panel = GITG_REVISION_CHANGES_PANEL (panel); - - if (changes_panel->priv->panel_widget) - { - return changes_panel->priv->panel_widget; - } - - builder = gitg_utils_new_builder ("gitg-revision-changes-panel.ui"); - changes_panel->priv->builder = builder; - - ret = GTK_WIDGET (gtk_builder_get_object (builder, "revision_changes_page")); - changes_panel->priv->panel_widget = ret; - - initialize_ui (changes_panel); - - return ret; -} - -static gboolean -select_diff_file (GitgRevisionChangesPanel *changes_panel, - gchar const *filename) -{ - GtkTreeModel *store; - GtkTreeIter iter; - - store = gtk_tree_view_get_model (changes_panel->priv->diff_files); - - if (!gtk_tree_model_get_iter_first (store, &iter)) - { - return FALSE; - } - - do - { - DiffFile *file; - - gtk_tree_model_get (store, &iter, 0, &file, -1); - - if (g_strcmp0 (file->filename, filename) == 0) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (changes_panel->priv->diff_files); - - gtk_tree_selection_unselect_all (selection); - gtk_tree_selection_select_iter (selection, &iter); - - diff_file_unref (file); - return TRUE; - } - - diff_file_unref (file); - } while (gtk_tree_model_iter_next (store, &iter)); - - return FALSE; -} - -static gboolean -gitg_activatable_activate_impl (GitgActivatable *activatable, - gchar const *action) -{ - GitgRevisionChangesPanel *changes_panel; - - changes_panel = GITG_REVISION_CHANGES_PANEL (activatable); - - if (select_diff_file (changes_panel, action)) - { - return TRUE; - } - - g_free (changes_panel->priv->selection); - changes_panel->priv->selection = g_strdup (action); - - return TRUE; -} - -static void -gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface) -{ - iface->get_id = gitg_revision_panel_get_id_impl; - iface->update = gitg_revision_panel_update_impl; - iface->get_label = gitg_revision_panel_get_label_impl; - iface->get_panel = gitg_revision_panel_get_panel_impl; -} - -static void -gitg_activatable_iface_init (GitgActivatableInterface *iface) -{ - iface->get_id = gitg_activatable_get_id_impl; - iface->activate = gitg_activatable_activate_impl; -} - -static void -free_cached_header (gpointer header) -{ - g_slice_free (CachedHeader, header); -} - -static void -free_cached_headers (GitgRevisionChangesPanel *changes_panel) -{ - g_slist_free_full (changes_panel->priv->cached_headers, free_cached_header); - - changes_panel->priv->cached_headers = NULL; -} - -static void -gitg_revision_changes_panel_finalize (GObject *object) -{ - free_cached_headers (GITG_REVISION_CHANGES_PANEL (object)); - - G_OBJECT_CLASS (gitg_revision_changes_panel_parent_class)->finalize (object); -} - -static void -gitg_revision_changes_panel_dispose (GObject *object) -{ - GitgRevisionChangesPanel *changes_panel; - - changes_panel = GITG_REVISION_CHANGES_PANEL (object); - - set_revision (changes_panel, NULL, NULL); - - if (changes_panel->priv->diff_settings) - { - g_object_unref (changes_panel->priv->diff_settings); - changes_panel->priv->diff_settings = NULL; - } - - if (changes_panel->priv->diff_files_shell) - { - g_object_unref (changes_panel->priv->diff_files_shell); - changes_panel->priv->diff_files_shell = NULL; - } - - if (changes_panel->priv->diff_files_shell) - { - g_object_unref (changes_panel->priv->diff_shell); - changes_panel->priv->diff_shell = NULL; - } - - if (changes_panel->priv->builder) - { - g_object_unref (changes_panel->priv->builder); - changes_panel->priv->builder = NULL; - } - - if (changes_panel->priv->selection) - { - g_free (changes_panel->priv->selection); - changes_panel->priv->selection = NULL; - } - - G_OBJECT_CLASS (gitg_revision_changes_panel_parent_class)->dispose (object); -} - -static void -gitg_revision_changes_panel_class_init (GitgRevisionChangesPanelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_revision_changes_panel_finalize; - object_class->dispose = gitg_revision_changes_panel_dispose; - - g_type_class_add_private (object_class, sizeof(GitgRevisionChangesPanelPrivate)); -} - -static void -reload_diff (GitgRevisionChangesPanel *changes_panel) -{ - GtkTreeSelection *selection; - - // First cancel a possibly still running diff - gitg_io_cancel (GITG_IO (changes_panel->priv->diff_shell)); - gitg_io_cancel (GITG_IO (changes_panel->priv->diff_files_shell)); - - free_cached_headers (changes_panel); - - // Clear the buffer - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (changes_panel->priv->diff)); - gtk_text_buffer_set_text (buffer, "", 0); - - selection = gtk_tree_view_get_selection (changes_panel->priv->diff_files); - g_signal_handlers_block_by_func (selection, - G_CALLBACK (on_diff_files_selection_changed), - changes_panel); - - gtk_list_store_clear (changes_panel->priv->list_store_diff_files); - - g_signal_handlers_unblock_by_func (selection, - G_CALLBACK (on_diff_files_selection_changed), - changes_panel); - - if (!changes_panel->priv->revision) - { - return; - } - - gchar sign = gitg_revision_get_sign (changes_panel->priv->revision); - gboolean allow_external; - - allow_external = g_settings_get_boolean (changes_panel->priv->diff_settings, - "external"); - - switch (sign) - { - case 't': - gitg_shell_run (changes_panel->priv->diff_shell, - gitg_command_new (changes_panel->priv->repository, - "diff", - allow_external ? "--ext-diff" : "--no-ext-diff", - "--cached", - "-M", - "--pretty=format:", - "--encoding=UTF-8", - "--no-color", - NULL), - NULL); - break; - case 'u': - gitg_shell_run (changes_panel->priv->diff_shell, - gitg_command_new (changes_panel->priv->repository, - "diff", - allow_external ? "--ext-diff" : "--no-ext-diff", - "-M", - "--pretty=format:", - "--encoding=UTF-8", - "--no-color", - NULL), - NULL); - break; - default: - { - gchar *hash = gitg_revision_get_sha1 (changes_panel->priv->revision); - - gitg_shell_run (changes_panel->priv->diff_shell, - gitg_command_new (changes_panel->priv->repository, - "show", - "-M", - "--pretty=format:", - "--encoding=UTF-8", - "--no-color", - hash, - NULL), - NULL); - - g_free (hash); - } - break; - } -} - -static void -set_revision (GitgRevisionChangesPanel *changes_panel, - GitgRepository *repository, - GitgRevision *revision) -{ - if (changes_panel->priv->repository == repository && - changes_panel->priv->revision == revision) - { - return; - } - - if (changes_panel->priv->diff_shell) - { - gitg_io_cancel (GITG_IO (changes_panel->priv->diff_shell)); - } - - if (changes_panel->priv->diff_files_shell) - { - gitg_io_cancel (GITG_IO (changes_panel->priv->diff_files_shell)); - } - - if (changes_panel->priv->repository) - { - g_object_unref (changes_panel->priv->repository); - } - - if (changes_panel->priv->revision) - { - gitg_revision_unref (changes_panel->priv->revision); - } - - if (repository) - { - changes_panel->priv->repository = g_object_ref (repository); - } - else - { - changes_panel->priv->repository = NULL; - } - - if (revision) - { - changes_panel->priv->revision = gitg_revision_ref (revision); - } - else - { - changes_panel->priv->revision = NULL; - } - - reload_diff (changes_panel); -} - -static void -on_diff_files_begin_loading (GitgShell *shell, - GitgRevisionChangesPanel *self) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (self->priv->diff_files)), - cursor); - - g_object_unref (cursor); -} - -static void -on_diff_files_end_loading (GitgShell *shell, - gboolean cancelled, - GitgRevisionChangesPanel *self) -{ - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff_files)), - NULL); - - if (self->priv->selection) - { - select_diff_file (self, self->priv->selection); - - g_free (self->priv->selection); - self->priv->selection = NULL; - } -} - -static gboolean -match_indices (DiffFile *f, - gchar const *from, - gchar const *to) -{ - return g_str_has_prefix (f->index_from, from) && - (g_str_has_prefix (f->index_to, to) || - g_str_has_prefix (f->index_to, "0000000")); -} - -static void -visible_from_cached_headers (GitgRevisionChangesPanel *view, - DiffFile *f) -{ - GSList *item; - - for (item = view->priv->cached_headers; item; item = g_slist_next (item)) - { - CachedHeader *header = (CachedHeader *)item->data; - gchar *from; - gchar *to; - - gitg_diff_iter_get_index (&header->iter, &from, &to); - - if (gitg_diff_iter_get_index (&header->iter, &from, &to) && match_indices (f, from, to)) - { - f->visible = TRUE; - f->iter = header->iter; - - return; - } - } -} - -static void -add_diff_file (GitgRevisionChangesPanel *view, - DiffFile *f) -{ - GtkTreeIter iter; - gtk_list_store_append (view->priv->list_store_diff_files, &iter); - - /* see if it is in the cached headers */ - visible_from_cached_headers (view, f); - gtk_list_store_set (view->priv->list_store_diff_files, &iter, 0, f, -1); -} - -static void -on_diff_files_update (GitgShell *shell, - gchar **buffer, - GitgRevisionChangesPanel *self) -{ - gchar **line; - - while (*(line = buffer++)) - { - if (**line == '\0') - { - continue; - } - - // Count parents - gint parents = 0; - gchar *ptr = *line; - - while (*(ptr++) == ':') - { - ++parents; - } - - gint numparts = 3 + 2 * parents; - gchar **parts = g_strsplit (ptr, " ", numparts); - - if (g_strv_length (parts) == numparts) - { - gchar **files = g_strsplit (parts[numparts - 1], "\t", -1); - - DiffFile *f = diff_file_new (parts[parents + 1], parts[numparts - 2], files[0], files[1]); - - add_diff_file (self, f); - diff_file_unref (f); - - g_strfreev (files); - } - - g_strfreev (parts); - } -} - -static void -on_diff_begin_loading (GitgShell *shell, - GitgRevisionChangesPanel *self) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff)), - cursor); - g_object_unref (cursor); -} - -static void -on_diff_end_loading (GitgShell *shell, - gboolean cancelled, - GitgRevisionChangesPanel *self) -{ - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(self->priv->diff)), - NULL); - - if (cancelled) - { - return; - } - - gchar sign = gitg_revision_get_sign (self->priv->revision); - gboolean allow_external; - - allow_external = g_settings_get_boolean (self->priv->diff_settings, - "external"); - - if (sign == 't' || sign == 'u') - { - gchar *head = gitg_repository_parse_head (self->priv->repository); - const gchar *cached = NULL; - - if (sign == 't') - cached = "--cached"; - - gitg_shell_run (self->priv->diff_files_shell, - gitg_command_new (self->priv->repository, - "diff-index", - allow_external ? "--ext-diff" : "--no-ext-diff", - "--raw", - "-M", - "--abbrev=40", - head, - cached, - NULL), - NULL); - g_free (head); - } - else - { - gchar *sha = gitg_revision_get_sha1 (self->priv->revision); - gitg_shell_run (self->priv->diff_files_shell, - gitg_command_new (self->priv->repository, - "show", - "--encoding=UTF-8", - "--raw", - "-M", - "--pretty=format:", - "--abbrev=40", - sha, - NULL), - NULL); - g_free (sha); - } -} - -static void -on_diff_update (GitgShell *shell, - gchar **buffer, - GitgRevisionChangesPanel *self) -{ - gchar *line; - GtkTextBuffer *buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(self->priv->diff)); - GtkTextIter iter; - - gtk_text_buffer_get_end_iter (buf, &iter); - - while ((line = *buffer++)) - { - gtk_text_buffer_insert (buf, &iter, line, -1); - gtk_text_buffer_insert (buf, &iter, "\n", -1); - } -} - -static void -gitg_revision_changes_panel_init (GitgRevisionChangesPanel *self) -{ - self->priv = GITG_REVISION_CHANGES_PANEL_GET_PRIVATE (self); - - self->priv->diff_settings = g_settings_new ("org.gnome.gitg.preferences.diff"); - self->priv->diff_shell = gitg_shell_new (2000); - - g_signal_connect (self->priv->diff_shell, - "begin", - G_CALLBACK (on_diff_begin_loading), - self); - - g_signal_connect (self->priv->diff_shell, - "update", - G_CALLBACK (on_diff_update), - self); - - g_signal_connect (self->priv->diff_shell, - "end", - G_CALLBACK (on_diff_end_loading), - self); - - self->priv->diff_files_shell = gitg_shell_new (2000); - - g_signal_connect (self->priv->diff_files_shell, - "begin", - G_CALLBACK(on_diff_files_begin_loading), - self); - - g_signal_connect (self->priv->diff_files_shell, - "update", - G_CALLBACK(on_diff_files_update), - self); - - g_signal_connect (self->priv->diff_files_shell, - "end", - G_CALLBACK(on_diff_files_end_loading), - self); -} - -static gboolean -find_diff_file (GitgRevisionChangesPanel *view, - GitgDiffIter *iter, - GtkTreeIter *it, - DiffFile **f) -{ - gchar *from; - gchar *to; - - if (!gitg_diff_iter_get_index (iter, &from, &to)) - { - return FALSE; - } - - GtkTreeModel *model = GTK_TREE_MODEL (view->priv->list_store_diff_files); - - if (!gtk_tree_model_get_iter_first (model, it)) - { - return FALSE; - } - - do - { - gtk_tree_model_get (model, it, 0, f, -1); - - if (match_indices (*f, from, to)) - { - return TRUE; - } - - diff_file_unref (*f); - } while (gtk_tree_model_iter_next (model, it)); - - return FALSE; -} - -static void -on_header_added (GitgDiffView *view, - GitgDiffIter *iter, - GitgRevisionChangesPanel *self) -{ - GtkTreeIter it; - DiffFile *f; - - if (find_diff_file (self, iter, &it, &f)) - { - if (!f->visible) - { - f->visible = TRUE; - f->iter = *iter; - - diff_file_unref (f); - - GtkTreeModel *model = GTK_TREE_MODEL (self->priv->list_store_diff_files); - GtkTreePath *path = gtk_tree_model_get_path (model, &it); - - gtk_tree_model_row_changed (model, path, &it); - gtk_tree_path_free (path); - } - } - else - { - /* Insert in cached headers */ - CachedHeader *header = g_slice_new (CachedHeader); - header->iter = *iter; - - self->priv->cached_headers = g_slist_prepend (self->priv->cached_headers, header); - } -} - -typedef struct -{ - gint numselected; - GtkTreeSelection *selection; -} ForeachSelectionData; - -static gboolean -foreach_selection_changed (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - ForeachSelectionData *data) -{ - gboolean visible = data->numselected == 0 || - gtk_tree_selection_path_is_selected (data->selection, - path); - - DiffFile *f = NULL; - gtk_tree_model_get (model, iter, 0, &f, -1); - - if (f->visible) - { - gitg_diff_iter_set_visible (&f->iter, visible); - } - - diff_file_unref (f); - return FALSE; -} - -static void -on_diff_files_selection_changed (GtkTreeSelection *selection, - GitgRevisionChangesPanel *self) -{ - ForeachSelectionData data = { - gtk_tree_selection_count_selected_rows (selection), - selection - }; - - gtk_tree_model_foreach (gtk_tree_view_get_model (self->priv->diff_files), - (GtkTreeModelForeachFunc)foreach_selection_changed, - &data); -} - diff --git a/gitg/gitg-revision-changes-panel.h b/gitg/gitg-revision-changes-panel.h deleted file mode 100644 index 0741d003..00000000 --- a/gitg/gitg-revision-changes-panel.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __GITG_REVISION_CHANGES_PANEL_H__ -#define __GITG_REVISION_CHANGES_PANEL_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_REVISION_CHANGES_PANEL (gitg_revision_changes_panel_get_type ()) -#define GITG_REVISION_CHANGES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanel)) -#define GITG_REVISION_CHANGES_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanel const)) -#define GITG_REVISION_CHANGES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelClass)) -#define GITG_IS_REVISION_CHANGES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_CHANGES_PANEL)) -#define GITG_IS_REVISION_CHANGES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REVISION_CHANGES_PANEL)) -#define GITG_REVISION_CHANGES_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REVISION_CHANGES_PANEL, GitgRevisionChangesPanelClass)) - -typedef struct _GitgRevisionChangesPanel GitgRevisionChangesPanel; -typedef struct _GitgRevisionChangesPanelClass GitgRevisionChangesPanelClass; -typedef struct _GitgRevisionChangesPanelPrivate GitgRevisionChangesPanelPrivate; - -struct _GitgRevisionChangesPanel { - GObject parent; - - GitgRevisionChangesPanelPrivate *priv; -}; - -struct _GitgRevisionChangesPanelClass { - GObjectClass parent_class; -}; - -GType gitg_revision_changes_panel_get_type (void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __GITG_REVISION_CHANGES_PANEL_H__ */ diff --git a/gitg/gitg-revision-changes-panel.ui b/gitg/gitg-revision-changes-panel.ui deleted file mode 100644 index aab03bf1..00000000 --- a/gitg/gitg-revision-changes-panel.ui +++ /dev/null @@ -1,79 +0,0 @@ - - - - True - 3 - vertical - - - True - 200 - - - True - True - automatic - automatic - etched-in - - - True - True - False - True - - - fixed - 20 - Icon - - - - - - - - Filename - - - - - - - - - - False - True - - - - - True - True - automatic - automatic - etched-in - - - False - False - False - 4 - True - True - - - - - True - True - - - - - 2 - - - - diff --git a/gitg/gitg-revision-details-panel.c b/gitg/gitg-revision-details-panel.c deleted file mode 100644 index f45aeac1..00000000 --- a/gitg/gitg-revision-details-panel.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * gitg-revision-details-panel.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-revision-details-panel.h" -#include "gitg-utils.h" -#include "gitg-revision-panel.h" -#include "gitg-stat-view.h" -#include "gitg-uri.h" -#include "gitg-avatar-cache.h" - -#include -#include - -#define GITG_REVISION_DETAILS_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_DETAILS_PANEL, GitgRevisionDetailsPanelPrivate)) - -typedef struct -{ - gchar *file; - guint added; - guint removed; -} StatInfo; - -struct _GitgRevisionDetailsPanelPrivate -{ - GtkLabel *sha; - GtkLabel *author; - GtkLabel *committer; - GtkLabel *subject; - GtkTable *parents; - GtkImage *avatar; - - GtkWidget *panel_widget; - GtkTextView *text_view; - - GtkBuilder *builder; - - GitgRepository *repository; - GitgRevision *revision; - - GitgShell *shell; - gboolean in_stat; - - GSList *stats; - GitgWindow *window; - - GitgAvatarCache *cache; -}; - -static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface); - -static void set_revision (GitgRevisionDetailsPanel *panel, - GitgRepository *repository, - GitgRevision *revision); - -G_DEFINE_TYPE_EXTENDED (GitgRevisionDetailsPanel, - gitg_revision_details_panel, - G_TYPE_OBJECT, - 0, - G_IMPLEMENT_INTERFACE (GITG_TYPE_REVISION_PANEL, - gitg_revision_panel_iface_init)); - -static void -update_markup (GObject *object) -{ - GtkLabel *label = GTK_LABEL(object); - gchar const *text = gtk_label_get_text (label); - - gchar *newtext = g_strconcat ("", - text, - "", - NULL); - - gtk_label_set_markup (label, newtext); - g_free (newtext); -} - -static void -gitg_revision_panel_update_impl (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - GitgRevisionDetailsPanel *details_panel; - - details_panel = GITG_REVISION_DETAILS_PANEL (panel); - - set_revision (details_panel, repository, revision); -} - -static gchar * -gitg_revision_panel_get_id_impl (GitgRevisionPanel *panel) -{ - return g_strdup ("details"); -} - -static gchar * -gitg_revision_panel_get_label_impl (GitgRevisionPanel *panel) -{ - return g_strdup (_("Details")); -} - -static void -initialize_ui (GitgRevisionDetailsPanel *panel) -{ - GitgRevisionDetailsPanelPrivate *priv = panel->priv; - - priv->sha = GTK_LABEL (gtk_builder_get_object (priv->builder, "label_sha")); - priv->author = GTK_LABEL (gtk_builder_get_object (priv->builder, "label_author")); - priv->committer = GTK_LABEL (gtk_builder_get_object (priv->builder, "label_committer")); - 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", - "label_author_lbl", - "label_committer_lbl", - "label_sha_lbl", - "label_parent_lbl" - }; - - gint i; - - for (i = 0; i < sizeof (lbls) / sizeof (gchar *); ++i) - { - update_markup (gtk_builder_get_object (priv->builder, lbls[i])); - } -} - -static GtkWidget * -gitg_revision_panel_get_panel_impl (GitgRevisionPanel *panel) -{ - GtkBuilder *builder; - GtkWidget *ret; - GitgRevisionDetailsPanel *details_panel; - - details_panel = GITG_REVISION_DETAILS_PANEL (panel); - - if (details_panel->priv->panel_widget) - { - return details_panel->priv->panel_widget; - } - - builder = gitg_utils_new_builder ("gitg-revision-details-panel.ui"); - details_panel->priv->builder = builder; - - ret = GTK_WIDGET (gtk_builder_get_object (builder, "revision_details_page")); - details_panel->priv->panel_widget = ret; - - initialize_ui (details_panel); - - return ret; -} - -static void -gitg_revision_panel_initialize_impl (GitgRevisionPanel *panel, - GitgWindow *window) -{ - GITG_REVISION_DETAILS_PANEL (panel)->priv->window = window; -} - -static void -gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface) -{ - iface->initialize = gitg_revision_panel_initialize_impl; - iface->get_id = gitg_revision_panel_get_id_impl; - iface->update = gitg_revision_panel_update_impl; - iface->get_label = gitg_revision_panel_get_label_impl; - iface->get_panel = gitg_revision_panel_get_panel_impl; -} - -static void -gitg_revision_details_panel_finalize (GObject *object) -{ - G_OBJECT_CLASS (gitg_revision_details_panel_parent_class)->finalize (object); -} - -static void -gitg_revision_details_panel_dispose (GObject *object) -{ - GitgRevisionDetailsPanel *panel = GITG_REVISION_DETAILS_PANEL (object); - - set_revision (panel, NULL, NULL); - - if (panel->priv->builder) - { - g_object_unref (panel->priv->builder); - panel->priv->builder = NULL; - } - - if (panel->priv->shell) - { - gitg_io_cancel (GITG_IO (panel->priv->shell)); - g_object_unref (panel->priv->shell); - - 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 -gitg_revision_details_panel_class_init (GitgRevisionDetailsPanelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->finalize = gitg_revision_details_panel_finalize; - object_class->dispose = gitg_revision_details_panel_dispose; - - g_type_class_add_private (object_class, sizeof (GitgRevisionDetailsPanelPrivate)); -} - -static void -on_shell_begin (GitgShell *shell, - GitgRevisionDetailsPanel *panel) -{ - GdkCursor *cursor; - - cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (panel->priv->text_view)), - cursor); - - panel->priv->in_stat = FALSE; - - g_object_unref (cursor); -} - -static gboolean -link_button_activate_link_cb (GtkLinkButton *button, - GitgWindow *window) -{ - const gchar *uri; - GFile *file; - GitgRepository *repository; - gchar *work_tree_path; - gchar *selection; - gchar *activatable; - gchar *action; - - uri = gtk_link_button_get_uri (button); - file = g_file_new_for_uri (uri); - repository = gitg_window_get_repository (window); - - if (g_file_has_uri_scheme (file, "gitg") && - gitg_uri_parse (uri, &work_tree_path, &selection, - &activatable, &action)) - { - GFile *wt; - GFile *work_tree; - gboolean equal; - - wt = gitg_repository_get_work_tree (repository); - work_tree = g_file_new_for_path (work_tree_path); - equal = g_file_equal (wt, work_tree); - - g_object_unref (wt); - g_object_unref (work_tree); - - if (equal) - { - gitg_window_select (window, selection); - gitg_window_activate (window, activatable, action); - } - - g_free (work_tree_path); - g_free (selection); - g_free (activatable); - g_free (action); - g_object_unref (file); - - return TRUE; - } - - g_object_unref (file); - - return FALSE; -} - -static void -make_stats_table (GitgRevisionDetailsPanel *panel) -{ - guint num; - GtkTable *table; - GSList *item; - guint i; - guint max_lines = 0; - GtkTextChildAnchor *anchor; - GtkTextBuffer *buffer; - GtkTextIter iter; - gchar *path; - gchar *repo_uri; - gchar *sha1; - GFile *work_tree; - - if (!panel->priv->stats) - { - return; - } - - num = g_slist_length (panel->priv->stats); - table = GTK_TABLE (gtk_table_new (num, 3, FALSE)); - gtk_table_set_row_spacings (table, 3); - gtk_table_set_col_spacings (table, 6); - - for (item = panel->priv->stats; item; item = g_slist_next (item)) - { - StatInfo *info = item->data; - guint total = info->added + info->removed; - - if (total > max_lines) - { - max_lines = total; - } - } - - item = panel->priv->stats; - work_tree = gitg_repository_get_work_tree (panel->priv->repository); - path = g_file_get_path (work_tree); - sha1 = gitg_revision_get_sha1 (panel->priv->revision); - - g_object_unref (work_tree); - - repo_uri = g_strdup_printf ("gitg://%s:%s", path, sha1); - - g_free (sha1); - g_free (path); - - for (i = 0; i < num; ++i) - { - StatInfo *info = item->data; - GtkWidget *view; - GtkWidget *file; - GtkWidget *total; - GtkWidget *align; - gchar *total_str; - gchar *uri; - - view = gitg_stat_view_new (info->added, - info->removed, - max_lines); - - align = gtk_alignment_new (0, 0.5, 1, 0); - gtk_widget_set_size_request (view, 300, 18); - - gtk_container_add (GTK_CONTAINER (align), view); - - uri = g_strdup_printf ("%s/changes/%s", repo_uri, info->file); - - file = gtk_link_button_new_with_label (uri, - info->file); - - g_free (uri); - - gtk_button_set_alignment (GTK_BUTTON (file), - 0, - 0.5); - g_signal_connect (file, - "activate-link", - G_CALLBACK (link_button_activate_link_cb), - panel->priv->window); - - total_str = g_strdup_printf ("%d", info->added + info->removed); - total = gtk_label_new (total_str); - g_free (total_str); - - g_free (info->file); - g_slice_free (StatInfo, info); - - gtk_table_attach (table, file, - 0, 1, i, i + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, - 0, 0); - - gtk_table_attach (table, align, - 1, 2, i, i + 1, - GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, - 0, 0); - - gtk_table_attach (table, total, - 2, 3, i, i + 1, - GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, - 0, 0); - - gtk_widget_show (view); - gtk_widget_show (file); - gtk_widget_show (total); - gtk_widget_show (align); - - item = g_slist_next (item); - } - - gtk_widget_show (GTK_WIDGET (table)); - - buffer = gtk_text_view_get_buffer (panel->priv->text_view); - - gtk_text_buffer_get_end_iter (buffer, &iter); - gtk_text_buffer_insert (buffer, &iter, "\n\n", 2); - - anchor = gtk_text_buffer_create_child_anchor (buffer, - &iter); - - gtk_text_view_add_child_at_anchor (panel->priv->text_view, - GTK_WIDGET (table), - anchor); -} - -static void -on_shell_end (GitgShell *shell, - gboolean cancelled, - GitgRevisionDetailsPanel *panel) -{ - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (panel->priv->text_view)), - NULL); - - panel->priv->stats = g_slist_reverse (panel->priv->stats); - - make_stats_table (panel); - - g_slist_free (panel->priv->stats); - panel->priv->stats = NULL; -} - -static void -strip_trailing_newlines (GtkTextBuffer *buffer) -{ - GtkTextIter iter; - GtkTextIter end; - - gtk_text_buffer_get_end_iter (buffer, &iter); - - if (!gtk_text_iter_starts_line (&iter)) - { - return; - } - - while (!gtk_text_iter_is_start (&iter) && - gtk_text_iter_ends_line (&iter)) - { - if (!gtk_text_iter_backward_line (&iter)) - { - break; - } - } - - gtk_text_iter_forward_to_line_end (&iter); - - gtk_text_buffer_get_end_iter (buffer, &end); - gtk_text_buffer_delete (buffer, &iter, &end); -} - -static void -add_stat (GitgRevisionDetailsPanel *panel, - gchar const *line) -{ - gchar **parts; - - parts = g_strsplit_set (line, "\t ", -1); - - if (g_strv_length (parts) == 3) - { - StatInfo *stat; - - stat = g_slice_new (StatInfo); - - stat->added = (guint)atoi (parts[0]); - stat->removed = (guint)atoi (parts[1]); - stat->file = g_strdup (parts[2]); - - panel->priv->stats = g_slist_prepend (panel->priv->stats, - stat); - } - - g_strfreev (parts); -} - -static void -on_shell_update (GitgShell *shell, - gchar **lines, - GitgRevisionDetailsPanel *panel) -{ - GtkTextBuffer *buffer; - GtkTextIter end; - - buffer = gtk_text_view_get_buffer (panel->priv->text_view); - gtk_text_buffer_get_end_iter (buffer, &end); - - while (lines && *lines) - { - gchar const *line = *lines; - ++lines; - - if (panel->priv->in_stat) - { - add_stat (panel, line); - } - else - { - if (!gtk_text_iter_is_start (&end)) - { - gtk_text_buffer_insert (buffer, &end, "\n", 1); - } - - if (line[0] == '\x01' && !line[1]) - { - panel->priv->in_stat = TRUE; - strip_trailing_newlines (buffer); - } - else - { - gtk_text_buffer_insert (buffer, &end, line, -1); - } - } - } -} - -static void -gitg_revision_details_panel_init (GitgRevisionDetailsPanel *self) -{ - self->priv = GITG_REVISION_DETAILS_PANEL_GET_PRIVATE(self); - - self->priv->shell = gitg_shell_new (1000); - - g_signal_connect (self->priv->shell, - "begin", - G_CALLBACK (on_shell_begin), - self); - - g_signal_connect (self->priv->shell, - "end", - G_CALLBACK (on_shell_end), - self); - - g_signal_connect (self->priv->shell, - "update", - G_CALLBACK (on_shell_update), - self); - - self->priv->cache = gitg_avatar_cache_new (); -} - -#define HASH_KEY "GitgRevisionDetailsPanelHashKey" - -static gboolean -on_parent_clicked (GtkWidget *ev, - GdkEventButton *event, - gpointer userdata) -{ - GitgRevisionDetailsPanel *panel; - gchar *hash; - - if (event->button != 1) - { - return FALSE; - } - - panel = GITG_REVISION_DETAILS_PANEL (userdata); - hash = (gchar *)g_object_get_data (G_OBJECT (ev), HASH_KEY); - - gitg_window_select (panel->priv->window, hash); - return FALSE; -} - -static GtkWidget * -make_parent_label (GitgRevisionDetailsPanel *self, - gchar const *sha1) -{ - GtkWidget *ev = gtk_event_box_new (); - GtkWidget *lbl = gtk_label_new (NULL); - - gchar *markup = g_strconcat ("", - sha1, - "", - NULL); - - gtk_label_set_markup (GTK_LABEL(lbl), markup); - g_free (markup); - - gtk_widget_set_halign (lbl, GTK_ALIGN_START); - gtk_container_add (GTK_CONTAINER(ev), lbl); - - gtk_widget_show (ev); - gtk_widget_show (lbl); - - g_object_set_data_full (G_OBJECT(ev), - HASH_KEY, - g_strdup (sha1), - (GDestroyNotify)g_free); - - g_signal_connect (ev, - "button-release-event", - G_CALLBACK(on_parent_clicked), - self); - - return ev; -} - -static void -update_parents (GitgRevisionDetailsPanel *self) -{ - GList *children; - GList *item; - - children = gtk_container_get_children (GTK_CONTAINER (self->priv->parents)); - - for (item = children; item; item = g_list_next (item)) - { - gtk_container_remove (GTK_CONTAINER (self->priv->parents), - GTK_WIDGET (item->data)); - } - - g_list_free (children); - - if (!self->priv->revision) - { - return; - } - - gchar **parents = gitg_revision_get_parents (self->priv->revision); - gint num = g_strv_length (parents); - gint i; - - gtk_table_resize (self->priv->parents, num ? num : num + 1, 2); - GdkCursor *cursor = gdk_cursor_new (GDK_HAND1); - GitgHash hash; - - for (i = 0; i < num; ++i) - { - GtkWidget *widget = make_parent_label (self, parents[i]); - gtk_table_attach (self->priv->parents, - widget, - 0, - 1, - i, - i + 1, - GTK_FILL | GTK_SHRINK, - GTK_FILL | GTK_SHRINK, - 0, - 0); - - gtk_widget_realize (widget); - gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); - - /* find subject */ - gitg_hash_sha1_to_hash (parents[i], hash); - - GitgRevision *revision; - - revision = gitg_repository_lookup (self->priv->repository, hash); - - if (revision) - { - GtkWidget *subject = gtk_label_new (NULL); - - gchar *text; - - text = g_markup_printf_escaped (": %s", - gitg_revision_get_subject (revision)); - - gtk_label_set_markup (GTK_LABEL(subject), text); - - g_free (text); - - gtk_widget_show (subject); - - gtk_widget_set_halign (subject, GTK_ALIGN_START); - gtk_label_set_ellipsize (GTK_LABEL(subject), PANGO_ELLIPSIZE_END); - gtk_label_set_single_line_mode (GTK_LABEL(subject), TRUE); - - gtk_table_attach (self->priv->parents, - subject, - 1, - 2, - i, - i + 1, - GTK_FILL | GTK_EXPAND, - GTK_FILL | GTK_SHRINK, - 0, - 0); - } - } - - g_object_unref (cursor); - g_strfreev (parents); -} - -static void -update_details (GitgRevisionDetailsPanel *panel) -{ - gchar *sha1; - - gitg_io_cancel (GITG_IO (panel->priv->shell)); - - gtk_text_buffer_set_text (gtk_text_view_get_buffer (panel->priv->text_view), - "", - 0); - - if (!panel->priv->revision) - { - return; - } - - sha1 = gitg_revision_get_sha1 (panel->priv->revision); - - gitg_shell_run (panel->priv->shell, - gitg_command_new (panel->priv->repository, - "show", - "--numstat", - "--pretty=format:%s%n%n%b%n\x01", - sha1, - NULL), - NULL); - - g_free (sha1); -} - -static void -update_author (GitgRevisionDetailsPanel *panel) -{ - gchar const *author; - gchar const *author_email; - - author = gitg_revision_get_author (panel->priv->revision); - author_email = gitg_revision_get_author_email (panel->priv->revision); - - if (author == NULL || author_email == NULL || - *author == '\0' || *author_email == '\0') - { - gtk_label_set_text (panel->priv->author, ""); - } - else - { - gchar *tmp; - gchar *date; - - date = gitg_revision_get_author_date_for_display (panel->priv->revision); - tmp = g_markup_printf_escaped ("%s <%s> (%s)", - author_email, - author, - author_email, - date); - - gtk_label_set_markup (panel->priv->author, tmp); - - g_free (tmp); - g_free (date); - } -} - -static void -update_committer (GitgRevisionDetailsPanel *panel) -{ - gchar const *committer; - gchar const *committer_email; - - committer = gitg_revision_get_committer (panel->priv->revision); - committer_email = gitg_revision_get_committer_email (panel->priv->revision); - - if (committer == NULL || committer_email == NULL || - *committer == '\0' || *committer_email == '\0') - { - gtk_label_set_text (panel->priv->committer, ""); - } - else - { - gchar *tmp; - gchar *date; - - date = gitg_revision_get_committer_date_for_display (panel->priv->revision); - tmp = g_markup_printf_escaped ("%s <%s> (%s)", - committer_email, - committer, - committer_email, - date); - - gtk_label_set_markup (panel->priv->committer, tmp); - - g_free (tmp); - g_free (date); - } -} - -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); - - gtk_widget_set_visible (GTK_WIDGET (panel->priv->avatar), - error == NULL); - - if (error == NULL) - { - gtk_image_set_from_pixbuf (panel->priv->avatar, pixbuf); - } -} - -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; - - // Update labels - if (panel->priv->revision) - { - gchar *tmp; - - update_author (panel); - update_committer (panel); - - tmp = g_markup_printf_escaped ("%s", - gitg_revision_get_subject (panel->priv->revision)); - - gtk_label_set_markup (panel->priv->subject, tmp); - - g_free (tmp); - - tmp = gitg_revision_get_sha1 (panel->priv->revision); - gtk_label_set_text (panel->priv->sha, tmp); - - cb = gtk_clipboard_get (GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text (cb, tmp, -1); - - g_free (tmp); - - set_avatar (panel, gitg_revision_get_author_email (panel->priv->revision)); - } - else - { - gtk_label_set_text (panel->priv->author, ""); - 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 - update_parents (panel); - update_details (panel); -} - -static void -set_revision (GitgRevisionDetailsPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - if (panel->priv->repository == repository && - panel->priv->revision == revision) - { - return; - } - - if (panel->priv->repository) - { - g_object_unref (panel->priv->repository); - } - - if (panel->priv->revision) - { - gitg_revision_unref (panel->priv->revision); - } - - if (repository) - { - panel->priv->repository = g_object_ref (repository); - } - else - { - panel->priv->repository = NULL; - } - - if (revision) - { - panel->priv->revision = gitg_revision_ref (revision); - } - else - { - panel->priv->revision = NULL; - } - - reload (panel); -} diff --git a/gitg/gitg-revision-details-panel.h b/gitg/gitg-revision-details-panel.h deleted file mode 100644 index 772f6e14..00000000 --- a/gitg/gitg-revision-details-panel.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * gitg-revision-details-panel.h - * This file is part of gitg - git repository details_paneler - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REVISION_DETAILS_PANEL_H__ -#define __GITG_REVISION_DETAILS_PANEL_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_REVISION_DETAILS_PANEL (gitg_revision_details_panel_get_type ()) -#define GITG_REVISION_DETAILS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_DETAILS_PANEL, GitgRevisionDetailsPanel)) -#define GITG_REVISION_DETAILS_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_DETAILS_PANEL, GitgRevisionDetailsPanel const)) -#define GITG_REVISION_DETAILS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REVISION_DETAILS_PANEL, GitgRevisionDetailsPanelClass)) -#define GITG_IS_REVISION_DETAILS_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_DETAILS_PANEL)) -#define GITG_IS_REVISION_DETAILS_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REVISION_DETAILS_PANEL)) -#define GITG_REVISION_DETAILS_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REVISION_DETAILS_PANEL, GitgRevisionDetailsClass)) - -typedef struct _GitgRevisionDetailsPanel GitgRevisionDetailsPanel; -typedef struct _GitgRevisionDetailsPanelClass GitgRevisionDetailsPanelClass; -typedef struct _GitgRevisionDetailsPanelPrivate GitgRevisionDetailsPanelPrivate; - -struct _GitgRevisionDetailsPanel -{ - GObject parent; - - GitgRevisionDetailsPanelPrivate *priv; -}; - -struct _GitgRevisionDetailsPanelClass -{ - GObjectClass parent_class; -}; - -GType gitg_revision_details_panel_get_type (void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __GITG_REVISION_DETAILS_PANEL_H__ */ diff --git a/gitg/gitg-revision-details-panel.ui b/gitg/gitg-revision-details-panel.ui deleted file mode 100644 index 85a988ef..00000000 --- a/gitg/gitg-revision-details-panel.ui +++ /dev/null @@ -1,270 +0,0 @@ - - - - - True - False - vertical - 3 - - - True - False - - - True - False - True - 6 - 6 - - - True - False - 1 - SHA: - True - - - 0 - 0 - 1 - 1 - - - - - True - False - 1 - Author: - - - 0 - 1 - 1 - 1 - - - - - True - False - 1 - Committer: - - - 0 - 2 - 1 - 1 - - - - - True - False - 1 - Subject: - - - 0 - 3 - 1 - 1 - - - - - True - False - 1 - 0 - Parent: - - - 0 - 4 - 1 - 1 - - - - - True - False - True - 2 - 3 - 2 - - - - - - - - - 1 - 4 - 1 - 1 - - - - - True - False - 0 - True - True - end - - - 1 - 3 - 1 - 1 - - - - - True - False - 0 - True - True - - - 1 - 2 - 1 - 1 - - - - - True - False - 0 - True - True - - - 1 - 1 - 1 - 1 - - - - - True - False - 0 - True - True - - - 1 - 0 - 1 - 1 - - - - - - - - - - - - - - 0 - 0 - 1 - 1 - - - - - True - False - vertical - 6 - - - True - False - gtk-missing-image - - - False - True - 0 - - - - - 1 - 0 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - False - True - 0 - - - - - True - True - True - etched-in - - - True - True - False - word-char - False - False - - - - - False - True - 1 - - - - diff --git a/gitg/gitg-revision-files-panel.c b/gitg/gitg-revision-files-panel.c deleted file mode 100644 index 700362f7..00000000 --- a/gitg/gitg-revision-files-panel.c +++ /dev/null @@ -1,1524 +0,0 @@ -/* - * gitg-revision-files-panel.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "gitg-revision-files-panel.h" -#include "gitg-utils.h" -#include "gitg-revision-panel.h" -#include "gitg-dirs.h" -#include "gitg-blame-renderer.h" - -#define GITG_REVISION_FILES_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_FILES_VIEW, GitgRevisionFilesViewPrivate)) - -#define GITG_REVISION_FILES_PANEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanelPrivate)) - -#define BLAME_DATA "GitgRevisionFilesPanelBlame" - -enum -{ - ICON_COLUMN, - NAME_COLUMN, - CONTENT_TYPE_COLUMN, - N_COLUMNS -}; - -typedef struct _GitgRevisionFilesView GitgRevisionFilesView; -typedef struct _GitgRevisionFilesViewClass GitgRevisionFilesViewClass; -typedef struct _GitgRevisionFilesViewPrivate GitgRevisionFilesViewPrivate; - -struct _GitgRevisionFilesViewPrivate -{ - GSettings *settings; - - GtkTreeView *tree_view; - - GtkSourceView *contents; - GitgShell *content_shell; - GtkTreeStore *store; - - GtkToggleButton *blame_checkbutton; - GHashTable *blames; /* hash : tag */ - GitgBlameRenderer *blame_renderer; - gint blame_offset; - GtkTextTag *active_tag; - - glong query_data_id; - glong query_tooltip_id; - - GtkWidget *active_view; - - gchar *drag_dir; - gchar **drag_files; - - GitgRepository *repository; - GitgRevision *revision; - GitgShell *loader; - GtkTreePath *load_path; - - gboolean skipped_blank_line; - gboolean disposed; -}; - -struct _GitgRevisionFilesView -{ - GtkHPaned parent; - - GitgRevisionFilesViewPrivate *priv; -}; - -struct _GitgRevisionFilesViewClass -{ - GtkHPanedClass parent_class; -}; - -struct _GitgRevisionFilesPanelPrivate -{ - GitgRevisionFilesView *panel; -}; - -#define GITG_TYPE_REVISION_FILES_VIEW (gitg_revision_files_view_get_type ()) -#define GITG_REVISION_FILES_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_FILES_VIEW, GitgRevisionFilesView)) - -static void gitg_revision_files_view_buildable_iface_init (GtkBuildableIface *iface); -static void gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface); - -static void load_node (GitgRevisionFilesView *view, GtkTreeIter *parent); -static gchar *node_identity (GitgRevisionFilesView *view, GtkTreeIter *iter); - -G_DEFINE_TYPE_EXTENDED (GitgRevisionFilesPanel, - gitg_revision_files_panel, - G_TYPE_OBJECT, - 0, - G_IMPLEMENT_INTERFACE (GITG_TYPE_REVISION_PANEL, - gitg_revision_panel_iface_init)); - -G_DEFINE_TYPE_EXTENDED (GitgRevisionFilesView, - gitg_revision_files_view, - GTK_TYPE_HPANED, - 0, - G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gitg_revision_files_view_buildable_iface_init)); - -static GtkBuildableIface parent_iface; - -static void -gitg_revision_files_view_finalize (GObject *object) -{ - GitgRevisionFilesView *self = GITG_REVISION_FILES_VIEW (object); - - if (self->priv->load_path) - { - gtk_tree_path_free (self->priv->load_path); - } - - g_free (self->priv->drag_dir); - - if (self->priv->drag_files) - { - g_strfreev (self->priv->drag_files); - } - - gitg_io_cancel (GITG_IO (self->priv->loader)); - g_object_unref (self->priv->loader); - - gitg_io_cancel (GITG_IO (self->priv->content_shell)); - g_object_unref (self->priv->content_shell); - - g_hash_table_unref (self->priv->blames); - - G_OBJECT_CLASS (gitg_revision_files_view_parent_class)->finalize (object); -} - -static void -load_tree (GitgRevisionFilesView *files_view) -{ - load_node (files_view, NULL); -} - -static void -set_revision (GitgRevisionFilesView *files_view, - GitgRepository *repository, - GitgRevision *revision) -{ - if (files_view->priv->repository == repository && - files_view->priv->revision == revision) - { - return; - } - - gitg_io_cancel (GITG_IO (files_view->priv->loader)); - gtk_tree_store_clear (files_view->priv->store); - - if (files_view->priv->repository) - { - g_object_unref (files_view->priv->repository); - } - - if (files_view->priv->revision) - { - gitg_revision_unref (files_view->priv->revision); - } - - if (repository) - { - files_view->priv->repository = g_object_ref (repository); - } - else - { - files_view->priv->repository = NULL; - } - - if (revision) - { - files_view->priv->revision = gitg_revision_ref (revision); - } - else - { - files_view->priv->revision = NULL; - } - - if (files_view->priv->repository && files_view->priv->revision) - { - load_tree (files_view); - } -} - -static GtkTextTag * -get_blame_tag_from_iter (GitgRevisionFilesView *files_view, - GtkTextIter *iter) -{ - GtkTextTag *tag = NULL; - GSList *tags, *l; - - tags = gtk_text_iter_get_tags (iter); - - for (l = tags; l != NULL; l = g_slist_next (l)) - { - if (g_object_get_data (l->data, BLAME_DATA) != NULL) - { - tag = l->data; - break; - } - } - - g_slist_free (tags); - - return tag; -} - -static void -blame_renderer_query_data_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *start, - GtkTextIter *end, - GtkSourceGutterRendererState state, - GitgRevisionFilesView *files_view) -{ - GtkTextTag *tag; - GitgRevision *rev; - GtkTextIter iter; - - iter = *start; - gtk_text_iter_set_line_offset (&iter, 0); - - tag = get_blame_tag_from_iter (files_view, &iter); - - if (tag == NULL) - return; - - rev = g_object_get_data (G_OBJECT (tag), BLAME_DATA); - - if (gtk_text_iter_begins_tag (&iter, tag)) - { - gboolean group_start = FALSE; - - if (!gtk_text_iter_is_start (&iter)) - { - group_start = TRUE; - } - - g_object_set (renderer, - "revision", rev, - "show", TRUE, - "group-start", group_start, - NULL); - } - else - { - g_object_set (renderer, - "revision", rev, - "show", FALSE, - "group-start", FALSE, - NULL); - } -} - -static gboolean -blame_renderer_query_tooltip_cb (GtkSourceGutterRenderer *renderer, - GtkTextIter *iter, - GdkRectangle *area, - gint x, - gint y, - GtkTooltip *tooltip, - GitgRevisionFilesView *tree) -{ - GtkTextTag *tag; - GitgRevision *rev; - const gchar *author; - const gchar *committer; - const gchar *subject; - gchar *text; - gchar *sha1; - gchar *author_date; - gchar *committer_date; - - tag = get_blame_tag_from_iter (tree, iter); - - if (tag == NULL) - return FALSE; - - rev = g_object_get_data (G_OBJECT (tag), BLAME_DATA); - - if (rev == NULL) - return FALSE; - - sha1 = gitg_revision_get_sha1 (rev); - author_date = gitg_revision_get_author_date_for_display (rev); - committer_date = gitg_revision_get_committer_date_for_display (rev); - - author = _("Author"); - committer = _("Committer"); - subject = _("Subject"); - - text = g_markup_printf_escaped ("SHA: %s\n" - "%s: %s <%s> (%s)\n" - "%s: %s <%s> (%s)\n" - "%s: %s", - sha1, - author, gitg_revision_get_author (rev), - gitg_revision_get_author_email (rev), - author_date, - committer, gitg_revision_get_committer (rev), - gitg_revision_get_committer_email (rev), - committer_date, - subject, gitg_revision_get_subject (rev)); - - g_free (sha1); - g_free (author_date); - g_free (committer_date); - gtk_tooltip_set_markup (tooltip, text); - g_free (text); - - return TRUE; -} - -static void -remove_blames (GitgRevisionFilesView *tree) -{ - GtkTextBuffer *buffer; - GList *tags, *tag; - GtkTextTagTable *table; - gboolean blame_mode; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tree->priv->contents)); - table = gtk_text_buffer_get_tag_table (buffer); - - if (tree->priv->query_data_id != 0) - { - g_signal_handler_disconnect (tree->priv->blame_renderer, - tree->priv->query_data_id); - tree->priv->query_data_id = 0; - } - - if (tree->priv->query_tooltip_id != 0) - { - g_signal_handler_disconnect (tree->priv->blame_renderer, - tree->priv->query_tooltip_id); - tree->priv->query_tooltip_id = 0; - } - - tags = g_hash_table_get_values (tree->priv->blames); - - for (tag = tags; tag != NULL; tag = g_list_next (tag)) - { - g_object_set_data (tag->data, BLAME_DATA, NULL); - gtk_text_tag_table_remove (table, tag->data); - } - - g_hash_table_remove_all (tree->priv->blames); - - g_list_free (tags); - - tree->priv->blame_offset = 0; - tree->priv->active_tag = NULL; - - g_object_set (tree->priv->blame_renderer, - "revision", NULL, - "show", FALSE, - "group-start", FALSE, - NULL); - - blame_mode = gtk_toggle_button_get_active (tree->priv->blame_checkbutton); - - if (blame_mode) - { - gitg_blame_renderer_set_max_line_count (tree->priv->blame_renderer, 0); - } -} - -static void -gitg_revision_files_view_dispose (GObject *object) -{ - GitgRevisionFilesView* files_view = GITG_REVISION_FILES_VIEW (object); - - if (!files_view->priv->disposed) - { - set_revision (files_view, NULL, NULL); - remove_blames (files_view); - - files_view->priv->disposed = TRUE; - } - - if (files_view->priv->blame_renderer != NULL) - { - g_object_unref (files_view->priv->blame_renderer); - files_view->priv->blame_renderer = NULL; - } - - if (files_view->priv->settings != NULL) - { - g_object_unref (files_view->priv->settings); - files_view->priv->settings = NULL; - } - - G_OBJECT_CLASS (gitg_revision_files_view_parent_class)->dispose (object); -} - -static gboolean -loaded (GitgRevisionFilesView *view, - GtkTreeIter *iter) -{ - gint num; - - num = gtk_tree_model_iter_n_children (GTK_TREE_MODEL(view->priv->store), - iter); - - if (num != 1) - { - return TRUE; - } - - gchar *content_type = NULL; - GtkTreeIter child; - - if (!gtk_tree_model_iter_children (GTK_TREE_MODEL(view->priv->store), - &child, - iter)) - { - return FALSE; - } - - gtk_tree_model_get (GTK_TREE_MODEL(view->priv->store), - &child, - CONTENT_TYPE_COLUMN, - &content_type, - -1); - - gboolean ret = content_type != NULL; - g_free (content_type); - - return ret; -} - -static void -on_row_expanded (GtkTreeView *files_view, - GtkTreeIter *iter, - GtkTreePath *path, - GitgRevisionFilesView *view) -{ - if (loaded (view, iter)) - { - return; - } - - load_node (view, iter); -} - -static void -show_binary_information (GitgRevisionFilesView *tree, - GtkTextBuffer *buffer) -{ - gtk_text_buffer_set_text (buffer, - _("Cannot display file content as text"), - -1); - - gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), NULL); -} - -static void -on_selection_changed (GtkTreeSelection *selection, - GitgRevisionFilesView *tree) -{ - GtkTextBuffer *buffer; - gboolean blame_mode; - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreePath *path = NULL; - GList *rows; - gchar *name; - gchar *content_type; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tree->priv->contents)); - gitg_io_cancel (GITG_IO (tree->priv->content_shell)); - - blame_mode = gtk_toggle_button_get_active (tree->priv->blame_checkbutton); - - remove_blames (tree); - - gtk_text_buffer_set_text (buffer, "", -1); - - if (!tree->priv->revision) - { - return; - } - - rows = gtk_tree_selection_get_selected_rows (selection, &model); - - if (g_list_length (rows) == 1) - { - path = gtk_tree_path_copy ((GtkTreePath *)rows->data); - } - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); - - if (!path) - { - return; - } - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - gtk_tree_model_get (model, - &iter, - NAME_COLUMN, - &name, - CONTENT_TYPE_COLUMN, - &content_type, - -1); - - if (!content_type) - { - g_free (name); - return; - } - - if (!gitg_utils_can_display_content_type (content_type)) - { - show_binary_information (tree, buffer); - } - else - { - GtkSourceLanguage *language; - gchar *id; - - language = gitg_utils_get_language (name, content_type); - gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), - language); - - id = node_identity (tree, &iter); - - if (!blame_mode) - { - gitg_shell_run (tree->priv->content_shell, - gitg_command_new (tree->priv->repository, - "show", - "--encoding=UTF-8", - id, - NULL), - NULL); - } - else - { - gchar **hash_name; - - gitg_blame_renderer_set_max_line_count (tree->priv->blame_renderer, 0); - - hash_name = g_strsplit (id, ":", 2); - gitg_shell_run (tree->priv->content_shell, - gitg_command_new (tree->priv->repository, - "blame", - "--encoding=UTF-8", - "--root", - "-l", - hash_name[0], - "--", - hash_name[1], - NULL), - NULL); - - g_strfreev (hash_name); - } - - g_free (id); - } - - g_free (name); - g_free (content_type); -} - -static gchar * -node_path (GtkTreeModel *model, - GtkTreeIter *parent) -{ - if (!parent) - { - return NULL; - } - - gchar *name; - gtk_tree_model_get (model, - parent, - NAME_COLUMN, - &name, - -1); - - GtkTreeIter parent_iter; - gchar *ret; - - if (gtk_tree_model_iter_parent (model, &parent_iter, parent)) - { - gchar *path = node_path (model, &parent_iter); - ret = g_build_filename (path, name, NULL); - g_free (path); - g_free (name); - } - else - { - ret = name; - } - - return ret; -} - -static void -export_drag_files (GitgRevisionFilesView *files_view) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (files_view->priv->tree_view); - - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - gint num = g_list_length (rows); - - if (num == 0) - { - g_list_free (rows); - return; - } - - GList *item; - - files_view->priv->drag_files = g_new (gchar *, num + 1); - gchar **ptr = files_view->priv->drag_files; - - for (item = rows; item; item = item->next) - { - GtkTreePath *path = (GtkTreePath *)item->data; - GtkTreeIter iter; - gtk_tree_model_get_iter (model, &iter, path); - - *ptr++ = node_path (model, &iter); - gtk_tree_path_free (path); - } - - *ptr = NULL; - g_list_free (rows); - - // Prepend temporary directory in uri list - g_free (files_view->priv->drag_dir); - gchar const *tmp = g_get_tmp_dir (); - files_view->priv->drag_dir = g_build_filename (tmp, - "gitg-export-XXXXXX", - NULL); - - if (!mkdtemp (files_view->priv->drag_dir)) - { - g_warning ("Could not create temporary directory for export"); - return; - } - - // Do the export - gitg_utils_export_files (files_view->priv->repository, - files_view->priv->revision, - files_view->priv->drag_dir, - files_view->priv->drag_files); - - ptr = files_view->priv->drag_files; - - while (*ptr) - { - gchar *tmp = g_build_filename (files_view->priv->drag_dir, *ptr, NULL); - g_free (*ptr); - - GFile *file = g_file_new_for_path (tmp); - *ptr++ = g_file_get_uri (file); - - g_free (tmp); - } -} - -static void -on_drag_data_get (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection, - guint info, - guint time, - GitgRevisionFilesView *files_view) -{ - if (!files_view->priv->drag_files) - { - export_drag_files (files_view); - } - - gtk_selection_data_set_uris (selection, files_view->priv->drag_files); -} - -static gboolean -test_selection (GtkTreeSelection *selection, - GtkTreeModel *model, - GtkTreePath *path, - gboolean path_currently_selected, - gpointer data) -{ - if (path_currently_selected) - { - return TRUE; - } - - // Test for (Empty) - GtkTreeIter iter; - - if (!gtk_tree_model_get_iter (model, &iter, path)) - { - return FALSE; - } - - gchar *content_type; - gtk_tree_model_get (model, - &iter, - CONTENT_TYPE_COLUMN, - &content_type, - -1); - - if (!content_type) - { - return FALSE; - } - - g_free (content_type); - return TRUE; -} - -static void -on_drag_end (GtkWidget *widget, - GdkDragContext *context, - GitgRevisionFilesView *files_view) -{ - if (files_view->priv->drag_files != NULL) - { - g_strfreev (files_view->priv->drag_files); - files_view->priv->drag_files = NULL; - - g_free (files_view->priv->drag_dir); - files_view->priv->drag_dir = NULL; - } -} - -static void -blame_mode_set_active (GitgRevisionFilesView *tree, - gboolean active) -{ - GtkSourceGutter *gutter; - - gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (tree->priv->contents), - GTK_TEXT_WINDOW_LEFT); - - gtk_source_view_set_show_line_numbers (tree->priv->contents, !active); - - if (active) - { - gtk_source_gutter_insert (gutter, - GTK_SOURCE_GUTTER_RENDERER (tree->priv->blame_renderer), - 0); - } - else - { - gtk_source_gutter_remove (gutter, - GTK_SOURCE_GUTTER_RENDERER (tree->priv->blame_renderer)); - } -} - -static void -gitg_revision_files_view_parser_finished (GtkBuildable *buildable, - GtkBuilder *builder) -{ - GitgRevisionFilesView *files_view = GITG_REVISION_FILES_VIEW (buildable); - GtkTreeSelection *selection; - - if (parent_iface.parser_finished) - { - parent_iface.parser_finished (buildable, builder); - } - - // Store widgets - files_view->priv->tree_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, - "revision_files")); - files_view->priv->contents = GTK_SOURCE_VIEW (gtk_builder_get_object (builder, - "revision_files_contents")); - files_view->priv->blame_checkbutton = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, - "blame_mode_checkbutton")); - files_view->priv->blame_renderer = gitg_blame_renderer_new (); - g_object_ref (files_view->priv->blame_renderer); - - gitg_utils_set_monospace_font (GTK_WIDGET(files_view->priv->contents)); - gtk_tree_view_set_model (files_view->priv->tree_view, - GTK_TREE_MODEL(files_view->priv->store)); - - selection = gtk_tree_view_get_selection (files_view->priv->tree_view); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); - gtk_tree_selection_set_select_function (selection, - test_selection, - NULL, - NULL); - - // Setup drag source - GtkTargetEntry targets[] = { - {"text/uri-list", GTK_TARGET_OTHER_APP, 0} - }; - - // Set tree view as a drag source - gtk_drag_source_set (GTK_WIDGET(files_view->priv->tree_view), - GDK_BUTTON1_MASK, - targets, - 1, - GDK_ACTION_DEFAULT | GDK_ACTION_COPY); - - // Connect signals - g_signal_connect_after (files_view->priv->tree_view, - "row-expanded", - G_CALLBACK(on_row_expanded), - files_view); - - g_signal_connect (files_view->priv->tree_view, - "drag-data-get", - G_CALLBACK(on_drag_data_get), - files_view); - - g_signal_connect (files_view->priv->tree_view, - "drag-end", - G_CALLBACK(on_drag_end), - files_view); - - g_signal_connect (selection, - "changed", - G_CALLBACK(on_selection_changed), - files_view); - - g_settings_bind (files_view->priv->settings, - "blame-mode", - files_view->priv->blame_checkbutton, - "active", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - blame_mode_set_active (files_view, - gtk_toggle_button_get_active (files_view->priv->blame_checkbutton)); -} - -static void -gitg_revision_panel_update_impl (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - GitgRevisionFilesPanel *files_view_panel; - - files_view_panel = GITG_REVISION_FILES_PANEL (panel); - - set_revision (files_view_panel->priv->panel, repository, revision); -} - -static gchar * -gitg_revision_panel_get_id_impl (GitgRevisionPanel *panel) -{ - return g_strdup ("files"); -} - -static gchar * -gitg_revision_panel_get_label_impl (GitgRevisionPanel *panel) -{ - return g_strdup (_("Files")); -} - -static GtkWidget * -gitg_revision_panel_get_panel_impl (GitgRevisionPanel *panel) -{ - GtkBuilder *builder; - GtkWidget *ret; - GitgRevisionFilesPanel *files_view_panel; - - files_view_panel = GITG_REVISION_FILES_PANEL (panel); - - if (files_view_panel->priv->panel) - { - return GTK_WIDGET (files_view_panel->priv->panel); - } - - builder = gitg_utils_new_builder ("gitg-revision-files-panel.ui"); - ret = GTK_WIDGET (gtk_builder_get_object (builder, "revision_files_view")); - files_view_panel->priv->panel = g_object_ref (ret); - - g_object_unref (builder); - - return ret; -} - -static void -gitg_revision_panel_iface_init (GitgRevisionPanelInterface *iface) -{ - iface->get_id = gitg_revision_panel_get_id_impl; - iface->update = gitg_revision_panel_update_impl; - iface->get_label = gitg_revision_panel_get_label_impl; - iface->get_panel = gitg_revision_panel_get_panel_impl; -} - -static void -gitg_revision_files_view_buildable_iface_init (GtkBuildableIface *iface) -{ - parent_iface = *iface; - - iface->parser_finished = gitg_revision_files_view_parser_finished; -} - -static void -gitg_revision_files_view_class_init (GitgRevisionFilesViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->finalize = gitg_revision_files_view_finalize; - object_class->dispose = gitg_revision_files_view_dispose; - - g_type_class_add_private (object_class, sizeof (GitgRevisionFilesViewPrivate)); -} - -static void -gitg_revision_files_panel_dispose (GObject *object) -{ - GitgRevisionFilesPanel *panel; - - panel = GITG_REVISION_FILES_PANEL (object); - - if (panel->priv->panel) - { - g_object_unref (panel->priv->panel); - panel->priv->panel = NULL; - } - - G_OBJECT_CLASS (gitg_revision_files_panel_parent_class)->dispose (object); -} - -static void -gitg_revision_files_panel_class_init (GitgRevisionFilesPanelClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gitg_revision_files_panel_dispose; - - g_type_class_add_private (object_class, sizeof (GitgRevisionFilesPanelPrivate)); -} - -static gchar * -get_content_type (gchar *name, - gboolean dir) -{ - if (dir) - { - return g_strdup ("inode/directory"); - } - else - { - return g_content_type_guess (name, NULL, 0, NULL); - } -} - -static void -remove_dummy (GitgRevisionFilesView *tree) -{ - if (!tree->priv->load_path) - { - return; - } - - GtkTreeIter parent; - GtkTreeModel *model = GTK_TREE_MODEL(tree->priv->store); - gtk_tree_model_get_iter (model, &parent, tree->priv->load_path); - - if (gtk_tree_model_iter_n_children (model, &parent) != 2) - { - return; - } - - GtkTreeIter child; - gtk_tree_model_iter_children (model, &child, &parent); - - do - { - gchar *content_type; - gtk_tree_model_get (model, - &child, - CONTENT_TYPE_COLUMN, - &content_type, - -1); - - if (!content_type) - { - gtk_tree_store_remove (tree->priv->store, &child); - break; - } - g_free (content_type); - } while (gtk_tree_model_iter_next (model, &child)); -} - -static void -append_node (GitgRevisionFilesView *tree, - gchar *line) -{ - GtkTreeIter parent; - GtkTreeIter iter; - - if (tree->priv->load_path) - { - gtk_tree_model_get_iter (GTK_TREE_MODEL(tree->priv->store), - &parent, - tree->priv->load_path); - gtk_tree_store_append (tree->priv->store, &iter, &parent); - } - else - { - gtk_tree_store_append (tree->priv->store, &iter, NULL); - } - - int len = strlen (line); - gboolean isdir = FALSE; - - if (line[len - 1] == '/') - { - isdir = TRUE; - line[len - 1] = '\0'; - } - - GIcon *icon; - - if (isdir) - { - GtkTreeIter empty; - gtk_tree_store_append (tree->priv->store, &empty, &iter); - gtk_tree_store_set (tree->priv->store, - &empty, - NAME_COLUMN, - _ ("(Empty)"), - -1); - - gchar *content_type = get_content_type (line, TRUE); - gtk_tree_store_set (tree->priv->store, - &iter, - CONTENT_TYPE_COLUMN, - content_type, - -1); - icon = g_content_type_get_icon (content_type); - g_free (content_type); - - if (icon && G_IS_THEMED_ICON(icon)) - { - g_themed_icon_append_name (G_THEMED_ICON(icon), "folder"); - } - } - else - { - gchar *content_type = get_content_type (line, FALSE); - icon = g_content_type_get_icon (content_type); - gtk_tree_store_set (tree->priv->store, - &iter, - CONTENT_TYPE_COLUMN, - content_type, - -1); - g_free (content_type); - - if (icon && G_IS_THEMED_ICON(icon)) - { - g_themed_icon_append_name (G_THEMED_ICON(icon), - "text-x-generic"); - } - } - - if (G_IS_THEMED_ICON(icon)) - { - GtkIconTheme *theme = gtk_icon_theme_get_default (); - - gchar **names; - g_object_get (icon, "names", &names, NULL); - - GtkIconInfo *info; - - info = gtk_icon_theme_choose_icon (theme, - (gchar const **)names, - 16, - 0); - - if (info) - { - GError *error = NULL; - GdkPixbuf *pixbuf = gtk_icon_info_load_icon (info, &error); - - if (!pixbuf) - { - g_warning ("Error loading icon: %s", error->message); - g_error_free (error); - } - - gtk_tree_store_set (tree->priv->store, - &iter, - ICON_COLUMN, - pixbuf, - -1); - - if (pixbuf) - { - g_object_unref (pixbuf); - } - - gtk_icon_info_free (info); - } - - g_strfreev (names); - } - - if (icon) - { - g_object_unref (icon); - } - - gtk_tree_store_set (tree->priv->store, - &iter, - NAME_COLUMN, - line, - -1); - remove_dummy (tree); -} - -static void -on_update (GitgShell *shell, - gchar **buffer, - GitgRevisionFilesView *tree) -{ - gchar *line; - - while ((line = *buffer++)) - { - if (!tree->priv->skipped_blank_line) - { - if (*line == '\0') - { - tree->priv->skipped_blank_line = TRUE; - } - - continue; - } - - append_node (tree, line); - } -} - -static gint -compare_func (GtkTreeModel *model, - GtkTreeIter *a, - GtkTreeIter *b, - GitgRevisionFilesView *self) -{ - // First sort directories before files - gboolean da = gtk_tree_model_iter_has_child (model, a) != 0; - gboolean db = gtk_tree_model_iter_has_child (model, b) != 0; - - if (da != db) - { - return da ? -1 : 1; - } - - // Then sort on name - gchar *s1; - gchar *s2; - - gtk_tree_model_get (model, - a, - NAME_COLUMN, - &s1, - -1); - - gtk_tree_model_get (model, - b, - NAME_COLUMN, - &s2, - -1); - - int ret = gitg_utils_sort_names (s1, s2); - - g_free (s1); - g_free (s2); - - return ret; -} - -/** - * parse_blame: - * @line: the line to be parsed - * @real_line: the real connect to be inserted in the text buffer - * @sha: the sha get from @line - * @size: the size for the gutter - */ -static void -parse_blame (const gchar *line, - const gchar **real_line, - gchar **sha, - gint *size) -{ - gunichar c; - const gchar *name_end; - - *sha = g_strndup (line, GITG_HASH_SHA_SIZE); - line += GITG_HASH_SHA_SIZE; - *real_line = strstr (line, ") "); - *real_line += 2; - - line = strstr (line, " ("); - line += 2; - name_end = line; - c = g_utf8_get_char (name_end); - - while (!g_unichar_isdigit (c)) - { - name_end = g_utf8_next_char (name_end); - c = g_utf8_get_char (name_end); - } - name_end--; - - *size = name_end - line + 15; /* hash name + extra space */ -} - -static GtkTextTag * -get_tag_for_sha (GitgRevisionFilesView *tree, - GtkTextBuffer *buffer, - const gchar *sha) -{ - GtkTextTag *tag; - - tag = g_hash_table_lookup (tree->priv->blames, sha); - - if (tag == NULL) - { - GitgHash hash; - GitgRevision *revision; - - tag = gtk_text_buffer_create_tag (buffer, NULL, NULL); - - gitg_hash_sha1_to_hash (sha, hash); - revision = gitg_repository_lookup (tree->priv->repository, - hash); - g_object_set_data (G_OBJECT (tag), BLAME_DATA, revision); - - g_hash_table_insert (tree->priv->blames, g_strdup (sha), - g_object_ref (tag)); - } - - return tag; -} - -static void -apply_active_blame_tag (GitgRevisionFilesView *tree, - GtkTextBuffer *buffer, - GtkTextIter *end) -{ - GtkTextIter start; - - gtk_text_buffer_get_iter_at_offset (buffer, &start, - tree->priv->blame_offset); - gtk_text_buffer_apply_tag (buffer, tree->priv->active_tag, - &start, end); - - tree->priv->blame_offset = gtk_text_iter_get_offset (end); -} - -static void -insert_blame_line (GitgRevisionFilesView *tree, - GtkTextBuffer *buffer, - const gchar *line, - GtkTextIter *iter) -{ - GtkTextTag *tag; - const gchar *real_line; - gint size; - gchar *sha; - - parse_blame (line, &real_line, &sha, &size); - gitg_blame_renderer_set_max_line_count (tree->priv->blame_renderer, size); - - tag = get_tag_for_sha (tree, buffer, sha); - - if (tag != tree->priv->active_tag) - { - if (tree->priv->active_tag != NULL) - { - apply_active_blame_tag (tree, buffer, iter); - } - - tree->priv->active_tag = tag; - } - - g_free (sha); - - gtk_text_buffer_insert (buffer, iter, real_line, -1); - gtk_text_buffer_insert (buffer, iter, "\n", -1); -} - -static void -on_contents_update (GitgShell *shell, - gchar **buffer, - GitgRevisionFilesView *tree) -{ - GtkTextBuffer *buf; - GtkTextIter end; - gchar *line; - gboolean blame_mode; - - buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tree->priv->contents)); - gtk_text_buffer_get_end_iter (buf, &end); - blame_mode = gtk_toggle_button_get_active (tree->priv->blame_checkbutton); - - if (blame_mode) - { - while ((line = *buffer++)) - { - insert_blame_line (tree, buf, line, &end); - } - - if (tree->priv->active_tag != NULL) - { - apply_active_blame_tag (tree, buf, &end); - } - } - else - { - while ((line = *buffer++)) - { - gtk_text_buffer_insert (buf, &end, line, -1); - gtk_text_buffer_insert (buf, &end, "\n", -1); - } - } - - if (gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (buf)) == NULL) - { - gchar *content_type = gitg_utils_guess_content_type (buf); - - if (content_type && !gitg_utils_can_display_content_type (content_type)) - { - gitg_io_cancel (GITG_IO (shell)); - show_binary_information (tree, buf); - } - else - { - GtkSourceLanguage *language; - - language = gitg_utils_get_language (NULL, content_type); - gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buf), - language); - } - - g_free (content_type); - } -} - -static void -on_contents_end (GitgShell *shell, - GError *error, - GitgRevisionFilesView *tree) -{ - gboolean blame_mode; - - blame_mode = gtk_toggle_button_get_active (tree->priv->blame_checkbutton); - - if (blame_mode) - { - GtkSourceGutter *gutter; - - tree->priv->query_data_id = - g_signal_connect (tree->priv->blame_renderer, - "query-data", - G_CALLBACK (blame_renderer_query_data_cb), - tree); - - tree->priv->query_tooltip_id = - g_signal_connect (tree->priv->blame_renderer, - "query-tooltip", - G_CALLBACK (blame_renderer_query_tooltip_cb), - tree); - - gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (tree->priv->contents), - GTK_TEXT_WINDOW_LEFT); - gtk_source_gutter_queue_draw (gutter); - } -} - -static void -on_blame_mode_changed (GSettings *settings, - const gchar *key, - GitgRevisionFilesView *files_view) -{ - GtkTreeSelection *selection; - - blame_mode_set_active (files_view, g_settings_get_boolean (settings, key)); - - selection = gtk_tree_view_get_selection (files_view->priv->tree_view); - on_selection_changed (selection, files_view); -} - -static void -gitg_revision_files_view_init (GitgRevisionFilesView *self) -{ - self->priv = GITG_REVISION_FILES_VIEW_GET_PRIVATE (self); - - self->priv->settings = g_settings_new ("org.gnome.gitg.preferences.view.files"); - - g_signal_connect (self->priv->settings, - "changed::blame-mode", - G_CALLBACK (on_blame_mode_changed), - self); - - self->priv->store = gtk_tree_store_new (N_COLUMNS, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_STRING); - - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (self->priv->store), - 1, - (GtkTreeIterCompareFunc)compare_func, - self, - NULL); - - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->priv->store), - NAME_COLUMN, - GTK_SORT_ASCENDING); - - self->priv->loader = gitg_shell_new (1000); - g_signal_connect (self->priv->loader, - "update", - G_CALLBACK (on_update), - self); - - self->priv->content_shell = gitg_shell_new (5000); - g_signal_connect (self->priv->content_shell, - "update", - G_CALLBACK (on_contents_update), - self); - g_signal_connect (self->priv->content_shell, - "end", - G_CALLBACK (on_contents_end), - self); - - self->priv->blames = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - NULL); -} - -static void -gitg_revision_files_panel_init (GitgRevisionFilesPanel *self) -{ - self->priv = GITG_REVISION_FILES_PANEL_GET_PRIVATE (self); -} - -static gchar * -node_identity (GitgRevisionFilesView *tree, - GtkTreeIter *parent) -{ - gchar *sha = gitg_revision_get_sha1 (tree->priv->revision); - - // Path consists of the SHA1 of the revision and the actual file path - // from parent - gchar *par = node_path (GTK_TREE_MODEL (tree->priv->store), parent); - gchar *path = g_strconcat (sha, ":", par, NULL); - g_free (sha); - g_free (par); - - return path; -} - -static void -load_node (GitgRevisionFilesView *tree, - GtkTreeIter *parent) -{ - if (gitg_io_get_running (GITG_IO (tree->priv->loader))) - { - return; - } - - if (tree->priv->load_path) - { - gtk_tree_path_free (tree->priv->load_path); - } - - gchar *id = node_identity (tree, parent); - - if (parent) - { - tree->priv->load_path = - gtk_tree_model_get_path (GTK_TREE_MODEL (tree->priv->store), - parent); - } - else - { - tree->priv->load_path = NULL; - } - - tree->priv->skipped_blank_line = FALSE; - gitg_shell_run (tree->priv->loader, - gitg_command_new (tree->priv->repository, - "show", - "--encoding=UTF-8", - id, - NULL), - NULL); - g_free (id); -} diff --git a/gitg/gitg-revision-files-panel.h b/gitg/gitg-revision-files-panel.h deleted file mode 100644 index 220aa21f..00000000 --- a/gitg/gitg-revision-files-panel.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * gitg-revision-files-panel.h - * This file is part of gitg - git repository view_paneler - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REVISION_FILES_PANEL__H__ -#define __GITG_REVISION_FILES_PANEL__H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_REVISION_FILES_PANEL (gitg_revision_files_panel_get_type ()) -#define GITG_REVISION_FILES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanel)) -#define GITG_REVISION_FILES_PANEL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanel const)) -#define GITG_REVISION_FILES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesPanelClass)) -#define GITG_IS_REVISION_FILES_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_FILES_PANEL)) -#define GITG_IS_REVISION_FILES_PANEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_REVISION_FILES_PANEL)) -#define GITG_REVISION_FILES_PANEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_REVISION_FILES_PANEL, GitgRevisionFilesViewPanelClass)) - -typedef struct _GitgRevisionFilesPanel GitgRevisionFilesPanel; -typedef struct _GitgRevisionFilesPanelClass GitgRevisionFilesPanelClass; -typedef struct _GitgRevisionFilesPanelPrivate GitgRevisionFilesPanelPrivate; - -struct _GitgRevisionFilesPanel -{ - GObject parent; - - GitgRevisionFilesPanelPrivate *priv; -}; - -struct _GitgRevisionFilesPanelClass -{ - GObjectClass parent_class; -}; - -GType gitg_revision_files_panel_get_type (void) G_GNUC_CONST; -GType gitg_revision_files_view_get_type (void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* __GITG_REVISION_FILES_PANEL__H__ */ diff --git a/gitg/gitg-revision-files-panel.ui b/gitg/gitg-revision-files-panel.ui deleted file mode 100644 index 5f172eb3..00000000 --- a/gitg/gitg-revision-files-panel.ui +++ /dev/null @@ -1,96 +0,0 @@ - - - - - True - True - 200 - - - True - True - automatic - automatic - etched-in - - - True - True - False - - - Filename - - - - 0 - - - - - - 1 - - - - - - - - - False - True - - - - - True - vertical - - - True - horizontal - - - Switch to Blame mode - True - True - False - False - 0 - True - - - False - True - end - 0 - - - - - - - True - True - automatic - automatic - etched-in - - - source_buffer - False - False - True - - - - - - - True - True - - - - diff --git a/gitg/gitg-revision-panel.c b/gitg/gitg-revision-panel.c deleted file mode 100644 index 979969e8..00000000 --- a/gitg/gitg-revision-panel.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * gitg-revision-panel.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-revision-panel.h" - -G_DEFINE_INTERFACE(GitgRevisionPanel, gitg_revision_panel, G_TYPE_OBJECT) - -/* Default implementation */ -static void -gitg_revision_panel_initialize_default (GitgRevisionPanel *panel, - GitgWindow *window) -{ - /* No default implementation */ -} - -static gchar * -gitg_revision_panel_get_id_default (GitgRevisionPanel *panel) -{ - g_return_val_if_reached (NULL); -} - -static gchar * -gitg_revision_panel_get_label_default (GitgRevisionPanel *panel) -{ - g_return_val_if_reached (NULL); -} - -static GtkWidget * -gitg_revision_panel_get_panel_default (GitgRevisionPanel *panel) -{ - g_return_val_if_reached (NULL); -} - -static void -gitg_revision_panel_update_default (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - /* No default implementation */ -} - -static void -gitg_revision_panel_default_init (GitgRevisionPanelInterface *iface) -{ - static gboolean initialized = FALSE; - - iface->initialize = gitg_revision_panel_initialize_default; - iface->get_id = gitg_revision_panel_get_id_default; - iface->get_label = gitg_revision_panel_get_label_default; - iface->get_panel = gitg_revision_panel_get_panel_default; - iface->update = gitg_revision_panel_update_default; - - if (!initialized) - { - initialized = TRUE; - } -} - -gchar * -gitg_revision_panel_get_id (GitgRevisionPanel *panel) -{ - g_return_val_if_fail (GITG_IS_REVISION_PANEL (panel), NULL); - - return GITG_REVISION_PANEL_GET_INTERFACE (panel)->get_id (panel); -} - -gchar * -gitg_revision_panel_get_label (GitgRevisionPanel *panel) -{ - g_return_val_if_fail (GITG_IS_REVISION_PANEL (panel), NULL); - - return GITG_REVISION_PANEL_GET_INTERFACE (panel)->get_label (panel); -} - -GtkWidget * -gitg_revision_panel_get_panel (GitgRevisionPanel *panel) -{ - g_return_val_if_fail (GITG_IS_REVISION_PANEL (panel), NULL); - - return GITG_REVISION_PANEL_GET_INTERFACE (panel)->get_panel (panel); -} - -void -gitg_revision_panel_update (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision) -{ - g_return_if_fail (GITG_IS_REVISION_PANEL (panel)); - - GITG_REVISION_PANEL_GET_INTERFACE (panel)->update (panel, - repository, - revision); -} - -void -gitg_revision_panel_initialize (GitgRevisionPanel *panel, - GitgWindow *window) -{ - g_return_if_fail (GITG_IS_REVISION_PANEL (panel)); - g_return_if_fail (GITG_IS_WINDOW (window)); - - GITG_REVISION_PANEL_GET_INTERFACE (panel)->initialize (panel, - window); -} - diff --git a/gitg/gitg-revision-panel.h b/gitg/gitg-revision-panel.h deleted file mode 100644 index 29cd6042..00000000 --- a/gitg/gitg-revision-panel.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * gitg-revision-panel.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REVISION_PANEL_H__ -#define __GITG_REVISION_PANEL_H__ - -#include -#include -#include "gitg-window.h" - -G_BEGIN_DECLS - -#define GITG_TYPE_REVISION_PANEL (gitg_revision_panel_get_type ()) -#define GITG_REVISION_PANEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_REVISION_PANEL, GitgRevisionPanel)) -#define GITG_IS_REVISION_PANEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_REVISION_PANEL)) -#define GITG_REVISION_PANEL_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GITG_TYPE_REVISION_PANEL, GitgRevisionPanelInterface)) - -typedef struct _GitgRevisionPanel GitgRevisionPanel; -typedef struct _GitgRevisionPanelInterface GitgRevisionPanelInterface; - -struct _GitgRevisionPanelInterface -{ - GTypeInterface parent; - - void (*initialize) (GitgRevisionPanel *panel, - GitgWindow *window); - - void (*update) (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision); - - gchar *(*get_label) (GitgRevisionPanel *panel); - gchar *(*get_id) (GitgRevisionPanel *panel); - GtkWidget *(*get_panel) (GitgRevisionPanel *panel); -}; - -GType gitg_revision_panel_get_type (void) G_GNUC_CONST; - -void gitg_revision_panel_initialize (GitgRevisionPanel *panel, - GitgWindow *window); - -GtkWidget *gitg_revision_panel_get_panel (GitgRevisionPanel *panel); -gchar *gitg_revision_panel_get_id (GitgRevisionPanel *panel); -gchar *gitg_revision_panel_get_label (GitgRevisionPanel *panel); -void gitg_revision_panel_update (GitgRevisionPanel *panel, - GitgRepository *repository, - GitgRevision *revision); - -G_END_DECLS - -#endif /* __GITG_REVISION_PANEL_H__ */ diff --git a/gitg/gitg-stat-view.c b/gitg/gitg-stat-view.c deleted file mode 100644 index d22573d6..00000000 --- a/gitg/gitg-stat-view.c +++ /dev/null @@ -1,500 +0,0 @@ -#include "gitg-stat-view.h" - -#include "gitg-utils.h" -#include -#include - -#define GITG_STAT_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_STAT_VIEW, GitgStatViewPrivate)) - -enum -{ - PROP_0, - PROP_LINES_ADDED, - PROP_LINES_REMOVED, - PROP_MAX_LINES -}; - -struct _GitgStatViewPrivate -{ - gdouble color_added[3]; - gdouble color_removed[3]; - - cairo_pattern_t *gradient_added; - cairo_pattern_t *gradient_removed; - - guint lines_added; - guint lines_removed; - guint max_lines; - - guint radius; - guint stat_padding; - gboolean show_lines; - guint lines_spacing; -}; - -G_DEFINE_TYPE (GitgStatView, gitg_stat_view, GTK_TYPE_DRAWING_AREA) - -static void -clear_gradients (GitgStatView *view) -{ - if (view->priv->gradient_added) - { - cairo_pattern_destroy (view->priv->gradient_added); - view->priv->gradient_added = NULL; - } - - if (view->priv->gradient_removed) - { - cairo_pattern_destroy (view->priv->gradient_removed); - view->priv->gradient_removed = NULL; - } -} - -static void -gitg_stat_view_finalize (GObject *object) -{ - GitgStatView *view = GITG_STAT_VIEW (object); - - clear_gradients (view); - - G_OBJECT_CLASS (gitg_stat_view_parent_class)->finalize (object); -} - -static void -update_colors (GitgStatView *view) -{ - GtkStyleContext *style_context; - GtkStateFlags state; - GdkRGBA bg_color; - gdouble hue, sat, val; - - if (!gtk_widget_get_realized (GTK_WIDGET (view))) - { - return; - } - - style_context = gtk_widget_get_style_context (GTK_WIDGET (view)); - state = gtk_widget_get_state (GTK_WIDGET (view)); - gtk_style_context_get_background_color (style_context, state, &bg_color); - - gtk_rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue, &hue, &sat, &val); - - sat = MIN(sat * 0.5 + 0.5, 1); - val = MIN((pow(val + 1, 3) - 1) / 7 * 0.6 + 0.2, 1); - - gtk_hsv_to_rgb (0, - sat, - val, - &(view->priv->color_removed[0]), - &(view->priv->color_removed[1]), - &(view->priv->color_removed[2])); - - gtk_hsv_to_rgb (0.3, - sat, - val, - &(view->priv->color_added[0]), - &(view->priv->color_added[1]), - &(view->priv->color_added[2])); - - clear_gradients (view); -} - -static void -gitg_stat_view_realize (GtkWidget *widget) -{ - if (GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->realize) - { - GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->realize (widget); - } - - update_colors (GITG_STAT_VIEW (widget)); -} - -static void -update_styles (GitgStatView *view) -{ - gtk_style_context_get_style (gtk_widget_get_style_context (GTK_WIDGET (view)), - gtk_widget_get_state (GTK_WIDGET (view)), - "radius", &view->priv->radius, - "stat-padding", &view->priv->stat_padding, - "show-lines", &view->priv->show_lines, - "lines-spacing", &view->priv->lines_spacing, - NULL); -} - -static void -gitg_stat_view_style_updated (GtkWidget *widget) -{ - if (GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->style_updated) - { - GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->style_updated (widget); - } - - update_colors (GITG_STAT_VIEW (widget)); - update_styles (GITG_STAT_VIEW (widget)); -} - -static void -multiply_color (gdouble *color, gdouble factor, gdouble *ret) -{ - guint i; - - for (i = 0; i < 3; ++i) - { - ret[i] = color[i] * factor; - } -} - -static cairo_pattern_t * -create_gradient (gdouble *base_color, - gint y, - gint height) -{ - cairo_pattern_t *gradient; - gdouble ret[3]; - - gradient = cairo_pattern_create_linear (0, y, 0, height); - - cairo_pattern_add_color_stop_rgb (gradient, - 0, - base_color[0], - base_color[1], - base_color[2]); - - multiply_color (base_color, 1.3, ret); - - cairo_pattern_add_color_stop_rgb (gradient, - 1, - ret[0], - ret[1], - ret[2]); - - return gradient; -} - -static void -update_gradients (GitgStatView *view, - GdkRectangle *alloc) -{ - if (view->priv->gradient_added == NULL) - { - view->priv->gradient_added = create_gradient (view->priv->color_added, - 0, - alloc->height); - } - - if (view->priv->gradient_removed == NULL) - { - view->priv->gradient_removed = create_gradient (view->priv->color_removed, - 0, - alloc->height); - } -} - -static void -draw_stat (GitgStatView *view, - cairo_t *ctx, - gdouble *color, - cairo_pattern_t *gradient, - gint x, - gint y, - gint width, - gint height) -{ - gdouble darker[3]; - gdouble xoff; - cairo_matrix_t mat; - - x += 0.5; - y += 0.5; - width -= 1; - height -= 1; - - gitg_utils_rounded_rectangle (ctx, - x, - y, - width, - height, - view->priv->radius); - - cairo_set_source (ctx, gradient); - cairo_fill_preserve (ctx); - - multiply_color (color, 0.4, darker); - - cairo_set_line_width (ctx, 1); - - cairo_set_source_rgb (ctx, darker[0], darker[1], darker[2]); - cairo_stroke (ctx); - - if (view->priv->show_lines) - { - xoff = x + view->priv->lines_spacing; - - cairo_matrix_init_rotate (&mat, M_PI); - cairo_pattern_set_matrix (gradient, &mat); - - cairo_set_source (ctx, gradient); - - while (xoff < x + width - view->priv->lines_spacing / 2) - { - cairo_move_to (ctx, xoff, y + 2); - cairo_line_to (ctx, xoff, y + height - 2); - cairo_stroke (ctx); - - xoff += view->priv->lines_spacing; - } - - cairo_matrix_init_identity (&mat); - cairo_pattern_set_matrix (gradient, &mat); - } -} - -static gboolean -gitg_stat_view_draw (GtkWidget *widget, - cairo_t *ctx) -{ - GdkRectangle alloc; - guint added_width; - guint removed_width; - gdouble unit; - GitgStatView *view; - guint padding; - - if (GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->draw) - { - GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->draw (widget, ctx); - } - - view = GITG_STAT_VIEW (widget); - - if (view->priv->max_lines == 0 || - (view->priv->lines_added == 0 && view->priv->lines_removed == 0)) - { - return TRUE; - } - - if (view->priv->lines_added == 0 || view->priv->lines_removed == 0) - { - padding = 0; - } - else - { - padding = 2; - } - - gtk_widget_get_allocation (widget, &alloc); - - update_gradients (view, &alloc); - - unit = (alloc.width - padding) / (gdouble)view->priv->max_lines; - - added_width = MAX(view->priv->radius * 2 + 1, (guint)(unit * view->priv->lines_added)); - removed_width = MAX(view->priv->radius * 2 + 1, (guint)(unit * view->priv->lines_removed)); - - if (view->priv->lines_added > 0) - { - draw_stat (view, - ctx, - view->priv->color_added, - view->priv->gradient_added, - 0, - 0, - added_width, - alloc.height); - } - else - { - added_width = 0; - } - - if (view->priv->lines_removed > 0) - { - draw_stat (view, - ctx, - view->priv->color_removed, - view->priv->gradient_removed, - added_width + padding, - 0, - removed_width, - alloc.height); - } - - return TRUE; -} - -static void -gitg_stat_view_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgStatView *self = GITG_STAT_VIEW (object); - - switch (prop_id) - { - case PROP_LINES_ADDED: - self->priv->lines_added = g_value_get_uint (value); - gtk_widget_queue_draw (GTK_WIDGET (self)); - break; - case PROP_LINES_REMOVED: - self->priv->lines_removed = g_value_get_uint (value); - gtk_widget_queue_draw (GTK_WIDGET (self)); - break; - case PROP_MAX_LINES: - self->priv->max_lines = g_value_get_uint (value); - gtk_widget_queue_draw (GTK_WIDGET (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_stat_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgStatView *self = GITG_STAT_VIEW (object); - - switch (prop_id) - { - case PROP_LINES_ADDED: - g_value_set_uint (value, self->priv->lines_added); - break; - case PROP_LINES_REMOVED: - g_value_set_uint (value, self->priv->lines_removed); - break; - case PROP_MAX_LINES: - g_value_set_uint (value, self->priv->max_lines); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gboolean -gitg_stat_view_configure (GtkWidget *widget, - GdkEventConfigure *event) -{ - gboolean ret; - - if (GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->configure_event) - { - ret = GTK_WIDGET_CLASS (gitg_stat_view_parent_class)->configure_event (widget, event); - } - else - { - ret = FALSE; - } - - clear_gradients (GITG_STAT_VIEW (widget)); - - return ret; -} - -static void -gitg_stat_view_class_init (GitgStatViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->draw = gitg_stat_view_draw; - widget_class->style_updated = gitg_stat_view_style_updated; - widget_class->realize = gitg_stat_view_realize; - widget_class->configure_event = gitg_stat_view_configure; - - object_class->finalize = gitg_stat_view_finalize; - object_class->set_property = gitg_stat_view_set_property; - object_class->get_property = gitg_stat_view_get_property; - - g_object_class_install_property (object_class, - PROP_LINES_ADDED, - g_param_spec_uint ("lines-added", - "Lines Added", - "Lines added", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_LINES_REMOVED, - g_param_spec_uint ("lines-removed", - "Lines Removed", - "Lines removed", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_MAX_LINES, - g_param_spec_uint ("max-lines", - "Max Lines", - "Max lines", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_uint ("radius", - "Radius", - "Radius", - 0, - G_MAXUINT, - 4, - G_PARAM_READWRITE)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_uint ("stat-padding", - "Stat padding", - "Stat padding", - 0, - G_MAXUINT, - 2, - G_PARAM_READWRITE)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_boolean ("show-lines", - "Show lines", - "Show lines", - TRUE, - G_PARAM_READWRITE)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_uint ("lines-spacing", - "Lines spacing", - "Lines spacing", - 1, - G_MAXUINT, - 10, - G_PARAM_READWRITE)); - - g_type_class_add_private (object_class, sizeof(GitgStatViewPrivate)); -} - -static void -gitg_stat_view_init (GitgStatView *self) -{ - self->priv = GITG_STAT_VIEW_GET_PRIVATE (self); -} - -GtkWidget * -gitg_stat_view_new (guint lines_added, - guint lines_removed, - guint max_lines) -{ - return g_object_new (GITG_TYPE_STAT_VIEW, - "lines-added", - lines_added, - "lines-removed", - lines_removed, - "max-lines", - max_lines, - NULL); -} diff --git a/gitg/gitg-stat-view.h b/gitg/gitg-stat-view.h deleted file mode 100644 index e78a636b..00000000 --- a/gitg/gitg-stat-view.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __GITG_STAT_VIEW_H__ -#define __GITG_STAT_VIEW_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_STAT_VIEW (gitg_stat_view_get_type ()) -#define GITG_STAT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_STAT_VIEW, GitgStatView)) -#define GITG_STAT_VIEW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_STAT_VIEW, GitgStatView const)) -#define GITG_STAT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_STAT_VIEW, GitgStatViewClass)) -#define GITG_IS_STAT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_STAT_VIEW)) -#define GITG_IS_STAT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_STAT_VIEW)) -#define GITG_STAT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_STAT_VIEW, GitgStatViewClass)) - -typedef struct _GitgStatView GitgStatView; -typedef struct _GitgStatViewClass GitgStatViewClass; -typedef struct _GitgStatViewPrivate GitgStatViewPrivate; - -struct _GitgStatView { - GtkDrawingArea parent; - - GitgStatViewPrivate *priv; -}; - -struct _GitgStatViewClass { - GtkDrawingAreaClass parent_class; -}; - -GType gitg_stat_view_get_type (void) G_GNUC_CONST; -GtkWidget *gitg_stat_view_new (guint lines_added, - guint lines_removed, - guint max_lines); - -G_END_DECLS - -#endif /* __GITG_STAT_VIEW_H__ */ diff --git a/gitg/gitg-tag.ui b/gitg/gitg-tag.ui deleted file mode 100644 index 03758d70..00000000 --- a/gitg/gitg-tag.ui +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - 5 - Properties - center-always - 400 - 200 - True - normal - - - True - 2 - vertical - - - True - 3 - 2 - 6 - 6 - - - True - 0 - Name: - - - GTK_SHRINK | GTK_FILL - GTK_SHRINK - - - - - True - 0 - 0 - Message: - - - 1 - 2 - GTK_SHRINK | GTK_FILL - GTK_SHRINK | GTK_FILL - - - - - True - True - - - - 1 - 2 - GTK_FILL - - - - - True - True - automatic - automatic - etched-in - - - True - True - - - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - Create signed tag object - True - True - False - True - - - 2 - 2 - 3 - - - - - - 1 - - - - - True - end - - - gtk-cancel - True - True - True - True - - - False - False - 0 - - - - - Create tag - True - True - True - True - True - True - True - image_tag - - - False - False - 1 - - - - - False - end - 0 - - - - - - button_cancel - button_tag - - - - True - gtk-apply - - diff --git a/gitg/gitg-ui.xml b/gitg/gitg-ui.xml deleted file mode 100644 index b65e59cb..00000000 --- a/gitg/gitg-ui.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - _File - - - - - _Edit - - - - - _View - - - - - _Help - - - - - - - - - gtk-open - _Open... - - - - - - R_ecently Opened - - - - - - gtk-quit - - - - - - - - - - gtk-cut - - - - - - gtk-copy - - - - - - gtk-paste - - - - - - gtk-preferences - - - - - - - - - - gtk-properties - _Repository Properties - - - - - - - gtk-refresh - - - - - - - - - - - gtk-about - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/gitg/gitg-uri.c b/gitg/gitg-uri.c deleted file mode 100644 index 74717c35..00000000 --- a/gitg/gitg-uri.c +++ /dev/null @@ -1,103 +0,0 @@ -#include "gitg-uri.h" - -#include - -gboolean -gitg_uri_parse (gchar const *uri, - gchar **work_tree, - gchar **selection, - gchar **activatable, - gchar **action) -{ - gchar *selection_sep; - gchar *activatable_sep; - gchar *action_sep; - gchar *dupped; - - if (uri == NULL) - { - return FALSE; - } - - if (!g_str_has_prefix (uri, "gitg://")) - { - return FALSE; - } - - if (work_tree) - { - *work_tree = NULL; - } - - if (selection) - { - *selection = NULL; - } - - if (activatable) - { - *activatable = NULL; - } - - if (action) - { - *action = NULL; - } - - dupped = g_strdup (uri + 7); - selection_sep = strchr (dupped, ':'); - - if (selection_sep) - { - *selection_sep = '\0'; - } - - if (work_tree) - { - *work_tree = g_strdup (dupped); - } - - if (!selection_sep) - { - g_free (dupped); - return TRUE; - } - - activatable_sep = strchr (selection_sep + 1, '/'); - - if (activatable_sep) - { - *activatable_sep = '\0'; - } - - if (selection) - { - *selection = g_strdup (selection_sep + 1); - } - - if (!activatable_sep) - { - g_free (dupped); - return TRUE; - } - - action_sep = strchr (activatable_sep + 1, '/'); - - if (action_sep) - { - *action_sep = '\0'; - } - - if (activatable) - { - *activatable = g_strdup (activatable_sep + 1); - } - - if (action_sep && action) - { - *action = g_strdup (action_sep + 1); - } - - g_free (dupped); - return TRUE; -} diff --git a/gitg/gitg-uri.h b/gitg/gitg-uri.h deleted file mode 100644 index 90001c3c..00000000 --- a/gitg/gitg-uri.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __GITG_URI_H__ -#define __GITG_URI_H__ - -#include - -G_BEGIN_DECLS - -gboolean gitg_uri_parse (gchar const *uri, - gchar **work_tree, - gchar **selection, - gchar **activatable, - gchar **action); - -G_END_DECLS - -#endif /* __GITG_URI_H__ */ - diff --git a/gitg/gitg-utils.c b/gitg/gitg-utils.c deleted file mode 100644 index ad748b05..00000000 --- a/gitg/gitg-utils.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * gitg-utils.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-dirs.h" -#include "gitg-utils.h" - -#include -#include -#include - -gchar * -gitg_utils_get_content_type(GFile *file) -{ - GFileInfo *info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); - - if (!info || !g_file_info_has_attribute(info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)) - return NULL; - - gchar *content_type = g_strdup(g_file_info_get_content_type(info)); - g_object_unref(info); - - return content_type; -} - -gboolean -gitg_utils_can_display_content_type (gchar const *content_type) -{ - return g_content_type_is_a (content_type, "text/plain") || - g_content_type_equals (content_type, "application/octet-stream"); -} - -gchar * -gitg_utils_guess_content_type(GtkTextBuffer *buffer) -{ - GtkTextIter start; - GtkTextIter end; - - gtk_text_buffer_get_start_iter(buffer, &start); - end = start; - - gtk_text_iter_forward_chars(&end, 256); - gchar *data = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); - - gchar *content_type = g_content_type_guess(NULL, (guchar *)data, strlen(data), NULL); - g_free(data); - - return content_type; -} - -static void -append_escape (GString *gstr, gchar const *item) -{ - gchar *escape = g_shell_quote (item); - - g_string_append_printf (gstr, " %s", escape); - g_free (escape); -} - -gboolean -gitg_utils_export_files (GitgRepository *repository, - GitgRevision *revision, - gchar const *todir, - gchar * const *paths) -{ - GString *gstr = g_string_new("sh -c \"git --git-dir"); - - GFile *git_dir = gitg_repository_get_git_dir (repository); - gchar *git_path = g_file_get_path (git_dir); - - append_escape (gstr, git_path); - - g_free (git_path); - g_object_unref (git_dir); - - // Append the revision - gchar *sha = gitg_revision_get_sha1 (revision); - g_string_append_printf (gstr, " archive --format=tar %s", sha); - g_free(sha); - - // Append the files - while (*paths) - { - append_escape (gstr, *paths); - paths++; - } - - g_string_append (gstr, " | tar -xC"); - append_escape (gstr, todir); - g_string_append (gstr, "\""); - - GError *error = NULL; - gint status; - - gboolean ret = g_spawn_command_line_sync (gstr->str, NULL, NULL, &status, &error); - - if (!ret) - { - g_warning ("Export failed:\n%s\n%s", gstr->str, error->message); - g_error_free (error); - } - - g_string_free (gstr, TRUE); - return ret; -} - -GtkSourceLanguage * -gitg_utils_get_language(gchar const *filename, gchar const *content_type) -{ - if (!gitg_utils_can_display_content_type(content_type)) - return NULL; - - GtkSourceLanguageManager *manager = gtk_source_language_manager_get_default(); - return gtk_source_language_manager_guess_language(manager, filename, content_type); -} - -gchar * -gitg_utils_get_monospace_font_name(void) -{ - GSettings *interface; - gchar *name; - - interface = g_settings_new ("org.gnome.desktop.interface"); - name = g_settings_get_string (interface, "monospace-font-name"); - - g_object_unref (interface); - - return name; -} - -void -gitg_utils_set_monospace_font(GtkWidget *widget) -{ - gchar *name = gitg_utils_get_monospace_font_name(); - - if (name) - { - PangoFontDescription *description = pango_font_description_from_string(name); - - if (description) - { - gtk_widget_override_font(widget, description); - pango_font_description_free(description); - } - } - - g_free(name); -} - -GtkBuilder * -gitg_utils_new_builder (gchar const *filename) -{ - GtkBuilder *b = gtk_builder_new (); - GError *error = NULL; - - gchar *path = gitg_dirs_get_data_filename ("ui", filename, NULL); - - if (!gtk_builder_add_from_file (b, path, &error)) - { - g_critical ("Could not open UI file: %s (%s)", path, error->message); - g_error_free (error); - - g_free (path); - exit (1); - } - - g_free (path); - return b; -} - -gint -gitg_utils_sort_names(gchar const *s1, gchar const *s2) -{ - if (s1 == NULL) - return -1; - - if (s2 == NULL) - return 1; - - gchar *c1 = s1 ? g_utf8_casefold(s1, -1) : NULL; - gchar *c2 = s2 ? g_utf8_casefold(s2, -1) : NULL; - - gint ret = g_utf8_collate(c1, c2); - - g_free(c1); - g_free(c2); - - return ret; -} - -/* Copied from gedit-utils.c */ -void -gitg_utils_menu_position_under_widget (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GtkWidget *w = GTK_WIDGET (user_data); - GtkRequisition requisition; - - gdk_window_get_origin (gtk_widget_get_window (w), x, y); - gtk_widget_get_preferred_size (GTK_WIDGET (menu), &requisition, NULL); - - GtkAllocation alloc; - gtk_widget_get_allocation (w, &alloc); - - if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL) - { - *x += alloc.x + alloc.width - requisition.width; - } - else - { - *x += alloc.x; - } - - *y += alloc.y + alloc.height; - *push_in = TRUE; -} - -void -gitg_utils_menu_position_under_tree_view (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GtkTreeView *tree = GTK_TREE_VIEW (user_data); - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - model = gtk_tree_view_get_model (tree); - g_return_if_fail (model != NULL); - - selection = gtk_tree_view_get_selection (tree); - g_return_if_fail (selection != NULL); - - if (gtk_tree_selection_get_selected (selection, NULL, &iter)) - { - GtkTreePath *path; - GdkRectangle rect; - - gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (tree)), x, y); - - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_view_get_cell_area (tree, path, - gtk_tree_view_get_column (tree, 0), /* FIXME 0 for RTL ? */ - &rect); - gtk_tree_path_free (path); - - *x += rect.x; - *y += rect.y + rect.height; - - if (gtk_widget_get_direction (GTK_WIDGET (tree)) == GTK_TEXT_DIR_RTL) - { - GtkRequisition requisition; - gtk_widget_get_preferred_size (GTK_WIDGET (menu), &requisition, NULL); - *x += rect.width - requisition.width; - } - } - else - { - /* no selection -> regular "under widget" positioning */ - gitg_utils_menu_position_under_widget (menu, - x, y, push_in, - tree); - } -} - -gchar * -gitg_utils_rewrite_hunk_counters (gchar const *header, - guint old_count, - guint new_count) -{ - if (!header) - { - return NULL; - } - - gchar *copy = g_strdup (header); - gchar *ptr1 = g_utf8_strchr (copy, -1, ','); - - if (!ptr1) - { - g_free (copy); - return NULL; - } - - gchar *ptrs1 = g_utf8_strchr (ptr1 + 1, -1, ' '); - - if (!ptrs1) - { - g_free (copy); - return NULL; - } - - gchar *ptr2 = g_utf8_strchr (ptrs1 + 1, -1, ','); - - if (!ptr2) - { - g_free (copy); - return NULL; - } - - gchar *ptrs2 = g_utf8_strchr (ptr2 + 1, -1, ' '); - - if (!ptrs2) - { - g_free (copy); - return NULL; - } - - *ptr1 = *ptr2 = '\0'; - - gchar *ret; - - ret = g_strdup_printf ("%s,%d%s,%d%s", - copy, - old_count, - ptrs1, - new_count, - ptrs2); - - g_free (copy); - return ret; -} - -GtkCellRenderer * -gitg_utils_find_cell_at_pos (GtkTreeView *tree_view, GtkTreeViewColumn *column, GtkTreePath *path, gint x) -{ - GList *cells; - GList *item; - GtkTreeIter iter; - GtkTreeModel *model = gtk_tree_view_get_model (tree_view); - - gtk_tree_model_get_iter (model, &iter, path); - - gtk_tree_view_column_cell_set_cell_data (column, model, &iter, FALSE, FALSE); - - cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)); - GtkCellRenderer *ret = NULL; - - for (item = cells; item; item = g_list_next (item)) - { - GtkCellRenderer *renderer = GTK_CELL_RENDERER (item->data); - gint start; - gint width; - - if (!gtk_tree_view_column_cell_get_position (column, renderer, &start, &width)) - { - continue; - } - - gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (tree_view), &width, NULL); - - if (x >= start && x <= start + width) - { - ret = renderer; - break; - } - } - - g_list_free (cells); - return ret; -} - -typedef struct -{ - gint position; - gboolean reversed; -} PanedRestoreInfo; - -static void -free_paned_restore_info (PanedRestoreInfo *info) -{ - g_slice_free (PanedRestoreInfo, info); -} - -static void -paned_set_position (GtkPaned *paned, gint position, gboolean reversed) -{ - if (position == -1) - { - return; - } - - if (!reversed) - { - gtk_paned_set_position (paned, position); - } - else - { - GtkAllocation alloc; - gtk_widget_get_allocation (GTK_WIDGET (paned), &alloc); - - gtk_paned_set_position (paned, alloc.width - position); - } -} - -static void -on_paned_mapped (GtkPaned *paned, PanedRestoreInfo *info) -{ - paned_set_position (paned, info->position, info->reversed); - - g_signal_handlers_disconnect_by_func (paned, on_paned_mapped, info); -} - -void -gitg_utils_restore_pane_position (GtkPaned *paned, gint position, gboolean reversed) -{ - g_return_if_fail (GTK_IS_PANED (paned)); - - if (gtk_widget_get_mapped (GTK_WIDGET (paned))) - { - paned_set_position (paned, position, reversed); - - return; - } - - PanedRestoreInfo *info = g_slice_new (PanedRestoreInfo); - info->position = position; - info->reversed = reversed; - - g_signal_connect_data (paned, - "map", - G_CALLBACK (on_paned_mapped), - info, - (GClosureNotify)free_paned_restore_info, - G_CONNECT_AFTER); -} - -void -gitg_utils_rounded_rectangle(cairo_t *ctx, gdouble x, gdouble y, gdouble width, gdouble height, gdouble radius) -{ - cairo_move_to (ctx, x + radius, y); - cairo_rel_line_to (ctx, width - 2 * radius, 0); - cairo_arc (ctx, x + width - radius, y + radius, radius, 1.5 * M_PI, 0.0); - - cairo_rel_line_to (ctx, 0, height - 2 * radius); - cairo_arc (ctx, x + width - radius, y + height - radius, radius, 0.0, 0.5 * M_PI); - - cairo_rel_line_to (ctx, -(width - radius * 2), 0); - cairo_arc (ctx, x + radius, y + height - radius, radius, 0.5 * M_PI, M_PI); - - cairo_rel_line_to (ctx, 0, -(height - radius * 2)); - cairo_arc (ctx, x + radius, y + radius, radius, M_PI, 1.5 * M_PI); -} diff --git a/gitg/gitg-utils.h b/gitg/gitg-utils.h deleted file mode 100644 index f202fb7b..00000000 --- a/gitg/gitg-utils.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * gitg-utils.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_UTILS_H__ -#define __GITG_UTILS_H__ - -#include -#include -#include -#include - -#include -#include - -gchar *gitg_utils_get_content_type(GFile *file); -gboolean gitg_utils_can_display_content_type(gchar const *content_type); -gchar *gitg_utils_guess_content_type(GtkTextBuffer *buffer); - -gboolean gitg_utils_export_files(GitgRepository *repository, GitgRevision *revision, -gchar const *todir, gchar * const *paths); - -GtkSourceLanguage *gitg_utils_get_language(gchar const *filename, gchar const *content_type); - -gchar *gitg_utils_get_monospace_font_name(void); -void gitg_utils_set_monospace_font(GtkWidget *widget); - -GtkBuilder *gitg_utils_new_builder (gchar const *filename); - -gint gitg_utils_sort_names(gchar const *s1, gchar const *s2); - -void gitg_utils_menu_position_under_widget(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data); -void gitg_utils_menu_position_under_tree_view(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data); - -gchar *gitg_utils_rewrite_hunk_counters (gchar const *hunk, guint old_count, guint new_count); - -GtkCellRenderer *gitg_utils_find_cell_at_pos (GtkTreeView *tree_view, GtkTreeViewColumn *column, GtkTreePath *path, gint x); - -void gitg_utils_restore_pane_position (GtkPaned *paned, gint position, gboolean reversed); - -void gitg_utils_rounded_rectangle (cairo_t *ctx, gdouble x, gdouble y, gdouble width, gdouble height, gdouble radius); - -#endif /* __GITG_UTILS_H__ */ diff --git a/gitg/gitg-window.c b/gitg/gitg-window.c deleted file mode 100644 index fa30e521..00000000 --- a/gitg/gitg-window.c +++ /dev/null @@ -1,3584 +0,0 @@ -/* - * gitg-window.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "gitg-dirs.h" -#include "gitg-window.h" -#include "gitg-cell-renderer-path.h" -#include "gitg-commit-view.h" -#include "gitg-preferences-dialog.h" -#include "gitg-repository-dialog.h" -#include "gitg-dnd.h" -#include "gitg-branch-actions.h" -#include "gitg-utils.h" -#include "gitg-revision-panel.h" -#include "gitg-revision-details-panel.h" -#include "gitg-revision-changes-panel.h" -#include "gitg-revision-files-panel.h" -#include "gitg-activatable.h" -#include "gitg-uri.h" - -#define DYNAMIC_ACTION_DATA_KEY "GitgDynamicActionDataKey" -#define DYNAMIC_ACTION_DATA_REMOTE_KEY "GitgDynamicActionDataRemoteKey" -#define DYNAMIC_ACTION_DATA_BRANCH_KEY "GitgDynamicActionDataBranchKey" - -#define GITG_WINDOW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_WINDOW, GitgWindowPrivate)) - -enum -{ - COLUMN_BRANCHES_NAME, - COLUMN_BRANCHES_REF, - COLUMN_BRANCHES_ICON, - COLUMN_BRANCHES_SELECTION -}; - -struct _GitgWindowPrivate -{ - GitgRepository *repository; - - GtkTreeStore *branches_store; - - /* Widget placeholders */ - GtkNotebook *notebook_main; - GtkTreeView *tree_view; - GtkStatusbar *statusbar; - GitgCommitView *commit_view; - GtkWidget *search_popup; - GtkComboBox *combo_branches; - - GtkUIManager *menus_ui_manager; - - GtkWidget *vpaned_main; - GtkWidget *hpaned_commit1; - GtkWidget *hpaned_commit2; - GtkWidget *vpaned_commit; - GtkNotebook *notebook_revision; - - GtkActionGroup *edit_group; - GtkActionGroup *repository_group; - GtkWidget *open_dialog; - - GitgCellRendererPath *renderer_path; - - GTimer *load_timer; - GdkCursor *hand; - - gboolean destroy_has_run; - guint merge_rebase_uid; - GtkActionGroup *merge_rebase_action_group; - - guint cherry_pick_uid; - GtkActionGroup *cherry_pick_action_group; - GitgRef *popup_refs[2]; - - GList *branch_actions; - GitgHash select_on_load; - - GSList *revision_panels; - GSList *activatables; - - GSettings *state_settings; - GSettings *view_settings; - GSettings *history_settings; - GSettings *hidden_settings; -}; - -static gboolean on_tree_view_motion (GtkTreeView *treeview, - GdkEventMotion *event, - GitgWindow *window); - -static gboolean on_tree_view_button_release (GtkTreeView *treeview, - GdkEventButton *event, - GitgWindow *window); - -static void gitg_window_buildable_iface_init (GtkBuildableIface *iface); - -void on_subject_activate (GtkAction *action, GitgWindow *window); -void on_author_activate (GtkAction *action, GitgWindow *window); -void on_date_activate (GtkAction *action, GitgWindow *window); -void on_hash_activate (GtkAction *action, GitgWindow *window); -void on_file_quit (GtkAction *action, GitgWindow *window); -void on_file_open (GtkAction *action, GitgWindow *window); -void on_edit_cut (GtkAction *action, GitgWindow *window); -void on_edit_copy (GtkAction *action, GitgWindow *window); -void on_edit_paste (GtkAction *action, GitgWindow *window); -void on_view_refresh (GtkAction *action, GitgWindow *window); -void on_recent_open (GtkRecentChooser *chooser, GitgWindow *window); -void on_help_about (GtkAction *action, GitgWindow *window); -void on_edit_preferences (GtkAction *action, GitgWindow *window); -void on_repository_properties (GtkAction *action, GitgWindow *window); - -void on_tree_view_rv_button_press_event (GtkWidget *widget, - GdkEvent *event, - GitgWindow *window); - -void on_checkout_branch_action_activate (GtkAction *action, GitgWindow *window); -void on_remove_branch_action_activate (GtkAction *action, GitgWindow *window); -void on_rename_branch_action_activate (GtkAction *action, GitgWindow *window); -void on_rebase_branch_action_activate (GtkAction *action, GitgWindow *window); -void on_merge_branch_action_activate (GtkAction *action, GitgWindow *window); -void on_revision_format_patch_activate (GtkAction *action, GitgWindow *window); -void on_revision_new_branch_activate (GtkAction *action, GitgWindow *window); -void on_revision_tag_activate (GtkAction *action, GitgWindow *window); -void on_revision_squash_activate (GtkAction *action, GitgWindow *window); - -G_DEFINE_TYPE_EXTENDED(GitgWindow, gitg_window, GTK_TYPE_WINDOW, 0, - G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE, gitg_window_buildable_iface_init)); - -static GtkBuildableIface parent_iface; -static GtkWindowClass *parent_class = NULL; - -static void -on_branch_action_shell_end (GitgShell *shell, - gboolean cancelled, - GitgWindow *window) -{ - window->priv->branch_actions = g_list_remove (window->priv->branch_actions, shell); - g_object_unref (shell); -} - -gboolean -gitg_window_add_branch_action (GitgWindow *window, - GitgShell *shell) -{ - if (shell != NULL && gitg_io_get_running (GITG_IO (shell))) - { - window->priv->branch_actions = g_list_prepend (window->priv->branch_actions, shell); - - g_signal_connect (shell, "end", G_CALLBACK (on_branch_action_shell_end), window); - } - else if (shell) - { - g_object_unref (shell); - shell = NULL; - } - - return shell != NULL; -} - -static void -gitg_window_finalize (GObject *object) -{ - GitgWindow *self = GITG_WINDOW(object); - - g_timer_destroy (self->priv->load_timer); - g_object_unref (self->priv->hand); - - GList *copy = g_list_copy (self->priv->branch_actions); - GList *item; - - for (item = copy; item; item = g_list_next (item)) - { - gitg_io_cancel (item->data); - } - - g_list_free (copy); - - G_OBJECT_CLASS (gitg_window_parent_class)->finalize (object); -} - -static void -gitg_window_dispose (GObject *object) -{ - GitgWindow *self = GITG_WINDOW (object); - - if (self->priv->state_settings) - { - g_object_unref (self->priv->state_settings); - self->priv->state_settings = NULL; - } - - if (self->priv->view_settings) - { - g_object_unref (self->priv->view_settings); - self->priv->view_settings = NULL; - } - - if (self->priv->history_settings) - { - g_object_unref (self->priv->history_settings); - self->priv->history_settings = NULL; - } - - if (self->priv->hidden_settings) - { - g_object_unref (self->priv->hidden_settings); - self->priv->hidden_settings = NULL; - } - - G_OBJECT_CLASS (gitg_window_parent_class)->dispose (object); -} - -static void -on_revision_panel_mapped (GtkWidget *page, - GitgWindow *window) -{ - gint nth; - GitgRevisionPanel *panel; - GitgRevision *revision = NULL; - GtkTreeModel *model; - GtkTreeSelection *selection; - GtkTreeIter iter; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &revision, -1); - } - - if (!revision) - { - return; - } - - nth = gtk_notebook_page_num (window->priv->notebook_revision, - page); - - panel = g_slist_nth_data (window->priv->revision_panels, nth); - - gitg_revision_panel_update (panel, - window->priv->repository, - revision); - - gitg_revision_unref (revision); -} - -static void -add_revision_panel (GitgWindow *window, - GType panel_type) -{ - GitgRevisionPanel *panel; - gchar *label; - GtkWidget *label_widget; - GtkWidget *page; - - g_return_if_fail (g_type_is_a (panel_type, GITG_TYPE_REVISION_PANEL)); - - panel = g_object_new (panel_type, NULL); - gitg_revision_panel_initialize (panel, window); - - window->priv->revision_panels = g_slist_append (window->priv->revision_panels, - panel); - - if (GITG_IS_ACTIVATABLE (panel)) - { - window->priv->activatables = g_slist_append (window->priv->activatables, - g_object_ref (panel)); - } - - label = gitg_revision_panel_get_label (panel); - label_widget = gtk_label_new (label); - gtk_widget_show (label_widget); - - g_free (label); - - page = gitg_revision_panel_get_panel (panel); - gtk_widget_show (page); - - g_signal_connect (page, - "map", - G_CALLBACK (on_revision_panel_mapped), - window); - - gtk_notebook_append_page (window->priv->notebook_revision, - page, - label_widget); -} - -static void -on_selection_changed (GtkTreeSelection *selection, - GitgWindow *window) -{ - GtkTreeModel *model; - GtkTreeIter iter; - GitgRevision *revision = NULL; - GSList *item; - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - { - gtk_tree_model_get (GTK_TREE_MODEL(model), &iter, 0, &revision, -1); - } - - gint i = 0; - - for (item = window->priv->revision_panels; item; item = g_slist_next (item)) - { - GtkWidget *page; - - page = gtk_notebook_get_nth_page (window->priv->notebook_revision, - i++); - - if (gtk_widget_get_mapped (page) || !revision) - { - gitg_revision_panel_update (item->data, - window->priv->repository, - revision); - } - } - - if (revision) - { - if (gitg_repository_get_loaded (window->priv->repository)) - { - memcpy (window->priv->select_on_load, - gitg_revision_get_hash (revision), - GITG_HASH_BINARY_SIZE); - } - - gitg_revision_unref (revision); - } - else - { - if (gitg_repository_get_loaded (window->priv->repository)) - { - memset (window->priv->select_on_load, 0, GITG_HASH_BINARY_SIZE); - } - } -} - -static void -on_search_icon_release (GtkEntry *entry, - GtkEntryIconPosition icon_pos, - int button, - GitgWindow *window) -{ - gtk_menu_popup (GTK_MENU(window->priv->search_popup), - NULL, - NULL, - NULL, - NULL, - button, - gtk_get_current_event_time ()); -} - -static void -search_column_activate (GtkAction *action, - gint column, - GtkTreeView *tree_view) -{ - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(action))) - { - return; - } - - gtk_tree_view_set_search_column (tree_view, column); -} - -void -on_subject_activate (GtkAction *action, - GitgWindow *window) -{ - search_column_activate (action, 1, window->priv->tree_view); -} - -void -on_author_activate (GtkAction *action, - GitgWindow *window) -{ - search_column_activate (action, 2, window->priv->tree_view); -} - -void -on_date_activate (GtkAction *action, - GitgWindow *window) -{ - search_column_activate (action, 3, window->priv->tree_view); -} - -void -on_hash_activate (GtkAction *action, - GitgWindow *window) -{ - search_column_activate (action, 4, window->priv->tree_view); -} - -static gboolean -search_hash_equal_func (GtkTreeModel *model, - gchar const *key, - GtkTreeIter *iter) -{ - GitgRevision *rv; - gtk_tree_model_get (model, iter, 0, &rv, -1); - - gchar *sha = gitg_revision_get_sha1 (rv); - - gboolean ret = !g_str_has_prefix (sha, key); - - g_free (sha); - gitg_revision_unref (rv); - - return ret; -} - -static gboolean -search_equal_func (GtkTreeModel *model, - gint column, - gchar const *key, - GtkTreeIter *iter, - gpointer userdata) -{ - if (column == 4) - { - return search_hash_equal_func (model, key, iter); - } - - gchar *cmp; - gtk_tree_model_get (model, iter, column, &cmp, -1); - - gchar *s1 = g_utf8_casefold (key, -1); - gchar *s2 = g_utf8_casefold (cmp, -1); - - gboolean ret = strstr (s2, s1) == NULL; - - g_free (s1); - g_free (s2); - - g_free (cmp); - - return ret; -} - -static void -focus_search (GtkAccelGroup *group, - GObject *acceleratable, - guint keyval, - GdkModifierType modifier, - gpointer userdata) -{ - gtk_widget_grab_focus (GTK_WIDGET(userdata)); -} - -static void -build_search_entry (GitgWindow *window, - GtkBuilder *builder) -{ - GtkWidget *box; - GtkWidget *entry; - GtkWidget *popup; - - box = GTK_WIDGET (gtk_builder_get_object (builder, "hbox_top")); - entry = gtk_entry_new (); - - gtk_entry_set_icon_from_stock (GTK_ENTRY (entry), - GTK_ENTRY_ICON_PRIMARY, - GTK_STOCK_FIND); - - gtk_tree_view_set_search_entry (window->priv->tree_view, GTK_ENTRY(entry)); - gtk_widget_show (entry); - gtk_box_pack_end (GTK_BOX(box), entry, FALSE, FALSE, 0); - - popup = gtk_ui_manager_get_widget (window->priv->menus_ui_manager, - "/ui/search_popup"); - - window->priv->search_popup = popup; - g_object_ref (popup); - - g_signal_connect (entry, - "icon-release", - G_CALLBACK(on_search_icon_release), - window); - - gtk_tree_view_set_search_column (window->priv->tree_view, 1); - - gtk_tree_view_set_search_equal_func (window->priv->tree_view, - search_equal_func, - window, - NULL); - - GtkAccelGroup *group = gtk_accel_group_new (); - - GClosure *closure = g_cclosure_new (G_CALLBACK (focus_search), entry, NULL); - - gtk_accel_group_connect (group, GDK_KEY_f, GDK_CONTROL_MASK, 0, closure); - gtk_window_add_accel_group (GTK_WINDOW(window), group); -} - -static gboolean -goto_hash (GitgWindow *window, - gchar const *hash) -{ - GtkTreeIter iter; - - if (!gitg_repository_find_by_hash (window->priv->repository, hash, &iter)) - { - return FALSE; - } - - gtk_tree_selection_select_iter (gtk_tree_view_get_selection (window->priv->tree_view), - &iter); - GtkTreePath *path; - - path = gtk_tree_model_get_path (GTK_TREE_MODEL(window->priv->repository), - &iter); - - gtk_tree_view_scroll_to_cell (window->priv->tree_view, - path, - NULL, - TRUE, - 0.5, - 0); - gtk_tree_path_free (path); - - return TRUE; -} - -static void -on_renderer_path (GtkTreeViewColumn *column, - GitgCellRendererPath *renderer, - GtkTreeModel *model, - GtkTreeIter *iter, - GitgWindow *window) -{ - GitgRevision *rv; - - gtk_tree_model_get (model, iter, 0, &rv, -1); - GtkTreeIter iter1 = *iter; - - GitgRevision *next_revision = NULL; - - if (gtk_tree_model_iter_next (model, &iter1)) - { - gtk_tree_model_get (model, &iter1, 0, &next_revision, -1); - } - - GSList *labels; - const gchar *lbl = NULL; - - switch (gitg_revision_get_sign (rv)) - { - case 't': - lbl = "staged"; - break; - case 'u': - lbl = "unstaged"; - break; - default: - break; - } - - if (lbl != NULL) - { - g_object_set (renderer, "style", PANGO_STYLE_ITALIC, NULL); - labels = g_slist_append (NULL, - gitg_ref_new (gitg_revision_get_hash (rv), - lbl)); - } - else - { - g_object_set (renderer, "style", PANGO_STYLE_NORMAL, NULL); - labels = gitg_repository_get_refs_for_hash (GITG_REPOSITORY(model), - gitg_revision_get_hash (rv)); - } - - g_object_set (renderer, - "revision", rv, - "next_revision", next_revision, - "labels", labels, - NULL); - - gitg_revision_unref (next_revision); - gitg_revision_unref (rv); -} - -static gboolean -branches_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer data) -{ - gchar *name; - GitgRef *ref; - - gtk_tree_model_get (model, - iter, - COLUMN_BRANCHES_NAME, &name, - COLUMN_BRANCHES_REF, &ref, - -1); - - gboolean ret = (name == NULL && ref == NULL); - - g_free (name); - gitg_ref_free (ref); - - return ret; -} - -static void -on_branches_combo_changed (GtkComboBox *combo, - GitgWindow *window) -{ - if (gtk_combo_box_get_active (combo) < 2) - { - return; - } - - GtkTreeIter iter; - gchar **selection; - - gtk_combo_box_get_active_iter (combo, &iter); - - gtk_tree_model_get (gtk_combo_box_get_model (combo), - &iter, - COLUMN_BRANCHES_SELECTION, &selection, - -1); - - if (selection != NULL) - { - gitg_repository_load (window->priv->repository, 1, (gchar const **)selection, NULL); - g_strfreev (selection); - } -} - -static void -build_branches_combo (GitgWindow *window, - GtkBuilder *builder) -{ - GtkComboBox *combo; - window->priv->branches_store = gtk_tree_store_new (4, - G_TYPE_STRING, - GITG_TYPE_REF, - G_TYPE_STRING, - G_TYPE_STRV); - - combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, - "combo_box_branches")); - - window->priv->combo_branches = combo; - - GtkTreeIter iter; - gtk_tree_store_append (window->priv->branches_store, &iter, NULL); - gtk_tree_store_set (window->priv->branches_store, - &iter, - COLUMN_BRANCHES_NAME, _ ("Select branch"), - COLUMN_BRANCHES_REF, NULL, - COLUMN_BRANCHES_SELECTION, NULL, - -1); - - gtk_combo_box_set_model (combo, GTK_TREE_MODEL(window->priv->branches_store)); - gtk_combo_box_set_active (combo, 0); - - gtk_combo_box_set_row_separator_func (combo, - branches_separator_func, - window, - NULL); - - g_signal_connect (combo, - "changed", - G_CALLBACK(on_branches_combo_changed), - window); -} - -static void -restore_state (GitgWindow *window) -{ - gint width; - gint height; - - g_settings_get (window->priv->state_settings, "size", "(ii)", &width, &height); - - gtk_window_set_default_size (GTK_WINDOW(window), - width, height); - - gitg_utils_restore_pane_position (GTK_PANED(window->priv->vpaned_main), - g_settings_get_int (window->priv->state_settings, - "vpaned-main-position"), - FALSE); - - gitg_utils_restore_pane_position (GTK_PANED(window->priv->vpaned_commit), - g_settings_get_int (window->priv->state_settings, - "vpaned-commit-position"), - FALSE); - - gitg_utils_restore_pane_position (GTK_PANED(window->priv->hpaned_commit1), - g_settings_get_int (window->priv->state_settings, - "hpaned-commit1-position"), - FALSE); - - gitg_utils_restore_pane_position (GTK_PANED(window->priv->hpaned_commit2), - g_settings_get_int (window->priv->state_settings, - "hpaned-commit2-position"), - TRUE); -} - -static void -update_dnd_status (GitgWindow *window, - GitgRef *source, - GitgRef *dest) -{ - if (!dest) - { - gtk_statusbar_push (window->priv->statusbar, 0, ""); - } - else - { - gchar *message = NULL; - GitgRefType source_type = gitg_ref_get_ref_type (source); - GitgRefType dest_type = gitg_ref_get_ref_type (dest); - - if (source_type == GITG_REF_TYPE_BRANCH && - dest_type== GITG_REF_TYPE_REMOTE) - { - message = g_strdup_printf (_ ("Push local branch <%s> to remote branch <%s>"), - gitg_ref_get_shortname (source), - gitg_ref_get_shortname (dest)); - } - else if (source_type == GITG_REF_TYPE_BRANCH && - dest_type == GITG_REF_TYPE_BRANCH) - { - message = g_strdup_printf (_ ("Merge/rebase local branch <%s> with/on local branch <%s>"), - gitg_ref_get_shortname (source), - gitg_ref_get_shortname (dest)); - } - else if (source_type == GITG_REF_TYPE_REMOTE && - dest_type == GITG_REF_TYPE_BRANCH) - { - message = g_strdup_printf (_ ("Merge/rebase local branch <%s> with/on remote branch <%s>"), - gitg_ref_get_shortname (dest), - gitg_ref_get_shortname (source)); - } - else if (source_type == GITG_REF_TYPE_STASH && - dest_type == GITG_REF_TYPE_BRANCH) - { - message = g_strdup_printf (_ ("Apply stash to local branch <%s>"), - gitg_ref_get_shortname (dest)); - } - - if (message) - { - gtk_statusbar_push (window->priv->statusbar, 0, message); - } - - g_free (message); - } -} - -static gboolean -on_refs_dnd (GitgRef *source, - GitgRef *dest, - gboolean dropped, - GitgWindow *window) -{ - if (!dropped) - { - update_dnd_status (window, source, dest); - return FALSE; - } - - gboolean ret = FALSE; - GitgRefType source_type = gitg_ref_get_ref_type (source); - GitgRefType dest_type = gitg_ref_get_ref_type (dest); - - if (source_type == GITG_REF_TYPE_BRANCH && - dest_type == GITG_REF_TYPE_REMOTE) - { - ret = gitg_window_add_branch_action (window, - gitg_branch_actions_push (window, - source, - dest)); - } - else if (source_type == GITG_REF_TYPE_STASH) - { - if (dest_type == GITG_REF_TYPE_BRANCH) - { - ret = gitg_branch_actions_apply_stash (window, - source, - dest); - } - } - else if (dest_type == GITG_REF_TYPE_BRANCH) - { - GtkWidget *popup; - - popup = gtk_ui_manager_get_widget (window->priv->menus_ui_manager, - "/ui/dnd_popup"); - - window->priv->popup_refs[0] = source; - window->priv->popup_refs[1] = dest; - - gtk_menu_popup (GTK_MENU (popup), - NULL, - NULL, - NULL, - NULL, - 1, - gtk_get_current_event_time ()); - } - - gtk_statusbar_push (window->priv->statusbar, 0, ""); - return ret; -} - -static void -update_revision_dnd_status (GitgWindow *window, - GitgRevision *source, - GitgRef *dest) -{ - if (!dest) - { - gtk_statusbar_push (window->priv->statusbar, 0, ""); - } - else - { - gchar *message = g_strdup_printf (_ ("Cherry-pick revision on <%s>"), - gitg_ref_get_shortname (dest)); - - gtk_statusbar_push (window->priv->statusbar, 0, message); - g_free (message); - } -} - -static gboolean -on_revision_dnd (GitgRevision *source, - GitgRef *dest, - gboolean dropped, - GitgWindow *window) -{ - if (!dropped) - { - update_revision_dnd_status (window, source, dest); - return FALSE; - } - - if (gitg_ref_get_ref_type (dest) != GITG_REF_TYPE_BRANCH) - { - return FALSE; - } - - return gitg_window_add_branch_action (window, - gitg_branch_actions_cherry_pick (window, source, dest)); -} - -static void -init_tree_view (GitgWindow *window, - GtkBuilder *builder) -{ - GtkTreeViewColumn *col; - - col = GTK_TREE_VIEW_COLUMN (gtk_builder_get_object (builder, - "rv_column_subject")); - - window->priv->renderer_path = GITG_CELL_RENDERER_PATH (gtk_builder_get_object (builder, - "rv_renderer_subject")); - - gtk_tree_view_column_set_cell_data_func (col, - GTK_CELL_RENDERER (window->priv->renderer_path), - (GtkTreeCellDataFunc)on_renderer_path, - window, - NULL); - - gitg_dnd_enable (window->priv->tree_view, - (GitgDndCallback)on_refs_dnd, - (GitgDndRevisionCallback)on_revision_dnd, - window); -} - -static void -gitg_window_parser_finished (GtkBuildable *buildable, - GtkBuilder *builder) -{ - if (parent_iface.parser_finished) - parent_iface.parser_finished (buildable, builder); - - // Store widgets - GitgWindow *window = GITG_WINDOW(buildable); - - // Insert menu from second ui file - GtkBuilder *b = gitg_utils_new_builder ("gitg-ui.xml"); - GtkUIManager *uiman = GTK_UI_MANAGER (gtk_builder_get_object (b, "uiman")); - - GtkRecentChooser *chooser = GTK_RECENT_CHOOSER(gtk_builder_get_object (b, "RecentOpenAction")); - GtkRecentFilter *filter = gtk_recent_filter_new (); - gtk_recent_filter_add_group (filter, "gitg"); - - gtk_recent_chooser_add_filter (chooser, filter); - gtk_recent_chooser_set_show_tips (chooser, TRUE); - gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU); - - GtkWidget *menu = gtk_ui_manager_get_widget (uiman, "/ui/menubar_main"); - GtkWidget *vbox = GTK_WIDGET(gtk_builder_get_object (builder, "vbox_main")); - - gtk_box_pack_start (GTK_BOX(vbox), menu, FALSE, FALSE, 0); - gtk_box_reorder_child (GTK_BOX(vbox), menu, 0); - - gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (uiman)); - - window->priv->edit_group = GTK_ACTION_GROUP(gtk_builder_get_object (b, "action_group_menu_edit")); - window->priv->repository_group = GTK_ACTION_GROUP(gtk_builder_get_object (b, "action_group_menu_repository")); - - gtk_builder_connect_signals (b, window); - g_object_unref (b); - - window->priv->vpaned_main = GTK_WIDGET (gtk_builder_get_object (builder, - "vpaned_main")); - - g_settings_bind (window->priv->view_settings, - "layout-vertical", - window->priv->vpaned_main, - "orientation", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - window->priv->hpaned_commit1 = GTK_WIDGET (gtk_builder_get_object (builder, - "hpaned_commit1")); - - window->priv->hpaned_commit2 = GTK_WIDGET (gtk_builder_get_object (builder, - "hpaned_commit2")); - - window->priv->vpaned_commit = GTK_WIDGET (gtk_builder_get_object (builder, - "vpaned_commit")); - - window->priv->notebook_main = GTK_NOTEBOOK (gtk_builder_get_object (builder, - "notebook_main")); - - window->priv->notebook_revision = GTK_NOTEBOOK (gtk_builder_get_object (builder, - "notebook_revision")); - - window->priv->tree_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, - "tree_view_rv")); - - window->priv->statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, - "statusbar")); - - window->priv->commit_view = GITG_COMMIT_VIEW (gtk_builder_get_object (builder, - "vpaned_commit")); - - restore_state (window); - - init_tree_view (window, builder); - - // Intialize branches - build_branches_combo (window, builder); - - // Get menus ui - b = gitg_utils_new_builder ("gitg-menus.xml"); - window->priv->menus_ui_manager = GTK_UI_MANAGER (g_object_ref (gtk_builder_get_object (b, - "uiman"))); - - gtk_builder_connect_signals (b, window); - g_object_unref (b); - - // Create search entry - build_search_entry (window, builder); - - gtk_builder_connect_signals (builder, window); - - // Initialize revision panels - add_revision_panel (window, GITG_TYPE_REVISION_DETAILS_PANEL); - add_revision_panel (window, GITG_TYPE_REVISION_CHANGES_PANEL); - add_revision_panel (window, GITG_TYPE_REVISION_FILES_PANEL); - - // Connect signals - GtkTreeSelection *selection = gtk_tree_view_get_selection (window->priv->tree_view); - g_signal_connect (selection, - "changed", - G_CALLBACK(on_selection_changed), - window); - - g_signal_connect (window->priv->tree_view, - "motion-notify-event", - G_CALLBACK(on_tree_view_motion), - window); - - g_signal_connect (window->priv->tree_view, - "button-release-event", - G_CALLBACK(on_tree_view_button_release), - window); -} - -static void -gitg_window_buildable_iface_init (GtkBuildableIface *iface) -{ - parent_iface = *iface; - - iface->parser_finished = gitg_window_parser_finished; -} - -static void -save_state (GitgWindow *window) -{ - GtkAllocation allocation; - gint position; - - gtk_widget_get_allocation (GTK_WIDGET (window), &allocation); - - g_settings_set (window->priv->state_settings, "size", "(ii)", - allocation.width, allocation.height); - - if (gtk_widget_get_mapped (window->priv->vpaned_main)) - { - position = gtk_paned_get_position (GTK_PANED (window->priv->vpaned_main)); - g_settings_set_int (window->priv->state_settings, "vpaned-main-position", - position); - } - - if (gtk_widget_get_mapped (window->priv->vpaned_commit)) - { - position = gtk_paned_get_position (GTK_PANED (window->priv->vpaned_commit)); - g_settings_set_int (window->priv->state_settings, "vpaned-commit-position", - position); - } - - if (gtk_widget_get_mapped (window->priv->hpaned_commit1)) - { - position = gtk_paned_get_position (GTK_PANED (window->priv->hpaned_commit1)); - g_settings_set_int (window->priv->state_settings, "hpaned-commit1-position", - position); - } - - if (gtk_widget_get_mapped (window->priv->hpaned_commit2)) - { - GtkAllocation alloc; - - gtk_widget_get_allocation (GTK_WIDGET (window->priv->hpaned_commit2), - &alloc); - - position = gtk_paned_get_position (GTK_PANED (window->priv->hpaned_commit2)); - g_settings_set_int (window->priv->state_settings, "hpaned-commit2-position", - alloc.width - position); - } -} - -static gboolean -gitg_window_delete_event (GtkWidget *widget, - GdkEventAny *event) -{ - save_state (GITG_WINDOW (widget)); - - if (GTK_WIDGET_CLASS (parent_class)->delete_event) - { - return GTK_WIDGET_CLASS (parent_class)->delete_event (widget, event); - } - else - { - gtk_widget_destroy (widget); - return TRUE; - } -} - -static void -gitg_window_destroy (GtkWidget *widget) -{ - GitgWindow *window = GITG_WINDOW(widget); - - if (!window->priv->destroy_has_run) - { - gtk_tree_view_set_model (window->priv->tree_view, NULL); - - g_slist_free_full (window->priv->revision_panels, g_object_unref); - g_slist_free_full (window->priv->activatables, g_object_unref); - - window->priv->revision_panels = NULL; - window->priv->activatables = NULL; - - window->priv->destroy_has_run = TRUE; - } - - if (GTK_WIDGET_CLASS(parent_class)->destroy) - { - GTK_WIDGET_CLASS(parent_class)->destroy (widget); - } -} - -static gboolean -gitg_window_window_state_event (GtkWidget *widget, - GdkEventWindowState *event) -{ - GitgWindow *window = GITG_WINDOW(widget); - - if (event->changed_mask & - (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) - { - gboolean show; - - show = !(event->new_window_state & - (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)); - - gtk_window_set_has_resize_grip (GTK_WINDOW (window), show); - } - - /* Save the window state */ - g_settings_set_int (window->priv->state_settings, "state", event->new_window_state); - - return FALSE; -} - -static void -gitg_window_set_focus (GtkWindow *wnd, - GtkWidget *widget) -{ - GitgWindow *window; - - if (GTK_WINDOW_CLASS (gitg_window_parent_class)->set_focus) - { - GTK_WINDOW_CLASS (gitg_window_parent_class)->set_focus (wnd, widget); - } - - if (widget == NULL) - { - return; - } - - window = GITG_WINDOW (wnd); - - gboolean cancopy = g_signal_lookup ("copy-clipboard", - G_OBJECT_TYPE(widget)) != 0; - gboolean selection = FALSE; - gboolean editable = FALSE; - - if (GTK_IS_EDITABLE (widget)) - { - selection = gtk_editable_get_selection_bounds (GTK_EDITABLE (widget), - NULL, - NULL); - editable = gtk_editable_get_editable (GTK_EDITABLE(widget)); - cancopy = cancopy && selection; - } - - gtk_action_set_sensitive (gtk_action_group_get_action (window->priv->edit_group, - "EditPasteAction"), - editable); - - gtk_action_set_sensitive (gtk_action_group_get_action (window->priv->edit_group, - "EditCutAction"), - editable && selection); - gtk_action_set_sensitive (gtk_action_group_get_action (window->priv->edit_group, - "EditCopyAction"), - cancopy); -} - -static void -gitg_window_class_init (GitgWindowClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->finalize = gitg_window_finalize; - object_class->dispose = gitg_window_dispose; - - widget_class->destroy = gitg_window_destroy; - widget_class->delete_event = gitg_window_delete_event; - widget_class->window_state_event = gitg_window_window_state_event; - window_class->set_focus = gitg_window_set_focus; - - g_type_class_add_private (object_class, sizeof (GitgWindowPrivate)); -} - -static void -gitg_window_init (GitgWindow *self) -{ - self->priv = GITG_WINDOW_GET_PRIVATE(self); - - self->priv->load_timer = g_timer_new (); - self->priv->hand = gdk_cursor_new (GDK_HAND1); - self->priv->state_settings = g_settings_new ("org.gnome.gitg.state.window"); - self->priv->view_settings = g_settings_new ("org.gnome.gitg.preferences.view.main"); - self->priv->history_settings = g_settings_new ("org.gnome.gitg.preferences.view.history"); - self->priv->hidden_settings = g_settings_new ("org.gnome.gitg.preferences.hidden"); -} - -static void -on_repository_loaded (GitgRepository *repository, - GitgWindow *window) -{ - gchar *msg = g_strdup_printf (_ ("Loaded %d revisions in %.2fs"), - gtk_tree_model_iter_n_children (GTK_TREE_MODEL(window->priv->repository), NULL), - g_timer_elapsed (window->priv->load_timer, NULL)); - - gtk_statusbar_push (window->priv->statusbar, 0, msg); - - g_free (msg); - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window->priv->tree_view)), NULL); - - gtk_tree_view_set_model (window->priv->tree_view, - GTK_TREE_MODEL (window->priv->repository)); - - GitgHash hash = {0,}; - - if (memcmp (window->priv->select_on_load, hash, GITG_HASH_BINARY_SIZE) != 0) - { - goto_hash (window, window->priv->select_on_load); - } -} - -static void -on_update (GitgShell *loader, - gchar **revisions, - GitgWindow *window) -{ - gchar *msg = g_strdup_printf (_ ("Loading %d revisions..."), - gtk_tree_model_iter_n_children (GTK_TREE_MODEL(window->priv->repository), NULL)); - - gtk_statusbar_push (window->priv->statusbar, 0, msg); - g_free (msg); -} - -void -gitg_window_set_select_on_load (GitgWindow *window, - gchar const *selection) -{ - if (!selection || !window->priv->repository) - { - return; - } - - gchar *resolved; - - resolved = gitg_repository_parse_ref (window->priv->repository, - selection); - - if (resolved && strlen (resolved) == GITG_HASH_SHA_SIZE) - { - gitg_hash_sha1_to_hash (resolved, window->priv->select_on_load); - } - - g_free (resolved); -} - -static gboolean -convert_setting_to_inactive_max (GValue *value, - GVariant *variant, - gpointer userdata) -{ - gint s = g_variant_get_int32 (variant); - g_value_set_int (value, 2 + s * 8); - - return TRUE; -} - -static gboolean -convert_setting_to_inactive_collapse (GValue *value, - GVariant *variant, - gpointer userdata) -{ - gint s = g_variant_get_int32 (variant); - g_value_set_int (value, 1 + s * 3); - - return TRUE; -} - -static gboolean -convert_setting_to_inactive_gap (GValue *value, - GVariant *variant, - gpointer userdata) -{ - g_value_set_int (value, 10); - - return TRUE; -} - -static void -bind_repository (GitgWindow *window) -{ - if (window->priv->repository == NULL) - return; - - g_settings_bind_with_mapping (window->priv->history_settings, - "collapse-inactive-lanes", - window->priv->repository, - "inactive-max", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, - convert_setting_to_inactive_max, - NULL, - window, - NULL); - - g_settings_bind (window->priv->history_settings, - "show-virtual-stash", - window->priv->repository, - "show-stash", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (window->priv->history_settings, - "show-virtual-staged", - window->priv->repository, - "show-staged", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (window->priv->history_settings, - "show-virtual-unstaged", - window->priv->repository, - "show-unstaged", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind (window->priv->history_settings, - "topo-order", - window->priv->repository, - "topo-order", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); - - g_settings_bind_with_mapping (window->priv->history_settings, - "collapse-inactive-lanes", - window->priv->repository, - "inactive-collapse", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, - convert_setting_to_inactive_collapse, - NULL, - window, - NULL); - - g_settings_bind_with_mapping (window->priv->history_settings, - "collapse-inactive-lanes", - window->priv->repository, - "inactive-gap", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, - convert_setting_to_inactive_gap, - NULL, - window, - NULL); - - g_settings_bind (window->priv->history_settings, - "collapse-inactive-lanes-active", - window->priv->repository, - "inactive-enabled", - G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); -} - -static gboolean -create_repository (GitgWindow *window, - GFile *git_dir, - GFile *work_tree, - gchar const *selection) -{ - window->priv->repository = gitg_repository_new (git_dir, work_tree); - - if (!gitg_repository_exists (window->priv->repository)) - { - g_object_unref (window->priv->repository); - window->priv->repository = NULL; - } - else if (selection) - { - gitg_window_set_select_on_load (window, selection); - } - - bind_repository (window); - - return window->priv->repository != NULL; -} - -static int -sort_by_ref_type (GitgRef *a, - GitgRef *b) -{ - if (gitg_ref_get_ref_type (a) == gitg_ref_get_ref_type (b)) - { - if (g_ascii_strcasecmp (gitg_ref_get_shortname (a), "master") == 0) - { - return -1; - } - else if (g_ascii_strcasecmp (gitg_ref_get_shortname (b), "master") == 0) - { - return 1; - } - else - { - return g_ascii_strcasecmp (gitg_ref_get_shortname (a), - gitg_ref_get_shortname (b)); - } - } - else - { - return gitg_ref_get_ref_type (a) - gitg_ref_get_ref_type (b); - } -} - -static void -clear_branches_combo (GitgWindow *window) -{ - GtkTreeIter iter; - - if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(window->priv->branches_store), &iter, NULL, 1)) - { - while (gtk_tree_store_remove (window->priv->branches_store, &iter)) - ; - } - - gtk_combo_box_set_active (window->priv->combo_branches, 0); -} - -static gboolean -equal_selection (gchar const **s1, - gchar const **s2) -{ - if (!s1 || !s2) - { - return s1 == s2; - } - - gint i = 0; - - while (s1[i] && s2[i]) - { - if (strcmp (s1[i], s2[i]) != 0) - { - return FALSE; - } - - ++i; - } - - return !s1[i] && !s2[i]; -} - -static void -fill_branches_combo (GitgWindow *window) -{ - if (!window->priv->repository) - { - return; - } - - guint children; - - children = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (window->priv->branches_store), - NULL); - - if (children > 1) - { - return; - } - - GSList *refs = gitg_repository_get_refs (window->priv->repository); - - refs = g_slist_sort (refs, (GCompareFunc)sort_by_ref_type); - GSList *item; - - GitgRefType prevtype = GITG_REF_TYPE_NONE; - GtkTreeIter iter; - GtkTreeIter parent; - GitgRef *parentref = NULL; - GtkTreeStore *store = window->priv->branches_store; - - GitgRef *current_ref; - GitgRef *working_ref; - - current_ref = gitg_repository_get_current_ref (window->priv->repository); - working_ref = gitg_repository_get_current_working_ref (window->priv->repository); - - gchar const **current_selection = gitg_repository_get_current_selection (window->priv->repository); - - GtkTreeRowReference *active_from_current_ref = NULL; - GtkTreeRowReference *active_from_selection = NULL; - - for (item = refs; item; item = item->next) - { - GitgRef *ref = (GitgRef *)item->data; - - if (!(gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_REMOTE || - gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH)) - { - continue; - } - - if (gitg_ref_get_ref_type (ref) != prevtype) - { - /* Insert separator */ - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, - &iter, - COLUMN_BRANCHES_NAME, NULL, - COLUMN_BRANCHES_REF, NULL, - COLUMN_BRANCHES_SELECTION, NULL, - -1); - - prevtype = gitg_ref_get_ref_type (ref); - } - - if (gitg_ref_get_prefix (ref)) - { - if (!parentref || !gitg_ref_equal_prefix (parentref, ref)) - { - parentref = ref; - - /* Add parent item */ - gtk_tree_store_append (store, &parent, NULL); - gtk_tree_store_set (store, - &parent, - COLUMN_BRANCHES_NAME, gitg_ref_get_prefix (ref), - COLUMN_BRANCHES_REF, NULL, - -1); - - if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_REMOTE) - { - /* Add remote icon */ - gtk_tree_store_set (store, - &parent, - COLUMN_BRANCHES_ICON, g_strdup (GTK_STOCK_NETWORK), - -1); - } - } - - gtk_tree_store_append (store, &iter, &parent); - } - else - { - gtk_tree_store_append (store, &iter, NULL); - } - - gchar const *selection[] = { - gitg_ref_get_name (ref), - NULL - }; - - gtk_tree_store_set (store, - &iter, - COLUMN_BRANCHES_NAME, gitg_ref_get_shortname (ref), - COLUMN_BRANCHES_REF, ref, - COLUMN_BRANCHES_SELECTION, selection, - -1); - - if (!active_from_current_ref && gitg_ref_equal (current_ref, ref)) - { - GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), - &iter); - - active_from_current_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), - path); - gtk_tree_path_free (path); - } - - if (!active_from_selection && - ((current_selection && equal_selection (selection, current_selection)) || - (!current_selection && gitg_ref_equal (ref, working_ref)))) - { - GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), - &iter); - - active_from_selection = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), - path); - gtk_tree_path_free (path); - } - } - - /* Separator */ - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, - &iter, - COLUMN_BRANCHES_NAME, NULL, - COLUMN_BRANCHES_REF, NULL, - COLUMN_BRANCHES_SELECTION, NULL, - -1); - - gchar const *selection[] = { - "--branches", - NULL - }; - - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, - &iter, - COLUMN_BRANCHES_NAME, _ ("Local branches"), - COLUMN_BRANCHES_REF, NULL, - COLUMN_BRANCHES_SELECTION, selection, - -1); - - if (!active_from_selection && - current_selection && equal_selection (selection, current_selection)) - { - GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), - &iter); - - active_from_selection = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), - path); - gtk_tree_path_free (path); - } - - selection[0] = "--all"; - - gtk_tree_store_append (store, &iter, NULL); - gtk_tree_store_set (store, - &iter, - COLUMN_BRANCHES_NAME, _ ("All branches"), - COLUMN_BRANCHES_REF, NULL, - COLUMN_BRANCHES_SELECTION, selection, - -1); - - if (!active_from_selection && - current_selection && equal_selection (selection, current_selection)) - { - GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), - &iter); - - active_from_selection = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), - path); - gtk_tree_path_free (path); - } - - if (active_from_selection != NULL || active_from_current_ref != NULL) - { - GtkTreePath *path; - GtkTreeIter active; - - path = gtk_tree_row_reference_get_path (active_from_selection ? active_from_selection : active_from_current_ref); - - gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &active, path); - gtk_combo_box_set_active_iter (window->priv->combo_branches, &active); - } - - g_slist_free_full (refs, (GDestroyNotify)gitg_ref_free); - - if (active_from_selection) - { - gtk_tree_row_reference_free (active_from_selection); - } - - if (active_from_current_ref) - { - gtk_tree_row_reference_free (active_from_current_ref); - } -} - -static void -update_window_title (GitgWindow *window) -{ - if (!window->priv->repository) - { - gtk_window_set_title (GTK_WINDOW (window), _ ("gitg")); - return; - } - - GitgRef *ref = gitg_repository_get_current_working_ref (window->priv->repository); - gchar *refname = NULL; - - if (ref) - { - refname = g_strconcat (" (", gitg_ref_get_shortname (ref), ")", NULL); - } - - GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository); - gchar *basename = g_file_get_basename (work_tree); - gchar *title = g_strconcat (_ ("gitg"), " - ", basename, refname, NULL); - - gtk_window_set_title (GTK_WINDOW (window), title); - - g_object_unref (work_tree); - g_free (basename); - g_free (title); - g_free (refname); -} - -static void -on_repository_load (GitgRepository *repository, - GitgWindow *window) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_WATCH); - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (window->priv->tree_view)), cursor); - g_object_unref (cursor); - - gtk_statusbar_push (window->priv->statusbar, 0, _ ("Begin loading repository")); - - g_timer_reset (window->priv->load_timer); - g_timer_start (window->priv->load_timer); - - g_signal_handlers_block_by_func (window->priv->combo_branches, - on_branches_combo_changed, - window); - - clear_branches_combo (window); - fill_branches_combo (window); - - g_signal_handlers_unblock_by_func (window->priv->combo_branches, - on_branches_combo_changed, - window); - - gtk_tree_view_set_model (window->priv->tree_view, NULL); - - update_window_title (window); -} - -static void -add_recent_item (GitgWindow *window) -{ - GtkRecentManager *manager = gtk_recent_manager_get_default (); - GtkRecentData data = { 0 }; - gchar *groups[] = {"gitg", NULL}; - GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository); - gchar *basename = g_file_get_basename (work_tree); - - data.display_name = basename; - data.app_name = "gitg"; - data.mime_type = "inode/directory"; - data.app_exec = "gitg %f"; - data.groups = groups; - - gchar *uri = g_file_get_uri (work_tree); - gtk_recent_manager_add_full (manager, uri, &data); - - g_free (basename); - g_free (uri); - g_object_unref (work_tree); -} - -static void -update_sensitivity (GitgWindow *window) -{ - gboolean sens = window->priv->repository != NULL; - - gtk_widget_set_sensitive (GTK_WIDGET (window->priv->notebook_main), sens); - gtk_action_group_set_sensitive (window->priv->repository_group, sens); -} - -gboolean -gitg_window_select (GitgWindow *window, - gchar const *selection) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - - gitg_window_set_select_on_load (window, selection); - - if (!window->priv->repository) - { - return FALSE; - } - - return goto_hash (window, window->priv->select_on_load); -} - -static gboolean -load_repository (GitgWindow *window, - GFile *git_dir, - GFile *work_tree, - gint argc, - gchar const **argv, - gchar const *selection) -{ - if (window->priv->repository) - { - gtk_tree_view_set_model (window->priv->tree_view, NULL); - - g_signal_handlers_disconnect_by_func (window->priv->repository, - G_CALLBACK (on_repository_load), - window); - - g_signal_handlers_disconnect_by_func (window->priv->repository, - G_CALLBACK (on_repository_loaded), - window); - - g_object_unref (window->priv->repository); - window->priv->repository = NULL; - - gitg_repository_dialog_close (); - - memset (window->priv->select_on_load, 0, GITG_HASH_BINARY_SIZE); - } - - if ((git_dir || work_tree) && - create_repository (window, git_dir, work_tree, selection)) - { - GitgShell *loader = gitg_repository_get_loader (window->priv->repository); - - gitg_window_set_select_on_load (window, selection); - - g_signal_connect (loader, "update", G_CALLBACK (on_update), window); - g_object_unref (loader); - - g_signal_connect (window->priv->repository, - "load", - G_CALLBACK (on_repository_load), - window); - - g_signal_connect (window->priv->repository, - "loaded", - G_CALLBACK (on_repository_loaded), - window); - - clear_branches_combo (window); - - gitg_repository_load (window->priv->repository, argc, argv, NULL); - - gitg_commit_view_set_repository (window->priv->commit_view, - window->priv->repository); - - add_recent_item (window); - } - else - { - clear_branches_combo (window); - - gitg_commit_view_set_repository (window->priv->commit_view, - NULL); - - update_window_title (window); - } - - update_sensitivity (window); - - return window->priv->repository != NULL; -} - -static gboolean -activate_activatable (GitgWindow *window, - GitgActivatable *activatable, - gchar const *action) -{ - if (!gitg_activatable_activate (activatable, action)) - { - return FALSE; - } - - if (GITG_IS_REVISION_PANEL (activatable)) - { - GtkWidget *page; - GitgRevisionPanel *panel; - gint nth; - - panel = GITG_REVISION_PANEL (activatable); - page = gitg_revision_panel_get_panel (panel); - - nth = gtk_notebook_page_num (window->priv->notebook_revision, - page); - - if (nth >= 0) - { - gtk_notebook_set_current_page (window->priv->notebook_revision, - nth); - } - } - - return TRUE; -} - -gboolean -gitg_window_activate (GitgWindow *window, - gchar const *activatable, - gchar const *action) -{ - GSList *item; - - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - g_return_val_if_fail (activatable != NULL, FALSE); - - for (item = window->priv->activatables; item; item = g_slist_next (item)) - { - GitgActivatable *act = item->data; - gchar *id; - gboolean match; - - id = gitg_activatable_get_id (act); - match = g_strcmp0 (activatable, id) == 0; - g_free (id); - - if (match) - { - return activate_activatable (window, act, action); - } - } - - return FALSE; -} - -gboolean -gitg_window_load_repository (GitgWindow *window, - GFile *git_dir, - GFile *work_tree, - gint argc, - gchar const **argv, - gchar const *selection) -{ - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - - return load_repository (window, - git_dir, - work_tree, - argc, - argv, - selection); -} - -static GFile * -find_dot_git (GFile *location, - gboolean *from_first) -{ - location = g_file_dup (location); - - if (from_first) - { - *from_first = TRUE; - } - - do - { - GFile *tmp; - gboolean exists; - - tmp = g_file_get_child (location, ".git"); - exists = g_file_query_exists (tmp, NULL); - - if (exists) - { - g_object_unref (location); - location = tmp; - - break; - } - - if (from_first) - { - *from_first = FALSE; - } - - g_object_unref (tmp); - - tmp = g_file_get_parent (location); - - g_object_unref (location); - location = tmp; - } while (location != NULL); - - return location; -} - -static gboolean -load_repository_for_command_line (GitgWindow *window, - gint argc, - gchar const **argv, - gchar const *selection) -{ - gboolean ret = FALSE; - GFile *git_dir = NULL; - GFile *work_tree = NULL; - - if (argc > 0) - { - GFile *first_arg; - gchar *uri; - gchar *sel = NULL; - gchar *work_tree_path = NULL; - gchar *activatable = NULL; - gchar *action = NULL; - gboolean from_first; - - first_arg = g_file_new_for_commandline_arg (argv[0]); - uri = g_file_get_uri (first_arg); - - if (!gitg_uri_parse (uri, &work_tree_path, &sel, &activatable, &action)) - { - git_dir = find_dot_git (first_arg, &from_first); - } - else - { - work_tree = g_file_new_for_path (work_tree_path); - } - - g_free (uri); - - if (git_dir || (work_tree && g_file_query_exists (work_tree, NULL))) - { - gint offset; - - if (git_dir && !from_first) - { - offset = 0; - } - else - { - offset = 1; - } - - ret = load_repository (window, - git_dir, - work_tree, - argc - offset, - argv + offset, - selection ? selection : sel); - - if (ret && activatable) - { - gitg_window_activate (window, activatable, action); - } - } - - g_free (sel); - g_free (activatable); - g_free (action); - g_free (work_tree_path); - - g_object_unref (first_arg); - } - - if (!ret) - { - gchar *cwd = g_get_current_dir (); - - GFile *file = g_file_new_for_path (cwd); - git_dir = find_dot_git (file, NULL); - - g_free (cwd); - g_object_unref (file); - - ret = load_repository (window, - git_dir, - NULL, - argc, - argv, - selection); - } - - if (git_dir) - { - g_object_unref (git_dir); - } - - if (work_tree) - { - g_object_unref (work_tree); - } - - return ret; -} - -gboolean -gitg_window_load_repository_for_command_line (GitgWindow *window, - gint argc, - gchar const **argv, - gchar const *selection) -{ - gboolean ret; - - g_return_val_if_fail (GITG_IS_WINDOW (window), FALSE); - - gchar const *git_dir_path = g_getenv ("GIT_DIR"); - gchar const *work_tree_path = g_getenv ("GIT_WORK_TREE"); - - if (!git_dir_path && !work_tree_path) - { - return load_repository_for_command_line (window, argc, argv, selection); - } - - GFile *git_dir = NULL; - GFile *work_tree = NULL; - - if (git_dir_path) - { - git_dir = g_file_new_for_commandline_arg (git_dir_path); - } - - if (work_tree_path) - { - work_tree = g_file_new_for_commandline_arg (work_tree_path); - } - - ret = gitg_window_load_repository (window, - git_dir, - work_tree, - argc, - argv, - selection); - - if (git_dir) - { - g_object_unref (git_dir); - } - - if (work_tree) - { - g_object_unref (work_tree); - } - - return ret; -} - -void -gitg_window_show_commit (GitgWindow *window) -{ - g_return_if_fail (GITG_IS_WINDOW(window)); - - gtk_notebook_set_current_page (window->priv->notebook_main, 1); -} - -GitgRepository * -gitg_window_get_repository (GitgWindow *window) -{ - g_return_val_if_fail (GITG_IS_WINDOW(window), NULL); - - return window->priv->repository; -} - -void -on_file_quit (GtkAction *action, - GitgWindow *window) -{ - gtk_main_quit (); -} - -static void -on_open_dialog_response (GtkFileChooser *dialog, - gint response, - GitgWindow *window) -{ - if (response != GTK_RESPONSE_ACCEPT) - { - gtk_widget_destroy (GTK_WIDGET(dialog)); - - return; - } - - GFile *file = gtk_file_chooser_get_file (dialog); - gtk_widget_destroy (GTK_WIDGET(dialog)); - - load_repository (window, NULL, file, 0, NULL, NULL); - g_object_unref (file); -} - -void -on_file_open (GtkAction *action, - GitgWindow *window) -{ - if (window->priv->open_dialog) - { - gtk_window_present (GTK_WINDOW(window->priv->open_dialog)); - return; - } - - window->priv->open_dialog = gtk_file_chooser_dialog_new (_ ("Open git repository"), - GTK_WINDOW (window), - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, - GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(window->priv->open_dialog), TRUE); - g_object_add_weak_pointer (G_OBJECT(window->priv->open_dialog), (gpointer *)&(window->priv->open_dialog)); - gtk_window_present (GTK_WINDOW(window->priv->open_dialog)); - - g_signal_connect (window->priv->open_dialog, "response", G_CALLBACK(on_open_dialog_response), window); -} - -void -on_edit_copy (GtkAction *action, - GitgWindow *window) -{ - GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (window)); - - g_signal_emit_by_name (focus, "copy-clipboard", 0); -} - -void -on_edit_cut (GtkAction *action, - GitgWindow *window) -{ - GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (window)); - - g_signal_emit_by_name (focus, "cut-clipboard", 0); -} - -void -on_edit_paste (GtkAction *action, - GitgWindow *window) -{ - GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (window)); - - g_signal_emit_by_name (focus, "paste-clipboard", 0); -} - -void -on_view_refresh (GtkAction *action, - GitgWindow *window) -{ - if (window->priv->repository && - gitg_repository_exists (window->priv->repository)) - { - gitg_repository_reload (window->priv->repository); - } -} - -void -on_recent_open (GtkRecentChooser *chooser, - GitgWindow *window) -{ - gchar *uri = gtk_recent_chooser_get_current_uri (chooser); - GFile *work_tree = g_file_new_for_uri (uri); - g_free (uri); - - load_repository (window, NULL, work_tree, 0, NULL, NULL); - - g_object_unref (work_tree); -} - -void -on_help_about (GtkAction *action, - GitgWindow *window) -{ - static gchar const copyright[] = "Copyright \xc2\xa9 2009 Jesse van den Kieboom"; - static gchar const *authors[] = {"Jesse van den Kieboom ", NULL}; - static gchar const *comments = N_ ("gitg is a git repository viewer for gtk+/GNOME"); - - - gchar *path = gitg_dirs_get_data_filename ("icons", "gitg.svg", NULL); - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (path, NULL); - g_free (path); - - if (!pixbuf) - { - path = gitg_dirs_get_data_filename ("icons", "gitg128x128.png", NULL); - pixbuf = gdk_pixbuf_new_from_file (path, NULL); - g_free (path); - } - - gtk_show_about_dialog (GTK_WINDOW(window), - "authors", authors, - "copyright", copyright, - "comments", _ (comments), - "version", VERSION, - "website", PACKAGE_URL, - "website-label", "gitg homepage", - "logo", pixbuf, - "license-type", GTK_LICENSE_GPL_2_0, - NULL); - - if (pixbuf) - { - g_object_unref (pixbuf); - } -} - -static gboolean -find_lane_boundary (GitgWindow *window, - GtkTreePath *path, - gint cell_x, - gchar const **hash) -{ - GtkTreeModel *model = GTK_TREE_MODEL(window->priv->repository); - GtkTreeIter iter; - guint width; - GitgRevision *revision; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, 0, &revision, -1); - - /* Determine lane at cell_x */ - g_object_get (window->priv->renderer_path, "lane-width", &width, NULL); - guint laneidx = cell_x / width; - - GSList *lanes = gitg_revision_get_lanes (revision); - GitgLane *lane = (GitgLane *)g_slist_nth_data (lanes, laneidx); - gboolean ret; - - if (lane && GITG_IS_LANE_BOUNDARY(lane)) - { - if (hash) - *hash = ((GitgLaneBoundary *)lane)->hash; - - ret = TRUE; - } - else - { - ret = FALSE; - } - - gitg_revision_unref (revision); - return ret; -} - -static gboolean -is_boundary_from_event (GitgWindow *window, - GdkEventAny *event, - gint x, - gint y, - gchar const **hash) -{ - GtkTreePath *path; - GtkTreeViewColumn *column; - gint cell_x; - gint cell_y; - - if (event->window != gtk_tree_view_get_bin_window (window->priv->tree_view)) - return FALSE; - - gtk_tree_view_get_path_at_pos (window->priv->tree_view, - x, - y, - &path, - &column, - &cell_x, - &cell_y); - - if (!path) - return FALSE; - - /* First check on correct column */ - if (gtk_tree_view_get_column (window->priv->tree_view, 0) != column) - { - if (path) - gtk_tree_path_free (path); - - return FALSE; - } - - /* Check for lanes that have TYPE_END or TYPE_START and where the mouse - is actually placed */ - gboolean ret = find_lane_boundary (window, path, cell_x, hash); - gtk_tree_path_free (path); - - return ret; -} - -static gboolean -on_tree_view_motion (GtkTreeView *treeview, - GdkEventMotion *event, - GitgWindow *window) -{ - GdkWindow *win; - - win = gtk_widget_get_window (GTK_WIDGET (treeview)); - - if (is_boundary_from_event (window, (GdkEventAny *)event, event->x, event->y, NULL)) - { - gdk_window_set_cursor (win, window->priv->hand); - } - else - { - gdk_window_set_cursor (win, NULL); - } - - return FALSE; -} - -static gboolean -on_tree_view_button_release (GtkTreeView *treeview, - GdkEventButton *event, - GitgWindow *window) -{ - if (event->button != 1) - { - return FALSE; - } - - gchar const *hash; - - if (!is_boundary_from_event (window, - (GdkEventAny *)event, - event->x, - event->y, - &hash)) - { - return FALSE; - } - - goto_hash (window, hash); - return TRUE; -} - -void -on_edit_preferences (GtkAction *action, - GitgWindow *window) -{ - gitg_preferences_dialog_present (GTK_WINDOW(window)); -} - -void -on_repository_properties (GtkAction *action, - GitgWindow *window) -{ - gitg_repository_dialog_present (window); -} - -static void -on_push_activated (GtkAction *action, - GitgWindow *window) -{ - gchar const *remote = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_REMOTE_KEY); - gchar const *branch = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_BRANCH_KEY); - - gitg_window_add_branch_action (window, - gitg_branch_actions_push_remote (window, window->priv->popup_refs[0], remote, branch)); -} - -static void -on_rebase_activated (GtkAction *action, - GitgWindow *window) -{ - GitgRef *dest = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_KEY); - - gitg_window_add_branch_action (window, - gitg_branch_actions_rebase (window, - window->priv->popup_refs[0], - dest)); -} - -static void -on_merge_activated (GtkAction *action, - GitgWindow *window) -{ - GitgRef *dest = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_KEY); - - gitg_window_add_branch_action (window, - gitg_branch_actions_merge (window, - dest, - window->priv->popup_refs[0])); -} - -static void -on_stash_activated (GtkAction *action, - GitgWindow *window) -{ - GitgRef *dest = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_KEY); - - gitg_branch_actions_apply_stash (window, window->priv->popup_refs[0], dest); -} - -static void -get_tracked_ref (GitgWindow *window, - GitgRef *branch, - gchar **retremote, - gchar **retbranch) -{ - GitgConfig *config = gitg_config_new (window->priv->repository); - gchar *merge; - gchar *var; - - var = g_strconcat ("branch.", gitg_ref_get_shortname (branch), ".remote", NULL); - *retremote = gitg_config_get_value (config, var); - g_free (var); - - if (!*retremote || !**retremote) - { - g_free (*retremote); - *retremote = NULL; - - g_object_unref (config); - - return; - } - - var = g_strconcat ("branch.", gitg_ref_get_shortname (branch), ".merge", NULL); - merge = gitg_config_get_value (config, var); - g_free (var); - - g_object_unref (config); - - if (merge && g_str_has_prefix (merge, "refs/heads")) - { - *retbranch = g_strdup (merge + 11); - } - else - { - *retbranch = NULL; - } - - g_free (merge); -} - -static gboolean -repository_has_ref (GitgWindow *window, - gchar const *remote, - gchar const *branch) -{ - GSList *refs = gitg_repository_get_refs (window->priv->repository); - gchar *combined = g_strconcat (remote, "/", branch, NULL); - - while (refs) - { - GitgRef *r = (GitgRef *)refs->data; - - if (gitg_ref_get_ref_type (r) == GITG_REF_TYPE_REMOTE && - strcmp (gitg_ref_get_shortname (r), combined) == 0) - { - g_free (combined); - return TRUE; - } - - refs = g_slist_next (refs); - } - - g_free (combined); - return FALSE; -} - -static void -add_push_action (GitgWindow *window, - GtkActionGroup *group, - gchar const *remote, - gchar const *branch) -{ - gchar *acname = g_strconcat ("Push", remote, branch, "Action", NULL); - gchar *name; - - if (gtk_action_group_get_action (group, acname) != NULL) - { - /* No need for twice the same */ - g_free (acname); - return; - } - - if (repository_has_ref (window, remote, branch)) - { - name = g_strconcat (remote, "/", branch, NULL); - } - else - { - name = g_strconcat (remote, "/", branch, " (", _ ("new"), ")", NULL); - } - - GtkAction *pushac = gtk_action_new (acname, name, NULL, NULL); - gtk_action_group_add_action (group, pushac); - - gchar *nm = g_strconcat ("Push", remote, branch, NULL); - gtk_ui_manager_add_ui (window->priv->menus_ui_manager, - window->priv->merge_rebase_uid, - "/ui/ref_popup/Push/Placeholder", - nm, - acname, - GTK_UI_MANAGER_MENUITEM, - FALSE); - - g_object_set_data_full (G_OBJECT (pushac), - DYNAMIC_ACTION_DATA_REMOTE_KEY, - g_strdup (remote), - (GDestroyNotify)g_free); - - g_object_set_data_full (G_OBJECT (pushac), - DYNAMIC_ACTION_DATA_BRANCH_KEY, - g_strdup (branch), - (GDestroyNotify)g_free); - - g_signal_connect (pushac, - "activate", - G_CALLBACK (on_push_activated), - window); - - g_free (acname); - g_free (name); - g_free (nm); -} - -static void -update_merge_rebase (GitgWindow *window, - GitgRef *ref) -{ - if (window->priv->merge_rebase_uid != 0) - { - gtk_ui_manager_remove_ui (window->priv->menus_ui_manager, - window->priv->merge_rebase_uid); - } - - GtkActionGroup *ac = window->priv->merge_rebase_action_group; - - if (ac) - { - GList *actions = gtk_action_group_list_actions (ac); - GList *item; - - for (item = actions; item; item = g_list_next (item)) - { - gtk_action_group_remove_action (ac, (GtkAction *)item->data); - } - - g_list_free (actions); - } - - if (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH && - gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_STASH) - { - return; - } - - if (window->priv->merge_rebase_uid == 0) - { - window->priv->merge_rebase_uid = gtk_ui_manager_new_merge_id (window->priv->menus_ui_manager); - } - - if (ac == NULL) - { - ac = gtk_action_group_new ("GitgMergeRebaseActions"); - window->priv->merge_rebase_action_group = ac; - gtk_ui_manager_insert_action_group (window->priv->menus_ui_manager, - ac, - 0); - } - - GSList *refs = gitg_repository_get_refs (window->priv->repository); - GSList *item; - - for (item = refs; item; item = g_slist_next (item)) - { - GitgRef *r = GITG_REF (item->data); - - if (gitg_ref_get_ref_type (r) == GITG_REF_TYPE_BRANCH && !gitg_ref_equal (r, ref)) - { - gchar const *rname = gitg_ref_get_shortname (r); - - if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH) - { - gchar *rebase = g_strconcat ("Rebase", rname, "Action", NULL); - gchar *merge = g_strconcat ("Merge", rname, "Action", NULL); - - GtkAction *rebaseac = gtk_action_new (rebase, rname, NULL, NULL); - GtkAction *mergeac = gtk_action_new (merge, rname, NULL, NULL); - - g_object_set_data_full (G_OBJECT (rebaseac), - DYNAMIC_ACTION_DATA_KEY, - gitg_ref_copy (r), - (GDestroyNotify)gitg_ref_free); - g_object_set_data_full (G_OBJECT (mergeac), - DYNAMIC_ACTION_DATA_KEY, - gitg_ref_copy (r), - (GDestroyNotify)gitg_ref_free); - - g_signal_connect (rebaseac, - "activate", - G_CALLBACK (on_rebase_activated), - window); - g_signal_connect (mergeac, - "activate", - G_CALLBACK (on_merge_activated), - window); - - gtk_action_group_add_action (ac, rebaseac); - gtk_action_group_add_action (ac, mergeac); - - gchar *name = g_strconcat ("Rebase", rname, NULL); - - gtk_ui_manager_add_ui (window->priv->menus_ui_manager, - window->priv->merge_rebase_uid, - "/ui/ref_popup/Rebase/Placeholder", - name, - rebase, - GTK_UI_MANAGER_MENUITEM, - FALSE); - g_free (name); - - name = g_strconcat ("Merge", rname, NULL); - - gtk_ui_manager_add_ui (window->priv->menus_ui_manager, - window->priv->merge_rebase_uid, - "/ui/ref_popup/Merge/Placeholder", - name, - merge, - GTK_UI_MANAGER_MENUITEM, - FALSE); - g_free (name); - - g_object_unref (rebaseac); - g_object_unref (mergeac); - - g_free (rebase); - g_free (merge); - } - else - { - gchar *stash = g_strconcat ("Stash", rname, "Action", NULL); - - GtkAction *stashac = gtk_action_new (stash, rname, NULL, NULL); - - g_object_set_data_full (G_OBJECT (stashac), - DYNAMIC_ACTION_DATA_KEY, - gitg_ref_copy (r), - (GDestroyNotify)gitg_ref_free); - - g_signal_connect (stashac, - "activate", - G_CALLBACK (on_stash_activated), - window); - - gtk_action_group_add_action (ac, stashac); - - gchar *name = g_strconcat ("Stash", rname, NULL); - - gtk_ui_manager_add_ui (window->priv->menus_ui_manager, - window->priv->merge_rebase_uid, - "/ui/ref_popup/Stash/Placeholder", - name, - stash, - GTK_UI_MANAGER_MENUITEM, - FALSE); - g_free (name); - - g_object_unref (stashac); - } - } - } - - g_slist_free_full (refs, (GDestroyNotify)gitg_ref_free); - - if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH) - { - /* Get the tracked remote of this ref (if any) */ - gchar *remote = NULL; - gchar *branch = NULL; - - get_tracked_ref (window, ref, &remote, &branch); - - if (remote) - { - add_push_action (window, - ac, - remote, - branch ? branch : gitg_ref_get_shortname (ref)); - - g_free (remote); - g_free (branch); - } - - GSList const *ref_pushes = gitg_repository_get_ref_pushes (window->priv->repository, - ref); - - /* Get configured ref pushes */ - while (ref_pushes) - { - GitgRef *push_ref = ref_pushes->data; - - add_push_action (window, - ac, - gitg_ref_get_prefix (push_ref), - gitg_ref_get_local_name (push_ref)); - - ref_pushes = g_slist_next (ref_pushes); - } - - gchar **remotes = gitg_repository_get_remotes (window->priv->repository); - gchar **ptr = remotes; - - while (*ptr) - { - add_push_action (window, - ac, - *ptr, - gitg_ref_get_shortname (ref)); - - ++ptr; - } - - g_strfreev (remotes); - } - - gtk_ui_manager_ensure_update (window->priv->menus_ui_manager); -} - -static gboolean -has_local_ref (GitgWindow *window, - gchar const *name) -{ - GSList *refs = gitg_repository_get_refs (window->priv->repository); - GSList *item; - gboolean ret = FALSE; - - for (item = refs; item; item = g_slist_next (item)) - { - GitgRef *ref = GITG_REF (item->data); - - if (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH) - { - continue; - } - - gchar const *nm = gitg_ref_get_shortname (ref); - - if (g_strcmp0 (name, nm) == 0) - { - ret = TRUE; - break; - } - } - - g_slist_free_full (refs, (GDestroyNotify)gitg_ref_free); - - return ret; -} - -static gboolean -popup_ref (GitgWindow *window, - GdkEventButton *event) -{ - gint cell_x; - gint cell_y; - GtkTreePath *path; - GtkTreeViewColumn *column; - - GtkTreeView *tree_view = window->priv->tree_view; - - if (!gtk_tree_view_get_path_at_pos (tree_view, - (gint)event->x, - (gint)event->y, - &path, - &column, - &cell_x, - &cell_y)) - { - return FALSE; - } - - GtkCellRenderer *cell = gitg_utils_find_cell_at_pos (tree_view, column, path, cell_x); - - if (!cell || !GITG_IS_CELL_RENDERER_PATH (cell)) - { - return FALSE; - } - - GitgRef *ref = gitg_cell_renderer_path_get_ref_at_pos (GTK_WIDGET (tree_view), - GITG_CELL_RENDERER_PATH (cell), - cell_x, - NULL); - gtk_tree_path_free (path); - - if (!ref || (gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_BRANCH && - gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_REMOTE && - gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_STASH && - gitg_ref_get_ref_type (ref) != GITG_REF_TYPE_TAG)) - { - return FALSE; - } - - GtkWidget *popup = gtk_ui_manager_get_widget (window->priv->menus_ui_manager, - "/ui/ref_popup"); - - GtkAction *checkout = gtk_ui_manager_get_action (window->priv->menus_ui_manager, - "/ui/ref_popup/CheckoutAction"); - GtkAction *remove = gtk_ui_manager_get_action (window->priv->menus_ui_manager, - "/ui/ref_popup/RemoveAction"); - GtkAction *rename = gtk_ui_manager_get_action (window->priv->menus_ui_manager, - "/ui/ref_popup/RenameAction"); - - if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_REMOTE) - { - gchar const *local = gitg_ref_get_local_name (ref); - - if (!has_local_ref (window, local)) - { - gchar *label = g_strdup_printf (_ ("New local branch <%s>"), local); - - g_object_set (checkout, "label", label, NULL); - gtk_action_set_visible (checkout, TRUE); - g_free (label); - } - else - { - gtk_action_set_visible (checkout, FALSE); - } - - g_object_set (remove, "label", _ ("Remove remote branch"), NULL); - gtk_action_set_visible (rename, FALSE); - } - else if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_BRANCH) - { - g_object_set (checkout, "label", _ ("Checkout working copy"), NULL); - g_object_set (remove, "label", _ ("Remove local branch"), NULL); - gtk_action_set_visible (rename, TRUE); - g_object_set (rename, "label", _ ("Rename local branch"), NULL); - - GitgRef *working = gitg_repository_get_current_working_ref (window->priv->repository); - - gtk_action_set_visible (checkout, !gitg_ref_equal (working, ref)); - } - else if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_STASH) - { - g_object_set (remove, "label", _ ("Remove stash"), NULL); - gtk_action_set_visible (rename, FALSE); - gtk_action_set_visible (checkout, FALSE); - } - else if (gitg_ref_get_ref_type (ref) == GITG_REF_TYPE_TAG) - { - g_object_set (remove, "label", _ ("Remove tag"), NULL); - gtk_action_set_visible (rename, FALSE); - - if (!has_local_ref (window, gitg_ref_get_shortname (ref))) - { - gchar *label = g_strdup_printf (_ ("New local branch <%s>"), gitg_ref_get_shortname (ref)); - - g_object_set (checkout, "label", label, NULL); - gtk_action_set_visible (checkout, TRUE); - g_free (label); - } - else - { - gtk_action_set_visible (checkout, FALSE); - } - } - - update_merge_rebase (window, ref); - window->priv->popup_refs[0] = ref; - - gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, window, event->button, event->time); - return TRUE; -} - -static gboolean -consecutive_revisions (GitgWindow *window, - GList *rows) -{ - return FALSE; -} - -static void -on_cherry_pick_activated (GtkAction *action, - GitgWindow *window) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - - if (!rows || rows->next) - { - return; - } - - GtkTreeIter iter; - GitgRevision *rev; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)rows->data); - gtk_tree_model_get (model, &iter, 0, &rev, -1); - - GitgRef *ref = g_object_get_data (G_OBJECT (action), - DYNAMIC_ACTION_DATA_KEY); - - gitg_window_add_branch_action (window, - gitg_branch_actions_cherry_pick (window, - rev, - ref)); - - gitg_revision_unref (rev); - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -static void -update_cherry_pick (GitgWindow *window) -{ - if (window->priv->cherry_pick_uid != 0) - { - gtk_ui_manager_remove_ui (window->priv->menus_ui_manager, - window->priv->cherry_pick_uid); - } - - GtkActionGroup *ac = window->priv->cherry_pick_action_group; - - if (ac) - { - GList *actions = gtk_action_group_list_actions (ac); - GList *item; - - for (item = actions; item; item = g_list_next (item)) - { - gtk_action_group_remove_action (ac, (GtkAction *)item->data); - } - - g_list_free (actions); - } - - if (window->priv->cherry_pick_uid == 0) - { - window->priv->cherry_pick_uid = gtk_ui_manager_new_merge_id (window->priv->menus_ui_manager); - } - - if (ac == NULL) - { - ac = gtk_action_group_new ("GitgCherryPickActions"); - - window->priv->cherry_pick_action_group = ac; - - gtk_ui_manager_insert_action_group (window->priv->menus_ui_manager, - ac, - 0); - } - - GSList *refs = gitg_repository_get_refs (window->priv->repository); - GSList *item; - - for (item = refs; item; item = g_slist_next (item)) - { - GitgRef *r = GITG_REF (item->data); - - if (gitg_ref_get_ref_type (r) == GITG_REF_TYPE_BRANCH) - { - gchar const *rname = gitg_ref_get_shortname (r); - gchar *acname = g_strconcat ("CherryPick", rname, "Action", NULL); - - GtkAction *action = gtk_action_new (acname, rname, NULL, NULL); - - g_object_set_data_full (G_OBJECT (action), - DYNAMIC_ACTION_DATA_KEY, - gitg_ref_copy (r), - (GDestroyNotify)gitg_ref_free); - - g_signal_connect (action, - "activate", - G_CALLBACK (on_cherry_pick_activated), - window); - - gtk_action_group_add_action (ac, action); - - gchar *name = g_strconcat ("CherryPick", rname, NULL); - - gtk_ui_manager_add_ui (window->priv->menus_ui_manager, - window->priv->cherry_pick_uid, - "/ui/revision_popup/CherryPick/Placeholder", - name, - acname, - GTK_UI_MANAGER_MENUITEM, - FALSE); - g_free (name); - - g_object_unref (action); - g_free (acname); - } - } - - g_slist_free_full (refs, (GDestroyNotify)gitg_ref_free); -} - -static gboolean -popup_revision (GitgWindow *window, - GdkEventButton *event) -{ - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - GList *rows = gtk_tree_selection_get_selected_rows (selection, NULL); - - if (!rows) - { - return FALSE; - } - - gboolean show = FALSE; - - update_cherry_pick (window); - - GtkAction *tag; - - tag = gtk_ui_manager_get_action (window->priv->menus_ui_manager, - "/ui/revision_popup/TagAction"); - - GtkAction *squash; - - squash = gtk_ui_manager_get_action (window->priv->menus_ui_manager, - "/ui/revision_popup/SquashAction"); - - if (!rows->next) - { - GtkTreeModel *model; - GtkTreeIter iter; - GitgRevision *rev; - gchar sign; - - model = GTK_TREE_MODEL (window->priv->repository); - gtk_tree_model_get_iter (model, &iter, rows->data); - - gtk_tree_model_get (model, &iter, 0, &rev, -1); - - sign = gitg_revision_get_sign (rev); - gitg_revision_unref (rev); - - if (sign) - { - show = FALSE; - } - else - { - show = TRUE; - - gtk_action_set_visible (squash, FALSE); - gtk_action_set_visible (tag, TRUE); - } - } - else if (consecutive_revisions (window, rows)) - { - show = TRUE; - - gtk_action_set_visible (squash, TRUE); - gtk_action_set_visible (tag, FALSE); - } - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); - - if (!show) - { - return FALSE; - } - - gtk_menu_popup (GTK_MENU (gtk_ui_manager_get_widget (window->priv->menus_ui_manager, "/ui/revision_popup")), - NULL, - NULL, - NULL, - window, - event->button, - event->time); - - return TRUE; -} - -void -on_tree_view_rv_button_press_event (GtkWidget *widget, - GdkEvent *event, - GitgWindow *window) -{ - if (event->type == GDK_BUTTON_PRESS) - { - GdkEventButton *button = (GdkEventButton *)event; - - if (button->button == 3) - { - if (!popup_ref (window, button)) - { - popup_revision (window, button); - } - } - } -} - -void -on_checkout_branch_action_activate (GtkAction *action, - GitgWindow *window) -{ - if (gitg_branch_actions_checkout (window, window->priv->popup_refs[0])) - { - update_window_title (window); - } -} - -void -on_remove_branch_action_activate (GtkAction *action, - GitgWindow *window) -{ - gitg_branch_actions_remove (window, window->priv->popup_refs[0]); -} - -void -on_rename_branch_action_activate (GtkAction *action, - GitgWindow *window) -{ - gitg_branch_actions_rename (window, window->priv->popup_refs[0]); -} - -void -on_rebase_branch_action_activate (GtkAction *action, - GitgWindow *window) -{ - gint source; - - if (gitg_ref_get_ref_type (window->priv->popup_refs[0]) == GITG_REF_TYPE_REMOTE) - { - source = 1; - } - else - { - source = 0; - } - - gitg_window_add_branch_action (window, - gitg_branch_actions_rebase (window, - window->priv->popup_refs[source], - window->priv->popup_refs[!source])); -} - -void -on_merge_branch_action_activate (GtkAction *action, - GitgWindow *window) -{ - gitg_window_add_branch_action (window, - gitg_branch_actions_merge (window, - window->priv->popup_refs[0], - window->priv->popup_refs[1])); -} - -typedef struct -{ - GtkBuilder *builder; - GitgWindow *window; - GitgRevision *revision; -} TagInfo; - -static void -free_tag_info (TagInfo *info) -{ - g_object_unref (info->builder); - gitg_revision_unref (info->revision); - - g_slice_free (TagInfo, info); -} - -static void -on_new_branch_dialog_response (GtkWidget *dialog, - gint response, - TagInfo *info) -{ - gboolean destroy = TRUE; - - if (response == GTK_RESPONSE_ACCEPT) - { - gchar const *name = gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (info->builder, "entry_name"))); - - if (*name) - { - gchar *sha1 = gitg_revision_get_sha1 (info->revision); - - if (!gitg_branch_actions_create (info->window, sha1, name)) - { - destroy = FALSE; - } - - g_free (sha1); - } - else - { - GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (dialog), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _ ("Not all fields are correctly filled in")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", - _("Please make sure to fill in the branch name")); - - g_signal_connect (dlg, "response", G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dlg); - - destroy = FALSE; - } - } - - if (destroy) - { - free_tag_info (info); - gtk_widget_destroy (dialog); - } -} - -static void -on_tag_dialog_response (GtkWidget *dialog, - gint response, - TagInfo *info) -{ - gboolean destroy = TRUE; - - if (response == GTK_RESPONSE_ACCEPT) - { - gchar const *name = gtk_entry_get_text (GTK_ENTRY (gtk_builder_get_object (info->builder, "entry_name"))); - gboolean sign = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (info->builder, "check_button_sign"))); - - GtkTextView *view = GTK_TEXT_VIEW (gtk_builder_get_object (info->builder, "text_view_message")); - GtkTextIter start; - GtkTextIter end; - - gtk_text_buffer_get_bounds (gtk_text_view_get_buffer (view), &start, &end); - gchar *message = gtk_text_iter_get_text (&start, &end); - - const gchar *secondary_text = NULL; - - if (sign && (!*name || !*message)) - { - secondary_text = _ ("Please make sure to fill in both the tag name and the commit message"); - } - else if (!sign && !*name) - { - secondary_text = _ ("Please make sure to fill in the tag name"); - } - - if (secondary_text) - { - GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (dialog), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _ ("Not all fields are correctly filled in")); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", - secondary_text); - - g_signal_connect (dlg, "response", G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dlg); - - destroy = FALSE; - } - else - { - gchar *sha1 = gitg_revision_get_sha1 (info->revision); - if (!gitg_branch_actions_tag (info->window, - sha1, - name, - message, - sign)) - { - destroy = FALSE; - } - - g_free (sha1); - - g_settings_set_boolean (info->window->priv->hidden_settings, - "sign-tag", sign); - } - - g_free (message); - } - - if (destroy) - { - free_tag_info (info); - gtk_widget_destroy (dialog); - } -} - -typedef struct -{ - GitgWindow *window; - GList *revisions; -} FormatPatchInfo; - -static void -on_format_patch_response (GtkDialog *dialog, - gint response, - FormatPatchInfo *info) -{ - if (response == GTK_RESPONSE_ACCEPT) - { - if (!info->revisions->next) - { - gchar *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); - gboolean ret; - - ret = gitg_window_add_branch_action (info->window, - gitg_branch_actions_format_patch (info->window, - info->revisions->data, - uri)); - g_free (uri); - - if (!ret) - { - GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (dialog), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - _ ("Format patch failed for unknown reason")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), - "%s", - _("Please check if you have the right permissions to write the file")); - - g_signal_connect (dlg, "response", G_CALLBACK (gtk_widget_destroy), NULL); - gtk_widget_show (dlg); - } - } - else - { - /* TODO: implement once multiple selection is realized */ - } - } - - g_list_free_full (info->revisions, (GDestroyNotify)gitg_revision_unref); - g_slice_free (FormatPatchInfo, info); - - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -void -on_revision_format_patch_activate (GtkAction *action, - GitgWindow *window) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - - GtkWidget *dialog = NULL; - - if (!rows->next) - { - GtkTreeIter iter; - GitgRevision *revision; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)rows->data); - gtk_tree_model_get (model, &iter, 0, &revision, -1); - - /* Single one, pick filename */ - dialog = gtk_file_chooser_dialog_new (_ ("Save format patch"), - GTK_WINDOW (window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), - TRUE); - - gchar *name = gitg_revision_get_format_patch_name (revision); - gchar *filename = g_strdup_printf ("0001-%s.patch", name); - - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename); - g_free (filename); - g_free (name); - - gitg_revision_unref (revision); - } - else - { - /* TODO: Implement selecting folder once multiple selection is realized */ - } - - GFile *work_tree = gitg_repository_get_work_tree (window->priv->repository); - - gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (dialog), - work_tree, - NULL); - - g_object_unref (work_tree); - - FormatPatchInfo *info = g_slice_new (FormatPatchInfo); - info->window = window; - info->revisions = NULL; - - GList *item; - - for (item = rows; item; item = g_list_next (item)) - { - GtkTreeIter iter; - GitgRevision *revision; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)rows->data); - gtk_tree_model_get (model, &iter, 0, &revision, -1); - - info->revisions = g_list_prepend (info->revisions, revision); - } - - info->revisions = g_list_reverse (info->revisions); - - g_signal_connect (dialog, - "response", - G_CALLBACK (on_format_patch_response), - info); - - gtk_widget_show (dialog); - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -void -on_revision_new_branch_activate (GtkAction *action, - GitgWindow *window) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - - if (rows && !rows->next) - { - GtkBuilder *builder = gitg_utils_new_builder ("gitg-new-branch.ui"); - GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_branch")); - - gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (window)); - - GtkTreeIter iter; - GitgRevision *rev; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)rows->data); - gtk_tree_model_get (model, &iter, 0, &rev, -1); - - TagInfo *info = g_slice_new (TagInfo); - - info->revision = gitg_revision_ref (rev); - info->window = window; - info->builder = builder; - - g_signal_connect (widget, - "response", - G_CALLBACK (on_new_branch_dialog_response), - info); - - gtk_widget_show (widget); - - gtk_widget_grab_focus (GTK_WIDGET (gtk_builder_get_object (builder, "entry_name"))); - gitg_revision_unref (rev); - } - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -void -on_revision_tag_activate (GtkAction *action, - GitgWindow *window) -{ - GtkTreeSelection *selection; - GtkTreeModel *model; - - selection = gtk_tree_view_get_selection (window->priv->tree_view); - GList *rows = gtk_tree_selection_get_selected_rows (selection, &model); - - if (rows && !rows->next) - { - GtkBuilder *builder = gitg_utils_new_builder ("gitg-tag.ui"); - GtkWidget *widget = GTK_WIDGET (gtk_builder_get_object (builder, "dialog_tag")); - - GtkToggleButton *toggle = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "check_button_sign")); - - gboolean active; - - active = g_settings_get_boolean (window->priv->hidden_settings, - "sign-tag"); - gtk_toggle_button_set_active (toggle, active); - - gtk_window_set_transient_for (GTK_WINDOW (widget), GTK_WINDOW (window)); - - GtkTreeIter iter; - GitgRevision *rev; - - gtk_tree_model_get_iter (model, &iter, (GtkTreePath *)rows->data); - gtk_tree_model_get (model, &iter, 0, &rev, -1); - - TagInfo *info = g_slice_new (TagInfo); - - info->revision = gitg_revision_ref (rev); - info->window = window; - info->builder = builder; - - g_signal_connect (widget, - "response", - G_CALLBACK (on_tag_dialog_response), - info); - - gtk_widget_show (widget); - - gtk_widget_grab_focus (GTK_WIDGET (gtk_builder_get_object (builder, "entry_name"))); - gitg_revision_unref (rev); - } - - g_list_free_full (rows, (GDestroyNotify)gtk_tree_path_free); -} - -void -on_revision_squash_activate (GtkAction *action, - GitgWindow *window) -{ - -} diff --git a/gitg/gitg-window.h b/gitg/gitg-window.h deleted file mode 100644 index 3245013f..00000000 --- a/gitg/gitg-window.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * gitg-window.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_WINDOW_H__ -#define __GITG_WINDOW_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_WINDOW (gitg_window_get_type ()) -#define GITG_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_WINDOW, GitgWindow)) -#define GITG_WINDOW_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_WINDOW, GitgWindow const)) -#define GITG_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_WINDOW, GitgWindowClass)) -#define GITG_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_WINDOW)) -#define GITG_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_WINDOW)) -#define GITG_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_WINDOW, GitgWindowClass)) - -typedef struct _GitgWindow GitgWindow; -typedef struct _GitgWindowClass GitgWindowClass; -typedef struct _GitgWindowPrivate GitgWindowPrivate; - -struct _GitgWindow -{ - GtkWindow parent; - - GitgWindowPrivate *priv; -}; - -struct _GitgWindowClass -{ - GtkWindowClass parent_class; -}; - -GType gitg_window_get_type (void) G_GNUC_CONST; - -gboolean gitg_window_load_repository (GitgWindow *window, - GFile *git_dir, - GFile *work_tree, - gint argc, - gchar const **argv, - gchar const *selection); - -gboolean gitg_window_load_repository_for_command_line (GitgWindow *window, - gint argc, - gchar const **argv, - gchar const *selection); - -gboolean gitg_window_load_repository_from_environment (GitgWindow *window, - gint argc, - gchar const **argv, - gchar const *selection); - -void gitg_window_show_commit (GitgWindow *window); - -GitgRepository *gitg_window_get_repository (GitgWindow *window); -void gitg_window_set_select_on_load (GitgWindow *window, gchar const *selection); - -gboolean gitg_window_add_branch_action (GitgWindow *window, GitgShell *shell); - -gboolean gitg_window_select (GitgWindow *window, gchar const *selection); -gboolean gitg_window_activate (GitgWindow *window, gchar const *activatable, gchar const *action); - -G_END_DECLS - -#endif /* __GITG_WINDOW_H__ */ diff --git a/gitg/gitg-window.ui b/gitg/gitg-window.ui deleted file mode 100644 index 46bc3539..00000000 --- a/gitg/gitg-window.ui +++ /dev/null @@ -1,576 +0,0 @@ - - - - - - - - 3 - 1 - 10 - 1 - 1 - 1 - - - gitg - 800 - 800 - - - True - vertical - - - True - True - - - True - vertical - - - True - True - 350 - - - True - 6 - vertical - - - True - 3 - horizontal - - - Branch: - - - False - 0 - - - - - - - - 2 - - - - - - 0 - - - - - False - 1 - - - - - False - 3 - 0 - - - - - True - True - automatic - automatic - etched-in - - - True - True - True - 1 - True - True - - - - True - fixed - 400 - Subject - True - - - - 1 - - - - - - - True - fixed - 200 - Author - - - - 2 - - - - - - - True - fixed - 200 - Date - - - - 3 - - - - - - - - - 1 - - - - - True - False - - - - - True - True - 6 - - - False - True - - - - - 0 - - - - - - - True - History - - - False - - - - - True - True - 6 - vertical - 450 - True - - - True - vertical - 3 - - - True - 3 - horizontal - - - True - 0 - 1 - Changes - source_view_changes - - - False - 0 - - - - - Context: - - - False - end - 2 - - - - - 200 - False - True - adjustment_context - 0 - right - - - False - end - 1 - - - - - False - 0 - - - - - True - True - automatic - automatic - etched-in - - - True - False - 2 - 2 - False - False - 4 - True - - - - - 1 - - - - - False - True - - - - - True - True - - - True - vertical - 3 - - - True - 0 - 1 - _Unstaged - True - tree_view_unstaged - - - False - 0 - - - - - True - True - automatic - automatic - etched-in - - - True - True - False - False - True - - - fixed - 20 - - - - - - - - True - Unstaged - - - - 0 - - - - - - - - - 1 - - - - - False - False - - - - - True - True - - - True - vertical - 3 - - - True - 0 - 1 - Co_mmit message - True - text_view_comment - - - False - 0 - - - - - True - True - automatic - automatic - etched-in - - - True - True - word-char - 2 - 2 - True - - - - - 1 - - - - - True - 3 - horizontal - - - True - vertical - - - Amend - True - False - True - - - False - 0 - - - - - Add signed-off-by - True - False - True - - - False - 1 - - - - - 1 - - - - - True - 1 - 0 - - - _Commit - True - True - True - image_commit - True - - - - - False - False - end - 0 - - - - - False - 2 - - - - - True - False - - - - - True - vertical - 3 - - - True - 0 - _Staged - True - tree_view_staged - - - False - 0 - - - - - True - True - automatic - automatic - etched-in - - - True - True - False - False - True - - - fixed - 20 - - - - - - - - True - - - - 0 - - - - - - - - - 1 - - - - - False - False - - - - - True - False - - - - - True - True - - - - - 1 - - - - - True - Commit - - - 1 - False - - - - - 1 - - - - - True - 2 - - - False - 2 - - - - - - - True - gtk-apply - - diff --git a/gitg/gitg-window.vala b/gitg/gitg-window.vala new file mode 100644 index 00000000..80d176b4 --- /dev/null +++ b/gitg/gitg-window.vala @@ -0,0 +1,457 @@ +namespace Gitg +{ + +public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable, Gtk.Buildable +{ + private class ActiveView + { + public GitgExt.View view; + public Gtk.RadioToolButton? navigation_button; + + public ActiveView(GitgExt.View v) + { + view = v; + } + } + + private Repository? d_repository; + private GitgExt.MessageBus d_message_bus; + private Peas.ExtensionSet d_extensions_view; + private Peas.ExtensionSet d_extensions_navigation; + private GitgExt.View? d_current_view; + private HashTable d_view_map; + private GitgExt.ViewAction d_action; + + private HashTable d_active_views; + + // Widgets + private Gtk.Toolbar d_topnav; + private Gtk.Toolbar d_subnav; + private Gtk.Paned d_paned; + private Gtk.Paned d_panels; + private Gtk.Notebook d_notebook_panels; + private GitgExt.NavigationTreeView d_navigation; + private Gtk.Frame d_main_frame; + + public GitgExt.View? current_view + { + owned get { return d_current_view; } + } + + public GitgExt.MessageBus message_bus + { + owned get { return d_message_bus; } + } + + public Repository? repository + { + owned get { return d_repository; } + } + + private Gtk.RadioToolButton? create_topnav_button(GitgExt.View v) + { + Icon? icon = v.icon; + + if (icon == null) + { + return null; + } + + var img = new Gtk.Image.from_gicon(icon, d_topnav.get_icon_size()); + img.show(); + + Gtk.RadioToolButton button; + + if (d_topnav.get_n_items() != 0) + { + var ic = d_topnav.get_nth_item(0); + button = new Gtk.RadioToolButton.from_widget(ic as Gtk.RadioToolButton); + } + else + { + button = new Gtk.RadioToolButton(null); + } + + button.set_icon_widget(img); + button.set_label(v.display_name); + + button.show(); + + return button; + } + + private void add_view(GitgExt.View v) + { + // Add a navigation button if needed + Gtk.RadioToolButton? button = create_topnav_button(v); + ActiveView av = new ActiveView(v); + + av.navigation_button = button; + + if (button != null) + { + d_topnav.add(button); + } + + button.toggled.connect((b) => { + if (b.active) + { + set_view(v); + } + }); + + d_active_views.insert(v.id, av); + } + + private void set_view(GitgExt.View v) + { + /* This function updates the view to @v. The following steps are + * involved: + * + * 1) Clear navigation tree + * 2) Remove all panels and panel navigation widgets + * 3) Remove main view widget + * 3) Hide panels and panel navigation + * 4) Set the current view to @v + * 5) Fill the navigation model with navigation from @v (if needed) + * 6) Query nagivation extensions to fill the navigation model + */ + + if (d_current_view == v) + { + return; + } + + d_navigation.model.clear(); + + // Remove panel widgets + while (d_notebook_panels.get_n_pages() > 0) + { + d_notebook_panels.remove_page(0); + } + + // Remove panel navigation buttons + while (d_subnav.get_n_items() > 0) + { + d_subnav.remove(d_subnav.get_nth_item(0)); + } + + var child = d_main_frame.get_child(); + if (child != null) + { + d_main_frame.remove(child); + } + + // Hide panel note book and panel navigation toolbar + d_notebook_panels.hide(); + d_subnav.hide(); + + if (d_current_view != null) + { + var av = d_active_views.lookup(d_current_view.id); + + if (av != null) + { + av.navigation_button.set_active(false); + } + } + + // Set the current view + d_current_view = v; + + // Populate navigation from the view first + GitgExt.Navigation? nav = v.navigation; + + if (nav != null) + { + d_navigation.model.populate(nav); + } + + // Populate navigation from the extensions + d_extensions_navigation.foreach((s, info, obj) => { + nav = obj as GitgExt.Navigation; + + if (nav.available) + { + d_navigation.model.populate(nav); + } + }); + + // Expand all the navigation by default + d_navigation.expand_all(); + + // Select the first item of the navigation list + d_navigation.select_first(); + + // Set the main widget + var widget = v.widget; + + if (widget != null) + { + widget.show(); + d_main_frame.add(widget); + } + + var av = d_active_views.lookup(v.id); + + if (av.navigation_button != null) + { + + av.navigation_button.set_active(true); + } + } + + private void remove_view(GitgExt.View v, bool update_current) + { + ActiveView av; + + if (d_active_views.lookup_extended(v.id, null, out av)) + { + av.navigation_button.destroy(); + + d_view_map.remove(v.id); + d_active_views.remove(v.id); + + if (av.view == d_current_view) + { + d_current_view = null; + + if (update_current) + { + activate_default_view(); + } + } + } + } + + private void extension_view_added(Peas.ExtensionSet s, + Peas.PluginInfo info, + Object obj) + { + GitgExt.View v = obj as GitgExt.View; + + d_view_map.insert(v.id, v); + + if (v.is_available()) + { + add_view(v); + } + } + + private void extension_view_removed(Peas.ExtensionSet s, + Peas.PluginInfo info, + Object obj) + { + remove_view(obj as GitgExt.View, true); + } + + private void update_nav_visibility(Gtk.Toolbar tb) + { + tb.visible = (tb.get_n_items() > 1); + } + + private void parser_finished(Gtk.Builder builder) + { + d_topnav = builder.get_object("toolbar_topnav") as Gtk.Toolbar; + d_subnav = builder.get_object("toolbar_subnav") as Gtk.Toolbar; + d_paned = builder.get_object("paned_main") as Gtk.Paned; + d_panels = builder.get_object("paned_panel") as Gtk.Paned; + d_main_frame = builder.get_object("frame_main") as Gtk.Frame; + + d_navigation = builder.get_object("tree_view_navigation") as GitgExt.NavigationTreeView; + d_notebook_panels = builder.get_object("notebook_panels") as Gtk.Notebook; + + d_topnav.add.connect((t, widget) => { + update_nav_visibility(d_topnav); + }); + + d_topnav.remove.connect((t, widget) => { + update_nav_visibility(d_topnav); + }); + + d_subnav.add.connect((t, widget) => { + update_nav_visibility(d_subnav); + }); + + d_subnav.remove.connect((t, widget) => { + update_nav_visibility(d_subnav); + }); + + base.parser_finished(builder); + } + + private bool init(Cancellable? cancellable) + { + // Setup message bus + d_message_bus = new GitgExt.MessageBus(); + + // Initialize peas extensions set for views + var engine = PluginsEngine.get_default(); + + d_extensions_view = new Peas.ExtensionSet(engine, + typeof(GitgExt.View), + "application", + this); + + d_extensions_navigation = new Peas.ExtensionSet(engine, + typeof(GitgExt.Navigation), + "application", + this); + + d_view_map = new HashTable(str_hash, str_equal); + d_active_views = new HashTable(str_hash, str_equal); + + // Add all the extensions + d_extensions_view.foreach(extension_view_added); + + d_extensions_view.extension_added.connect(extension_view_added); + d_extensions_view.extension_removed.connect(extension_view_removed); + + activate_default_view(); + + return true; + } + + public static Window? create_new(Gtk.Application app, + Repository repository, + GitgExt.ViewAction action) + { + Window? ret = Resource.load_object("ui/gitg-window.ui", "window"); + + if (ret != null) + { + ret.d_repository = repository; + ret.d_action = action; + } + + try + { + ((Initable)ret).init(null); + } catch {} + + return ret; + } + + private void activate_default_view() + { + GitgExt.View? def = null; + + // Activate the default view + d_extensions_view.foreach((s, info, obj) => { + GitgExt.View v = obj as GitgExt.View; + + if (d_active_views.lookup_extended(v.id, null, null)) + { + if (v.is_default_for(d_action)) + { + set_view(v); + def = null; + return; + } + else if (def == null) + { + def = v; + } + } + }); + + if (def != null) + { + set_view(def); + } + } + + private void update_views() + { + /* This method is called after some state has changed and thus a new + * set of views needs to be computed. Currently the only state change + * is opening or closing a repository. + */ + + // Now see if new views became available + d_extensions_view.foreach((s, info, obj) => { + GitgExt.View v = obj as GitgExt.View; + + bool isavail = v.is_available(); + bool isactive = d_active_views.lookup_extended(v.id, null, null); + + if (isavail == isactive) + { + return; + } + + if (isactive) + { + // should be inactive + remove_view(v, false); + } + else + { + add_view(v); + } + }); + + activate_default_view(); + } + + /* public API implementation of GitgExt.Application */ + public GitgExt.View? view(string id) + { + GitgExt.View v; + + if (d_view_map.lookup_extended(id, null, out v)) + { + set_view(v); + } + + return null; + } + + public void open(File path) + { + File repo; + + if (d_repository != null && + d_repository.get_location().equal(path)) + { + return; + } + + try + { + repo = Ggit.Repository.discover(path); + } + catch + { + // TODO + return; + } + + if (d_repository != null) + { + close(); + } + + try + { + d_repository = new Gitg.Repository(repo, null); + } + catch {} + + update_views(); + } + + public void create(File path) + { + // TODO + } + + public void close() + { + // TODO + } +} + +} + +// ex:ts=4 noet diff --git a/gitg/gitg.c b/gitg/gitg.c deleted file mode 100644 index 0355b690..00000000 --- a/gitg/gitg.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * gitg.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "gitg-window.h" -#include "config.h" -#include "gitg-dirs.h" -#include "gitg-utils.h" -#include "gitg-uri.h" - -static gboolean commit_mode = FALSE; -static gchar *select_sha1 = NULL; - -static void -show_version_and_quit (void) -{ - g_print ("%s - Version %s\n", g_get_application_name (), VERSION); - - exit (0); -} - -static GOptionEntry entries[] = -{ - { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - show_version_and_quit, N_("Show the application's version"), NULL }, - { "commit", 'c', 0, G_OPTION_ARG_NONE, &commit_mode, N_("Start gitg in commit mode") }, - { "select", 's', 0, G_OPTION_ARG_STRING, &select_sha1, N_("Select commit after loading the repository") }, - { NULL } -}; - -static void -parse_options (int *argc, char ***argv) -{ - GError *error = NULL; - GOptionContext *context; - - context = g_option_context_new (_("- git repository viewer")); - - // Ignore unknown options so we can pass them to git - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - - if (!g_option_context_parse (context, argc, argv, &error)) - { - g_print ("option parsing failed: %s\n", error->message); - g_error_free (error); - exit (1); - } - - g_option_context_free(context); -} - -static gboolean -on_window_delete_event (GtkWidget *widget, gpointer userdata) -{ - gtk_main_quit (); - return FALSE; -} - -static GitgWindow * -build_ui () -{ - GtkBuilder *builder = gitg_utils_new_builder ("gitg-window.ui"); - - GtkWidget *window = GTK_WIDGET (gtk_builder_get_object(builder, "window")); - gtk_widget_show_all (window); - - g_signal_connect_after (window, "destroy", G_CALLBACK (on_window_delete_event), NULL); - g_object_unref (builder); - - return GITG_WINDOW (window); -} - -static void -set_language_search_path () -{ - GtkSourceLanguageManager *manager = gtk_source_language_manager_get_default (); - gchar const * const *orig = gtk_source_language_manager_get_search_path (manager); - gchar const **dirs = g_new0 (gchar const *, g_strv_length ((gchar **)orig) + 2); - guint i = 0; - - while (orig[i]) - { - dirs[i + 1] = orig[i]; - ++i; - } - - gchar *path = gitg_dirs_get_data_filename ("language-specs", NULL); - dirs[0] = path; - gtk_source_language_manager_set_search_path (manager, (gchar **)dirs); - g_free (path); - - g_free (dirs); -} - -static void -set_style_scheme_search_path () -{ - GtkSourceStyleSchemeManager *manager = gtk_source_style_scheme_manager_get_default (); - - gchar *path = gitg_dirs_get_data_filename ("styles", NULL); - gtk_source_style_scheme_manager_prepend_search_path (manager, path); - g_free (path); -} - -static void -set_icons () -{ - static gchar const *icon_infos[] = { - "gitg16x16.png", - "gitg22x22.png", - "gitg24x24.png", - "gitg32x32.png", - "gitg48x48.png", - "gitg64x64.png", - "gitg128x128.png", - NULL - }; - - int i; - GList *icons = NULL; - - for (i = 0; icon_infos[i]; ++i) - { - gchar *filename = gitg_dirs_get_data_filename ("icons", icon_infos[i], NULL); - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL); - g_free (filename); - - if (pixbuf) - { - icons = g_list_prepend (icons, pixbuf); - } - } - - gtk_window_set_default_icon_list (icons); - - g_list_free_full (icons, g_object_unref); -} - -int -main (int argc, char **argv) -{ - gboolean ret; - - gitg_debug_init (); - - bindtextdomain (GETTEXT_PACKAGE, GITG_LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - g_set_prgname ("gitg"); - - /* Translators: this is the application name as in g_set_application_name */ - g_set_application_name (_("gitg")); - - gitg_dirs_initialize (argc, argv); - gtk_init (&argc, &argv); - parse_options (&argc, &argv); - - set_language_search_path (); - set_style_scheme_search_path (); - set_icons (); - - GitgWindow *window = build_ui (); - - ret = gitg_window_load_repository_for_command_line (window, - argc - 1, - (gchar const **)argv + 1, - select_sha1); - - if (commit_mode && ret) - { - gitg_window_show_commit (window); - } - - gtk_main (); - - return 0; -} diff --git a/gitg/gitg.vala b/gitg/gitg.vala new file mode 100644 index 00000000..19d2428b --- /dev/null +++ b/gitg/gitg.vala @@ -0,0 +1,25 @@ +namespace Gitg +{ + +private const string version = Config.VERSION; + +public class Main +{ + public static int main(string[] args) + { + Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.GITG_LOCALEDIR); + Intl.textdomain(Config.GETTEXT_PACKAGE); + + Environment.set_prgname("gitg"); + Environment.set_application_name(_("gitg")); + + Gitg.init(); + + Application app = new Application(); + return app.run(args); + } +} + +} + +// ex:set ts=4 noet diff --git a/gitg/resources/gitg-resources.xml b/gitg/resources/gitg-resources.xml new file mode 100644 index 00000000..4700c6bf --- /dev/null +++ b/gitg/resources/gitg-resources.xml @@ -0,0 +1,10 @@ + + + + ui/gitg-window.ui + ui/gitg-menus.ui + ui/style.css + + + + diff --git a/gitg/resources/ui/gitg-menus.ui b/gitg/resources/ui/gitg-menus.ui new file mode 100644 index 00000000..cab18051 --- /dev/null +++ b/gitg/resources/ui/gitg-menus.ui @@ -0,0 +1,33 @@ + + + + +
+ + _New Window + app.new + <Primary>n + +
+
+ + _Help + app.help + F1 + + + _About + app.about + +
+
+ + _Quit + app.quit + <Primary>q + +
+
+ + +
diff --git a/gitg/resources/ui/gitg-window.ui b/gitg/resources/ui/gitg-window.ui new file mode 100644 index 00000000..cddb1dc0 --- /dev/null +++ b/gitg/resources/ui/gitg-window.ui @@ -0,0 +1,138 @@ + + + + + + False + gitg + 800 + 600 + + + True + True + 200 + True + paned_main + + + True + navigation_background + + + True + False + grid_navigation + True + fill + + + True + False + icons + 1 + True + fill + toolbar_topnav + False + + + + 0 + 0 + 1 + 1 + + + + + True + True + never + true + true + none + scrolled_window_navigation + + + True + False + tree_view_navigation + + + + + 0 + 1 + 1 + 1 + + + + + True + False + icons + True + 2 + toolbar_subnav + + + + 0 + 2 + 1 + 1 + + + + + + + False + True + + + + + True + True + vertical + + + True + frame_background + + + True + False + in + frame_main + + + + + + + + + + True + + + + + True + True + + + + + + + + diff --git a/gitg/resources/ui/style.css b/gitg/resources/ui/style.css new file mode 100644 index 00000000..5d934b1a --- /dev/null +++ b/gitg/resources/ui/style.css @@ -0,0 +1,56 @@ +GtkToolbar#toolbar_topnav, GtkToolbar#toolbar_subnav { + border-left: 0px; + border-right: 0px; +} + +GtkToolbar#toolbar_subnav { + border-bottom: 0px; +} + +#navigation_background { + background-color: shade(@theme_bg_color, 0.85); + background-image: none; +} + +#tree_view_navigation { + background-color: inherit; + background-image: none; + color: inherit; + background-color: shade(@theme_bg_color, 0.9); +} + +#paned_main { + border-style: solid; + border-color: @borders; + border-width: 0px 0px 0px 1px; + padding: 0px; + border-radius: 0px; + background-color: inherit; +} + +#tree_view_navigation.view:selected { + background-color: @theme_selected_bg_color; + color: @theme_selected_fg_color; +} + +#frame_main { + padding: 0px 6px 6px 6px; +} + +GtkLabel.title { + font-weight: bold; + font-size: 16; + color: @insensitive_fg_color; + text-shadow: 1 1 @theme_base_color; +} + +GtkLabel.description { + padding-bottom: 12px; + color: @insensitive_fg_color; +} + +GtkLabel.grid_title { + font-weight: bold; + + text-shadow: 1 1 @theme_base_color; +} diff --git a/libgit2 b/libgit2 new file mode 160000 index 00000000..242a1cea --- /dev/null +++ b/libgit2 @@ -0,0 +1 @@ +Subproject commit 242a1cea8d66d9ec185044f345b22fec1940178f diff --git a/libgit2-glib b/libgit2-glib new file mode 160000 index 00000000..1a17238b --- /dev/null +++ b/libgit2-glib @@ -0,0 +1 @@ +Subproject commit 1a17238b82e5d4ab65be78d90f356d2bf4aba912 diff --git a/libgitg-ext/GitgExt.py b/libgitg-ext/GitgExt.py new file mode 100644 index 00000000..976a4453 --- /dev/null +++ b/libgitg-ext/GitgExt.py @@ -0,0 +1,38 @@ +from gi.repository import GObject +from ..overrides import override +from ..importer import modules + +GitgExt = modules['GitgExt']._introspection_module +__all__ = [] + +class MessageBus(GitgExt.MessageBus): + def create(self, msgid, **kwargs): + tp = self.lookup(msgid) + + if not tp.is_a(GitgExt.Message.__gtype__): + return None + + kwargs['id'] = msgid + + return GObject.new(tp, **kwargs) + + def send(self, msgid, **kwargs): + msg = self.create(msgid, **kwargs) + self.send_message(msg) + + return msg + +MessageBus = override(MessageBus) +__all__.append('MessageBus') + +class Message(Gedit.Message): + def __getattribute__(self, name): + try: + return Gedit.Message.__getattribute__(self, name) + except: + return getattr(self.props, name) + +Message = override(Message) +__all__.append('Message') + +# vi:ex:ts=4:et diff --git a/libgitg-ext/Makefile.am b/libgitg-ext/Makefile.am new file mode 100644 index 00000000..37cad6c6 --- /dev/null +++ b/libgitg-ext/Makefile.am @@ -0,0 +1,100 @@ +lib_LTLIBRARIES = libgitg-ext-1.0.la + +INCLUDES = \ + -I$(top_srcdir) \ + -I$(srcdir) \ + $(LIBGITG_EXT_CFLAGS) \ + $(WARN_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + -DLIBDIR=\""$(libdir)"\" + +VALAFLAGS = \ + --pkg Ggit-1.0 \ + --pkg Gitg-1.0 \ + --pkg gio-2.0 \ + --pkg gtk+-3.0 \ + --header libgitg-ext.h \ + --includedir libgitg-ext \ + --basedir $(top_srcdir) \ + --gir GitgExt-1.0.gir \ + --library libgitg-ext-1.0 + +libgitg_ext_1_0_la_LDFLAGS = \ + -export-dynamic -no-undefined -export-symbols-regex "^[^_].*" + +libgitg_ext_1_0_la_LIBADD = $(LIBGITG_EXT_LIBS) + +INST_H_FILES = \ + libgitg-ext.h + +VALA_FILES = \ + gitg-ext-application.vala \ + gitg-ext-panel.vala \ + gitg-ext-view.vala \ + gitg-ext-navigation.vala \ + gitg-ext-navigation-tree-view.vala \ + gitg-ext-message-id.vala \ + gitg-ext-message.vala \ + gitg-ext-message-bus.vala + +libgitg_ext_1_0_la_SOURCES = \ + $(VALA_FILES) \ + gitg-ext-resources.c + +headerdir = $(prefix)/include/libgitg-ext-1.0/libgitg-ext +header_DATA = $(INST_H_FILES) + +GitgExt-1.0.gir: libgitg-ext-1.0.la + +# Ignore all warnings for vala code... +libgitg_ext_1_0_la_CFLAGS = \ + -w + +girdir = $(INTROSPECTION_GIRDIR) +gir_DATA = GitgExt-1.0.gir + +typelibdir = $(INTROSPECTION_TYPELIBDIR) +typelib_DATA = GitgExt-1.0.typelib + +%.typelib: %.gir + $(INTROSPECTION_COMPILER) $(INTROSPECTION_COMPILER_ARGS) --includedir=. -o $@ $< + +if ENABLE_PYTHON +overridesdir = $(pyoverridesdir) +overrides_PYTHON = \ + GitgExt.py +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libgitg-ext-1.0.pc + +gitg-ext-resources.c: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-source \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +gitg-ext-resources.h: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-header \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +BUILT_SOURCES = \ + $(gir_DATA) \ + libgitg-ext.h \ + gitg-ext-resources.c \ + gitg-ext-resources.h + +EXTRA_DIST = \ + $(pkgconfig_DATA) \ + resources/resources.xml \ + $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + +CLEANFILES = \ + $(VALA_FILES:.vala=.c) \ + GitgExt-1.0.gir \ + GitgExt-1.0.typelib + +dist-hook: + cd $(distdir); rm -f $(BUILT_SOURCES) + +-include $(top_srcdir)/git.mk diff --git a/libgitg-ext/gitg-ext-application.vala b/libgitg-ext/gitg-ext-application.vala new file mode 100644 index 00000000..8f0671ef --- /dev/null +++ b/libgitg-ext/gitg-ext-application.vala @@ -0,0 +1,19 @@ +namespace GitgExt +{ + +public interface Application : Object +{ + public abstract Gitg.Repository? repository { owned get; } + public abstract GitgExt.MessageBus message_bus { owned get; } + public abstract GitgExt.View? current_view { owned get; } + + public abstract GitgExt.View? view(string id); + + public abstract void open(File repository); + public abstract void create(File repository); + public abstract void close(); +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-message-bus.vala b/libgitg-ext/gitg-ext-message-bus.vala new file mode 100644 index 00000000..a15daa95 --- /dev/null +++ b/libgitg-ext/gitg-ext-message-bus.vala @@ -0,0 +1,294 @@ +namespace GitgExt +{ + +public delegate void MessageCallback(GitgExt.Message message); + +public class MessageBus : Object +{ + class Listener + { + public uint id; + public bool blocked; + + public MessageCallback callback; + + public Listener(uint id, owned MessageCallback callback) + { + this.id = id; + + // TODO: destroy notify is lost... + this.callback = (owned)callback; + this.blocked = false; + } + } + + class Message + { + public MessageId id; + public List listeners; + + public Message(MessageId id) + { + this.id = id.copy(); + this.listeners = new List(); + } + } + + class IdMap + { + public Message message; + public unowned List listener; + + public IdMap(Message message) + { + this.message = message; + } + } + + private HashTable d_messages; + private HashTable d_idmap; + private HashTable d_types; + private static MessageBus? s_instance; + private static uint s_next_id; + + public signal void registered(MessageId id); + public signal void unregistered(MessageId id); + + public virtual signal void dispatch(GitgExt.Message message) + { + Message? msg = lookup_message(message.id, false); + + if (msg != null) + { + dispatch_message_real(msg, message); + } + } + + public MessageBus() + { + d_messages = new HashTable(MessageId.hash, MessageId.equal); + d_idmap = new HashTable(direct_hash, direct_equal); + d_types = new HashTable(MessageId.hash, MessageId.equal); + } + + public static MessageBus get_default() + { + if (s_instance == null) + { + s_instance = new MessageBus(); + s_instance.add_weak_pointer(&s_instance); + } + + return s_instance; + } + + private void dispatch_message_real(Message msg, GitgExt.Message message) + { + foreach (Listener l in msg.listeners) + { + if (!l.blocked) + { + l.callback(message); + } + } + } + + public Type lookup(MessageId id) + { + Type ret; + + if (!d_types.lookup_extended(id, null, out ret)) + { + return Type.INVALID; + } + else + { + return ret; + } + } + + public void register(Type message_type, MessageId id) + { + if (is_registered(id)) + { + warning("Message type for `%s' is already registered", id.id); + return; + } + + var cp = id.copy(); + + d_types.insert(cp, message_type); + + registered(cp); + } + + private void unregister_real(MessageId id, bool remove_from_store) + { + var cp = id; + + if (!remove_from_store || d_types.remove(cp)) + { + unregistered(cp); + } + } + + public void unregister(MessageId id) + { + unregister_real(id, true); + } + + public void unregister_all(string object_path) + { + d_types.foreach_remove((key, val) => { + if (key.object_path == object_path) + { + unregister_real(key, true); + return true; + } + else + { + return false; + } + }); + } + + public bool is_registered(MessageId id) + { + return d_types.lookup_extended(id, null, null); + } + + private Message new_message(MessageId id) + { + var ret = new Message(id); + + d_messages.insert(id, ret); + return ret; + } + + private Message? lookup_message(MessageId id, bool create) + { + var message = d_messages.lookup(id); + + if (message == null && !create) + { + return null; + } + + if (message == null) + { + message = new_message(id); + } + + return message; + } + + private uint add_listener(Message message, owned MessageCallback callback) + { + var listener = new Listener(++s_next_id, (owned)callback); + + message.listeners.append(listener); + + var idmap = new IdMap(message); + idmap.listener = message.listeners.last(); + + d_idmap.insert(listener.id, idmap); + return listener.id; + } + + private void remove_listener(Message message, List listener) + { + unowned Listener lst = listener.data; + + d_idmap.remove(lst.id); + + message.listeners.delete_link(listener); + + if (message.listeners == null) + { + d_messages.remove(message.id); + } + } + + private void block_listener(Message message, List listener) + { + listener.data.blocked = true; + } + + private void unblock_listener(Message message, List listener) + { + listener.data.blocked = false; + } + + public new uint connect(MessageId id, owned MessageCallback callback) + { + var message = lookup_message(id, true); + + return add_listener(message, (owned)callback); + } + + private delegate void MatchCallback(Message message, List listeners); + + private void process_by_id(uint id, MatchCallback processor) + { + IdMap? idmap = d_idmap.lookup(id); + + if (idmap == null) + { + return; + } + + processor(idmap.message, idmap.listener); + } + + public new void disconnect(uint id) + { + process_by_id(id, remove_listener); + } + + public void block(uint id) + { + process_by_id(id, block_listener); + } + + public void unblock(uint id) + { + process_by_id(id, unblock_listener); + } + + private void dispatch_message(GitgExt.Message message) + { + dispatch(message); + } + + public GitgExt.Message send_message(GitgExt.Message message) + { + dispatch_message(message); + return message; + } + + public GitgExt.Message? send(MessageId id, string? firstprop, ...) + { + Type type = lookup(id); + + if (type == Type.INVALID) + { + warning("Could not find message type for `%s'", id.id); + return null; + } + + GitgExt.Message? msg = (GitgExt.Message?)Object.new_valist(type, firstprop, va_list()); + + if (msg != null) + { + msg.id = id; + } + + dispatch_message(msg); + + return msg; + } +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-message-id.vala b/libgitg-ext/gitg-ext-message-id.vala new file mode 100644 index 00000000..584da758 --- /dev/null +++ b/libgitg-ext/gitg-ext-message-id.vala @@ -0,0 +1,75 @@ +namespace GitgExt +{ + +public class MessageId : Object +{ + public string object_path { construct set; get; } + public string method { construct set; get; } + + public string id + { + owned get { return object_path + "." + method; } + } + + public uint hash() + { + return id.hash(); + } + + public bool equal(MessageId other) + { + return id == other.id; + } + + public MessageId(string object_path, string method) + { + Object(object_path: object_path, method: method); + } + + public MessageId copy() + { + return new MessageId(object_path, method); + } + + public static bool valid_object_path(string path) + { + if (path == null) + { + return false; + } + + if (path[0] != '/') + { + return false; + } + + int i = 0; + + while (i < path.length) + { + var c = path[i]; + + if (c == '/') + { + ++i; + + if (i == path.length || !(c.isalpha() || c == '_')) + { + return false; + } + } + else if (!(c.isalnum() || c == '_')) + { + return false; + } + + ++i; + } + + return true; + } +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-message.vala b/libgitg-ext/gitg-ext-message.vala new file mode 100644 index 00000000..a7f216dc --- /dev/null +++ b/libgitg-ext/gitg-ext-message.vala @@ -0,0 +1,40 @@ +namespace GitgExt +{ + +public abstract class Message : Object +{ + private MessageId d_id; + + public MessageId id + { + construct set + { + d_id = value.copy(); + } + get + { + return d_id; + } + } + + public bool has(string propname) + { + return get_class().find_property(propname) != null; + } + + public static bool type_has(Type type, string propname) + { + return ((ObjectClass)type.class_ref()).find_property(propname) != null; + } + + public static bool type_check(Type type, string propname, Type value_type) + { + ParamSpec? spec = ((ObjectClass)type.class_ref()).find_property(propname); + + return (spec != null && spec.value_type == value_type); + } +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-navigation-tree-view.vala b/libgitg-ext/gitg-ext-navigation-tree-view.vala new file mode 100644 index 00000000..84b59cb2 --- /dev/null +++ b/libgitg-ext/gitg-ext-navigation-tree-view.vala @@ -0,0 +1,476 @@ +namespace GitgExt +{ + +private enum Column +{ + ICON_NAME, + TEXT, + HINT, + SECTION, + OID +} + +private enum Hint +{ + NONE, + HEADER, + DEFAULT +} + +public delegate void NavigationActivated(int numclick); + +public class NavigationTreeModel : Gtk.TreeStore +{ + private class Activated : Object + { + private NavigationActivated d_activated; + + public Activated(owned NavigationActivated? activated) + { + d_activated = (owned)activated; + } + + public void activate(int numclick) + { + if (d_activated != null) + { + d_activated(numclick); + } + } + } + private SList d_parents; + private uint d_sections; + private uint d_oid; + private Activated[] d_callbacks; + + construct + { + set_column_types({typeof(string), typeof(string), typeof(uint), typeof(uint), typeof(uint)}); + + d_callbacks = new Activated[100]; + d_callbacks.length = 0; + } + + public uint begin_section() + { + d_parents = null; + return d_sections; + } + + public void end_section() + { + ++d_sections; + } + + private void append_one(string text, + string? icon_name, + uint hint, + owned NavigationActivated? callback, + out Gtk.TreeIter iter) + { + if (d_parents != null) + { + base.append(out iter, d_parents.data); + } + else + { + base.append(out iter, null); + } + + @set(iter, + Column.ICON_NAME, icon_name, + Column.TEXT, text, + Column.HINT, hint, + Column.SECTION, d_sections, + Column.OID, d_oid); + + d_callbacks += new Activated((owned)callback); + ++d_oid; + } + + public NavigationTreeModel begin_header(string text, + string? icon_name) + { + Gtk.TreeIter iter; + + append_one(text, icon_name, Hint.HEADER, null, out iter); + d_parents.prepend(iter); + + return this; + } + + public NavigationTreeModel end_header() + { + if (d_parents != null) + { + d_parents.remove_link(d_parents); + } + + return this; + } + + public new NavigationTreeModel append_default(string text, + string? icon_name, + owned NavigationActivated? callback) + { + Gtk.TreeIter iter; + append_one(text, icon_name, Hint.DEFAULT, (owned)callback, out iter); + + return this; + } + + public new NavigationTreeModel append(string text, + string? icon_name, + owned NavigationActivated? callback) + { + Gtk.TreeIter iter; + append_one(text, icon_name, Hint.NONE, (owned)callback, out iter); + + return this; + } + + public uint populate(GitgExt.Navigation nav) + { + uint ret = begin_section(); + + nav.populate(this); + + end_section(); + return ret; + } + + public void remove_section(uint section) + { + Gtk.TreeIter iter; + + if (!get_iter_first(out iter)) + { + return; + } + + while (true) + { + uint s; + + @get(iter, Column.SECTION, out s); + + if (s == section) + { + if (!base.remove(ref iter)) + { + break; + } + } + else + { + if (!iter_next(ref iter)) + { + break; + } + } + } + } + + public new void clear() + { + base.clear(); + + d_sections = 0; + d_oid = 0; + + d_callbacks.length = 0; + } + + public void activate(Gtk.TreeIter iter, int numclick) + { + uint oid; + + @get(iter, Column.OID, out oid); + + if (d_callbacks[oid] != null) + { + d_callbacks[oid].activate(numclick); + } + } +} + +public class NavigationRendererText : Gtk.CellRendererText +{ + private string d_icon_name; + private Gdk.Pixbuf d_pixbuf; + private Gtk.StateFlags d_state; + + public string? icon_name + { + get { return d_icon_name;} + set + { + if (d_icon_name != value) + { + d_icon_name = value; + reset_pixbuf(); + } + } + } + + public uint hint { get; set; } + + construct + { + ellipsize = Pango.EllipsizeMode.MIDDLE; + } + + private void reset_pixbuf() + { + d_pixbuf = null; + } + + private void ensure_pixbuf(Gtk.StyleContext ctx) + { + if (d_icon_name == null || (d_pixbuf != null && d_state == ctx.get_state())) + { + return; + } + + d_pixbuf = null; + + d_state = ctx.get_state(); + var screen = ctx.get_screen(); + var settings = Gtk.Settings.get_for_screen(screen); + + int w = 16; + int h = 16; + + Gtk.icon_size_lookup_for_settings(settings, Gtk.IconSize.MENU, out w, out h); + + Gtk.IconInfo? info = Gtk.IconTheme.get_default().lookup_icon(d_icon_name, + int.min(w, h), + Gtk.IconLookupFlags.USE_BUILTIN); + + if (info == null) + { + return; + } + + bool symbolic = false; + + try + { + d_pixbuf = info.load_symbolic_for_context(ctx, out symbolic); + } catch {}; + + if (d_pixbuf != null) + { + var source = new Gtk.IconSource(); + source.set_pixbuf(d_pixbuf); + + source.set_size(Gtk.IconSize.SMALL_TOOLBAR); + source.set_size_wildcarded(false); + + d_pixbuf = ctx.render_icon_pixbuf(source, Gtk.IconSize.SMALL_TOOLBAR); + } + } + + protected override void get_preferred_width(Gtk.Widget widget, + out int minimum_width, + out int minimum_height) + { + ensure_pixbuf(widget.get_style_context()); + + // Size of text + base.get_preferred_width(widget, out minimum_width, out minimum_height); + + if (d_pixbuf != null) + { + minimum_width += d_pixbuf.get_width() + 3; + minimum_height += d_pixbuf.get_height(); + } + } + + protected override void get_preferred_height_for_width(Gtk.Widget widget, + int width, + out int minimum_height, + out int natural_height) + { + base.get_preferred_height_for_width(widget, width, + out minimum_height, + out natural_height); + + ensure_pixbuf(widget.get_style_context()); + + if (d_pixbuf != null) + { + minimum_height = int.max(minimum_height, d_pixbuf.height); + natural_height = int.max(natural_height, d_pixbuf.height); + } + } + + protected override void render(Cairo.Context ctx, + Gtk.Widget widget, + Gdk.Rectangle background_area, + Gdk.Rectangle cell_area, + Gtk.CellRendererState state) + { + var stx = widget.get_style_context(); + ensure_pixbuf(stx); + + int xpad = 3; + + if (hint != Hint.HEADER) + { + cell_area.x -= 15; + } + + if (d_pixbuf == null) + { + base.render(ctx, widget, background_area, cell_area, state); + } + else + { + // render the text with an additional padding + Gdk.Rectangle area = cell_area; + area.x += d_pixbuf.width + xpad; + + base.render(ctx, widget, background_area, area, state); + + // render the pixbuf + int ypad = (cell_area.height - d_pixbuf.height) / 2; + + stx.render_icon(ctx, d_pixbuf, cell_area.x, cell_area.y + ypad); + } + } +} + +public class NavigationTreeView : Gtk.TreeView +{ + private Gdk.RGBA d_header_bg; + private Gdk.RGBA d_header_fg; + + construct + { + var model = new NavigationTreeModel(); + set_model(model); + + var cell = new NavigationRendererText(); + var col = new Gtk.TreeViewColumn.with_attributes("text", + cell, + "icon_name", Column.ICON_NAME, + "text", Column.TEXT, + "hint", Column.HINT); + + col.set_cell_data_func(cell, (col, cell, model, iter) => { + uint hint; + + model.get(iter, Column.HINT, out hint); + + Gtk.CellRendererText t = cell as Gtk.CellRendererText; + + if (hint == Hint.HEADER) + { + t.weight = Pango.Weight.BOLD; + t.background_rgba = d_header_bg; + t.foreground_rgba = d_header_fg; + } + else + { + t.weight = Pango.Weight.NORMAL; + t.background_set = false; + t.foreground_set = false; + } + }); + + append_column(col); + + get_selection().set_select_function((sel, model, path, cursel) => { + Gtk.TreeIter iter; + model.get_iter(out iter, path); + + uint hint; + + model.get(iter, Column.HINT, out hint); + + return hint != Hint.HEADER; + }); + + update_header_colors(); + + get_selection().changed.connect((sel) => { + Gtk.TreeIter iter; + + if (sel.get_selected(null, out iter)) + { + model.activate(iter, 1); + } + }); + } + + protected override void style_updated() + { + base.style_updated(); + update_header_colors(); + } + + private void update_header_colors() + { + get_style_context().lookup_color("insensitive_bg_color", out d_header_bg); + get_style_context().lookup_color("insensitive_fg_color", out d_header_fg); + } + + public new NavigationTreeModel model + { + get { return base.get_model() as NavigationTreeModel; } + } + + private bool select_first_in(Gtk.TreeIter? parent, bool seldef) + { + Gtk.TreeIter iter; + + if (!model.iter_children(out iter, parent)) + { + return false; + } + + while (true) + { + uint hint; + model.get(iter, Column.HINT, out hint); + + if (hint == Hint.HEADER) + { + if (select_first_in(iter, seldef)) + { + return true; + } + } + + if (!seldef || hint == Hint.DEFAULT) + { + get_selection().select_iter(iter); + + return true; + } + + if (!model.iter_next(ref iter)) + { + return false; + } + } + } + + public void select_first() + { + select_first_in(null, true) || select_first_in(null, false); + } + + protected override void row_activated(Gtk.TreePath path, Gtk.TreeViewColumn col) + { + Gtk.TreeIter iter; + + model.get_iter(out iter, path); + model.activate(iter, 2); + } +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-navigation.vala b/libgitg-ext/gitg-ext-navigation.vala new file mode 100644 index 00000000..cee99419 --- /dev/null +++ b/libgitg-ext/gitg-ext-navigation.vala @@ -0,0 +1,22 @@ +namespace GitgExt +{ + +public enum NavigationSide +{ + LEFT = 0, + TOP = 1 +} + +public interface Navigation : Object +{ + public abstract Application? application { owned get; construct; } + + public abstract void populate(GitgExt.NavigationTreeModel model); + public abstract bool available { get; } + + public abstract NavigationSide navigation_side { get; } +} + +} + +// ex:set ts=4 noet: diff --git a/libgitg-ext/gitg-ext-panel.vala b/libgitg-ext/gitg-ext-panel.vala new file mode 100644 index 00000000..1d6d105f --- /dev/null +++ b/libgitg-ext/gitg-ext-panel.vala @@ -0,0 +1,18 @@ +namespace GitgExt +{ + +public interface Panel : Object +{ + public abstract Application? application { owned get; construct; } + + public abstract string id { owned get; } + public abstract string display_name { owned get; } + public abstract Icon? icon { owned get; } + + public abstract bool supported { get; } + public abstract Gtk.Widget? widget { owned get; } +} + +} + +// ex: ts=4 noet diff --git a/libgitg-ext/gitg-ext-view.vala b/libgitg-ext/gitg-ext-view.vala new file mode 100644 index 00000000..b362597a --- /dev/null +++ b/libgitg-ext/gitg-ext-view.vala @@ -0,0 +1,112 @@ +namespace GitgExt +{ + +/** + * A view action. + * + * A view action indicates a user preference to open gitg in a particular view. + */ +public enum ViewAction +{ + /** + * Open gitg in the History view. + */ + HISTORY, + + /** + * Open gitg in the Commit view. + */ + COMMIT, + + /** + * Open gitg in the default view. + */ + DEFAULT = HISTORY +} + +/** + * gitg View interface. + * + * The GitgExtView interface can be implemented to provide a main view in + * gitg. An example of such views are the builtin Dashboard, History and + * Commit views. + * + * Implementations of the GitgExtView interface will be integrated + * automatically in the gitg interface according to the various interface + * methods and properties that need to be implemented. + * + * == Default View Navigation == + * To provide a default navigation when the view is active, the + * #GitgExtView::navigation property should be implemented and should return a + * non-null #GitgExtNavigation. This navigation section will always be present + * at the top of the navigation menu. Note that you should normally ''not'' + * export this type to Peas because you will end up having the navigation + * shown twice in the UI. + */ +public interface View : Object +{ + /** + * The main gitg application interface. This property is a "construct" + * property and will be automatically set when an instance of the view + * object is created. + */ + public abstract GitgExt.Application? application { owned get; construct; } + + /** + * A unique id for the view. Ids in gitg are normally of the form + * /org/gnome/gitg/... + */ + public abstract string id { owned get; } + + /** + * The display name of the view. This should result in a string which can + * be displayed in the gitg UI to identify the view. + */ + public abstract string display_name { owned get; } + + /** + * The view icon. If provided, the icon will be used in the top navigation + * toolbar so that users can easily switch to the view. If not provider, + * the only way to activate the view will be through the menu. + */ + public abstract Icon? icon { owned get; } + + /** + * The view widget. This widget will be embedded in the main gitg UI when + * the view is activated. + */ + public abstract Gtk.Widget? widget { owned get; } + + /** + * Main navigation for the view. When provided, the corresponding navigation + * section will be added in the navigation panel when the view is activated. + */ + public abstract Navigation? navigation { owned get; } + + /** + * This method is used by gitg to verify whether or not a particular view + * is available in the current state of #GitgExtView::application. + * Implementations usually at least verify whether there is a repository + * currently open, but other constraints for when a view should be + * available can also be implemented. + * + * @return %TRUE if the view is available, %FALSE otherwise. + */ + public abstract bool is_available(); + + /** + * @param action the action + * + * Implement this method when a view should be the preferred default view + * for a particular action. The first available view indicating to be + * a default view will be used as the default activated view when launching + * gitg (or when opening a repository). + * + * @return %TRUE if the view is a default for @action, %FALSE otherwise. + */ + public abstract bool is_default_for(ViewAction action); +} + +} + +// ex: ts=4 noet diff --git a/libgitg-ext/libgitg-ext-1.0.pc.in b/libgitg-ext/libgitg-ext-1.0.pc.in new file mode 100644 index 00000000..d8512883 --- /dev/null +++ b/libgitg-ext/libgitg-ext-1.0.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libgitg-ext +Description: gitg extensions library +Version: @PACKAGE_VERSION@ +Requires: libgit2-glib-1.0 libgitg-1.0 gtk+-3.0 glib-2.0 gobject-2.0 gmodule-2.0 gio-2.0 gio-unix-2.0 gthread-2.0 +Libs: -L${libdir} -lgitg-ext-1.0 +Cflags: -I${includedir}/libgitg-ext-1.0 diff --git a/libgitg-ext/resources/resources.xml b/libgitg-ext/resources/resources.xml new file mode 100644 index 00000000..a2e738ff --- /dev/null +++ b/libgitg-ext/resources/resources.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/libgitg/Makefile.am b/libgitg/Makefile.am index e6e6973d..7dec0e87 100644 --- a/libgitg/Makefile.am +++ b/libgitg/Makefile.am @@ -3,97 +3,70 @@ lib_LTLIBRARIES = libgitg-1.0.la INCLUDES = \ -I$(top_srcdir) \ -I$(srcdir) \ - $(GITG_CFLAGS) \ + $(LIBGITG_CFLAGS) \ $(WARN_CFLAGS) \ - $(DISABLE_DEPRECATED_CFLAGS) \ -DDATADIR=\""$(datadir)"\" \ - -DLIBDIR=\""$(libdir)"\" \ - -DGITG_LOCALEDIR=\""$(datadir)/locale"\" + -DLIBDIR=\""$(libdir)"\" -libgitg_1_0_la_LDFLAGS = \ +libgitg_1_0_la_LDFLAGS = \ -export-dynamic -no-undefined -export-symbols-regex "^[^_].*" -libgitg_1_0_la_LIBADD = $(GITG_LIBS) +libgitg_1_0_la_LIBADD = $(LIBGITG_LIBS) -BUILT_SOURCES = \ - gitg-enum-types.h \ - gitg-enum-types.c +INST_H_FILES = \ + libgitg.h -INST_H_FILES = \ - $(BUILT_H_FILES) \ - gitg-changed-file.h \ - gitg-color.h \ - gitg-commit.h \ - gitg-config.h \ - gitg-hash.h \ - gitg-lane.h \ - gitg-ref.h \ - gitg-repository.h \ - gitg-revision.h \ - gitg-runner.h \ - gitg-command.h \ - gitg-shell.h \ - gitg-io.h \ - gitg-line-parser.h +VALAFLAGS = \ + --pkg Ggit-1.0 \ + --pkg gio-2.0 \ + --header libgitg.h \ + --includedir libgitg \ + --basedir $(top_srcdir) \ + --gir Gitg-1.0.gir \ + --library libgitg-1.0 -NOINST_H_FILES = \ - gitg-convert.h \ - gitg-debug.h \ - gitg-i18n.h \ - gitg-lanes.h \ - gitg-smart-charset-converter.h \ - gitg-encodings.h +Gitg-1.0.gir: libgitg-1.0.la -C_FILES = \ - $(BUILT_SOURCES) \ - gitg-changed-file.c \ - gitg-color.c \ - gitg-commit.c \ - gitg-config.c \ - gitg-convert.c \ - gitg-hash.c \ - gitg-i18n.c \ - gitg-lane.c \ - gitg-lanes.c \ - gitg-ref.c \ - gitg-repository.c \ - gitg-revision.c \ - gitg-runner.c \ - gitg-smart-charset-converter.c \ - gitg-encodings.c \ - gitg-command.c \ - gitg-io.c \ - gitg-shell.c \ - gitg-line-parser.c +VALA_FILES = \ + gitg-repository.vala \ + gitg-ref.vala \ + gitg-lane.vala \ + gitg-lanes.vala \ + gitg-color.vala \ + gitg-init.vala \ + gitg-commit.vala \ + gitg-commit-model.vala -if ENABLE_DEBUG -C_FILES += gitg-debug.c -endif +# Ignore all warnings for vala code... +libgitg_1_0_la_CFLAGS = \ + -w -ENUM_H_FILES = \ - gitg-changed-file.h - -libgitg_1_0_la_SOURCES = \ - $(INST_H_FILES) \ - $(NOINST_H_FILES) \ - $(C_FILES) +libgitg_1_0_la_SOURCES = \ + $(VALA_FILES) headerdir = $(prefix)/include/libgitg-1.0/libgitg header_DATA = $(INST_H_FILES) -EXTRA_DIST = \ - gitg-enum-types.h.template \ - gitg-enum-types.c.template +girdir = $(INTROSPECTION_GIRDIR) +gir_DATA = Gitg-1.0.gir -CLEANFILES = $(BUILT_SOURCES) +typelibdir = $(INTROSPECTION_TYPELIBDIR) +typelib_DATA = Gitg-1.0.typelib + +%.typelib: %.gir + $(INTROSPECTION_COMPILER) $(INTROSPECTION_COMPILER_ARGS) --includedir=. -o $@ $< + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libgitg-1.0.pc + +BUILT_SOURCES = \ + $(gir_DATA) \ + libgitg.h + +EXTRA_DIST = $(pkgconfig_DATA) +CLEANFILES = $(VALA_FILES:.vala=.c) dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) -gitg-enum-types.h: gitg-enum-types.h.template $(ENUM_H_FILES) $(GLIB_MKENUMS) - $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gitg-enum-types.h.template $(ENUM_H_FILES)) > $@ - -gitg-enum-types.c: gitg-enum-types.c.template $(ENUM_H_FILES) $(GLIB_MKENUMS) - $(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gitg-enum-types.c.template $(ENUM_H_FILES)) > $@ - -include $(top_srcdir)/git.mk diff --git a/libgitg/gitg-changed-file.c b/libgitg/gitg-changed-file.c deleted file mode 100644 index 59883b73..00000000 --- a/libgitg/gitg-changed-file.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * gitg-changed-file.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-changed-file.h" -#include "gitg-enum-types.h" - -#define GITG_CHANGED_FILE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_CHANGED_FILE, GitgChangedFilePrivate)) - -struct _GitgChangedFilePrivate -{ - GFile *file; - - GitgChangedFileStatus status; - GitgChangedFileChanges changes; - - gchar *sha; - gchar *mode; - - GFileMonitor *monitor; -}; - -/* Properties */ -enum -{ - PROP_0, - PROP_FILE, - PROP_STATUS, - PROP_CHANGES, - PROP_SHA, - PROP_MODE -}; - -/* Signals */ -enum -{ - CHANGED, - NUM_SIGNALS -}; - -static guint changed_file_signals[NUM_SIGNALS] = {0,}; - -G_DEFINE_TYPE(GitgChangedFile, gitg_changed_file, G_TYPE_OBJECT) - -static void on_file_monitor_changed(GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, GitgChangedFile *self); - -static void -gitg_changed_file_finalize(GObject *object) -{ - GitgChangedFile *self = GITG_CHANGED_FILE(object); - - g_free(self->priv->sha); - g_free(self->priv->mode); - g_object_unref(self->priv->file); - - if (self->priv->monitor) - { - g_file_monitor_cancel(self->priv->monitor); - g_object_unref(self->priv->monitor); - } - - G_OBJECT_CLASS(gitg_changed_file_parent_class)->finalize(object); -} - -static void -gitg_changed_file_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - GitgChangedFile *self = GITG_CHANGED_FILE(object); - - switch (prop_id) - { - case PROP_FILE: - g_value_set_object(value, self->priv->file); - break; - case PROP_STATUS: - g_value_set_enum(value, self->priv->status); - break; - case PROP_CHANGES: - g_value_set_flags(value, self->priv->changes); - break; - case PROP_SHA: - g_value_set_string(value, self->priv->sha); - break; - case PROP_MODE: - g_value_set_string(value, self->priv->mode); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_sha_real(GitgChangedFile *self, gchar const *sha) -{ - g_free(self->priv->sha); - self->priv->sha = g_strdup(sha); -} - -static void -set_mode_real(GitgChangedFile *self, gchar const *mode) -{ - g_free(self->priv->mode); - self->priv->mode = g_strdup(mode); -} - -static void -update_monitor(GitgChangedFile *file) -{ - gboolean ismodified = (file->priv->status == GITG_CHANGED_FILE_STATUS_MODIFIED); - gboolean iscached = (file->priv->changes & GITG_CHANGED_FILE_CHANGES_CACHED); - - gboolean needmonitor = ismodified || iscached; - - if (needmonitor && !file->priv->monitor) - { - file->priv->monitor = g_file_monitor_file(file->priv->file, G_FILE_MONITOR_NONE, NULL, NULL); - g_file_monitor_set_rate_limit(file->priv->monitor, 1000); - g_signal_connect(file->priv->monitor, "changed", G_CALLBACK(on_file_monitor_changed), file); - } - else if (!needmonitor && file->priv->monitor) - { - g_file_monitor_cancel(file->priv->monitor); - g_object_unref(file->priv->monitor); - file->priv->monitor = NULL; - } -} - -static void -gitg_changed_file_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - GitgChangedFile *self = GITG_CHANGED_FILE(object); - - switch (prop_id) - { - case PROP_FILE: - self->priv->file = g_value_dup_object(value); - break; - case PROP_STATUS: - self->priv->status = g_value_get_enum(value); - update_monitor(self); - break; - case PROP_CHANGES: - self->priv->changes = g_value_get_flags(value); - update_monitor(self); - break; - case PROP_SHA: - set_sha_real(self, g_value_get_string(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -gitg_changed_file_class_init(GitgChangedFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_changed_file_finalize; - object_class->set_property = gitg_changed_file_set_property; - object_class->get_property = gitg_changed_file_get_property; - - g_object_class_install_property(object_class, PROP_FILE, - g_param_spec_object("file", - "FILE", - "File", - G_TYPE_OBJECT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property(object_class, PROP_STATUS, - g_param_spec_enum("status", - "STATUS", - "Status", - GITG_TYPE_CHANGED_FILE_STATUS, - GITG_CHANGED_FILE_STATUS_NEW, - G_PARAM_READWRITE)); - - g_object_class_install_property(object_class, PROP_CHANGES, - g_param_spec_flags("changes", - "CHANGES", - "Changes", - GITG_TYPE_CHANGED_FILE_CHANGES, - GITG_CHANGED_FILE_CHANGES_NONE, - G_PARAM_READWRITE)); - - g_object_class_install_property(object_class, PROP_SHA, - g_param_spec_string("sha", - "SHA", - "Sha", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property(object_class, PROP_MODE, - g_param_spec_string("mode", - "MODE", - "Mode", - NULL, - G_PARAM_READWRITE)); - - changed_file_signals[CHANGED] = - g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgChangedFileClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private(object_class, sizeof(GitgChangedFilePrivate)); -} - -static void -gitg_changed_file_init(GitgChangedFile *self) -{ - self->priv = GITG_CHANGED_FILE_GET_PRIVATE (self); -} - -GitgChangedFile* -gitg_changed_file_new(GFile *file) -{ - return g_object_new(GITG_TYPE_CHANGED_FILE, "file", file, NULL); -} - -GFile * -gitg_changed_file_get_file(GitgChangedFile *file) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), NULL); - - return g_object_ref(file->priv->file); -} - -gchar const * -gitg_changed_file_get_sha(GitgChangedFile *file) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), NULL); - - return file->priv->sha; -} - -gchar const * -gitg_changed_file_get_mode(GitgChangedFile *file) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), NULL); - - return file->priv->mode; -} - -void -gitg_changed_file_set_sha(GitgChangedFile *file, gchar const *sha) -{ - g_return_if_fail(GITG_IS_CHANGED_FILE(file)); - - set_sha_real(file, sha); - g_object_notify(G_OBJECT(file), "sha"); -} - -void -gitg_changed_file_set_mode(GitgChangedFile *file, gchar const *mode) -{ - g_return_if_fail(GITG_IS_CHANGED_FILE(file)); - - set_mode_real(file, mode); - g_object_notify(G_OBJECT(file), "mode"); -} - -GitgChangedFileStatus gitg_changed_file_get_status(GitgChangedFile *file) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), GITG_CHANGED_FILE_STATUS_NONE); - - return file->priv->status; -} - -GitgChangedFileChanges gitg_changed_file_get_changes(GitgChangedFile *file) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), GITG_CHANGED_FILE_CHANGES_NONE); - - return file->priv->changes; -} - -void gitg_changed_file_set_status(GitgChangedFile *file, GitgChangedFileStatus status) -{ - g_return_if_fail(GITG_IS_CHANGED_FILE(file)); - - if (status == file->priv->status) - return; - - g_object_set(file, "status", status, NULL); -} - -void -gitg_changed_file_set_changes(GitgChangedFile *file, GitgChangedFileChanges changes) -{ - g_return_if_fail(GITG_IS_CHANGED_FILE(file)); - - if (changes == file->priv->changes) - return; - - g_object_set(file, "changes", changes, NULL); -} - -gboolean -gitg_changed_file_equal(GitgChangedFile *file, GFile *other) -{ - g_return_val_if_fail(GITG_IS_CHANGED_FILE(file), FALSE); - - return g_file_equal(file->priv->file, other); -} - -static void -on_file_monitor_changed(GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event, GitgChangedFile *self) -{ - switch (event) - { - case G_FILE_MONITOR_EVENT_DELETED: - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGED: - g_signal_emit(self, changed_file_signals[CHANGED], 0); - break; - default: - break; - } -} diff --git a/libgitg/gitg-changed-file.h b/libgitg/gitg-changed-file.h deleted file mode 100644 index 9800cf3a..00000000 --- a/libgitg/gitg-changed-file.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * gitg-changed-file.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_CHANGED_FILE_H__ -#define __GITG_CHANGED_FILE_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_CHANGED_FILE (gitg_changed_file_get_type ()) -#define GITG_CHANGED_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CHANGED_FILE, GitgChangedFile)) -#define GITG_CHANGED_FILE_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CHANGED_FILE, GitgChangedFile const)) -#define GITG_CHANGED_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_CHANGED_FILE, GitgChangedFileClass)) -#define GITG_IS_CHANGED_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_CHANGED_FILE)) -#define GITG_IS_CHANGED_FILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_CHANGED_FILE)) -#define GITG_CHANGED_FILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_CHANGED_FILE, GitgChangedFileClass)) - -typedef struct _GitgChangedFile GitgChangedFile; -typedef struct _GitgChangedFileClass GitgChangedFileClass; -typedef struct _GitgChangedFilePrivate GitgChangedFilePrivate; - -typedef enum -{ - GITG_CHANGED_FILE_STATUS_NONE = 0, - GITG_CHANGED_FILE_STATUS_NEW, - GITG_CHANGED_FILE_STATUS_MODIFIED, - GITG_CHANGED_FILE_STATUS_DELETED -} GitgChangedFileStatus; - -typedef enum -{ - GITG_CHANGED_FILE_CHANGES_NONE = 0, - GITG_CHANGED_FILE_CHANGES_CACHED = 1 << 0, - GITG_CHANGED_FILE_CHANGES_UNSTAGED = 1 << 1 -} GitgChangedFileChanges; - -struct _GitgChangedFile { - GObject parent; - - GitgChangedFilePrivate *priv; -}; - -struct _GitgChangedFileClass { - GObjectClass parent_class; - - void (*changed)(GitgChangedFile *file); -}; - -GType gitg_changed_file_get_type (void) G_GNUC_CONST; -GitgChangedFile *gitg_changed_file_new(GFile *file); - -GFile *gitg_changed_file_get_file(GitgChangedFile *file); -gboolean gitg_changed_file_equal(GitgChangedFile *file, GFile *other); - -gchar const *gitg_changed_file_get_sha(GitgChangedFile *file); -gchar const *gitg_changed_file_get_mode(GitgChangedFile *file); - -void gitg_changed_file_set_sha(GitgChangedFile *file, gchar const *sha); -void gitg_changed_file_set_mode(GitgChangedFile *file, gchar const *mode); - -GitgChangedFileStatus gitg_changed_file_get_status(GitgChangedFile *file); -GitgChangedFileChanges gitg_changed_file_get_changes(GitgChangedFile *file); - -void gitg_changed_file_set_status(GitgChangedFile *file, GitgChangedFileStatus status); -void gitg_changed_file_set_changes(GitgChangedFile *file, GitgChangedFileChanges changes); - -G_END_DECLS - -#endif /* __GITG_CHANGED_FILE_H__ */ diff --git a/libgitg/gitg-color.c b/libgitg/gitg-color.c deleted file mode 100644 index d5eeb857..00000000 --- a/libgitg/gitg-color.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * gitg-color.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-color.h" -#include - -static gint8 current_index = 0; - -static gchar const *palette[] = { - "#c4a000", - "#4e9a06", - "#ce5c00", - "#204a87", - "#2e3436", - "#6c3566", - "#a40000", - - "#8ae234", - "#fcaf3e", - "#729fcf", - "#fce94f", - "#888a85", - "#ad7fa8", - "#e9b96e", - "#ef2929" -}; - -void -gitg_color_reset (void) -{ - current_index = 0; -} - -void -gitg_color_get (GitgColor *color, gdouble *r, gdouble *g, gdouble *b) -{ - gchar const *spec = palette[color->index]; - GdkColor c; - - gdk_color_parse(spec, &c); - - *r = c.red / 65535.0; - *g = c.green / 65535.0; - *b = c.blue / 65535.0; -} - -void -gitg_color_set_cairo_source (GitgColor *color, cairo_t *cr) -{ - gdouble r, g, b; - - gitg_color_get(color, &r, &g, &b); - cairo_set_source_rgb(cr, r, g, b); -} - -static gint8 -next_index () -{ - gint8 next = current_index++; - - if (current_index == sizeof(palette) / sizeof(gchar const *)) - current_index = 0; - - return next; -} - -GitgColor * -gitg_color_next (void) -{ - GitgColor *res = g_new(GitgColor, 1); - res->ref_count = 1; - res->index = next_index(); - - return res; -} - -GitgColor * -gitg_color_next_index (GitgColor *color) -{ - color->index = next_index(); - return color; -} - -GitgColor * -gitg_color_copy (GitgColor *color) -{ - GitgColor *copy = g_new(GitgColor, 1); - copy->ref_count = 1; - copy->index = color->index; - - return copy; -} - -GitgColor * -gitg_color_ref (GitgColor *color) -{ - if (!color) - return NULL; - - ++color->ref_count; - return color; -} - -GitgColor * -gitg_color_unref (GitgColor *color) -{ - if (!color) - return NULL; - - --color->ref_count; - - if (color->ref_count == 0) - { - g_free(color); - return NULL; - } - - return color; -} - diff --git a/libgitg/gitg-color.h b/libgitg/gitg-color.h deleted file mode 100644 index c3c9bd37..00000000 --- a/libgitg/gitg-color.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * gitg-color.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_COLOR_H__ -#define __GITG_COLOR_H__ - -#include -#include - -G_BEGIN_DECLS - -typedef struct _GitgColor GitgColor; - -struct _GitgColor -{ - gulong ref_count; - gint8 index; -}; - -void gitg_color_reset (void); -void gitg_color_get (GitgColor *color, gdouble *r, gdouble *g, gdouble *b); -void gitg_color_set_cairo_source (GitgColor *color, cairo_t *cr); - -GitgColor *gitg_color_next (void); -GitgColor *gitg_color_next_index (GitgColor *color); -GitgColor *gitg_color_ref (GitgColor *color); -GitgColor *gitg_color_copy (GitgColor *color); -GitgColor *gitg_color_unref (GitgColor *color); - -G_END_DECLS - -#endif /* __GITG_COLOR_H__ */ diff --git a/libgitg/gitg-color.vala b/libgitg/gitg-color.vala new file mode 100644 index 00000000..5dc40776 --- /dev/null +++ b/libgitg/gitg-color.vala @@ -0,0 +1,85 @@ +namespace Gitg +{ + +public class Color : Object +{ + private struct Rgb + { + ushort r; + ushort g; + ushort b; + } + + private static const Rgb[] palette = { + {196, 160, 0}, + {78, 154, 6}, + {206, 92, 0}, + {32, 74, 135}, + {46, 52, 54}, + {108, 53, 102}, + {164, 0, 0}, + + {138, 226, 52}, + {252, 175, 62}, + {114, 159, 207}, + {252, 233, 79}, + {136, 138, 133}, + {173, 127, 168}, + {233, 185, 110}, + {239, 41, 41} + }; + + private static uint current_index; + + public uint idx = 0; + + public static void reset() + { + current_index = 0; + } + + public void components(out double r, out double g, out double b) + { + r = palette[idx].r / 255.0; + g = palette[idx].g / 255.0; + b = palette[idx].b / 255.0; + } + + private static uint inc_index() + { + uint next = current_index++; + + if (current_index == palette.length) + { + current_index = 0; + } + + return next; + } + + public static Color next() + { + Color ret = new Color(); + ret.idx = inc_index(); + + return ret; + } + + public Color next_index() + { + this.idx = inc_index(); + return this; + } + + public Color copy() + { + Color ret = new Color(); + ret.idx = idx; + + return ret; + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-command.c b/libgitg/gitg-command.c deleted file mode 100644 index f6ef51ed..00000000 --- a/libgitg/gitg-command.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * gitg-command.c - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include "gitg-command.h" - -#define GITG_COMMAND_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_COMMAND, GitgCommandPrivate)) - -#define CONST_CONST(x) ((gchar const * const *)x) - -struct _GitgCommandPrivate -{ - GitgRepository *repository; - gchar **arguments; - gchar **environment; - GFile *working_directory; -}; - -G_DEFINE_TYPE (GitgCommand, gitg_command, G_TYPE_INITIALLY_UNOWNED) - -enum -{ - PROP_0, - PROP_REPOSITORY, - PROP_ARGUMENTS, - PROP_ENVIRONMENT, - PROP_WORKING_DIRECTORY -}; - -static void -gitg_command_finalize (GObject *object) -{ - GitgCommand *command; - - command = GITG_COMMAND (object); - - g_strfreev (command->priv->arguments); - g_strfreev (command->priv->environment); - - G_OBJECT_CLASS (gitg_command_parent_class)->finalize (object); -} - -static void -gitg_command_dispose (GObject *object) -{ - GitgCommand *command; - - command = GITG_COMMAND (object); - - if (command->priv->repository != NULL) - { - g_object_unref (command->priv->repository); - command->priv->repository = NULL; - } - - G_OBJECT_CLASS (gitg_command_parent_class)->dispose (object); -} - -static void -gitg_command_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgCommand *self = GITG_COMMAND (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - self->priv->repository = g_value_dup_object (value); - break; - case PROP_ARGUMENTS: - gitg_command_set_argumentsv (self, - g_value_get_boxed (value)); - break; - case PROP_ENVIRONMENT: - gitg_command_set_environmentv (self, - g_value_get_boxed (value)); - break; - case PROP_WORKING_DIRECTORY: - gitg_command_set_working_directory (self, - g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_command_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgCommand *self = GITG_COMMAND (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - g_value_set_object (value, self->priv->repository); - break; - case PROP_ARGUMENTS: - g_value_set_boxed (value, self->priv->arguments); - break; - case PROP_ENVIRONMENT: - g_value_set_boxed (value, self->priv->environment); - break; - case PROP_WORKING_DIRECTORY: - g_value_take_object (value, gitg_command_get_working_directory (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_command_class_init (GitgCommandClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_command_finalize; - object_class->dispose = gitg_command_dispose; - - object_class->get_property = gitg_command_get_property; - object_class->set_property = gitg_command_set_property; - - g_type_class_add_private (object_class, sizeof(GitgCommandPrivate)); - - g_object_class_install_property (object_class, - PROP_REPOSITORY, - g_param_spec_object ("repository", - "Repository", - "Repository", - GITG_TYPE_REPOSITORY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, - PROP_ARGUMENTS, - g_param_spec_boxed ("arguments", - "Arguments", - "Arguments", - G_TYPE_STRV, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_ENVIRONMENT, - g_param_spec_boxed ("environment", - "Environment", - "Environment", - G_TYPE_STRV, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_WORKING_DIRECTORY, - g_param_spec_object ("working-directory", - "Working Directory", - "Working directory", - G_TYPE_FILE, - G_PARAM_READWRITE)); -} - -static void -gitg_command_init (GitgCommand *self) -{ - self->priv = GITG_COMMAND_GET_PRIVATE (self); -} - -static gchar ** -collect_arguments (va_list ap) -{ - GPtrArray *arguments; - gchar const *arg; - - arguments = g_ptr_array_new (); - - while ((arg = va_arg (ap, gchar const *)) != NULL) - { - g_ptr_array_add (arguments, g_strdup (arg)); - } - - g_ptr_array_add (arguments, NULL); - - return (gchar **)g_ptr_array_free (arguments, FALSE); -} - -static gchar ** -combine_environment (gchar const * const *environment) -{ - GPtrArray *ret; - - ret = g_ptr_array_new (); - - while (*environment) - { - gchar const *key = *environment++; - gchar const *value = *environment++; - - gchar *combined = g_strconcat (key, "=", value, NULL); - - g_ptr_array_add (ret, combined); - } - - g_ptr_array_add (ret, NULL); - - return (gchar **)g_ptr_array_free (ret, FALSE); -} - -GitgCommand * -gitg_command_newv (GitgRepository *repository, - gchar const * const *arguments) -{ - g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL); - - return g_object_new (GITG_TYPE_COMMAND, - "repository", repository, - "arguments", arguments, - NULL); -} - -GitgCommand * -gitg_command_new (GitgRepository *repository, - ...) -{ - va_list ap; - GitgCommand *ret; - gchar **arguments; - - g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL); - - va_start (ap, repository); - - arguments = collect_arguments (ap); - ret = gitg_command_newv (repository, CONST_CONST (arguments)); - - g_strfreev (arguments); - va_end (ap); - - return ret; -} - -GitgRepository * -gitg_command_get_repository (GitgCommand *command) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), NULL); - - return command->priv->repository; -} - -void -gitg_command_set_argumentsv (GitgCommand *command, - gchar const * const *arguments) -{ - GPtrArray *ret; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - ret = g_ptr_array_new (); - - if (command->priv->repository) - { - GFile *git_dir; - GFile *work_tree; - - gchar *git_dir_path; - gchar *work_tree_path; - - git_dir = gitg_repository_get_git_dir (command->priv->repository); - work_tree = gitg_repository_get_work_tree (command->priv->repository); - - git_dir_path = g_file_get_path (git_dir); - work_tree_path = g_file_get_path (work_tree); - - g_object_unref (git_dir); - g_object_unref (work_tree); - - g_ptr_array_add (ret, g_strdup ("git")); - g_ptr_array_add (ret, g_strdup ("--git-dir")); - g_ptr_array_add (ret, git_dir_path); - g_ptr_array_add (ret, g_strdup ("--work-tree")); - g_ptr_array_add (ret, work_tree_path); - } - - while (*arguments) - { - g_ptr_array_add (ret, g_strdup (*arguments++)); - } - - g_ptr_array_add (ret, NULL); - - g_strfreev (command->priv->arguments); - command->priv->arguments = (gchar **)g_ptr_array_free (ret, FALSE); - - g_object_notify (G_OBJECT (command), "arguments"); -} - -void -gitg_command_set_arguments (GitgCommand *command, - ...) -{ - va_list ap; - gchar **arguments; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - va_start (ap, command); - arguments = collect_arguments (ap); - va_end (ap); - - gitg_command_set_argumentsv (command, CONST_CONST (arguments)); - - g_strfreev (arguments); -} - -void -gitg_command_add_argumentsv (GitgCommand *command, - gchar const * const *arguments) -{ - GPtrArray *args; - gchar **ptr; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - args = g_ptr_array_new (); - - for (ptr = command->priv->arguments; ptr && *ptr; ++ptr) - { - g_ptr_array_add (args, *ptr); - } - - while (arguments && *arguments) - { - g_ptr_array_add (args, g_strdup (*arguments++)); - } - - g_free (command->priv->arguments); - - g_ptr_array_add (args, NULL); - command->priv->arguments = (gchar **)g_ptr_array_free (args, FALSE); - - g_object_notify (G_OBJECT (command), "arguments"); -} - -void -gitg_command_add_arguments (GitgCommand *command, - ...) -{ - va_list ap; - gchar **arguments; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - va_start (ap, command); - arguments = collect_arguments (ap); - va_end (ap); - - gitg_command_add_argumentsv (command, CONST_CONST (arguments)); - - g_strfreev (arguments); -} - -gchar const * const * -gitg_command_get_arguments (GitgCommand *command) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), NULL); - return CONST_CONST (command->priv->arguments); -} - -void -gitg_command_set_environmentv (GitgCommand *command, - gchar const * const *environment) -{ - g_return_if_fail (GITG_IS_COMMAND (command)); - - g_strfreev (command->priv->environment); - command->priv->environment = combine_environment (environment); - - g_object_notify (G_OBJECT (command), "environment"); -} - -void -gitg_command_set_environment (GitgCommand *command, - ...) -{ - va_list ap; - gchar **environment; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - va_start (ap, command); - environment = collect_arguments (ap); - va_end (ap); - - gitg_command_set_environmentv (command, CONST_CONST (environment)); - - g_strfreev (environment); -} - -void -gitg_command_add_environmentv (GitgCommand *command, - gchar const * const *environment) -{ - GPtrArray *args; - gchar **combined; - gchar **ptr; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - args = g_ptr_array_new (); - - for (ptr = command->priv->environment; ptr && *ptr; ++ptr) - { - g_ptr_array_add (args, *ptr); - } - - combined = combine_environment (environment); - - for (ptr = combined; ptr && *ptr; ++ptr) - { - g_ptr_array_add (args, *ptr); - } - - g_free (combined); - g_free (command->priv->environment); - - g_ptr_array_add (args, NULL); - - command->priv->environment = (gchar **)g_ptr_array_free (args, FALSE); - - g_object_notify (G_OBJECT (command), "arguments"); -} - -void -gitg_command_add_environment (GitgCommand *command, - ...) -{ - va_list ap; - gchar **environment; - - g_return_if_fail (GITG_IS_COMMAND (command)); - - va_start (ap, command); - environment = collect_arguments (ap); - va_end (ap); - - gitg_command_add_environmentv (command, CONST_CONST (environment)); - g_strfreev (environment); -} - -gchar const * const * -gitg_command_get_environment (GitgCommand *command) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), NULL); - - return CONST_CONST (command->priv->environment); -} - -void -gitg_command_set_working_directory (GitgCommand *command, - GFile *working_directory) -{ - g_return_if_fail (GITG_IS_COMMAND (command)); - g_return_if_fail (working_directory == NULL || G_IS_FILE (working_directory)); - - if (command->priv->working_directory) - { - g_object_unref (command->priv->working_directory); - command->priv->working_directory = NULL; - } - - if (working_directory) - { - command->priv->working_directory = g_file_dup (working_directory); - } - - g_object_notify (G_OBJECT (command), "working-directory"); -} - -GFile * -gitg_command_get_working_directory (GitgCommand *command) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), NULL); - - if (command->priv->working_directory) - { - return g_file_dup (command->priv->working_directory); - } - else if (command->priv->repository) - { - return gitg_repository_get_work_tree (command->priv->repository); - } - - return NULL; -} diff --git a/libgitg/gitg-command.h b/libgitg/gitg-command.h deleted file mode 100644 index 4fe5924d..00000000 --- a/libgitg/gitg-command.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * gitg-command.h - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_COMMAND_H__ -#define __GITG_COMMAND_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_COMMAND (gitg_command_get_type ()) -#define GITG_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMAND, GitgCommand)) -#define GITG_COMMAND_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMAND, GitgCommand const)) -#define GITG_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_COMMAND, GitgCommandClass)) -#define GITG_IS_COMMAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_COMMAND)) -#define GITG_IS_COMMAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_COMMAND)) -#define GITG_COMMAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_COMMAND, GitgCommandClass)) - -typedef struct _GitgCommand GitgCommand; -typedef struct _GitgCommandClass GitgCommandClass; -typedef struct _GitgCommandPrivate GitgCommandPrivate; - -struct _GitgCommand -{ - /*< private >*/ - GInitiallyUnowned parent; - - GitgCommandPrivate *priv; - - /*< public >*/ -}; - -struct _GitgCommandClass -{ - /*< private >*/ - GInitiallyUnownedClass parent_class; - - /*< public >*/ -}; - -GType gitg_command_get_type (void) G_GNUC_CONST; - -GitgCommand *gitg_command_new (GitgRepository *repository, - ...) G_GNUC_NULL_TERMINATED; -GitgCommand *gitg_command_newv (GitgRepository *repository, - gchar const * const *arguments); - -GitgRepository *gitg_command_get_repository (GitgCommand *command); - -GFile *gitg_command_get_working_directory (GitgCommand *command); -void gitg_command_set_working_directory (GitgCommand *command, - GFile *file); - -void gitg_command_set_arguments (GitgCommand *command, - ...) G_GNUC_NULL_TERMINATED; -void gitg_command_set_argumentsv (GitgCommand *command, - gchar const * const *arguments); -void gitg_command_add_arguments (GitgCommand *command, - ...) G_GNUC_NULL_TERMINATED; -void gitg_command_add_argumentsv (GitgCommand *command, - gchar const * const *arguments); - -gchar const * const *gitg_command_get_arguments (GitgCommand *command); - -void gitg_command_set_environment (GitgCommand *command, - ...) G_GNUC_NULL_TERMINATED; -void gitg_command_set_environmentv (GitgCommand *command, - gchar const * const *environment); -void gitg_command_add_environment (GitgCommand *command, - ...) G_GNUC_NULL_TERMINATED; -void gitg_command_add_environmentv (GitgCommand *command, - gchar const * const *environment); - -gchar const * const *gitg_command_get_environment (GitgCommand *command); - -G_END_DECLS - -#endif /* __GITG_COMMAND_H__ */ diff --git a/libgitg/gitg-commit-model.vala b/libgitg/gitg-commit-model.vala new file mode 100644 index 00000000..87aca7b6 --- /dev/null +++ b/libgitg/gitg-commit-model.vala @@ -0,0 +1,246 @@ +namespace Gitg +{ + +public class CommitModel : Object +{ + private Repository d_repository; + private Cancellable? d_cancellable; + private Gitg.Commit[] d_ids; + private unowned Thread? d_thread; + private Ggit.RevisionWalker? d_walker; + private uint d_advertized_size; + private uint d_idleid; + + public uint limit { get; set; } + + private Ggit.OId[] include { get; set; } + private Ggit.OId[] exclude { get; set; } + + public signal void started(); + public signal void update(uint added); + public signal void finished(); + + public CommitModel(Repository repository) + { + d_repository = repository; + } + + ~CommitModel() + { + cancel(); + } + + private void cancel() + { + if (d_cancellable == null) + { + return; + } + + d_cancellable.cancel(); + d_thread.join(); + + if (d_idleid != 0) + { + Source.remove(d_idleid); + d_idleid = 0; + } + + d_thread = null; + d_cancellable = null; + + d_ids = new Gitg.Commit[0]; + d_advertized_size = 0; + + started(); + finished(); + } + + public void reload() + { + cancel(); + walk(); + } + + public uint size() + { + return d_advertized_size; + } + + public new Gitg.Commit? @get(uint idx) + { + Gitg.Commit? ret; + + if (idx >= d_advertized_size) + { + return null; + } + + lock(d_ids) + { + ret = d_ids[idx]; + } + + return ret; + } + + private void notify_batch(bool isend) + { + lock(d_idleid) + { + if (d_idleid != 0) + { + Source.remove(d_idleid); + d_idleid = 0; + } + } + + uint newsize = d_ids.length; + + d_idleid = Idle.add(() => { + lock(d_idleid) + { + if (d_idleid == 0) + { + return false; + } + + d_idleid = 0; + + uint added = newsize - d_advertized_size; + d_advertized_size = newsize; + + update(added); + + if (isend) + { + d_thread.join(); + d_thread = null; + d_cancellable = null; + + finished(); + } + } + + return false; + }); + } + + private void walk() + { + Ggit.OId[] included = include; + Ggit.OId[] excluded = exclude; + + d_cancellable = new Cancellable(); + uint limit = this.limit; + + ThreadFunc run = () => { + if (d_walker == null) + { + try + { + d_walker = new Ggit.RevisionWalker(d_repository); + } + catch + { + notify_batch(true); + return null; + } + } + + d_walker.reset(); + + foreach (Ggit.OId oid in included) + { + try + { + d_walker.push(oid); + } catch {}; + } + + foreach (Ggit.OId oid in excluded) + { + try + { + d_walker.hide(oid); + } catch {}; + } + + d_walker.set_sort_mode(Ggit.SortMode.TOPOLOGICAL | + Ggit.SortMode.TIME); + + uint size; + + // Pre-allocate array to store commits + lock(d_ids) + { + d_ids = new Gitg.Commit[1000]; + + size = d_ids.length; + + d_ids.length = 0; + d_advertized_size = 0; + } + + Timer timer = new Timer(); + + while (true) + { + Ggit.OId? id; + Gitg.Commit? commit; + + if (d_cancellable.is_cancelled()) + { + break; + } + + try + { + id = d_walker.next(); + commit = d_repository.lookup(id, typeof(Gitg.Commit)) as Gitg.Commit; + } catch { break; } + + // Add the id + if (d_ids.length == size) + { + lock(d_ids) + { + size *= 2; + + d_ids.resize((int)size); + } + } + + d_ids += commit; + + if (timer.elapsed() >= 200) + { + notify_batch(false); + timer.start(); + } + + if (limit > 0 && d_ids.length == limit) + { + break; + } + } + + notify_batch(true); + return null; + }; + + try + { + d_thread = Thread.create(run, true); + } + catch + { + finished(); + d_cancellable = null; + } + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-commit.c b/libgitg/gitg-commit.c deleted file mode 100644 index 6b734f1f..00000000 --- a/libgitg/gitg-commit.c +++ /dev/null @@ -1,1484 +0,0 @@ -/* - * gitg-commit.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-commit.h" -#include "gitg-shell.h" -#include "gitg-changed-file.h" -#include "gitg-config.h" - -#include - -#define GITG_COMMIT_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GITG_TYPE_COMMIT, GitgCommitPrivate)) - -#define CAN_DELETE_KEY "CanDeleteKey" - -/* Properties */ -enum -{ - PROP_0, - PROP_REPOSITORY -}; - -/* Signals */ -enum -{ - INSERTED, - REMOVED, - LAST_SIGNAL -}; - -struct _GitgCommitPrivate -{ - GitgRepository *repository; - GitgShell *shell; - - guint update_id; - guint end_id; - - GHashTable *files; -}; - -static guint commit_signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (GitgCommit, gitg_commit, G_TYPE_OBJECT) - -static void on_changed_file_changed (GitgChangedFile *file, GitgCommit *commit); - -GQuark -gitg_commit_error_quark () -{ - static GQuark quark = 0; - - if (G_UNLIKELY (quark == 0)) - quark = g_quark_from_string ("gitg_commit_error"); - - return quark; -} - -static void -shell_cancel (GitgCommit *commit) -{ - if (commit->priv->update_id) - { - g_signal_handler_disconnect (commit->priv->shell, - commit->priv->update_id); - commit->priv->update_id = 0; - } - - if (commit->priv->end_id) - { - g_signal_handler_disconnect (commit->priv->shell, - commit->priv->end_id); - commit->priv->end_id = 0; - } - - gitg_io_cancel (GITG_IO (commit->priv->shell)); -} - -static void -gitg_commit_finalize (GObject *object) -{ - GitgCommit *commit = GITG_COMMIT (object); - - shell_cancel (commit); - g_object_unref (commit->priv->shell); - - g_hash_table_destroy (commit->priv->files); - - G_OBJECT_CLASS (gitg_commit_parent_class)->finalize (object); -} - -static void -gitg_commit_dispose (GObject *object) -{ - GitgCommit *self = GITG_COMMIT (object); - - if (self->priv->repository) - { - g_signal_handlers_disconnect_by_func (self->priv->repository, - G_CALLBACK (gitg_commit_refresh), - self); - - g_object_unref (self->priv->repository); - self->priv->repository = NULL; - } -} - -static void -gitg_commit_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgCommit *self = GITG_COMMIT (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - g_value_set_object (value, self->priv->repository); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_commit_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgCommit *self = GITG_COMMIT (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - { - if (self->priv->repository) - { - g_object_unref (self->priv->repository); - } - - self->priv->repository = g_value_dup_object (value); - - g_signal_connect_swapped (self->priv->repository, - "load", - G_CALLBACK (gitg_commit_refresh), - self); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_commit_class_init (GitgCommitClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gitg_commit_dispose; - object_class->finalize = gitg_commit_finalize; - - object_class->set_property = gitg_commit_set_property; - object_class->get_property = gitg_commit_get_property; - - g_object_class_install_property (object_class, - PROP_REPOSITORY, - g_param_spec_object ("repository", - "REPOSITORY", - "Repository", - GITG_TYPE_REPOSITORY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - commit_signals[INSERTED] = - g_signal_new ("inserted", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgCommitClass, - inserted), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - GITG_TYPE_CHANGED_FILE); - - commit_signals[REMOVED] = - g_signal_new ("removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgCommitClass, - removed), - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - GITG_TYPE_CHANGED_FILE); - - g_type_class_add_private (object_class, sizeof (GitgCommitPrivate)); -} - -static void -gitg_commit_init (GitgCommit *self) -{ - self->priv = GITG_COMMIT_GET_PRIVATE (self); - - self->priv->shell = gitg_shell_new (10000); - self->priv->files = g_hash_table_new_full (g_file_hash, - (GEqualFunc)g_file_equal, - (GDestroyNotify)g_object_unref, - (GDestroyNotify)g_object_unref); -} - -GitgCommit * -gitg_commit_new (GitgRepository *repository) -{ - return g_object_new (GITG_TYPE_COMMIT, "repository", repository, NULL); -} - -static void -shell_connect (GitgCommit *commit, - GCallback updatefunc, - GCallback endfunc) -{ - if (commit->priv->update_id) - { - g_signal_handler_disconnect (commit->priv->shell, - commit->priv->update_id); - commit->priv->update_id = 0; - } - - if (commit->priv->end_id) - { - g_signal_handler_disconnect (commit->priv->shell, - commit->priv->end_id); - commit->priv->end_id = 0; - } - - if (updatefunc) - { - commit->priv->update_id = g_signal_connect (commit->priv->shell, - "update", - updatefunc, - commit); - } - - if (endfunc) - { - commit->priv->end_id = g_signal_connect (commit->priv->shell, - "end", - endfunc, - commit); - } -} - -static void -update_changed_file_status (GitgChangedFile *file, - char const *action, - gchar const *mode) -{ - GitgChangedFileStatus status; - - if (strcmp (action, "D") == 0) - { - status = GITG_CHANGED_FILE_STATUS_DELETED; - } - else if (strcmp (mode, "000000") == 0) - { - status = GITG_CHANGED_FILE_STATUS_NEW; - } - else - { - status = GITG_CHANGED_FILE_STATUS_MODIFIED; - } - - gitg_changed_file_set_status (file, status); -} - -static void -add_files (GitgCommit *commit, - gchar **buffer, - gboolean cached) -{ - gchar *line; - - while ((line = *buffer++) != NULL) - { - gchar **parts = g_strsplit (line, " ", 5); - guint len = g_strv_length (parts); - - gchar **subparts = NULL; - - if (len > 4) - { - subparts = g_strsplit (parts[4], "\t", 2); - } - - guint sublen = g_strv_length (subparts); - - if (len < 5 || sublen < 2) - { - g_warning ("Invalid line: %s (%d)", line, len); - g_strfreev (parts); - g_strfreev (subparts); - continue; - } - - /* Also split status and file path now */ - - gchar const *mode = parts[0] + 1; - gchar const *sha = parts[2]; - - GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository); - GFile *file = g_file_get_child (work_tree, subparts[1]); - - g_object_unref (work_tree); - - GitgChangedFile *f = GITG_CHANGED_FILE (g_hash_table_lookup (commit->priv->files, - file)); - - if (f) - { - GitgChangedFileChanges changes = gitg_changed_file_get_changes (f); - - g_object_set_data (G_OBJECT (f), CAN_DELETE_KEY, NULL); - update_changed_file_status (f, subparts[0], mode); - - if (cached) - { - gitg_changed_file_set_sha (f, sha); - gitg_changed_file_set_mode (f, mode); - - changes |= GITG_CHANGED_FILE_CHANGES_CACHED; - } - else - { - changes |= GITG_CHANGED_FILE_CHANGES_UNSTAGED; - } - - gitg_changed_file_set_changes (f, changes); - - if ((changes & GITG_CHANGED_FILE_CHANGES_CACHED) && - (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED)) - { - gitg_changed_file_set_status (f, GITG_CHANGED_FILE_STATUS_MODIFIED); - } - - g_object_unref (file); - g_strfreev (parts); - g_strfreev (subparts); - - continue; - } - - f = gitg_changed_file_new (file); - update_changed_file_status (f, subparts[0], mode); - - gitg_changed_file_set_sha (f, sha); - gitg_changed_file_set_mode (f, mode); - - GitgChangedFileChanges changes; - - changes = cached ? GITG_CHANGED_FILE_CHANGES_CACHED : GITG_CHANGED_FILE_CHANGES_UNSTAGED; - gitg_changed_file_set_changes (f, changes); - - g_hash_table_insert (commit->priv->files, file, f); - - g_signal_connect (f, "changed", G_CALLBACK (on_changed_file_changed), commit); - g_signal_emit (commit, commit_signals[INSERTED], 0, f); - - g_strfreev (parts); - g_strfreev (subparts); - } -} - -static void -read_cached_files_update (GitgShell *shell, - gchar **buffer, - GitgCommit *commit) -{ - add_files (commit, buffer, TRUE); -} - -static gboolean -delete_file (GFile *key, - GitgChangedFile *value, - GitgCommit *commit) -{ - if (!g_object_get_data (G_OBJECT (value), CAN_DELETE_KEY)) - { - return FALSE; - } - - g_signal_emit (commit, commit_signals[REMOVED], 0, value); - return TRUE; -} - -static void -refresh_done (GitgShell *shell, - gboolean cancelled, - GitgCommit *commit) -{ - g_hash_table_foreach_remove (commit->priv->files, - (GHRFunc)delete_file, - commit); -} - -static void -read_unstaged_files_end (GitgShell *shell, - gboolean cancelled, - GitgCommit *commit) -{ - gchar *head = gitg_repository_parse_head (commit->priv->repository); - gitg_io_cancel (GITG_IO (shell)); - - shell_connect (commit, - G_CALLBACK (read_cached_files_update), - G_CALLBACK (refresh_done)); - - gitg_shell_run (commit->priv->shell, - gitg_command_new (commit->priv->repository, - "diff-index", - "--no-ext-diff", - "--cached", - head, - NULL), - NULL); - - g_free (head); -} - -static void -read_unstaged_files_update (GitgShell *shell, - gchar **buffer, - GitgCommit *commit) -{ - add_files (commit, buffer, FALSE); -} - -static void -read_other_files_end (GitgShell *shell, - gboolean cancelled, - GitgCommit *commit) -{ - gitg_io_cancel (GITG_IO (shell)); - - shell_connect (commit, - G_CALLBACK (read_unstaged_files_update), - G_CALLBACK (read_unstaged_files_end)); - - gitg_shell_run (commit->priv->shell, - gitg_command_new (commit->priv->repository, - "diff-files", - "--no-ext-diff", - NULL), - NULL); -} - -static void -changed_file_new (GitgChangedFile *f) -{ - gitg_changed_file_set_status (f, GITG_CHANGED_FILE_STATUS_NEW); - gitg_changed_file_set_changes (f, GITG_CHANGED_FILE_CHANGES_UNSTAGED); - - g_object_set_data (G_OBJECT (f), CAN_DELETE_KEY, NULL); -} - -static void -read_other_files_update (GitgShell *shell, - gchar **buffer, - GitgCommit *commit) -{ - gchar *line; - - while ((line = *buffer++) != NULL) - { - /* Skip empty lines */ - if (!*line) - { - continue; - } - - /* Check if file is already in our index */ - GFile *work_tree = gitg_repository_get_work_tree (commit->priv->repository); - GFile *file = g_file_get_child (work_tree, line); - - g_object_unref (work_tree); - - GitgChangedFile *f = g_hash_table_lookup (commit->priv->files, file); - - if (f) - { - changed_file_new (f); - g_object_unref (file); - continue; - } - - f = gitg_changed_file_new (file); - - changed_file_new (f); - g_hash_table_insert (commit->priv->files, file, f); - - g_signal_emit (commit, commit_signals[INSERTED], 0, f); - } -} - -static void -update_index_end (GitgShell *shell, - gboolean cancelled, - GitgCommit *commit) -{ - gitg_io_cancel (GITG_IO (shell)); - - shell_connect (commit, - G_CALLBACK (read_other_files_update), - G_CALLBACK (read_other_files_end)); - - gitg_shell_run (commit->priv->shell, - gitg_command_new (commit->priv->repository, - "ls-files", - "--others", - "--exclude-standard", - NULL), - NULL); -} - -static void -update_index (GitgCommit *commit) -{ - shell_connect (commit, - NULL, - G_CALLBACK (update_index_end)); - - gitg_shell_run (commit->priv->shell, - gitg_command_new (commit->priv->repository, - "update-index", - "-q", - "--unmerged", - "--ignore-missing", - "--refresh", - NULL), - NULL); -} - -static void -set_can_delete (GFile *key, - GitgChangedFile *value, - GitgCommit *commit) -{ - g_object_set_data (G_OBJECT (value), - CAN_DELETE_KEY, - GINT_TO_POINTER (TRUE)); - - gitg_changed_file_set_changes (value, GITG_CHANGED_FILE_CHANGES_NONE); -} - -void -gitg_commit_refresh (GitgCommit *commit) -{ - g_return_if_fail (GITG_IS_COMMIT (commit)); - - shell_cancel (commit); - - g_hash_table_foreach (commit->priv->files, (GHFunc)set_can_delete, commit); - - /* Read other files */ - if (commit->priv->repository) - { - update_index (commit); - } - else - { - refresh_done (commit->priv->shell, FALSE, commit); - } -} - -static void -update_index_staged (GitgCommit *commit, - GitgChangedFile *file) -{ - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - gchar *head = gitg_repository_parse_head (commit->priv->repository); - gboolean retval; - gchar **ret; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "diff-index", - "--no-ext-diff", - "--cached", - head, - "--", - path, - NULL), - FALSE, - &ret, - NULL); - - g_free (path); - g_free (head); - g_object_unref (f); - - if (!retval) - { - g_strfreev (ret); - return; - } - - gchar **parts = *ret ? g_strsplit_set (*ret, " \t", 0) : NULL; - g_strfreev (ret); - - if (parts && g_strv_length (parts) > 2) - { - gitg_changed_file_set_mode (file, parts[0] + 1); - gitg_changed_file_set_sha (file, parts[2]); - - gitg_changed_file_set_changes (file, - gitg_changed_file_get_changes (file) | - GITG_CHANGED_FILE_CHANGES_CACHED); - - update_changed_file_status (file, parts[4], parts[0] + 1); - } - else - { - gitg_changed_file_set_changes (file, - gitg_changed_file_get_changes (file) & - ~GITG_CHANGED_FILE_CHANGES_CACHED); - } - - if (parts) - { - g_strfreev (parts); - } -} - -static void -update_index_unstaged (GitgCommit *commit, - GitgChangedFile *file) -{ - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - gboolean retval; - gchar **ret; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "diff-files", - "--no-ext-diff", - "--", - path, - NULL), - FALSE, - &ret, - NULL); - - g_free (path); - g_object_unref (f); - - if (retval && ret && *ret) - { - gitg_changed_file_set_changes (file, - gitg_changed_file_get_changes (file) | - GITG_CHANGED_FILE_CHANGES_UNSTAGED); - } - else - { - gitg_changed_file_set_changes (file, - gitg_changed_file_get_changes (file) & - ~GITG_CHANGED_FILE_CHANGES_UNSTAGED); - } - - g_strfreev (ret); -} - -static void -update_index_file (GitgCommit *commit, - GitgChangedFile *file) -{ - /* update the index */ - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - g_object_unref (f); - - gitg_shell_run_sync (gitg_command_new (commit->priv->repository, - "update-index", - "-q", - "--unmerged", - "--ignore-missing", - "--refresh", - NULL), - NULL); - - g_free (path); -} - -static void -refresh_changes (GitgCommit *commit, GitgChangedFile *file) -{ - /* update the index */ - update_index_file (commit, file); - - /* Determine if it still has staged/unstaged changes */ - update_index_staged (commit, file); - update_index_unstaged (commit, file); - - GitgChangedFileChanges changes = gitg_changed_file_get_changes (file); - GitgChangedFileStatus status = gitg_changed_file_get_status (file); - - if (changes == GITG_CHANGED_FILE_CHANGES_NONE && - status == GITG_CHANGED_FILE_STATUS_NONE) - { - gitg_changed_file_set_status (file, - GITG_CHANGED_FILE_STATUS_NEW); - } - else if ((changes & GITG_CHANGED_FILE_CHANGES_CACHED) && - (changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED)) - { - gitg_changed_file_set_status (file, - GITG_CHANGED_FILE_STATUS_MODIFIED); - } - - if (status == GITG_CHANGED_FILE_STATUS_NEW && - !(changes & GITG_CHANGED_FILE_CHANGES_CACHED)) - { - gitg_changed_file_set_changes (file, - GITG_CHANGED_FILE_CHANGES_UNSTAGED); - } -} - -static gboolean -apply_hunk (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - gboolean reverse, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE); - g_return_val_if_fail (GITG_IS_CHANGED_FILE (file), FALSE); - - g_return_val_if_fail (hunk != NULL, FALSE); - - gboolean ret = gitg_shell_run_sync_with_input (gitg_command_new (commit->priv->repository, - "apply", - "--cached", - reverse ? "--reverse" : NULL, - NULL), - hunk, - error); - - if (ret) - { - refresh_changes (commit, file); - } - - return ret; -} - -gboolean -gitg_commit_stage (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error) -{ - if (hunk) - { - return apply_hunk (commit, file, hunk, FALSE, error); - } - - /* Otherwise, stage whole file */ - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - g_object_unref (f); - - gboolean ret = gitg_shell_run_sync (gitg_command_new (commit->priv->repository, - "update-index", - "--add", - "--remove", - "--", - path, - NULL), - error); - g_free (path); - - if (ret) - { - refresh_changes (commit, file); - } - else - { - g_error ("Update index for stage failed"); - } - - return ret; -} - -gboolean -gitg_commit_unstage (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error) -{ - if (hunk) - { - return apply_hunk (commit, file, hunk, TRUE, error); - } - - /* Otherwise, unstage whole file */ - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - g_object_unref (f); - - gchar *input = g_strdup_printf ("%s %s\t%s\n", - gitg_changed_file_get_mode (file), - gitg_changed_file_get_sha (file), - path); - - gboolean ret = gitg_shell_run_sync_with_input (gitg_command_new (commit->priv->repository, - "update-index", - "--index-info", - NULL), - input, - error); - - g_free (input); - - if (ret) - { - refresh_changes (commit, file); - } - else - { - g_error ("Update index for unstage failed"); - } - - return ret; -} - -static void -find_staged (GFile *key, - GitgChangedFile *value, - gboolean *result) -{ - if (*result) - { - return; - } - - *result = (gitg_changed_file_get_changes (value) & - GITG_CHANGED_FILE_CHANGES_CACHED); -} - -gboolean -gitg_commit_has_changes (GitgCommit *commit) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE); - gboolean result = FALSE; - - g_hash_table_foreach (commit->priv->files, (GHFunc)find_staged, &result); - return result; -} - -static gchar * -comment_parse_subject (gchar const *comment) -{ - gchar *ptr; - gchar *subject; - - if ((ptr = g_utf8_strchr (comment, g_utf8_strlen (comment, -1), '\n')) != NULL) - { - subject = g_strndup (comment, ptr - comment); - } - else - { - subject = g_strdup (comment); - } - - gchar *commit = g_strconcat ("commit:", subject, NULL); - g_free (subject); - - return commit; -} - -static gboolean -write_tree (GitgCommit *commit, gchar **tree, GError **error) -{ - gchar **lines; - gboolean retval; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "write-tree", - NULL), - FALSE, - &lines, - error); - - if (!retval || !lines || strlen (*lines) != GITG_HASH_SHA_SIZE) - { - g_strfreev (lines); - return FALSE; - } - - *tree = g_strdup (*lines); - g_strfreev (lines); - - return TRUE; -} - -static gchar * -get_signed_off_line (GitgCommit *commit) -{ - gchar **user; - gboolean retval; - gchar **email; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "config", - "--get", - "user.name", - NULL), - FALSE, - &user, - NULL); - - if (!retval || !user) - { - return NULL; - } - - if (!*user || !**user) - { - g_strfreev (user); - return NULL; - } - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "config", - "--get", - "user.email", - NULL), - FALSE, - &email, - NULL); - - if (!retval || !email) - { - g_strfreev (user); - return NULL; - } - - if (!*email || !**email) - { - g_strfreev (user); - g_strfreev (email); - - return NULL; - } - - gchar *ret = g_strdup_printf ("Signed-off-by: %s <%s>", *user, *email); - g_strfreev (user); - g_strfreev (email); - - return ret; -} - -static void -set_amend_environment (GitgCommit *commit, - GitgCommand *command) -{ - gchar **out; - gboolean retval; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "cat-file", - "commit", - "HEAD", - NULL), - FALSE, - &out, - NULL); - - if (!retval) - { - g_strfreev (out); - return; - } - - // Parse author - GRegex *r = g_regex_new ("^author (.*) < ([^>]*)> ([0-9]+.*)$", - G_REGEX_CASELESS, - 0, - NULL); - - GMatchInfo *info = NULL; - gchar **ptr = out; - - while (ptr && *ptr) - { - if (g_regex_match (r, *ptr, 0, &info)) - { - gchar *name = g_match_info_fetch (info, 1); - gchar *email = g_match_info_fetch (info, 2); - gchar *date = g_match_info_fetch (info, 3); - - gitg_command_add_environment (command, "GIT_AUTHOR_NAME", name, NULL); - gitg_command_add_environment (command, "GIT_AUTHOR_EMAIL", email, NULL); - gitg_command_add_environment (command, "GIT_AUTHOR_DATE", date, NULL); - - g_free (name); - g_free (email); - g_free (date); - - break; - } - - ++ptr; - } - - g_strfreev (out); -} - -static gchar * -convert_commit_encoding (GitgCommit *commit, - gchar const *s) -{ - GitgConfig *config; - gchar *encoding; - gchar *ret; - - config = gitg_config_new (commit->priv->repository); - encoding = gitg_config_get_value (config, "i18n.commitencoding"); - - if (!encoding || !*encoding) - { - g_object_unref (config); - g_free (encoding); - - config = gitg_config_new (NULL); - - encoding = gitg_config_get_value (config, "i18n.commitencoding"); - } - - g_object_unref (config); - - if (!encoding || !*encoding || g_ascii_strcasecmp (encoding, "UTF-8") == 0) - { - g_free (encoding); - return g_strdup (s); - } - - // Try to convert from UTF-8 to 'encoding' - ret = g_convert (s, -1, encoding, "UTF-8", NULL, NULL, NULL); - - if (!ret) - { - // Just use 's' then, even if it is UTF-8... - ret = g_strdup (s); - } - - g_free (encoding); - return ret; -} - -static gboolean -commit_tree (GitgCommit *commit, - gchar const *tree, - gchar const *comment, - gboolean signoff, - gboolean amend, - gchar **ref, - GError **error) -{ - gchar *fullcomment; - gboolean retval; - - if (signoff) - { - gchar *line = get_signed_off_line (commit); - - if (!line) - { - if (error) - { - g_set_error (error, - GITG_COMMIT_ERROR, - GITG_COMMIT_ERROR_SIGNOFF, - "Could not retrieve user name or email for signoff message"); - } - - return FALSE; - } - - fullcomment = g_strconcat (comment, "\n\n", line, NULL); - } - else - { - fullcomment = g_strdup (comment); - } - - gchar *head; - - if (amend) - { - head = gitg_repository_parse_ref (commit->priv->repository, - "HEAD^"); - } - else - { - head = gitg_repository_parse_ref (commit->priv->repository, - "HEAD"); - } - - GitgCommand *command; - gchar **buffer; - - command = gitg_command_new (commit->priv->repository, - "commit-tree", - tree, - head ? "-p" : NULL, - head, - NULL); - - if (amend) - { - set_amend_environment (commit, command); - } - - gchar *converted = convert_commit_encoding (commit, fullcomment); - - retval = gitg_shell_run_sync_with_input_and_output (command, - FALSE, - converted, - &buffer, - error); - - g_free (head); - g_free (fullcomment); - g_free (converted); - g_object_unref (command); - - if (!retval || !buffer || !*buffer || strlen (*buffer) != GITG_HASH_SHA_SIZE) - { - g_strfreev (buffer); - return FALSE; - } - - *ref = g_strdup (*buffer); - g_strfreev (buffer); - - return TRUE; -} - -static gboolean -update_ref (GitgCommit *commit, - gchar const *ref, - gchar const *subject, - GError **error) -{ - gchar *converted = convert_commit_encoding (commit, subject); - - gboolean ret = gitg_shell_run_sync (gitg_command_new (commit->priv->repository, - "update-ref", - "-m", - converted, - "HEAD", - ref, - NULL), - error); - g_free (converted); - - return ret; -} - -gboolean -gitg_commit_commit (GitgCommit *commit, - gchar const *comment, - gboolean signoff, - gboolean amend, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE); - - gchar *tree; - - if (!gitg_repository_run_hook (commit->priv->repository, - "pre-commit", - error, - NULL)) - { - return FALSE; - } - - if (!write_tree (commit, &tree, error)) - { - return FALSE; - } - - GFile *git_dir = gitg_repository_get_git_dir (commit->priv->repository); - GFile *child = g_file_get_child (git_dir, "COMMIT_EDITMSG"); - gchar *path = g_file_get_path (child); - - g_object_unref (git_dir); - g_object_unref (child); - - g_file_set_contents (path, comment, -1, NULL); - - if (!gitg_repository_run_hook (commit->priv->repository, - "commit-msg", - error, - path, - NULL)) - { - g_free (path); - return FALSE; - } - - g_free (path); - - gchar *ref; - gboolean ret = commit_tree (commit, tree, comment, signoff, amend, &ref, error); - g_free (tree); - - if (!ret) - { - return FALSE; - } - - gchar *subject = comment_parse_subject (comment); - ret = update_ref (commit, ref, subject, error); - g_free (subject); - - if (!ret) - { - return FALSE; - } - - gitg_repository_run_hook (commit->priv->repository, - "post-commit", - NULL, - NULL); - - gitg_repository_reload (commit->priv->repository); - return TRUE; -} - -static void -remove_file (GitgCommit *commit, - GitgChangedFile *file) -{ - GFile *f = gitg_changed_file_get_file (file); - - g_hash_table_remove (commit->priv->files, f); - g_object_unref (f); - - g_signal_emit (commit, commit_signals[REMOVED], 0, file); -} - -gboolean -gitg_commit_revert (GitgCommit *commit, - GitgRevision *from, - GitgRevision *to, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE); - g_return_val_if_fail (from != NULL, FALSE); - g_return_val_if_fail (to != NULL, FALSE); - - return FALSE; - - // TODO - /*gchar *sha1from = gitg_revision_get_sha1 (from); - gchar *sha1to = gitg_revision_get_sha1 (to); - - gitg_repository_command_with_outputv (commit->priv->repository, - error, - "diff", - "--full-index", - "--binary", - "--no-color", - sha1to, - sha1from, - NULL) - git diff --full-index --binary --no-color to from*/ -} - -gboolean -gitg_commit_undo (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error) -{ - gboolean ret; - - if (!hunk) - { - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - - ret = gitg_shell_run_sync_with_input (gitg_command_new (commit->priv->repository, - "checkout-index", - "--index", - "--quiet", - "--force", - "--stdin", - NULL), - path, - error); - - g_free (path); - - update_index_file (commit, file); - update_index_unstaged (commit, file); - g_object_unref (f); - } - else - { - ret = gitg_shell_run_sync_with_input (gitg_command_new (commit->priv->repository, - "apply", - "-R", - "-", - NULL), - hunk, - error); - - update_index_file (commit, file); - update_index_unstaged (commit, file); - } - - return ret; -} - -gboolean -gitg_commit_add_ignore (GitgCommit *commit, - GitgChangedFile *file, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), FALSE); - g_return_val_if_fail (GITG_IS_CHANGED_FILE (file), FALSE); - - GFile *f = gitg_changed_file_get_file (file); - gchar *path = gitg_repository_relative (commit->priv->repository, f); - - GFile *git_dir = gitg_repository_get_work_tree (commit->priv->repository); - GFile *ignore = g_file_get_child (git_dir, ".gitignore"); - - GFileOutputStream *stream = g_file_append_to (ignore, - G_FILE_CREATE_NONE, - NULL, - error); - gboolean ret = FALSE; - - g_object_unref (git_dir); - g_object_unref (ignore); - - if (stream) - { - gchar *line = g_strdup_printf ("/%s\n", path); - - ret = g_output_stream_write_all (G_OUTPUT_STREAM (stream), - line, - strlen (line), - NULL, - NULL, - error); - - g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, NULL); - - g_object_unref (stream); - g_free (line); - } - - if (ret) - { - remove_file (commit, file); - } - - g_object_unref (f); - g_free (path); - - return ret; -} - -static void -on_changed_file_changed (GitgChangedFile *file, - GitgCommit *commit) -{ - refresh_changes (commit, file); -} - -GitgChangedFile * -gitg_commit_find_changed_file (GitgCommit *commit, - GFile *file) -{ - g_return_val_if_fail (GITG_IS_COMMIT (commit), NULL); - g_return_val_if_fail (G_IS_FILE (file), NULL); - - GitgChangedFile *f = g_hash_table_lookup (commit->priv->files, file); - - if (f != NULL) - { - return g_object_ref (f); - } - else - { - return NULL; - } -} - -gchar * -gitg_commit_amend_message (GitgCommit *commit) -{ - gchar **out; - gboolean retval; - - g_return_val_if_fail (GITG_IS_COMMIT (commit), NULL); - - retval = gitg_shell_run_sync_with_output (gitg_command_new (commit->priv->repository, - "cat-file", - "commit", - "HEAD", - NULL), - FALSE, - &out, - NULL); - - gchar *ret = NULL; - - if (retval && out) - { - gchar **ptr = out; - - while (*ptr) - { - if (!**ptr) - { - ++ptr; - break; - } - - ++ptr; - } - - if (*ptr && **ptr) - { - GString *buffer = g_string_new (""); - - while (*ptr) - { - if (buffer->len != 0) - { - g_string_append_c (buffer, '\n'); - } - - g_string_append (buffer, *ptr); - ++ptr; - } - - ret = g_string_free (buffer, FALSE); - } - } - - g_strfreev (out); - return ret; -} diff --git a/libgitg/gitg-commit.h b/libgitg/gitg-commit.h deleted file mode 100644 index 66a62d19..00000000 --- a/libgitg/gitg-commit.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * gitg-commit.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_COMMIT_H__ -#define __GITG_COMMIT_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_COMMIT (gitg_commit_get_type ()) -#define GITG_COMMIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMIT, GitgCommit)) -#define GITG_COMMIT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_COMMIT, GitgCommit const)) -#define GITG_COMMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_COMMIT, GitgCommitClass)) -#define GITG_IS_COMMIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_COMMIT)) -#define GITG_IS_COMMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_COMMIT)) -#define GITG_COMMIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_COMMIT, GitgCommitClass)) - -#define GITG_COMMIT_ERROR (gitg_commit_error_quark()) - -typedef struct _GitgCommit GitgCommit; -typedef struct _GitgCommitClass GitgCommitClass; -typedef struct _GitgCommitPrivate GitgCommitPrivate; - -typedef enum -{ - GITG_COMMIT_ERROR_NONE = 0, - GITG_COMMIT_ERROR_SIGNOFF, - GITG_COMMIT_ERROR_MERGE -} GitgCommitError; - -struct _GitgCommit { - GObject parent; - - GitgCommitPrivate *priv; -}; - -struct _GitgCommitClass { - GObjectClass parent_class; - - void (*inserted) (GitgCommit *commit, GitgChangedFile *file); - void (*removed) (GitgCommit *commit, GitgChangedFile *file); -}; - -GQuark gitg_commit_error_quark (void); - -GType gitg_commit_get_type (void) G_GNUC_CONST; -GitgCommit *gitg_commit_new (GitgRepository *repository); - -void gitg_commit_refresh (GitgCommit *commit); -gboolean gitg_commit_stage (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error); -gboolean gitg_commit_unstage (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error); -gboolean gitg_commit_has_changes (GitgCommit *commit); -gboolean gitg_commit_commit (GitgCommit *commit, - gchar const *comment, - gboolean signoff, - gboolean amend, - GError **error); - -gboolean gitg_commit_revert (GitgCommit *commit, - GitgRevision *from, - GitgRevision *to, - GError **error); - -gboolean gitg_commit_undo (GitgCommit *commit, - GitgChangedFile *file, - gchar const *hunk, - GError **error); - -gboolean gitg_commit_add_ignore (GitgCommit *commit, - GitgChangedFile *file, - GError **error); - -GitgChangedFile *gitg_commit_find_changed_file (GitgCommit *commit, - GFile *file); - -gchar *gitg_commit_amend_message (GitgCommit *commit); - -G_END_DECLS - -#endif /* __GITG_COMMIT_H__ */ diff --git a/libgitg/gitg-commit.vala b/libgitg/gitg-commit.vala new file mode 100644 index 00000000..ff67a220 --- /dev/null +++ b/libgitg/gitg-commit.vala @@ -0,0 +1,90 @@ +namespace Gitg +{ + +public class Commit : Ggit.Commit +{ + public Lane.Tag tag { get; set; } + public unowned SList lanes { get; set; } + + private ushort d_mylane; + + public ushort mylane + { + get { return d_mylane; } + set + { + d_mylane = value; + update_lane_tag(); + } + } + + public unowned Lane lane + { + get { return lanes.nth_data(d_mylane); } + } + + public unowned SList remove_lane(Lane lane) + { + lanes.remove(lane); + return lanes; + } + + private void update_lane_tag() + { + unowned Lane? lane = lanes.nth_data(d_mylane); + + if (lane == null) + { + return; + } + + lane.tag &= ~(Lane.Tag.SIGN_STASH | + Lane.Tag.SIGN_STAGED | + Lane.Tag.SIGN_UNSTAGED) | tag; + } + + public void update_lanes(SList lanes, int mylane) + { + this.lanes = lanes; + + if (mylane >= 0) + { + d_mylane = (ushort)mylane; + } + + update_lane_tag(); + } + + public string format_patch_name + { + owned get + { + return get_subject().replace(" ", "-").replace("/", "-");; + } + } + + private string date_for_display(DateTime dt) + { + return dt.format("%c"); + } + + public string committer_date_for_display + { + owned get + { + return date_for_display(get_committer().get_time()); + } + } + + public string author_date_for_display + { + owned get + { + return date_for_display(get_author().get_time()); + } + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-config.c b/libgitg/gitg-config.c deleted file mode 100644 index 56d2f324..00000000 --- a/libgitg/gitg-config.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * gitg-config.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-config.h" -#include "gitg-shell.h" -#include "gitg-debug.h" - -#define GITG_CONFIG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_CONFIG, GitgConfigPrivate)) - -enum -{ - PROP_0, - PROP_REPOSITORY -}; - -struct _GitgConfigPrivate -{ - GitgRepository *repository; - GitgShell *shell; - - GString *accumulated; -}; - -G_DEFINE_TYPE (GitgConfig, gitg_config, G_TYPE_OBJECT) - -static void -gitg_config_finalize (GObject *object) -{ - GitgConfig *config = GITG_CONFIG (object); - - if (config->priv->repository) - { - g_object_unref(config->priv->repository); - } - - g_string_free (config->priv->accumulated, TRUE); - - G_OBJECT_CLASS (gitg_config_parent_class)->finalize (object); -} - -static void -gitg_config_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - GitgConfig *self = GITG_CONFIG (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - if (self->priv->repository) - { - g_object_unref(self->priv->repository); - } - - self->priv->repository = GITG_REPOSITORY (g_value_dup_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_config_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - GitgConfig *self = GITG_CONFIG (object); - - switch (prop_id) - { - case PROP_REPOSITORY: - g_value_set_object (value, self->priv->repository); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_config_class_init (GitgConfigClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_config_finalize; - object_class->get_property = gitg_config_get_property; - object_class->set_property = gitg_config_set_property; - - g_object_class_install_property(object_class, PROP_REPOSITORY, - g_param_spec_object("repository", - "REPOSITORY", - "The repository", - GITG_TYPE_REPOSITORY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (object_class, sizeof(GitgConfigPrivate)); -} - -static void -gitg_config_accumulate (GitgShell *shell, - gchar **buffer, - GitgConfig *config) -{ - gchar **ptr = buffer; - - while (*ptr) - { - g_string_append (config->priv->accumulated, *ptr); - ++ptr; - } -} - -static void -gitg_config_begin (GitgShell *shell, - GitgConfig *config) -{ - g_string_erase (config->priv->accumulated, 0, -1); -} - -static void -gitg_config_init (GitgConfig *self) -{ - self->priv = GITG_CONFIG_GET_PRIVATE (self); - - self->priv->shell = gitg_shell_new_synchronized (1000); - gitg_shell_set_preserve_line_endings (self->priv->shell, TRUE); - - self->priv->accumulated = g_string_new (""); - - g_signal_connect (self->priv->shell, - "update", - G_CALLBACK (gitg_config_accumulate), - self); - - g_signal_connect (self->priv->shell, - "begin", - G_CALLBACK (gitg_config_begin), - self); -} - -GitgConfig * -gitg_config_new (GitgRepository *repository) -{ - return g_object_new (GITG_TYPE_CONFIG, "repository", repository, NULL); -} - -static gchar * -get_value_process (GitgConfig *config, gboolean ret) -{ - gchar *res; - - if (ret) - { - res = g_strndup (config->priv->accumulated->str, - config->priv->accumulated->len); - } - else - { - res = NULL; - } - - return res; -} - -static gchar * -get_value_global (GitgConfig *config, gchar const *key) -{ - GError *error = NULL; - - gboolean ret; - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (NULL, - "git", - "config", - "--global", - key, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to get config: %s", - error->message); - - g_error_free (error); - } - - return get_value_process (config, ret); -} - -static gchar * -get_value_global_regex (GitgConfig *config, - gchar const *regex, - gchar const *value_regex) -{ - GError *error = NULL; - - gboolean ret; - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (NULL, - "git", - "config", - "--global", - "--get-regexp", - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to get config: %s", - error->message); - - g_error_free (error); - } - - return get_value_process (config, ret); -} - -static gchar * -get_value_local (GitgConfig *config, gchar const *key) -{ - gboolean ret; - GFile *git_dir; - GFile *cfg_file; - gchar *cfg; - GError *error = NULL; - - git_dir = gitg_repository_get_git_dir (config->priv->repository); - - cfg_file = g_file_get_child (git_dir, "config"); - cfg = g_file_get_path (cfg_file); - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (config->priv->repository, - "config", - "--file", - cfg, - key, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to get config: %s", - error->message); - - g_error_free (error); - } - - g_free (cfg); - - g_object_unref (cfg_file); - g_object_unref (git_dir); - - return get_value_process (config, ret); -} - -static gchar * -get_value_local_regex (GitgConfig *config, - gchar const *regex, - gchar const *value_regex) -{ - gboolean ret; - GFile *git_dir; - GFile *cfg_file; - gchar *cfg; - GError *error = NULL; - - git_dir = gitg_repository_get_git_dir (config->priv->repository); - - cfg_file = g_file_get_child (git_dir, "config"); - cfg = g_file_get_path (cfg_file); - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (config->priv->repository, - "config", - "--file", - cfg, - "--get-regexp", - regex, - value_regex, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to get config: %s", - error->message); - - g_error_free (error); - } - - g_free (cfg); - - g_object_unref (cfg_file); - g_object_unref (git_dir); - - return get_value_process (config, ret); -} - -static gboolean -set_value_global (GitgConfig *config, gchar const *key, gchar const *value) -{ - GError *error = NULL; - gboolean ret; - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (NULL, - "git", - "config", - "--global", - value == NULL ? "--unset" : key, - value == NULL ? key : value, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to get config: %s", - error->message); - - g_error_free (error); - } - - return ret; -} - -static gboolean -set_value_local (GitgConfig *config, gchar const *key, gchar const *value) -{ - gboolean ret; - GFile *git_dir; - GFile *cfg_file; - gchar *cfg; - GError *error = NULL; - - git_dir = gitg_repository_get_git_dir (config->priv->repository); - - cfg_file = g_file_get_child (git_dir, "config"); - cfg = g_file_get_path (cfg_file); - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (config->priv->repository, - "config", - "--file", - cfg, - value == NULL ? "--unset" : key, - value == NULL ? key : value, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to set config: %s", - error->message); - - g_error_free (error); - } - - g_free (cfg); - - g_object_unref (cfg_file); - g_object_unref (git_dir); - - return ret; -} - -static gboolean -rename_global (GitgConfig *config, gchar const *old, gchar const *nw) -{ - gboolean ret; - GError *error = NULL; - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (NULL, - "git", - "config", - "--global", - "--rename-section", - old, - nw, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to rename config: %s", - error->message); - - g_error_free (error); - } - - return ret; -} - -static gboolean -rename_local (GitgConfig *config, gchar const *old, gchar const *nw) -{ - gboolean ret; - GFile *git_dir; - GFile *cfg_file; - gchar *cfg; - GError *error = NULL; - - git_dir = gitg_repository_get_git_dir (config->priv->repository); - - cfg_file = g_file_get_child (git_dir, "config"); - cfg = g_file_get_path (cfg_file); - - ret = gitg_shell_run (config->priv->shell, - gitg_command_new (config->priv->repository, - "config", - "--file", - cfg, - "--rename-section", - old, - nw, - NULL), - &error); - - if (error) - { - gitg_debug (GITG_DEBUG_CONFIG, - "Failed to rename config: %s", - error->message); - - g_error_free (error); - } - - g_free (cfg); - - g_object_unref (cfg_file); - g_object_unref (git_dir); - - return ret; -} - -gchar * -gitg_config_get_value (GitgConfig *config, gchar const *key) -{ - g_return_val_if_fail (GITG_IS_CONFIG (config), NULL); - g_return_val_if_fail (key != NULL, NULL); - - if (config->priv->repository != NULL) - { - return get_value_local (config, key); - } - else - { - return get_value_global (config, key); - } -} - -gchar * -gitg_config_get_value_regex (GitgConfig *config, - gchar const *regex, - gchar const *value_regex) -{ - g_return_val_if_fail (GITG_IS_CONFIG (config), NULL); - g_return_val_if_fail (regex != NULL, NULL); - - if (config->priv->repository != NULL) - { - return get_value_local_regex (config, regex, value_regex); - } - else - { - return get_value_global_regex (config, regex, value_regex); - } -} - -gboolean -gitg_config_set_value (GitgConfig *config, gchar const *key, gchar const *value) -{ - g_return_val_if_fail (GITG_IS_CONFIG (config), FALSE); - g_return_val_if_fail (key != NULL, FALSE); - - if (config->priv->repository != NULL) - { - return set_value_local (config, key, value); - } - else - { - return set_value_global (config, key, value); - } -} - -gboolean -gitg_config_rename (GitgConfig *config, gchar const *old, gchar const *nw) -{ - g_return_val_if_fail (GITG_IS_CONFIG (config), FALSE); - g_return_val_if_fail (old != NULL, FALSE); - g_return_val_if_fail (nw != NULL, FALSE); - - if (config->priv->repository != NULL) - { - return rename_local (config, old, nw); - } - else - { - return rename_global (config, old, nw); - } -} diff --git a/libgitg/gitg-config.h b/libgitg/gitg-config.h deleted file mode 100644 index a68363e6..00000000 --- a/libgitg/gitg-config.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * gitg-config.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_CONFIG_H__ -#define __GITG_CONFIG_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_CONFIG (gitg_config_get_type ()) -#define GITG_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CONFIG, GitgConfig)) -#define GITG_CONFIG_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_CONFIG, GitgConfig const)) -#define GITG_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_CONFIG, GitgConfigClass)) -#define GITG_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_CONFIG)) -#define GITG_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_CONFIG)) -#define GITG_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_CONFIG, GitgConfigClass)) - -typedef struct _GitgConfig GitgConfig; -typedef struct _GitgConfigClass GitgConfigClass; -typedef struct _GitgConfigPrivate GitgConfigPrivate; - -struct _GitgConfig -{ - GObject parent; - - GitgConfigPrivate *priv; -}; - -struct _GitgConfigClass -{ - GObjectClass parent_class; -}; - -GType gitg_config_get_type (void) G_GNUC_CONST; -GitgConfig *gitg_config_new (GitgRepository *repository); - -gchar *gitg_config_get_value (GitgConfig *config, - gchar const *key); - -gchar *gitg_config_get_value_regex (GitgConfig *config, - gchar const *regex, - gchar const *value_regex); - -gboolean gitg_config_rename (GitgConfig *config, - gchar const *old, - gchar const *nw); - -gboolean gitg_config_set_value (GitgConfig *config, - gchar const *key, - gchar const *value); - -G_END_DECLS - -#endif /* __GITG_CONFIG_H__ */ diff --git a/libgitg/gitg-convert.c b/libgitg/gitg-convert.c deleted file mode 100644 index 49784101..00000000 --- a/libgitg/gitg-convert.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * gitg-convert.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-convert.h" - -#include - -static void -utf8_validate_fallback (gchar *text, - gssize size) -{ - gchar const *end; - - while (!g_utf8_validate (text, size, &end)) - { - *((gchar *)end) = '?'; - } -} - -static gchar * -convert_fallback (gchar const *text, - gssize size, - gchar const *fallback) -{ - gchar *res; - gsize read, written; - GString *str = g_string_new (""); - - while ((res = g_convert(text, - size, - "UTF-8", - "ASCII", - &read, - &written, - NULL)) == NULL) - { - res = g_convert (text, read, "UTF-8", "ASCII", NULL, NULL, NULL); - str = g_string_append (str, res); - - str = g_string_append (str, fallback); - text = text + read + 1; - size = size - read; - } - - str = g_string_append (str, res); - g_free (res); - - utf8_validate_fallback (str->str, str->len); - return g_string_free (str, FALSE); -} - -gchar * -gitg_convert_utf8 (gchar const *str, gssize size) -{ - static gchar *encodings[] = { - "ISO-8859-15", - "ASCII" - }; - - if (str == NULL) - { - return NULL; - } - - if (size == -1) - { - size = strlen (str); - } - - if (g_utf8_validate (str, size, NULL)) - { - return g_strndup (str, size); - } - - int i; - for (i = 0; i < sizeof (encodings) / sizeof (gchar *); ++i) - { - gsize read; - gsize written; - - gchar *ret = g_convert (str, - size, - "UTF-8", - encodings[i], - &read, - &written, - NULL); - - if (ret && read == size) - { - utf8_validate_fallback (ret, written); - return ret; - } - - g_free (ret); - } - - return convert_fallback (str, size, "?"); -} diff --git a/libgitg/gitg-convert.h b/libgitg/gitg-convert.h deleted file mode 100644 index 614d26b4..00000000 --- a/libgitg/gitg-convert.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * gitg-convert.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_CONVERT_H__ -#define __GITG_CONVERT_H__ - -#include - -G_BEGIN_DECLS - -gchar *gitg_convert_utf8 (gchar const *str, gssize size); - -G_END_DECLS - -#endif /* __GITG_CONVERT_H__ */ diff --git a/libgitg/gitg-debug.c b/libgitg/gitg-debug.c deleted file mode 100644 index 6530e7a3..00000000 --- a/libgitg/gitg-debug.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * gitg-debug.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-debug.h" -#include -#include - -static guint debug_enabled = GITG_DEBUG_NONE; - -#define DEBUG_FROM_ENV(name) \ - { \ - if (g_getenv(#name)) \ - { \ - debug_enabled |= name; \ - } \ - } - -void -gitg_debug_init (void) -{ - DEBUG_FROM_ENV (GITG_DEBUG_SHELL); - DEBUG_FROM_ENV (GITG_DEBUG_SHELL_OUTPUT); - DEBUG_FROM_ENV (GITG_DEBUG_CHARSET_CONVERSION); - DEBUG_FROM_ENV (GITG_DEBUG_CONFIG); -} - -gboolean -gitg_debug_enabled (guint debug) -{ - return debug_enabled & debug; -} - -void -gitg_debug_message (guint level, - gchar const *file, - gint line, - gchar const *function, - gchar const *format, - ...) -{ - if (G_UNLIKELY (debug_enabled & level)) - { - va_list ap; - gchar *msg; - - va_start (ap, format); - msg = g_strdup_vprintf (format, ap); - va_end (ap); - - g_print ("%s:%d (%s) %s\n", file, line, function, msg); - fflush (stdout); - - g_free (msg); - } -} diff --git a/libgitg/gitg-debug.h b/libgitg/gitg-debug.h deleted file mode 100644 index 81183b6a..00000000 --- a/libgitg/gitg-debug.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * gitg-debug.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_DEBUG_H__ -#define __GITG_DEBUG_H__ - -#include -#include - -enum -{ - GITG_DEBUG_NONE = 0, - GITG_DEBUG_SHELL = 1 << 0, - GITG_DEBUG_SHELL_OUTPUT = 1 << 1, - GITG_DEBUG_CHARSET_CONVERSION = 1 << 2, - GITG_DEBUG_CONFIG = 1 << 3 -}; - -#if ENABLE_DEBUG -void gitg_debug_init (void); -gboolean gitg_debug_enabled (guint debug); - -void gitg_debug_message (guint level, - gchar const *file, - gint line, - gchar const *function, - gchar const *format, - ...); - -#define gitg_debug(level,args...) gitg_debug_message (level, __FILE__, __LINE__, G_STRFUNC, args) -#else - -#define gitg_debug_init(args...) ; -#define gitg_debug_enabled(x) FALSE -#define gitg_debug(level,args...) ; - -#endif - -#endif /* __GITG_DEBUG_H__ */ - diff --git a/libgitg/gitg-encodings.c b/libgitg/gitg-encodings.c deleted file mode 100644 index 7c3411f8..00000000 --- a/libgitg/gitg-encodings.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * This file was copied from gedit-encodings.c - * - * gedit-encodings.c - * This file is part of gedit - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * 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. - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include "gitg-encodings.h" - - -struct _GitgEncoding -{ - gint index; - const gchar *charset; - const gchar *name; -}; - -G_DEFINE_BOXED_TYPE (GitgEncoding, gitg_encoding, - gitg_encoding_copy, - gitg_encoding_free) - -/* - * The original versions of the following tables are taken from profterm - * - * Copyright (C) 2002 Red Hat, Inc. - */ - -typedef enum -{ - - GITG_ENCODING_ISO_8859_1, - GITG_ENCODING_ISO_8859_2, - GITG_ENCODING_ISO_8859_3, - GITG_ENCODING_ISO_8859_4, - GITG_ENCODING_ISO_8859_5, - GITG_ENCODING_ISO_8859_6, - GITG_ENCODING_ISO_8859_7, - GITG_ENCODING_ISO_8859_8, - GITG_ENCODING_ISO_8859_9, - GITG_ENCODING_ISO_8859_10, - GITG_ENCODING_ISO_8859_13, - GITG_ENCODING_ISO_8859_14, - GITG_ENCODING_ISO_8859_15, - GITG_ENCODING_ISO_8859_16, - - GITG_ENCODING_UTF_7, - GITG_ENCODING_UTF_16, - GITG_ENCODING_UTF_16_BE, - GITG_ENCODING_UTF_16_LE, - GITG_ENCODING_UTF_32, - GITG_ENCODING_UCS_2, - GITG_ENCODING_UCS_4, - - GITG_ENCODING_ARMSCII_8, - GITG_ENCODING_BIG5, - GITG_ENCODING_BIG5_HKSCS, - GITG_ENCODING_CP_866, - - GITG_ENCODING_EUC_JP, - GITG_ENCODING_EUC_JP_MS, - GITG_ENCODING_CP932, - GITG_ENCODING_EUC_KR, - GITG_ENCODING_EUC_TW, - - GITG_ENCODING_GB18030, - GITG_ENCODING_GB2312, - GITG_ENCODING_GBK, - GITG_ENCODING_GEOSTD8, - - GITG_ENCODING_IBM_850, - GITG_ENCODING_IBM_852, - GITG_ENCODING_IBM_855, - GITG_ENCODING_IBM_857, - GITG_ENCODING_IBM_862, - GITG_ENCODING_IBM_864, - - GITG_ENCODING_ISO_2022_JP, - GITG_ENCODING_ISO_2022_KR, - GITG_ENCODING_ISO_IR_111, - GITG_ENCODING_JOHAB, - GITG_ENCODING_KOI8_R, - GITG_ENCODING_KOI8__R, - GITG_ENCODING_KOI8_U, - - GITG_ENCODING_SHIFT_JIS, - GITG_ENCODING_TCVN, - GITG_ENCODING_TIS_620, - GITG_ENCODING_UHC, - GITG_ENCODING_VISCII, - - GITG_ENCODING_WINDOWS_1250, - GITG_ENCODING_WINDOWS_1251, - GITG_ENCODING_WINDOWS_1252, - GITG_ENCODING_WINDOWS_1253, - GITG_ENCODING_WINDOWS_1254, - GITG_ENCODING_WINDOWS_1255, - GITG_ENCODING_WINDOWS_1256, - GITG_ENCODING_WINDOWS_1257, - GITG_ENCODING_WINDOWS_1258, - - GITG_ENCODING_LAST, - - GITG_ENCODING_UTF_8, - GITG_ENCODING_UNKNOWN - -} GitgEncodingIndex; - -static const GitgEncoding utf8_encoding = { - GITG_ENCODING_UTF_8, - "UTF-8", - N_("Unicode") -}; - -/* initialized in gitg_encoding_lazy_init() */ -static GitgEncoding unknown_encoding = { - GITG_ENCODING_UNKNOWN, - NULL, - NULL -}; - -static const GitgEncoding encodings [] = { - - { GITG_ENCODING_ISO_8859_1, - "ISO-8859-1", N_("Western") }, - { GITG_ENCODING_ISO_8859_2, - "ISO-8859-2", N_("Central European") }, - { GITG_ENCODING_ISO_8859_3, - "ISO-8859-3", N_("South European") }, - { GITG_ENCODING_ISO_8859_4, - "ISO-8859-4", N_("Baltic") }, - { GITG_ENCODING_ISO_8859_5, - "ISO-8859-5", N_("Cyrillic") }, - { GITG_ENCODING_ISO_8859_6, - "ISO-8859-6", N_("Arabic") }, - { GITG_ENCODING_ISO_8859_7, - "ISO-8859-7", N_("Greek") }, - { GITG_ENCODING_ISO_8859_8, - "ISO-8859-8", N_("Hebrew Visual") }, - { GITG_ENCODING_ISO_8859_9, - "ISO-8859-9", N_("Turkish") }, - { GITG_ENCODING_ISO_8859_10, - "ISO-8859-10", N_("Nordic") }, - { GITG_ENCODING_ISO_8859_13, - "ISO-8859-13", N_("Baltic") }, - { GITG_ENCODING_ISO_8859_14, - "ISO-8859-14", N_("Celtic") }, - { GITG_ENCODING_ISO_8859_15, - "ISO-8859-15", N_("Western") }, - { GITG_ENCODING_ISO_8859_16, - "ISO-8859-16", N_("Romanian") }, - - { GITG_ENCODING_UTF_7, - "UTF-7", N_("Unicode") }, - { GITG_ENCODING_UTF_16, - "UTF-16", N_("Unicode") }, - { GITG_ENCODING_UTF_16_BE, - "UTF-16BE", N_("Unicode") }, - { GITG_ENCODING_UTF_16_LE, - "UTF-16LE", N_("Unicode") }, - { GITG_ENCODING_UTF_32, - "UTF-32", N_("Unicode") }, - { GITG_ENCODING_UCS_2, - "UCS-2", N_("Unicode") }, - { GITG_ENCODING_UCS_4, - "UCS-4", N_("Unicode") }, - - { GITG_ENCODING_ARMSCII_8, - "ARMSCII-8", N_("Armenian") }, - { GITG_ENCODING_BIG5, - "BIG5", N_("Chinese Traditional") }, - { GITG_ENCODING_BIG5_HKSCS, - "BIG5-HKSCS", N_("Chinese Traditional") }, - { GITG_ENCODING_CP_866, - "CP866", N_("Cyrillic/Russian") }, - - { GITG_ENCODING_EUC_JP, - "EUC-JP", N_("Japanese") }, - { GITG_ENCODING_EUC_JP_MS, - "EUC-JP-MS", N_("Japanese") }, - { GITG_ENCODING_CP932, - "CP932", N_("Japanese") }, - - { GITG_ENCODING_EUC_KR, - "EUC-KR", N_("Korean") }, - { GITG_ENCODING_EUC_TW, - "EUC-TW", N_("Chinese Traditional") }, - - { GITG_ENCODING_GB18030, - "GB18030", N_("Chinese Simplified") }, - { GITG_ENCODING_GB2312, - "GB2312", N_("Chinese Simplified") }, - { GITG_ENCODING_GBK, - "GBK", N_("Chinese Simplified") }, - { GITG_ENCODING_GEOSTD8, - "GEORGIAN-ACADEMY", N_("Georgian") }, /* FIXME GEOSTD8 ? */ - - { GITG_ENCODING_IBM_850, - "IBM850", N_("Western") }, - { GITG_ENCODING_IBM_852, - "IBM852", N_("Central European") }, - { GITG_ENCODING_IBM_855, - "IBM855", N_("Cyrillic") }, - { GITG_ENCODING_IBM_857, - "IBM857", N_("Turkish") }, - { GITG_ENCODING_IBM_862, - "IBM862", N_("Hebrew") }, - { GITG_ENCODING_IBM_864, - "IBM864", N_("Arabic") }, - - { GITG_ENCODING_ISO_2022_JP, - "ISO-2022-JP", N_("Japanese") }, - { GITG_ENCODING_ISO_2022_KR, - "ISO-2022-KR", N_("Korean") }, - { GITG_ENCODING_ISO_IR_111, - "ISO-IR-111", N_("Cyrillic") }, - { GITG_ENCODING_JOHAB, - "JOHAB", N_("Korean") }, - { GITG_ENCODING_KOI8_R, - "KOI8R", N_("Cyrillic") }, - { GITG_ENCODING_KOI8__R, - "KOI8-R", N_("Cyrillic") }, - { GITG_ENCODING_KOI8_U, - "KOI8U", N_("Cyrillic/Ukrainian") }, - - { GITG_ENCODING_SHIFT_JIS, - "SHIFT_JIS", N_("Japanese") }, - { GITG_ENCODING_TCVN, - "TCVN", N_("Vietnamese") }, - { GITG_ENCODING_TIS_620, - "TIS-620", N_("Thai") }, - { GITG_ENCODING_UHC, - "UHC", N_("Korean") }, - { GITG_ENCODING_VISCII, - "VISCII", N_("Vietnamese") }, - - { GITG_ENCODING_WINDOWS_1250, - "WINDOWS-1250", N_("Central European") }, - { GITG_ENCODING_WINDOWS_1251, - "WINDOWS-1251", N_("Cyrillic") }, - { GITG_ENCODING_WINDOWS_1252, - "WINDOWS-1252", N_("Western") }, - { GITG_ENCODING_WINDOWS_1253, - "WINDOWS-1253", N_("Greek") }, - { GITG_ENCODING_WINDOWS_1254, - "WINDOWS-1254", N_("Turkish") }, - { GITG_ENCODING_WINDOWS_1255, - "WINDOWS-1255", N_("Hebrew") }, - { GITG_ENCODING_WINDOWS_1256, - "WINDOWS-1256", N_("Arabic") }, - { GITG_ENCODING_WINDOWS_1257, - "WINDOWS-1257", N_("Baltic") }, - { GITG_ENCODING_WINDOWS_1258, - "WINDOWS-1258", N_("Vietnamese") } -}; - -static void -gitg_encoding_lazy_init (void) -{ - static gboolean initialized = FALSE; - const gchar *locale_charset; - - if (initialized) - { - return; - } - - if (g_get_charset (&locale_charset) == FALSE) - { - unknown_encoding.charset = g_strdup (locale_charset); - } - - initialized = TRUE; -} - -const GitgEncoding * -gitg_encoding_get_from_charset (const gchar *charset) -{ - gint i; - - g_return_val_if_fail (charset != NULL, NULL); - - gitg_encoding_lazy_init (); - - if (charset == NULL) - { - return NULL; - } - - if (g_ascii_strcasecmp (charset, "UTF-8") == 0) - { - return gitg_encoding_get_utf8 (); - } - - i = 0; - - while (i < GITG_ENCODING_LAST) - { - if (g_ascii_strcasecmp (charset, encodings[i].charset) == 0) - { - return &encodings[i]; - } - - ++i; - } - - if (unknown_encoding.charset != NULL) - { - if (g_ascii_strcasecmp (charset, unknown_encoding.charset) == 0) - { - return &unknown_encoding; - } - } - - return NULL; -} - -GSList * -gitg_encoding_get_candidates (void) -{ - static GSList *ret = NULL; - - if (ret == NULL) - { - ret = g_slist_prepend (ret, - (gpointer)gitg_encoding_get_from_index (GITG_ENCODING_WINDOWS_1250)); - - ret = g_slist_prepend (ret, - (gpointer)gitg_encoding_get_from_index (GITG_ENCODING_ISO_8859_1)); - - ret = g_slist_prepend (ret, - (gpointer)gitg_encoding_get_current ()); - - ret = g_slist_prepend (ret, - (gpointer)gitg_encoding_get_utf8 ()); - } - - return ret; -} - -const GitgEncoding * -gitg_encoding_get_from_index (gint idx) -{ - g_return_val_if_fail (idx >= 0, NULL); - - if (idx >= GITG_ENCODING_LAST) - { - return NULL; - } - - gitg_encoding_lazy_init (); - - return &encodings[idx]; -} - -const GitgEncoding * -gitg_encoding_get_utf8 (void) -{ - gitg_encoding_lazy_init (); - - return &utf8_encoding; -} - -const GitgEncoding * -gitg_encoding_get_current (void) -{ - static gboolean initialized = FALSE; - static const GitgEncoding *locale_encoding = NULL; - - const gchar *locale_charset; - - gitg_encoding_lazy_init (); - - if (initialized != FALSE) - { - return locale_encoding; - } - - if (g_get_charset (&locale_charset) == FALSE) - { - g_return_val_if_fail (locale_charset != NULL, &utf8_encoding); - - locale_encoding = gitg_encoding_get_from_charset (locale_charset); - } - else - { - locale_encoding = &utf8_encoding; - } - - if (locale_encoding == NULL) - { - locale_encoding = &unknown_encoding; - } - - g_return_val_if_fail (locale_encoding != NULL, NULL); - - initialized = TRUE; - - return locale_encoding; -} - -gchar * -gitg_encoding_to_string (const GitgEncoding* enc) -{ - g_return_val_if_fail (enc != NULL, NULL); - - gitg_encoding_lazy_init (); - - g_return_val_if_fail (enc->charset != NULL, NULL); - - if (enc->name != NULL) - { - return g_strdup_printf ("%s (%s)", _(enc->name), enc->charset); - } - else - { - if (g_ascii_strcasecmp (enc->charset, "ANSI_X3.4-1968") == 0) - { - return g_strdup_printf ("US-ASCII (%s)", enc->charset); - } - else - { - return g_strdup (enc->charset); - } - } -} - -const gchar * -gitg_encoding_get_charset (const GitgEncoding* enc) -{ - g_return_val_if_fail (enc != NULL, NULL); - - gitg_encoding_lazy_init (); - - g_return_val_if_fail (enc->charset != NULL, NULL); - - return enc->charset; -} - -const gchar * -gitg_encoding_get_name (const GitgEncoding* enc) -{ - g_return_val_if_fail (enc != NULL, NULL); - - gitg_encoding_lazy_init (); - - return (enc->name == NULL) ? _("Unknown") : _(enc->name); -} - -/* These are to make language bindings happy. Since Encodings are - * const, copy() just returns the same pointer and fres() doesn't - * do nothing */ - -GitgEncoding * -gitg_encoding_copy (const GitgEncoding *enc) -{ - g_return_val_if_fail (enc != NULL, NULL); - - return (GitgEncoding *) enc; -} - -void -gitg_encoding_free (GitgEncoding *enc) -{ - g_return_if_fail (enc != NULL); -} - -static gboolean -data_exists (GSList *list, - const gpointer data) -{ - while (list != NULL) - { - if (list->data == data) - return TRUE; - - list = g_slist_next (list); - } - - return FALSE; -} - -GSList * -_gitg_encoding_strv_to_list (const gchar * const *enc_str) -{ - GSList *res = NULL; - gchar **p; - const GitgEncoding *enc; - - for (p = (gchar **)enc_str; p != NULL && *p != NULL; p++) - { - const gchar *charset = *p; - - if (strcmp (charset, "CURRENT") == 0) - g_get_charset (&charset); - - g_return_val_if_fail (charset != NULL, NULL); - enc = gitg_encoding_get_from_charset (charset); - - if (enc != NULL) - { - if (!data_exists (res, (gpointer)enc)) - { - res = g_slist_prepend (res, (gpointer)enc); - } - } - } - - return g_slist_reverse (res); -} - -gchar ** -_gitg_encoding_list_to_strv (const GSList *enc_list) -{ - GSList *l; - GPtrArray *array; - - array = g_ptr_array_sized_new (g_slist_length ((GSList *)enc_list) + 1); - - for (l = (GSList *)enc_list; l != NULL; l = g_slist_next (l)) - { - const GitgEncoding *enc; - const gchar *charset; - - enc = (const GitgEncoding *)l->data; - - charset = gitg_encoding_get_charset (enc); - g_return_val_if_fail (charset != NULL, NULL); - - g_ptr_array_add (array, g_strdup (charset)); - } - - g_ptr_array_add (array, NULL); - - return (gchar **)g_ptr_array_free (array, FALSE); -} - -/* ex:ts=8:noet: */ diff --git a/libgitg/gitg-encodings.h b/libgitg/gitg-encodings.h deleted file mode 100644 index 1c7070ee..00000000 --- a/libgitg/gitg-encodings.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copied from gedit-encodings.h - * - * - * gedit-encodings.h - * This file is part of gedit - * - * Copyright (C) 2002-2005 Paolo Maggi - * - * 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. - */ - -/* - * Modified by the gedit Team, 2002-2005. See the AUTHORS file for a - * list of people on the gedit Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifndef __GITG_ENCODINGS_H__ -#define __GITG_ENCODINGS_H__ - -#include -#include - -G_BEGIN_DECLS - -typedef struct _GitgEncoding GitgEncoding; - -#define GITG_TYPE_ENCODING (gitg_encoding_get_type ()) - -GType gitg_encoding_get_type (void) G_GNUC_CONST; - -const GitgEncoding *gitg_encoding_get_from_charset (const gchar *charset); -const GitgEncoding *gitg_encoding_get_from_index (gint index); - -gchar *gitg_encoding_to_string (const GitgEncoding *enc); - -const gchar *gitg_encoding_get_name (const GitgEncoding *enc); -const gchar *gitg_encoding_get_charset (const GitgEncoding *enc); - -const GitgEncoding *gitg_encoding_get_utf8 (void); -const GitgEncoding *gitg_encoding_get_current (void); - -GSList *gitg_encoding_get_candidates (void); - -/* These should not be used, they are just to make python bindings happy */ -GitgEncoding *gitg_encoding_copy (const GitgEncoding *enc); -void gitg_encoding_free (GitgEncoding *enc); - -GSList *_gitg_encoding_strv_to_list (const gchar * const *enc_str); -gchar **_gitg_encoding_list_to_strv (const GSList *enc); - -G_END_DECLS - -#endif /* __GITG_ENCODINGS_H__ */ - -/* ex:ts=8:noet: */ diff --git a/libgitg/gitg-enum-types.c.template b/libgitg/gitg-enum-types.c.template deleted file mode 100644 index 69dd81d0..00000000 --- a/libgitg/gitg-enum-types.c.template +++ /dev/null @@ -1,40 +0,0 @@ -/*** BEGIN file-header ***/ -#include "gitg-enum-types.h" - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* enumerations from "@filename@" */ -#include "@filename@" - -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType -@enum_name@_get_type (void) -{ - static GType the_type = 0; - - if (the_type == 0) - { - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, - "@VALUENAME@", - "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - the_type = g_@type@_register_static ( - g_intern_static_string ("@EnumName@"), - values); - } - return the_type; -} - -/*** END value-tail ***/ - diff --git a/libgitg/gitg-enum-types.h.template b/libgitg/gitg-enum-types.h.template deleted file mode 100644 index 7808c8d0..00000000 --- a/libgitg/gitg-enum-types.h.template +++ /dev/null @@ -1,28 +0,0 @@ -/*** BEGIN file-header ***/ -#ifndef __GITG_ENUM_TYPES_H__ -#define __GITG_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* Enumerations from "@filename@" */ - -/*** END file-production ***/ - -/*** BEGIN enumeration-production ***/ -#define GITG_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) -GType @enum_name@_get_type (void) G_GNUC_CONST; - -/*** END enumeration-production ***/ - -/*** BEGIN file-tail ***/ -G_END_DECLS - -#endif /* __GITG_ENUM_TYPES_H__ */ -/*** END file-tail ***/ - - diff --git a/libgitg/gitg-hash.c b/libgitg/gitg-hash.c deleted file mode 100644 index 9bb4e061..00000000 --- a/libgitg/gitg-hash.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * gitg-hash.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 -#include -#include -#include - -#include "gitg-hash.h" - -inline static guint8 -atoh (gchar c) -{ - if (c >= 'a') - { - return c - 'a' + 10; - } - - if (c >= 'A') - { - return c - 'A' + 10; - } - - return c - '0'; -} - -void -gitg_hash_partial_sha1_to_hash (gchar const *sha, - gint length, - gchar *hash) -{ - if (length % 2 == 1) - { - --length; - } - - int i; - - for (i = 0; i < length / 2; ++i) - { - gchar h = atoh (*(sha++)) << 4; - hash[i] = h | atoh (*(sha++)); - } -} - -void -gitg_hash_sha1_to_hash (gchar const *sha, - gchar *hash) -{ - gitg_hash_partial_sha1_to_hash (sha, GITG_HASH_SHA_SIZE, hash); -} - -void -gitg_hash_hash_to_sha1 (gchar const *hash, - gchar *sha) -{ - char const *repr = "0123456789abcdef"; - int i; - int pos = 0; - - for (i = 0; i < GITG_HASH_BINARY_SIZE; ++i) - { - sha[pos++] = repr[(hash[i] >> 4) & 0x0f]; - sha[pos++] = repr[(hash[i] & 0x0f)]; - } -} - -gchar * -gitg_hash_hash_to_sha1_new (gchar const *hash) -{ - gchar *ret = g_new (gchar, GITG_HASH_SHA_SIZE + 1); - gitg_hash_hash_to_sha1 (hash, ret); - - ret[GITG_HASH_SHA_SIZE] = '\0'; - return ret; -} - -gchar * -gitg_hash_partial_sha1_to_hash_new (gchar const *sha, - gint length, - gint *retlen) -{ - if (length == -1) - { - length = strlen (sha); - } - - if (length % 2 != 0) - { - --length; - } - - *retlen = length / 2; - gchar *ret = g_new (gchar, *retlen); - - gitg_hash_partial_sha1_to_hash (sha, length, ret); - - return ret; -} - -gchar * -gitg_hash_sha1_to_hash_new (gchar const *sha1) -{ - gchar *ret = g_new (gchar, GITG_HASH_BINARY_SIZE); - gitg_hash_sha1_to_hash (sha1, ret); - - return ret; -} - -guint -gitg_hash_hash (gconstpointer v) -{ - /* 31 bit hash function, copied from g_str_hash */ - const signed char *p = v; - guint32 h = *p; - int i; - - for (i = 1; i < GITG_HASH_BINARY_SIZE; ++i) - h = (h << 5) - h + p[i]; - - return h; -} - -gboolean -gitg_hash_hash_equal (gconstpointer a, gconstpointer b) -{ - return memcmp (a, b, GITG_HASH_BINARY_SIZE) == 0; -} diff --git a/libgitg/gitg-hash.h b/libgitg/gitg-hash.h deleted file mode 100644 index 28238bcc..00000000 --- a/libgitg/gitg-hash.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * gitg-hash.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_HASH_H__ -#define __GITG_HASH_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_HASH_BINARY_SIZE 20 -#define GITG_HASH_SHA_SIZE 40 - -typedef gchar GitgHash[GITG_HASH_BINARY_SIZE]; - -void gitg_hash_sha1_to_hash(gchar const *sha, gchar *hash); -void gitg_hash_hash_to_sha1(gchar const *hash, gchar *sha); - -void gitg_hash_partial_sha1_to_hash (gchar const *sha, gint length, gchar *hash); - -gchar *gitg_hash_sha1_to_hash_new(gchar const *sha); -gchar *gitg_hash_hash_to_sha1_new(gchar const *hash); - -gchar *gitg_hash_partial_sha1_to_hash_new (gchar const *sha, gint length, gint *retlen); - -guint gitg_hash_hash(gconstpointer v); -gboolean gitg_hash_hash_equal(gconstpointer a, gconstpointer b); - -G_END_DECLS - -#endif /* __GITG_HASH_H__ */ diff --git a/libgitg/gitg-i18n.c b/libgitg/gitg-i18n.c deleted file mode 100644 index 359c2f20..00000000 --- a/libgitg/gitg-i18n.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation - * All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "gitg-i18n.h" - -/** - * _gitg_gettext: - * @msgid: The string to be translated - * - * Returns the translated string from the libgitg translations. - * This is an internal function and should only be used by - * the internals of libgitg - * - * Returns: the transation of @msgid to the current locale - */ -const gchar * -_gitg_gettext (const gchar *msgid) -{ - static gboolean initialized = FALSE; - - if (G_UNLIKELY (!initialized)) - { - bindtextdomain (GETTEXT_PACKAGE, GITG_LOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - - initialized = TRUE; - } - - return g_dgettext (GETTEXT_PACKAGE, msgid); -} diff --git a/libgitg/gitg-i18n.h b/libgitg/gitg-i18n.h deleted file mode 100644 index 7b47ff69..00000000 --- a/libgitg/gitg-i18n.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation - * All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -/* - * Handles all of the internationalization configuration options. - * Author: Tom Tromey - * - * This is a modified version of gtksourceview-i18n.h - */ - -#ifndef __GITG_18N_H__ -#define __GITG_18N_H__ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -G_BEGIN_DECLS - -#ifdef ENABLE_NLS -# include -# undef _ -# define _(String) _gitg_gettext (String) -# undef N_ -# ifdef gettext_noop -# define N_(String) gettext_noop (String) -# else -# define N_(String) (String) -# endif -#else -/* Stubs that do something close enough. */ -# undef textdomain -# define textdomain(String) (String) -# undef gettext -# define gettext(String) (String) -# undef dgettext -# define dgettext(Domain,Message) (Message) -# undef dcgettext -# define dcgettext(Domain,Message,Type) (Message) -# undef bindtextdomain -# define bindtextdomain(Domain,Directory) (Domain) -# undef bind_textdomain_codeset -# define bind_textdomain_codeset(Domain,CodeSet) (Domain) -# undef _ -# define _(String) (String) -# undef N_ -# define N_(String) (String) -#endif - -const gchar *_gitg_gettext (const char *msgid) G_GNUC_FORMAT(1); - -G_END_DECLS - -#endif /* __GITG_I18N_H__ */ diff --git a/libgitg/gitg-init.vala b/libgitg/gitg-init.vala new file mode 100644 index 00000000..841a3fe2 --- /dev/null +++ b/libgitg/gitg-init.vala @@ -0,0 +1,20 @@ +namespace Gitg +{ + +public void init() +{ + var factory = Ggit.ObjectFactory.get_default(); + + factory.register(typeof(Ggit.Repository), + typeof(Gitg.Repository)); + + factory.register(typeof(Ggit.Ref), + typeof(Gitg.Ref)); + + factory.register(typeof(Ggit.Commit), + typeof(Gitg.Commit)); +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-io.c b/libgitg/gitg-io.c deleted file mode 100644 index 955020a1..00000000 --- a/libgitg/gitg-io.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * gitg-io.c - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include "gitg-io.h" - -#define GITG_IO_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_IO, GitgIOPrivate)) - -struct _GitgIOPrivate -{ - GInputStream *input; - GOutputStream *output; - - gint exit_status; - - guint cancelled : 1; - guint running : 1; - guint auto_utf8 : 1; - guint stderr_to_stdout : 1; -}; - -enum -{ - PROP_0, - - PROP_INPUT, - PROP_OUTPUT, - PROP_CANCELLED, - PROP_EXIT_STATUS, - PROP_RUNNING, - PROP_AUTO_UTF8, - PROP_STDERR_TO_STDOUT -}; - -enum -{ - BEGIN, - END, - NUM_SIGNALS -}; - -G_DEFINE_TYPE (GitgIO, gitg_io, G_TYPE_OBJECT) - -static guint signals[NUM_SIGNALS] = {0,}; - -static void -gitg_io_finalize (GObject *object) -{ - G_OBJECT_CLASS (gitg_io_parent_class)->finalize (object); -} - -static void -gitg_io_dispose (GObject *object) -{ - GitgIO *io; - - io = GITG_IO (object); - - gitg_io_close (io); - - G_OBJECT_CLASS (gitg_io_parent_class)->dispose (object); -} - -static void -gitg_io_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgIO *self = GITG_IO (object); - - switch (prop_id) - { - case PROP_INPUT: - gitg_io_set_input (self, g_value_get_object (value)); - break; - case PROP_OUTPUT: - gitg_io_set_output (self, g_value_get_object (value)); - break; - case PROP_CANCELLED: - gitg_io_set_cancelled (self, g_value_get_boolean (value)); - break; - case PROP_EXIT_STATUS: - gitg_io_set_exit_status (self, g_value_get_int (value)); - break; - case PROP_RUNNING: - gitg_io_set_running (self, g_value_get_boolean (value)); - break; - case PROP_AUTO_UTF8: - gitg_io_set_auto_utf8 (self, g_value_get_boolean (value)); - break; - case PROP_STDERR_TO_STDOUT: - gitg_io_set_stderr_to_stdout (self, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_io_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgIO *self = GITG_IO (object); - - switch (prop_id) - { - case PROP_INPUT: - g_value_set_object (value, self->priv->input); - break; - case PROP_OUTPUT: - g_value_set_object (value, self->priv->output); - break; - case PROP_CANCELLED: - g_value_set_boolean (value, self->priv->cancelled); - break; - case PROP_EXIT_STATUS: - g_value_set_int (value, self->priv->exit_status); - break; - case PROP_RUNNING: - g_value_set_boolean (value, self->priv->running); - break; - case PROP_AUTO_UTF8: - g_value_set_boolean (value, self->priv->auto_utf8); - break; - case PROP_STDERR_TO_STDOUT: - g_value_set_boolean (value, self->priv->stderr_to_stdout); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_io_cancel_impl (GitgIO *io) -{ - io->priv->cancelled = TRUE; -} - -static void -gitg_io_begin_impl (GitgIO *io) -{ - gitg_io_set_running (io, TRUE); -} - -static void -gitg_io_end_impl (GitgIO *io, - GError *error) -{ - gitg_io_set_running (io, FALSE); -} - -static void -gitg_io_class_init (GitgIOClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_io_finalize; - object_class->dispose = gitg_io_dispose; - - object_class->get_property = gitg_io_get_property; - object_class->set_property = gitg_io_set_property; - - klass->cancel = gitg_io_cancel_impl; - klass->begin = gitg_io_begin_impl; - klass->end = gitg_io_end_impl; - - g_object_class_install_property (object_class, - PROP_INPUT, - g_param_spec_object ("input", - "Input", - "Input", - G_TYPE_INPUT_STREAM, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_OUTPUT, - g_param_spec_object ("output", - "Output", - "Output", - G_TYPE_OUTPUT_STREAM, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_CANCELLED, - g_param_spec_boolean ("cancelled", - "Cancelled", - "Cancelled", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_EXIT_STATUS, - g_param_spec_int ("exit-status", - "Exit status", - "Exit Status", - G_MININT, - G_MAXINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_RUNNING, - g_param_spec_boolean ("running", - "Running", - "Running", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_STDERR_TO_STDOUT, - g_param_spec_boolean ("stderr-to-stdout", - "stderr to stdout", - "Redirect stderr to stdout", - FALSE, - G_PARAM_READWRITE)); - - signals[BEGIN] = - g_signal_new ("begin", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GitgIOClass, begin), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - signals[END] = - g_signal_new ("end", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GitgIOClass, end), - NULL, - NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, - 1, - G_TYPE_ERROR); - - g_type_class_add_private (object_class, sizeof (GitgIOPrivate)); - - g_object_class_install_property (object_class, - PROP_AUTO_UTF8, - g_param_spec_boolean ("auto-utf8", - "Auto Utf8", - "Auto utf8", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -} - -static void -gitg_io_init (GitgIO *self) -{ - self->priv = GITG_IO_GET_PRIVATE (self); -} - -GitgIO * -gitg_io_new () -{ - return g_object_new (GITG_TYPE_IO, NULL); -} - -void -gitg_io_begin (GitgIO *io) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (!io->priv->running) - { - g_signal_emit (io, signals[BEGIN], 0); - } -} - -void -gitg_io_end (GitgIO *io, - GError *error) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->running) - { - g_signal_emit (io, signals[END], 0, error); - } -} - -void -gitg_io_cancel (GitgIO *io) -{ - if (GITG_IO_GET_CLASS (io)->cancel) - { - GITG_IO_GET_CLASS (io)->cancel (io); - } -} - -gboolean -gitg_io_get_cancelled (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), FALSE); - - return io->priv->cancelled; -} - -void -gitg_io_set_cancelled (GitgIO *io, - gboolean cancelled) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->cancelled != cancelled) - { - io->priv->cancelled = cancelled; - g_object_notify (G_OBJECT (io), "cancelled"); - } -} - -void -gitg_io_set_output (GitgIO *io, - GOutputStream *stream) -{ - g_return_if_fail (GITG_IS_IO (io)); - g_return_if_fail (G_IS_OUTPUT_STREAM (stream)); - - if (io->priv->output) - { - g_object_unref (io->priv->output); - io->priv->output = NULL; - } - - if (stream) - { - io->priv->output = g_object_ref (stream); - } -} - -void -gitg_io_set_input (GitgIO *io, - GInputStream *stream) -{ - g_return_if_fail (GITG_IS_IO (io)); - g_return_if_fail (G_IS_INPUT_STREAM (stream)); - - if (io->priv->input) - { - g_object_unref (io->priv->input); - io->priv->input = NULL; - } - - if (stream) - { - io->priv->input = g_object_ref (stream); - } -} - -GInputStream * -gitg_io_get_input (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), NULL); - return io->priv->input; -} - -GOutputStream * -gitg_io_get_output (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), NULL); - return io->priv->output; -} - -void -gitg_io_close (GitgIO *io) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->input) - { - g_input_stream_close (io->priv->input, NULL, NULL); - - g_object_unref (io->priv->input); - io->priv->input = NULL; - } - - if (io->priv->output) - { - g_output_stream_close (io->priv->output, NULL, NULL); - - g_object_unref (io->priv->output); - io->priv->output = NULL; - } -} - -gint -gitg_io_get_exit_status (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), 0); - - return io->priv->exit_status; -} - -void -gitg_io_set_exit_status (GitgIO *io, - gint exit_status) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->exit_status != exit_status) - { - io->priv->exit_status = exit_status; - g_object_notify (G_OBJECT (io), "exit-status"); - } -} - -gboolean -gitg_io_get_running (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), FALSE); - - return io->priv->running; -} - -void -gitg_io_set_running (GitgIO *io, - gboolean running) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->running != running) - { - io->priv->running = running; - - if (running) - { - io->priv->cancelled = FALSE; - } - - g_object_notify (G_OBJECT (io), "running"); - } -} - -void -gitg_io_set_auto_utf8 (GitgIO *io, - gboolean auto_utf8) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->auto_utf8 == auto_utf8) - { - return; - } - - io->priv->auto_utf8 = auto_utf8; - - g_object_notify (G_OBJECT (io), "auto-utf8"); -} - -gboolean -gitg_io_get_auto_utf8 (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), FALSE); - - return io->priv->auto_utf8; -} - -void -gitg_io_set_stderr_to_stdout (GitgIO *io, - gboolean redirect) -{ - g_return_if_fail (GITG_IS_IO (io)); - - if (io->priv->stderr_to_stdout == redirect) - { - return; - } - - io->priv->stderr_to_stdout = redirect; - - g_object_notify (G_OBJECT (io), "stderr-to-stdout"); -} - -gboolean -gitg_io_get_stderr_to_stdout (GitgIO *io) -{ - g_return_val_if_fail (GITG_IS_IO (io), FALSE); - - return io->priv->stderr_to_stdout; -} diff --git a/libgitg/gitg-io.h b/libgitg/gitg-io.h deleted file mode 100644 index 153ae871..00000000 --- a/libgitg/gitg-io.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * gitg-io.h - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * 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., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_IO_H__ -#define __GITG_IO_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_IO (gitg_io_get_type ()) -#define GITG_IO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_IO, GitgIO)) -#define GITG_IO_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_IO, GitgIO const)) -#define GITG_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_IO, GitgIOClass)) -#define GITG_IS_IO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_IO)) -#define GITG_IS_IO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_IO)) -#define GITG_IO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_IO, GitgIOClass)) - -typedef struct _GitgIO GitgIO; -typedef struct _GitgIOClass GitgIOClass; -typedef struct _GitgIOPrivate GitgIOPrivate; - -struct _GitgIO -{ - /*< private >*/ - GObject parent; - - GitgIOPrivate *priv; - - /*< public >*/ -}; - -struct _GitgIOClass -{ - /*< private >*/ - GObjectClass parent_class; - - /*< public >*/ - void (*cancel) (GitgIO *io); - - /* Signals */ - void (*begin) (GitgIO *io); - void (*end) (GitgIO *io, GError *error); -}; - -GType gitg_io_get_type (void) G_GNUC_CONST; -GitgIO *gitg_io_new (void); - -void gitg_io_begin (GitgIO *io); -void gitg_io_end (GitgIO *io, - GError *error); - -void gitg_io_set_input (GitgIO *io, - GInputStream *stream); -void gitg_io_set_output (GitgIO *io, - GOutputStream *stream); - -GInputStream *gitg_io_get_input (GitgIO *io); -GOutputStream *gitg_io_get_output (GitgIO *io); - -void gitg_io_close (GitgIO *io); -void gitg_io_cancel (GitgIO *io); - -gboolean gitg_io_get_cancelled (GitgIO *io); -void gitg_io_set_cancelled (GitgIO *io, - gboolean cancelled); - -gint gitg_io_get_exit_status (GitgIO *io); -void gitg_io_set_exit_status (GitgIO *io, - gint status); - -gboolean gitg_io_get_running (GitgIO *io); -void gitg_io_set_running (GitgIO *io, - gboolean running); - -void gitg_io_set_auto_utf8 (GitgIO *io, - gboolean auto_utf8); -gboolean gitg_io_get_auto_utf8 (GitgIO *io); - -gboolean gitg_io_get_stderr_to_stdout (GitgIO *io); -void gitg_io_set_stderr_to_stdout (GitgIO *io, - gboolean redirect); - -G_END_DECLS - -#endif /* __GITG_IO_H__ */ diff --git a/libgitg/gitg-lane.c b/libgitg/gitg-lane.c deleted file mode 100644 index f03e1435..00000000 --- a/libgitg/gitg-lane.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * gitg-lane.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-lane.h" - -/* GitgLane functions */ -GitgLane * -gitg_lane_copy (GitgLane *lane) -{ - GitgLane *copy = g_slice_new(GitgLane); - copy->color = gitg_color_ref(lane->color); - copy->from = g_slist_copy(lane->from); - copy->type = lane->type; - - return copy; -} - -GitgLane * -gitg_lane_dup (GitgLane *lane) -{ - GitgLane *dup = g_slice_new(GitgLane); - dup->color = gitg_color_copy(lane->color); - dup->from = g_slist_copy(lane->from); - dup->type = lane->type; - - return dup; -} - -void -gitg_lane_free (GitgLane *lane) -{ - gitg_color_unref(lane->color); - g_slist_free(lane->from); - - if (GITG_IS_LANE_BOUNDARY(lane)) - g_slice_free(GitgLaneBoundary, (GitgLaneBoundary *)lane); - else - g_slice_free(GitgLane, lane); -} - -GitgLane * -gitg_lane_new (void) -{ - return gitg_lane_new_with_color(NULL); -} - -GitgLane * -gitg_lane_new_with_color (GitgColor *color) -{ - GitgLane *lane = g_slice_new0(GitgLane); - lane->color = color ? gitg_color_ref(color) : gitg_color_next(); - - return lane; -} - -GitgLaneBoundary * -gitg_lane_convert_boundary (GitgLane *lane, GitgLaneType type) -{ - GitgLaneBoundary *boundary = g_slice_new(GitgLaneBoundary); - - boundary->lane = *lane; - boundary->lane.type |= type; - - g_slice_free(GitgLane, lane); - - return boundary; -} diff --git a/libgitg/gitg-lane.h b/libgitg/gitg-lane.h deleted file mode 100644 index 61664db5..00000000 --- a/libgitg/gitg-lane.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * gitg-lane.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_LANE_H__ -#define __GITG_LANE_H__ - -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_IS_LANE_BOUNDARY(lane) (lane->type & GITG_LANE_TYPE_START || lane->type & GITG_LANE_TYPE_END) - -typedef enum -{ - GITG_LANE_TYPE_NONE, - GITG_LANE_TYPE_START = 1 << 0, - GITG_LANE_TYPE_END = 1 << 1, - GITG_LANE_SIGN_LEFT = 1 << 2, - GITG_LANE_SIGN_RIGHT = 1 << 3, - GITG_LANE_SIGN_STASH = 1 << 4, - GITG_LANE_SIGN_STAGED = 1 << 5, - GITG_LANE_SIGN_UNSTAGED = 1 << 6, -} GitgLaneType; - -typedef struct -{ - GitgColor *color; /** Pointer to color */ - GSList *from; /** List of lanes merging on this lane */ - gint8 type; -} GitgLane; - -typedef struct -{ - GitgLane lane; - GitgHash hash; -} GitgLaneBoundary; - -GitgLane *gitg_lane_new (void); -GitgLane *gitg_lane_new_with_color (GitgColor *color); -GitgLane *gitg_lane_copy (GitgLane *lane); -GitgLane *gitg_lane_dup (GitgLane *lane); - -void gitg_lane_free (GitgLane *lane); -GitgLaneBoundary *gitg_lane_convert_boundary (GitgLane *lane, GitgLaneType type); - -G_END_DECLS - -#endif /* __GITG_LANE_H__ */ diff --git a/libgitg/gitg-lane.vala b/libgitg/gitg-lane.vala new file mode 100644 index 00000000..e62dbdb5 --- /dev/null +++ b/libgitg/gitg-lane.vala @@ -0,0 +1,63 @@ +namespace Gitg +{ + +[Compact] +public class Lane +{ + [Flags] + public enum Tag + { + NONE = 0, + START = 1 << 0, + END = 1 << 1, + SIGN_STASH = 1 << 2, + SIGN_STAGED = 1 << 3, + SIGN_UNSTAGED = 1 << 4 + } + + public Color color; + public SList from; + public Tag tag; + public Ggit.OId? boundary_id; + + public Lane() + { + this.with_color(null); + } + + public Lane.with_color(Color? color) + { + if (color != null) + { + this.color = color; + } + else + { + this.color = Color.next(); + } + } + + public Lane copy() + { + Lane ret = new Lane.with_color(color); + ret.from = from.copy(); + ret.tag = tag; + ret.boundary_id = boundary_id; + + return ret; + } + + public Lane dup() + { + Lane ret = new Lane.with_color(color.copy()); + ret.from = from.copy(); + ret.tag = tag; + ret.boundary_id = boundary_id; + + return ret; + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-lanes.c b/libgitg/gitg-lanes.c deleted file mode 100644 index 41b86508..00000000 --- a/libgitg/gitg-lanes.c +++ /dev/null @@ -1,750 +0,0 @@ -/* - * gitg-lanes.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-lanes.h" -#include "gitg-hash.h" -#include - -#define GITG_LANES_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_LANES, GitgLanesPrivate)) - -enum -{ - PROP_0, - PROP_INACTIVE_MAX, - PROP_INACTIVE_COLLAPSE, - PROP_INACTIVE_GAP, - PROP_INACTIVE_ENABLED -}; - -typedef struct -{ - GitgLane *lane; - guint8 inactive; - gchar const *from; - gchar const *to; -} LaneContainer; - -typedef struct -{ - GitgColor *color; - gint8 index; - gchar const *from; - gchar const *to; -} CollapsedLane; - -struct _GitgLanesPrivate -{ - /* list of last N GitgRevisions used to backtrack in case of lane - collapse/reactivation */ - GSList *previous; - - /* list of LaneContainer resembling the current lanes state for the - next revision */ - GSList *lanes; - - /* 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; - gboolean inactive_enabled; -}; - -G_DEFINE_TYPE (GitgLanes, gitg_lanes, G_TYPE_OBJECT) - -static void -lane_container_free (LaneContainer *container) -{ - gitg_lane_free (container->lane); - g_slice_free (LaneContainer, container); -} - -static void -collapsed_lane_free (CollapsedLane *lane) -{ - gitg_color_unref (lane->color); - g_slice_free (CollapsedLane, lane); -} - -static CollapsedLane * -collapsed_lane_new (LaneContainer *container) -{ - CollapsedLane *collapsed = g_slice_new (CollapsedLane); - collapsed->color = gitg_color_ref (container->lane->color); - collapsed->from = container->from; - collapsed->to = container->to; - - return collapsed; -} - -static void -free_lanes (GitgLanes *lanes) -{ - g_slist_free_full (lanes->priv->lanes, (GDestroyNotify)lane_container_free); - - lanes->priv->lanes = NULL; -} - -static LaneContainer * -find_lane_by_hash (GitgLanes *lanes, - gchar const *hash, - gint8 *pos) -{ - GSList *item; - gint8 p = 0; - - if (!hash) - { - return NULL; - } - - for (item = lanes->priv->lanes; item; item = g_slist_next (item)) - { - LaneContainer *container = (LaneContainer *)(item->data); - - if (container && container->to && gitg_hash_hash_equal (container->to, hash)) - { - if (pos) - { - *pos = p; - } - - return container; - } - - ++p; - } - - return NULL; -} - -/* GitgLanes functions */ -static void -gitg_lanes_finalize (GObject *object) -{ - GitgLanes *self = GITG_LANES (object); - - gitg_lanes_reset (self); - g_hash_table_destroy (self->priv->collapsed); - - 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; - case PROP_INACTIVE_ENABLED: - self->priv->inactive_enabled = g_value_get_boolean (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; - case PROP_INACTIVE_ENABLED: - g_value_set_boolean (value, self->priv->inactive_enabled); - 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_object_class_install_property (object_class, - PROP_INACTIVE_ENABLED, - g_param_spec_boolean ("inactive-enabled", - "INACTIVE_ENABLED", - "Lane collapsing enabled", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_type_class_add_private (object_class, sizeof (GitgLanesPrivate)); -} - -static void -gitg_lanes_init (GitgLanes *self) -{ - self->priv = GITG_LANES_GET_PRIVATE (self); - self->priv->collapsed = g_hash_table_new_full (gitg_hash_hash, - gitg_hash_hash_equal, - NULL, - (GDestroyNotify)collapsed_lane_free); -} - -GitgLanes * -gitg_lanes_new () -{ - return GITG_LANES (g_object_new (GITG_TYPE_LANES, NULL)); -} - -static LaneContainer * -lane_container_new_with_color (gchar const *from, - gchar const *to, - GitgColor *color) -{ - LaneContainer *ret = g_slice_new (LaneContainer); - - ret->from = from; - ret->to = to; - ret->lane = gitg_lane_new_with_color (color); - ret->inactive = 0; - - return ret; -} - -static LaneContainer * -lane_container_new (gchar const *from, - gchar const *to) -{ - return lane_container_new_with_color (from, to, NULL); -} - -static GSList * -lanes_list (GitgLanes *lanes) -{ - GSList *lns = NULL; - GSList *item; - - for (item = lanes->priv->lanes; item; item = item->next) - { - lns = g_slist_prepend (lns, gitg_lane_copy (((LaneContainer*)item->data)->lane)); - } - - return g_slist_reverse (lns); -} - -void -gitg_lanes_reset (GitgLanes *lanes) -{ - free_lanes (lanes); - gitg_color_reset (); - - g_slist_free_full (lanes->priv->previous, (GDestroyNotify)gitg_revision_unref); - - lanes->priv->previous = NULL; - - g_hash_table_remove_all (lanes->priv->collapsed); -} - -static void -lane_container_next (LaneContainer *container, - gint index) -{ - GitgLane *lane = gitg_lane_copy(container->lane); - - lane->type = GITG_LANE_TYPE_NONE; - g_slist_free (lane->from); - - gitg_lane_free (container->lane); - - container->lane = lane; - container->lane->from = g_slist_prepend (NULL, GINT_TO_POINTER ((gint)(index))); - - if (container->to) - { - ++container->inactive; - } -} - -static void -update_lane_merge_indices (GSList *from, - gint8 index, - gint direction) -{ - GSList *item; - - for (item = from; item; item = g_slist_next (item)) - { - gint8 idx = GPOINTER_TO_INT (item->data); - - if ((direction < 0 && idx > index) || (direction > 0 && idx >= index)) - { - item->data = GINT_TO_POINTER (idx + direction); - } - } -} - -static void -update_merge_indices (GSList *lanes, - gint8 index, - gint direction) -{ - GSList *item; - - for (item = lanes; item; item = g_slist_next (item)) - { - GitgLane *lane = (GitgLane *)item->data; - - update_lane_merge_indices (lane->from, index, direction); - } -} - -static void -add_collapsed (GitgLanes *lanes, - LaneContainer *container, - gint8 index) -{ - CollapsedLane *collapsed = collapsed_lane_new (container); - collapsed->index = index; - - g_hash_table_insert (lanes->priv->collapsed, (gpointer)container->to, collapsed); -} - -static void -collapse_lane (GitgLanes *lanes, - LaneContainer *container, - gint8 index) -{ - /* backtrack for inactive-collapse revisions and remove this container from - those revisions, appropriately updating merge indices etc */ - GSList *item; - - add_collapsed(lanes, container, index); - - for (item = lanes->priv->previous; item; item = g_slist_next(item)) - { - GitgRevision *revision = GITG_REVISION(item->data); - GSList *lns = gitg_revision_get_lanes(revision); - - /* remove lane at 'index' and update merge indices for the lanes - after 'index' in the list */ - if (item->next) - { - GSList *collapsed = g_slist_nth(lns, index); - GitgLane *lane = (GitgLane *)collapsed->data; - - gint8 newindex = GPOINTER_TO_INT(lane->from->data); - - lns = gitg_revision_remove_lane(revision, lane); - - if (item->next->next) - { - update_merge_indices(lns, newindex, -1); - } - - gint mylane = gitg_revision_get_mylane(revision); - - if (mylane > index) - { - gitg_revision_set_mylane(revision, mylane - 1); - } - - index = newindex; - } - else - { - /* the last item we keep, and set the style of the lane to END */ - GSList *lstlane = g_slist_nth(lns, index); - GitgLaneBoundary *boundary; - - boundary = gitg_lane_convert_boundary ((GitgLane *)lstlane->data, - GITG_LANE_TYPE_END); - - /* copy parent hash over */ - memcpy (boundary->hash, container->to, GITG_HASH_BINARY_SIZE); - lstlane->data = boundary; - } - } -} - -static void -update_current_lanes_merge_indices (GitgLanes *lanes, - gint8 index, - gint8 direction) -{ - GSList *item; - - for (item = lanes->priv->lanes; item; item = g_slist_next (item)) - { - update_lane_merge_indices (((LaneContainer *)item->data)->lane->from, - index, - direction); - } -} - -static void -collapse_lanes (GitgLanes *lanes) -{ - GSList *item = lanes->priv->lanes; - gint8 index = 0; - - while (item) - { - LaneContainer *container = (LaneContainer *)item->data; - - if (container->inactive != lanes->priv->inactive_max + lanes->priv->inactive_gap) - { - item = g_slist_next (item); - ++index; - continue; - } - - collapse_lane (lanes, - container, - GPOINTER_TO_INT (container->lane->from->data)); - - update_current_lanes_merge_indices (lanes, index, -1); - - GSList *next = g_slist_next (item); - - lane_container_free (container); - - lanes->priv->lanes = g_slist_remove_link (lanes->priv->lanes, item); - item = next; - } -} - -static gint8 -ensure_correct_index (GitgRevision *revision, - gint8 index) -{ - guint len = g_slist_length (gitg_revision_get_lanes (revision)); - - if (index > len) - { - index = len; - } - - return index; -} - -static void -expand_lane (GitgLanes *lanes, - CollapsedLane *lane) -{ - GSList *item; - gint8 index = lane->index; - - GitgLane *ln = gitg_lane_new_with_color (lane->color); - guint len = g_slist_length (lanes->priv->lanes); - gint8 next; - - if (index > len) - { - index = len; - } - - next = ensure_correct_index ((GitgRevision *)lanes->priv->previous->data, - index); - - LaneContainer *container = lane_container_new_with_color (lane->from, - lane->to, - lane->color); - - update_current_lanes_merge_indices (lanes, index, 1); - - container->lane->from = g_slist_prepend (NULL, GINT_TO_POINTER ((gint)next)); - lanes->priv->lanes = g_slist_insert (lanes->priv->lanes, container, index); - - index = next; - guint cnt = 0; - - for (item = lanes->priv->previous; item; item = g_slist_next (item)) - { - GitgRevision *revision = item->data; - - 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 == lanes->priv->inactive_collapse) - { - GitgLaneBoundary *boundary = gitg_lane_convert_boundary (copy, GITG_LANE_TYPE_START); - - /* copy child hash in boundary */ - memcpy (boundary->hash, lane->from, GITG_HASH_BINARY_SIZE); - copy = (GitgLane *)boundary; - } - else - { - next = ensure_correct_index (GITG_REVISION (item->next->data), index); - copy->from = g_slist_prepend (NULL, GINT_TO_POINTER ((gint)next)); - - /* update merge indices */ - update_merge_indices (lns, index, 1); - } - - lns = gitg_revision_insert_lane (revision, copy, index); - gint mylane = gitg_revision_get_mylane (revision); - - if (mylane >= index) - { - gitg_revision_set_mylane (revision, mylane + 1); - } - - index = next; - ++cnt; - } - - gitg_lane_free (ln); -} - -static void -expand_lane_from_hash (GitgLanes *lanes, gchar const *hash) -{ - CollapsedLane *collapsed = (CollapsedLane *)g_hash_table_lookup (lanes->priv->collapsed, hash); - - if (!collapsed) - { - return; - } - - expand_lane (lanes, collapsed); - g_hash_table_remove (lanes->priv->collapsed, hash); -} - -static void -expand_lanes (GitgLanes *lanes, GitgRevision *revision) -{ - /* expand any lanes that revision needs (own lane and parents lanes) */ - expand_lane_from_hash (lanes, gitg_revision_get_hash (revision)); - - guint num; - guint i; - GitgHash *parents = gitg_revision_get_parents_hash (revision, &num); - - for (i = 0; i < num; ++i) - { - expand_lane_from_hash (lanes, parents[i]); - } -} - -static void -init_next_layer (GitgLanes *lanes) -{ - GSList *item = lanes->priv->lanes; - gint8 index = 0; - - /* Initialize new set of lanes based on 'lanes'. It copies the lane (refs - the color) and adds the lane index as a merge (so it basicly represents - a passthrough) */ - for (item = lanes->priv->lanes; item; item = g_slist_next (item)) - { - LaneContainer *container = (LaneContainer *)item->data; - - lane_container_next (container, index++); - } -} - -static void -prepare_lanes (GitgLanes *lanes, GitgRevision *next, gint8 *pos) -{ - LaneContainer *mylane; - guint num; - GitgHash *parents; - guint i; - gchar const *myhash; - - parents = gitg_revision_get_parents_hash (next, &num); - myhash = gitg_revision_get_hash (next); - - /* prepare the next layer */ - init_next_layer (lanes); - - mylane = (LaneContainer *)g_slist_nth_data (lanes->priv->lanes, *pos); - - /* Iterate over all parents and find them a lane */ - for (i = 0; i < num; ++i) - { - gint8 lnpos; - LaneContainer *container = find_lane_by_hash (lanes, parents[i], &lnpos); - - if (container) - { - /* There already is a lane for this parent. This means that we add - mypos as a merge for the lane, also this means the color of - this lane incluis the merge should change to one color */ - container->lane->from = g_slist_append (container->lane->from, GINT_TO_POINTER ((gint)*pos)); - gitg_color_next_index (container->lane->color); - container->inactive = 0; - container->from = gitg_revision_get_hash (next); - - continue; - } - else if (mylane && mylane->to == NULL) - { - /* There is no parent yet which can proceed on the current - revision lane, so set it now */ - mylane->to = (gchar const *)parents[i]; - - /* If there is more than one parent, then also change the color - since this revision is a merge */ - if (num > 1) - { - gitg_color_unref (mylane->lane->color); - mylane->lane->color = gitg_color_next (); - } - else - { - GitgColor *nc = gitg_color_copy (mylane->lane->color); - gitg_color_unref (mylane->lane->color); - mylane->lane->color = nc; - } - } - else - { - /* Generate a new lane for this parent */ - LaneContainer *newlane = lane_container_new (myhash, parents[i]); - newlane->lane->from = g_slist_prepend (NULL, GINT_TO_POINTER ((gint)*pos)); - lanes->priv->lanes = g_slist_append (lanes->priv->lanes, newlane); - } - } - - /* Remove the current lane if it is no longer needed */ - if (mylane && mylane->to == NULL) - { - lanes->priv->lanes = g_slist_remove (lanes->priv->lanes, mylane); - } - - /* Store new revision in our track list */ - 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)); - - lanes->priv->previous = g_slist_remove_link (lanes->priv->previous, last); - } - - lanes->priv->previous = g_slist_prepend (lanes->priv->previous, gitg_revision_ref (next)); -} - -GSList * -gitg_lanes_next (GitgLanes *lanes, GitgRevision *next, gint8 *nextpos) -{ - LaneContainer *mylane; - GSList *res; - gchar const *myhash = gitg_revision_get_hash (next); - - if (lanes->priv->inactive_enabled) - { - collapse_lanes (lanes); - expand_lanes (lanes, next); - } - - mylane = find_lane_by_hash (lanes, myhash, nextpos); - - if (!mylane) - { - /* apparently, there is no lane reserved for this revision, we - add a new one */ - lanes->priv->lanes = g_slist_append (lanes->priv->lanes, lane_container_new (myhash, NULL)); - *nextpos = g_slist_length (lanes->priv->lanes) - 1; - } - else - { - /* copy the color here because this represents a new stop */ - GitgColor *nc = gitg_color_copy (mylane->lane->color); - gitg_color_unref (mylane->lane->color); - - mylane->lane->color = nc; - mylane->to = NULL; - mylane->from = gitg_revision_get_hash (next); - mylane->inactive = 0; - } - - res = lanes_list (lanes); - prepare_lanes (lanes, next, nextpos); - - return res; -} diff --git a/libgitg/gitg-lanes.h b/libgitg/gitg-lanes.h deleted file mode 100644 index ae71757f..00000000 --- a/libgitg/gitg-lanes.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * gitg-lanes.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_LANES_H__ -#define __GITG_LANES_H__ - -#include -#include "gitg-revision.h" -#include "gitg-lane.h" - -G_BEGIN_DECLS - -#define GITG_TYPE_LANES (gitg_lanes_get_type ()) -#define GITG_LANES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LANES, GitgLanes)) -#define GITG_LANES_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LANES, GitgLanes const)) -#define GITG_LANES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_LANES, GitgLanesClass)) -#define GITG_IS_LANES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_LANES)) -#define GITG_IS_LANES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_LANES)) -#define GITG_LANES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_LANES, GitgLanesClass)) - -typedef struct _GitgLanes GitgLanes; -typedef struct _GitgLanesClass GitgLanesClass; -typedef struct _GitgLanesPrivate GitgLanesPrivate; - -struct _GitgLanes { - GObject parent; - - GitgLanesPrivate *priv; -}; - -struct _GitgLanesClass { - GObjectClass parent_class; -}; - -GType gitg_lanes_get_type (void) G_GNUC_CONST; - -GitgLanes *gitg_lanes_new(void); -void gitg_lanes_reset(GitgLanes *lanes); -GSList *gitg_lanes_next(GitgLanes *lanes, GitgRevision *next, gint8 *mylane); - -G_END_DECLS - - -#endif /* __GITG_LANES_H__ */ - diff --git a/libgitg/gitg-lanes.vala b/libgitg/gitg-lanes.vala new file mode 100644 index 00000000..24e6fbc8 --- /dev/null +++ b/libgitg/gitg-lanes.vala @@ -0,0 +1,466 @@ +namespace Gitg +{ + +public class Lanes : Object +{ + public int inactive_max { get; set; } + public int inactive_collapse { get; set; } + public int inactive_gap { get; set; } + public bool inactive_enabled { get; set; } + + private SList d_previous; + private SList d_lanes; + private HashTable d_collapsed; + + [Compact] + class LaneContainer + { + public Lane lane; + public uint inactive; + public Ggit.OId? from; + public Ggit.OId? to; + + public LaneContainer.with_color(Ggit.OId from, + Ggit.OId to, + Color? color) + { + this.from = from; + this.to = to; + this.lane = new Lane.with_color(color); + this.inactive = 0; + } + + public LaneContainer(Ggit.OId? from, + Ggit.OId? to) + { + this.with_color(from, to, null); + } + + public void next(int index) + { + lane = lane.copy(); + + lane.tag = Lane.Tag.NONE; + lane.from = new SList(); + lane.from.prepend(index); + + if (to != null) + { + ++inactive; + } + } + } + + [Compact] + class CollapsedLane + { + public Color color; + public uint index; + public Ggit.OId? from; + public Ggit.OId? to; + + public CollapsedLane(LaneContainer container) + { + color = container.lane.color; + from = container.from; + to = container.to; + } + } + + public Lanes() + { + d_collapsed = new HashTable(Ggit.OId.hash, + Ggit.OId.equal); + + reset(); + } + + public void reset() + { + d_previous = new SList(); + d_lanes = new SList(); + + Color.reset(); + + d_collapsed.remove_all(); + } + + public SList next(Commit next, + out int nextpos) + { + var myoid = next.get_id(); + + if (inactive_enabled) + { + collapse_lanes(); + expand_lanes(next); + } + + unowned LaneContainer? mylane = find_lane_by_oid(myoid, out nextpos); + + if (mylane == null) + { + // there is no lane reserver for this comit, add a new lane + d_lanes.append(new LaneContainer(myoid, null)); + nextpos = (int)d_lanes.length() - 1; + } + else + { + // copy the color here because the commit is a new stop + mylane.lane.color = mylane.lane.color.copy(); + + mylane.to = null; + mylane.from = next.get_id(); + mylane.inactive = 0; + } + + var res = lanes_list(); + prepare_lanes(next, nextpos); + + return res; + } + + private void prepare_lanes(Commit next, int pos) + { + var parents = next.get_parents(); + var myoid = next.get_id(); + + init_next_layer(); + unowned LaneContainer mylane = d_lanes.nth_data(pos); + + for (uint i = 0; i < parents.size(); ++i) + { + int lnpos; + var poid = parents.get_id(i); + + unowned LaneContainer? container = find_lane_by_oid(poid, out lnpos); + + if (container != null) + { + // there is already a lane for this parent. This means that + // we add pos as a merge for the lane, also this means the + // color of this lane incluis the merge should change to + // one color + container.lane.from.append(pos); + container.lane.color.next_index(); + + container.inactive = 0; + container.from = myoid; + + continue; + } + else if (mylane != null && mylane.to == null) + { + // there is no parent yet which can proceed on the current + // commit lane, so set it now + mylane.to = poid; + + if (parents.size() > 1) + { + mylane.lane.color = Color.next(); + } + else + { + mylane.lane.color = mylane.lane.color.copy(); + } + } + else + { + // generate a new lane for this parent + LaneContainer newlane = new LaneContainer(myoid, poid); + + newlane.lane.from.prepend(pos); + d_lanes.append((owned)newlane); + } + } + + if (mylane != null && mylane.to == null) + { + // remove current lane if no longer needed (i.e. merged) + d_lanes.remove(mylane); + } + + // store new commit in track list + if (d_previous.length() == inactive_collapse + inactive_gap + 1) + { + d_previous.delete_link(d_previous.last()); + } + + d_previous.prepend(next); + } + + private void add_collapsed(LaneContainer container, + int index) + { + var collapsed = new CollapsedLane(container); + collapsed.index = index; + + d_collapsed.insert(container.to, (owned)collapsed); + } + + private void collapse_lane(LaneContainer container, + int index) + { + add_collapsed(container, index); + + unowned SList item = d_previous; + + while (item != null) + { + var commit = item.data; + unowned SList lns = commit.lanes; + unowned SList lstlane = lns.nth(index); + unowned Lane lane = lstlane.data; + + if (item.next != null) + { + var newindex = lane.from.data; + + lns = commit.remove_lane(lane); + + if (item.next.next != null) + { + update_merge_indices(lns, newindex, -1); + } + + var mylane = commit.mylane; + + if (mylane > index) + { + --commit.mylane; + } + + index = newindex; + } + else + { + lane.tag |= Lane.Tag.END; + lane.boundary_id = container.to; + } + + item = item.next; + } + } + + private void collapse_lanes() + { + int index = 0; + unowned SList item = d_lanes; + + while (item != null) + { + unowned LaneContainer container = item.data; + + if (container.inactive != inactive_max + inactive_gap) + { + item = item.next; + ++index; + continue; + } + + collapse_lane(container, container.lane.from.data); + update_current_lane_merge_indices(index, -1); + + unowned SList next = item.next; + d_lanes.remove_link(item); + item = next; + } + } + + private int ensure_correct_index(Commit commit, + int index) + { + var len = commit.lanes.length(); + + if (index > len) + { + return (int)len; + } + else + { + return index; + } + } + + private void update_lane_merge_indices(SList from, + int index, + int direction) + { + while (from != null) + { + int idx = from.data; + + if (idx > index || (direction > 0 && idx == index)) + { + from.data = idx + direction; + } + + from = from.next; + } + } + + private void update_merge_indices(SList lanes, + int index, + int direction) + { + foreach (unowned Lane lane in lanes) + { + update_lane_merge_indices(lane.from, index, direction); + } + } + private void update_current_lane_merge_indices(int index, + int direction) + { + foreach (unowned LaneContainer container in d_lanes) + { + update_lane_merge_indices(container.lane.from, + index, + direction); + } + } + + private void expand_lane(CollapsedLane lane) + { + var index = lane.index; + var ln = new Lane.with_color(lane.color); + var len = d_lanes.length(); + + if (index > len) + { + index = len; + } + + var next = ensure_correct_index(d_previous.data, (int)index); + + var container = new LaneContainer.with_color(lane.from, + lane.to, + lane.color); + + update_current_lane_merge_indices((int)index, 1); + + container.lane.from.prepend(next); + d_lanes.insert((owned)container, (int)index); + + index = next; + uint cnt = 0; + + unowned SList ptr = d_previous; + + while (ptr != null) + { + var commit = ptr.data; + + if (cnt == inactive_collapse) + { + break; + } + + // Insert new lane at the index + Lane copy = ln.copy(); + unowned SList lns = commit.lanes; + + if (ptr.next == null || cnt + 1 == inactive_collapse) + { + copy.boundary_id = lane.from; + copy.tag |= Lane.Tag.START; + } + else + { + next = ensure_correct_index(ptr.next.data, (int)index); + copy.from.prepend(next); + + update_merge_indices(lns, (int)index, 1); + } + + commit.lanes.insert((owned)copy, (int)index); + lns = commit.lanes; + + var mylane = commit.mylane; + + if (mylane >= index) + { + ++commit.mylane; + } + + index = next; + ++cnt; + + ptr = ptr.next; + } + } + + private void expand_lane_from_oid(Ggit.OId id) + { + unowned CollapsedLane? collapsed = d_collapsed.lookup(id); + + if (collapsed != null) + { + expand_lane(collapsed); + d_collapsed.remove(id); + } + } + + private void expand_lanes(Commit commit) + { + expand_lane_from_oid(commit.get_id()); + + var parents = commit.get_parents(); + + for (uint i = 0; i < parents.size(); ++i) + { + expand_lane_from_oid(parents.get_id(i)); + } + } + + private void init_next_layer() + { + int index = 0; + + foreach (unowned LaneContainer container in d_lanes) + { + container.next(index++); + } + } + + private unowned LaneContainer? find_lane_by_oid(Ggit.OId id, + out int pos) + { + int p = 0; + unowned SList ptr = d_lanes; + + while (ptr != null) + { + unowned LaneContainer? container = ptr.data; + + if (container != null && + id.equal(container.to)) + { + pos = p; + return container; + } + + ++p; + ptr = ptr.next; + } + + pos = -1; + return null; + } + + private SList lanes_list() + { + var ret = new SList(); + + foreach (unowned LaneContainer container in d_lanes) + { + ret.prepend(container.lane.copy()); + } + + ret.reverse(); + return ret; + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-line-parser.c b/libgitg/gitg-line-parser.c deleted file mode 100644 index e3fee83b..00000000 --- a/libgitg/gitg-line-parser.c +++ /dev/null @@ -1,479 +0,0 @@ -/* - * gitg-line-parser.c - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include "gitg-line-parser.h" -#include - -#define GITG_LINE_PARSER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_LINE_PARSER, GitgLineParserPrivate)) - -struct _GitgLineParserPrivate -{ - gchar *rest_buffer; - gsize rest_buffer_size; - - gchar **lines; - guint buffer_size; - - gchar *read_buffer; - - gboolean preserve_line_endings; -}; - -enum -{ - LINES, - DONE, - NUM_SIGNALS -}; - -G_DEFINE_TYPE (GitgLineParser, gitg_line_parser, G_TYPE_OBJECT) - -enum -{ - PROP_0, - PROP_BUFFER_SIZE, - PROP_PRESERVE_LINE_ENDINGS -}; - -static guint signals[NUM_SIGNALS] = {0,}; - -typedef struct -{ - GitgLineParser *parser; - GInputStream *stream; - GCancellable *cancellable; -} AsyncData; - -static AsyncData * -async_data_new (GitgLineParser *parser, - GInputStream *stream, - GCancellable *cancellable) -{ - AsyncData *data; - - data = g_slice_new (AsyncData); - data->parser = g_object_ref (parser); - data->stream = stream; - data->cancellable = g_object_ref (cancellable); - - return data; -} - -static void -async_data_free (AsyncData *data) -{ - g_object_unref (data->parser); - g_object_unref (data->cancellable); - g_slice_free (AsyncData, data); -} - -static void -free_lines (GitgLineParser *stream) -{ - gint i = 0; - - while (stream->priv->lines[i]) - { - g_free (stream->priv->lines[i++]); - } - - stream->priv->lines[0] = NULL; -} - -static void -gitg_line_parser_finalize (GObject *object) -{ - GitgLineParser *stream; - - stream = GITG_LINE_PARSER (object); - - free_lines (stream); - - g_slice_free1 (sizeof (gchar *) * (stream->priv->buffer_size + 1), stream->priv->lines); - g_slice_free1 (sizeof (gchar) * (stream->priv->buffer_size + 1), stream->priv->read_buffer); - - G_OBJECT_CLASS (gitg_line_parser_parent_class)->finalize (object); -} - -static const gchar * -find_newline (const gchar *ptr, - const gchar *end, - const gchar **line_end) -{ - - while (ptr < end) - { - gunichar c; - - c = g_utf8_get_char (ptr); - - if (c == '\n') - { - /* That's it */ - *line_end = g_utf8_next_char (ptr); - return ptr; - } - else if (c == '\r') - { - gchar *next; - - next = g_utf8_next_char (ptr); - - if (next < end) - { - gunichar n = g_utf8_get_char (next); - - if (n == '\n') - { - /* Consume both! */ - *line_end = g_utf8_next_char (next); - return ptr; - } - else - { - /* That's it! */ - *line_end = next; - return ptr; - } - } - else - { - /* Need to save it, it might come later... */ - break; - } - } - - ptr = g_utf8_next_char (ptr); - } - - return NULL; -} - -static void -parse_lines (GitgLineParser *stream, - const gchar *buffer, - gssize size) -{ - gchar const *ptr; - gchar const *newline = NULL; - gint i = 0; - gchar *all = NULL; - gchar const *end; - - if (stream->priv->rest_buffer_size > 0) - { - GString *str = g_string_sized_new (stream->priv->rest_buffer_size + size); - - g_string_append_len (str, stream->priv->rest_buffer, stream->priv->rest_buffer_size); - g_string_append_len (str, buffer, size); - - all = g_string_free (str, FALSE); - size += stream->priv->rest_buffer_size; - - g_free (stream->priv->rest_buffer); - stream->priv->rest_buffer = NULL; - stream->priv->rest_buffer_size = 0; - - ptr = all; - } - else - { - ptr = buffer; - } - - const gchar *line_end; - end = ptr + size; - - while ((newline = find_newline (ptr, end, &line_end))) - { - if (stream->priv->preserve_line_endings) - { - stream->priv->lines[i++] = g_strndup (ptr, line_end - ptr); - } - else - { - stream->priv->lines[i++] = g_strndup (ptr, newline - ptr); - } - - gitg_debug (GITG_DEBUG_SHELL_OUTPUT, "%s", stream->priv->lines[i - 1]); - - ptr = line_end; - - if (i == stream->priv->buffer_size) - { - break; - } - } - - if (ptr < end) - { - stream->priv->rest_buffer_size = end - ptr; - stream->priv->rest_buffer = g_strndup (ptr, stream->priv->rest_buffer_size); - } - - stream->priv->lines[i] = NULL; - - g_signal_emit (stream, signals[LINES], 0, stream->priv->lines); - - g_free (all); -} - -static void -emit_rest (GitgLineParser *stream) -{ - if (stream->priv->rest_buffer_size > 0) - { - if (!stream->priv->preserve_line_endings && - stream->priv->rest_buffer[stream->priv->rest_buffer_size - 1] == '\r') - { - stream->priv->rest_buffer[stream->priv->rest_buffer_size - 1] = '\0'; - } - - gchar *b[] = {stream->priv->rest_buffer, NULL}; - - g_signal_emit (stream, signals[LINES], 0, b); - - g_free (stream->priv->rest_buffer); - stream->priv->rest_buffer = NULL; - stream->priv->rest_buffer_size = 0; - } -} - -static void -parser_done (AsyncData *data, - GError *error) -{ - if (!error) - { - emit_rest (data->parser); - } - - g_signal_emit (data->parser, signals[DONE], 0, error); - - async_data_free (data); -} - -static void -gitg_line_parser_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgLineParser *self = GITG_LINE_PARSER (object); - - switch (prop_id) - { - case PROP_BUFFER_SIZE: - self->priv->buffer_size = g_value_get_uint (value); - break; - case PROP_PRESERVE_LINE_ENDINGS: - self->priv->preserve_line_endings = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_line_parser_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgLineParser *self = GITG_LINE_PARSER (object); - - switch (prop_id) - { - case PROP_BUFFER_SIZE: - g_value_set_uint (value, self->priv->buffer_size); - break; - case PROP_PRESERVE_LINE_ENDINGS: - g_value_set_boolean (value, self->priv->preserve_line_endings); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_line_parser_constructed (GObject *object) -{ - GitgLineParser *stream; - - stream = GITG_LINE_PARSER (object); - - stream->priv->lines = g_slice_alloc (sizeof (gchar *) * (stream->priv->buffer_size + 1)); - stream->priv->lines[0] = NULL; - - stream->priv->read_buffer = g_slice_alloc (sizeof (gchar) * (stream->priv->buffer_size + 1)); - - G_OBJECT_CLASS (gitg_line_parser_parent_class)->constructed (object); -} - -static void start_read_lines (AsyncData *data); - -static void -read_ready (GInputStream *stream, - GAsyncResult *result, - AsyncData *data) -{ - gssize read; - GError *error = NULL; - - read = g_input_stream_read_finish (stream, result, &error); - - if (g_cancellable_is_cancelled (data->cancellable)) - { - if (error) - { - g_error_free (error); - } - - async_data_free (data); - return; - } - - if (read == -1) - { - parser_done (data, error); - - if (error) - { - g_error_free (error); - } - } - else if (read == 0) - { - parser_done (data, NULL); - } - else - { - data->parser->priv->read_buffer[read] = '\0'; - - parse_lines (data->parser, - data->parser->priv->read_buffer, - read); - - start_read_lines (data); - } -} - -static void -start_read_lines (AsyncData *data) -{ - g_input_stream_read_async (data->stream, - data->parser->priv->read_buffer, - data->parser->priv->buffer_size, - G_PRIORITY_DEFAULT, - data->cancellable, - (GAsyncReadyCallback)read_ready, - data); -} - -static void -gitg_line_parser_class_init (GitgLineParserClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_line_parser_finalize; - object_class->constructed = gitg_line_parser_constructed; - - object_class->get_property = gitg_line_parser_get_property; - object_class->set_property = gitg_line_parser_set_property; - - g_type_class_add_private (object_class, sizeof(GitgLineParserPrivate)); - - signals[LINES] = - g_signal_new ("lines", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[DONE] = - g_signal_new ("done", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, - 1, - G_TYPE_ERROR); - - g_object_class_install_property (object_class, - PROP_BUFFER_SIZE, - g_param_spec_uint ("buffer-size", - "Buffer size", - "Buffer Size", - 1, - G_MAXUINT, - 100, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, - PROP_PRESERVE_LINE_ENDINGS, - g_param_spec_boolean ("preserve-line-endings", - "Preserve line endings", - "Preserve Line Endings", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -static void -gitg_line_parser_init (GitgLineParser *self) -{ - self->priv = GITG_LINE_PARSER_GET_PRIVATE (self); -} - -GitgLineParser * -gitg_line_parser_new (guint buffer_size, - gboolean preserve_line_endings) -{ - return g_object_new (GITG_TYPE_LINE_PARSER, - "buffer-size", buffer_size, - "preserve-line-endings", preserve_line_endings, - NULL); -} - -void -gitg_line_parser_parse (GitgLineParser *parser, - GInputStream *stream, - GCancellable *cancellable) -{ - AsyncData *data; - - g_return_if_fail (GITG_IS_LINE_PARSER (parser)); - g_return_if_fail (G_IS_INPUT_STREAM (stream)); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - data = async_data_new (parser, stream, cancellable); - start_read_lines (data); -} diff --git a/libgitg/gitg-line-parser.h b/libgitg/gitg-line-parser.h deleted file mode 100644 index e492def0..00000000 --- a/libgitg/gitg-line-parser.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gitg-line-parser.h - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_LINE_PARSER_H__ -#define __GITG_LINE_PARSER_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_LINE_PARSER (gitg_line_parser_get_type ()) -#define GITG_LINE_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LINE_PARSER, GitgLineParser)) -#define GITG_LINE_PARSER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_LINE_PARSER, GitgLineParser const)) -#define GITG_LINE_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_LINE_PARSER, GitgLineParserClass)) -#define GITG_IS_LINE_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_LINE_PARSER)) -#define GITG_IS_LINE_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_LINE_PARSER)) -#define GITG_LINE_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_LINE_PARSER, GitgLineParserClass)) - -typedef struct _GitgLineParser GitgLineParser; -typedef struct _GitgLineParserClass GitgLineParserClass; -typedef struct _GitgLineParserPrivate GitgLineParserPrivate; - -struct _GitgLineParser -{ - /*< private >*/ - GObject parent; - - GitgLineParserPrivate *priv; -}; - -struct _GitgLineParserClass -{ - /*< private >*/ - GObjectClass parent_class; -}; - -GType gitg_line_parser_get_type (void) G_GNUC_CONST; - -GitgLineParser *gitg_line_parser_new (guint buffer_size, - gboolean preserve_line_endings); - -void gitg_line_parser_parse (GitgLineParser *parser, - GInputStream *stream, - GCancellable *cancellable); - -G_END_DECLS - -#endif /* __GITG_LINE_PARSER_H__ */ diff --git a/libgitg/gitg-ref.c b/libgitg/gitg-ref.c deleted file mode 100644 index bc99c0fe..00000000 --- a/libgitg/gitg-ref.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * gitg-ref.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-ref.h" -#include "gitg-hash.h" -#include - -typedef struct -{ - gchar const *prefix; - GitgRefType type; -} PrefixTypeMap; - -struct _GitgRef -{ - GitgHash hash; - GitgRefType type; - - gchar *name; - gchar *shortname; - - gchar *prefix; - GitgRefState state; - - gboolean working; -}; - -G_DEFINE_BOXED_TYPE (GitgRef, gitg_ref, gitg_ref_copy, gitg_ref_free) - -GitgRef * -gitg_ref_new (gchar const *hash, gchar const *name) -{ - GitgRef *inst = g_slice_new0 (GitgRef); - - gitg_hash_sha1_to_hash (hash, inst->hash); - inst->name = g_strdup (name); - - PrefixTypeMap map[] = { - {"refs/heads/", GITG_REF_TYPE_BRANCH}, - {"refs/remotes/", GITG_REF_TYPE_REMOTE}, - {"refs/tags/", GITG_REF_TYPE_TAG}, - {"refs/stash", GITG_REF_TYPE_STASH} - }; - - inst->prefix = NULL; - - // set type from name - int i; - for (i = 0; i < sizeof (map) / sizeof (PrefixTypeMap); ++i) - { - gchar *pos; - - if (!g_str_has_prefix (name, map[i].prefix)) - { - continue; - } - - inst->type = map[i].type; - - if (inst->type == GITG_REF_TYPE_STASH) - { - inst->shortname = g_strdup ("stash"); - } - else - { - inst->shortname = g_strdup (name + strlen (map[i].prefix)); - } - - if (map[i].type == GITG_REF_TYPE_REMOTE && (pos = strchr (inst->shortname, '/'))) - { - inst->prefix = g_strndup (inst->shortname, pos - inst->shortname); - } - - break; - } - - if (inst->shortname == NULL) - { - inst->type = GITG_REF_TYPE_NONE; - inst->shortname = g_strdup (name); - } - - return inst; -} - -GitgRef * -gitg_ref_copy (GitgRef *ref) -{ - if (ref == NULL) - { - return NULL; - } - - GitgRef *ret = g_slice_new0 (GitgRef); - - ret->type = ref->type; - ret->name = g_strdup (ref->name); - ret->shortname = g_strdup (ref->shortname); - ret->prefix = g_strdup (ref->prefix); - ret->working = ref->working; - - gint i; - - for (i = 0; i < GITG_HASH_BINARY_SIZE; ++i) - { - ret->hash[i] = ref->hash[i]; - } - - return ret; -} - -void -gitg_ref_free (GitgRef *ref) -{ - if (!ref) - { - return; - } - - g_free (ref->name); - g_free (ref->shortname); - g_free (ref->prefix); - - g_slice_free (GitgRef, ref); -} - -gboolean -gitg_ref_equal (GitgRef *ref, GitgRef *other) -{ - if (ref == NULL && other == NULL) - { - return TRUE; - } - - if (ref == NULL || other == NULL) - { - return FALSE; - } - - return strcmp (ref->name, other->name) == 0; -} - -gboolean -gitg_ref_equal_prefix (GitgRef *ref, GitgRef *other) -{ - if (ref == NULL && other == NULL) - { - return TRUE; - } - - if (ref == NULL || other == NULL) - { - return FALSE; - } - - return strcmp (ref->prefix, other->prefix) == 0; -} - -gchar const * -gitg_ref_get_hash (GitgRef *ref) -{ - return ref->hash; -} - -GitgRefType -gitg_ref_get_ref_type (GitgRef *ref) -{ - return ref->type; -} - -gchar const * -gitg_ref_get_name (GitgRef *ref) -{ - return ref->name; -} - -gchar const * -gitg_ref_get_shortname (GitgRef *ref) -{ - return ref->shortname; -} - -gchar const * -gitg_ref_get_prefix (GitgRef *ref) -{ - return ref->prefix; -} - -GitgRefState -gitg_ref_get_state (GitgRef *ref) -{ - return ref->state; -} - -void -gitg_ref_set_state (GitgRef *ref, - GitgRefState state) -{ - ref->state = state; -} - -gchar const * -gitg_ref_get_local_name (GitgRef *ref) -{ - gchar const *shortname = gitg_ref_get_shortname (ref); - gchar const *prefix = gitg_ref_get_prefix (ref); - - if (prefix && g_str_has_prefix (shortname, prefix)) - { - return shortname + strlen (prefix) + 1; - } - else - { - return shortname; - } -} - -void -gitg_ref_set_working (GitgRef *ref, - gboolean working) -{ - ref->working = working; -} - -gboolean -gitg_ref_get_working (GitgRef *ref) -{ - return ref->working; -} diff --git a/libgitg/gitg-ref.h b/libgitg/gitg-ref.h deleted file mode 100644 index 3fba9bad..00000000 --- a/libgitg/gitg-ref.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * gitg-ref.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REF_H__ -#define __GITG_REF_H__ - -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_REF (gitg_ref_get_type ()) -#define GITG_REF(obj) ((GitgRef *)obj) -#define GITG_REF_CONST(obj) ((GitgRef const *)obj) - -typedef enum -{ - GITG_REF_TYPE_NONE = 0, - GITG_REF_TYPE_BRANCH, - GITG_REF_TYPE_REMOTE, - GITG_REF_TYPE_TAG, - GITG_REF_TYPE_STASH -} GitgRefType; - -typedef enum -{ - GITG_REF_STATE_NONE = 0, - GITG_REF_STATE_SELECTED, - GITG_REF_STATE_PRELIGHT -} GitgRefState; - -typedef struct _GitgRef GitgRef; - -GType gitg_ref_get_type (void) G_GNUC_CONST; - -GitgRef *gitg_ref_new (gchar const *hash, - gchar const *name); - -gchar const *gitg_ref_get_hash (GitgRef *ref); -GitgRefType gitg_ref_get_ref_type (GitgRef *ref); -gchar const *gitg_ref_get_name (GitgRef *ref); - -gchar const *gitg_ref_get_shortname (GitgRef *ref); -gchar const *gitg_ref_get_prefix (GitgRef *ref); - -gchar const *gitg_ref_get_local_name (GitgRef *ref); - -GitgRefState gitg_ref_get_state (GitgRef *ref); -void gitg_ref_set_state (GitgRef *ref, - GitgRefState state); - -void gitg_ref_set_working (GitgRef *ref, - gboolean working); -gboolean gitg_ref_get_working (GitgRef *ref); - -GitgRef *gitg_ref_copy (GitgRef *ref); -void gitg_ref_free (GitgRef *ref); - -gboolean gitg_ref_equal (GitgRef *ref, - GitgRef *other); - -gboolean gitg_ref_equal_prefix (GitgRef *ref, - GitgRef *other); - -G_END_DECLS - -#endif /* __GITG_REF_H__ */ - diff --git a/libgitg/gitg-ref.vala b/libgitg/gitg-ref.vala new file mode 100644 index 00000000..3914b072 --- /dev/null +++ b/libgitg/gitg-ref.vala @@ -0,0 +1,275 @@ +namespace Gitg +{ + +public enum RefType +{ + BRANCH, + REMOTE, + TAG, + STASH +} + +/** + * Parse ref name into components. + * + * This class parses a refname and splits it into several components. + * + */ +public class ParsedRefName : Object +{ + private string d_shortname; + private string d_name; + private string d_remote_name; + private string d_remote_branch; + + /** + * The type of ref. + */ + public RefType rtype { get; private set; } + + /** + * The full name of the ref. + */ + public string name + { + owned get { return d_name; } + } + + /** + * The short name of the ref. This represents the name of the ref + * without the information of the type of ref. + */ + public string shortname + { + owned get { return d_shortname; } + } + + /** + * The remote name of the ref (only for remote refs) + */ + public string? remote_name + { + owned get { return d_remote_name; } + } + + /** + * The remote branch name of the ref (only for remote refs) + */ + public string? remote_branch + { + owned get { return d_remote_branch; } + } + + public ParsedRefName(string name) + { + parse_name(name); + } + + private void parse_name(string name) + { + d_name = name; + + string[] prefixes = { + "refs/heads/", + "refs/remotes/", + "refs/tags/", + "refs/stash" + }; + + d_shortname = name; + + for (var i = 0; i < prefixes.length; ++i) + { + if (!d_name.has_prefix(prefixes[i])) + { + continue; + } + + rtype = (RefType)i; + + if (rtype == RefType.STASH) + { + d_shortname = "stash"; + } + else + { + d_shortname = d_name[prefixes[i].length:d_name.length]; + } + + if (rtype == RefType.REMOTE) + { + var pos = d_shortname.index_of_char('/'); + + if (pos != -1) + { + d_remote_name = d_shortname.substring(0, pos); + d_remote_branch = d_shortname.substring(pos + 1); + } + else + { + d_remote_name = d_shortname; + } + } + } + } +} + +public class Ref : Ggit.Ref +{ + private List? d_pushes; + + private static Regex? s_remote_key_regex; + private ParsedRefName d_parsed_name; + + public ParsedRefName parsed_name + { + owned get + { + if (d_parsed_name == null) + { + d_parsed_name = new ParsedRefName(get_name()); + } + + return d_parsed_name; + } + } + + public new Gitg.Repository get_owner() + { + return (Gitg.Repository)base.get_owner(); + } + + private void add_push_ref(string spec) + { + Gitg.Ref rf; + + try + { + rf = get_owner().lookup_reference(spec); + } catch { return; } + + if (d_pushes.find_custom(rf, (a, b) => { + return a.get_name().ascii_casecmp(b.get_name()); + }) == null) + { + d_pushes.append(rf); + } + } + + private void add_branch_configured_push(Ggit.Config cfg) + { + string remote; + string merge; + + try + { + remote = cfg.get_string(@"branch.$(parsed_name.shortname).remote"); + merge = cfg.get_string(@"branch.$(parsed_name.shortname).merge"); + } catch { return; } + + var nm = new ParsedRefName(merge); + + add_push_ref(@"refs/remotes/$remote/$(nm.shortname)"); + } + + private void add_remote_configured_push(Ggit.Config cfg) + { + Regex valregex; + + try + { + valregex = new Regex("^%s:(.*)".printf(Regex.escape_string(get_name()))); + + if (s_remote_key_regex == null) + { + s_remote_key_regex = new Regex("remote\\.(.*)\\.push"); + } + + cfg.match_foreach(s_remote_key_regex, (info, val) => { + MatchInfo vinfo; + + if (!valregex.match(val, 0, out vinfo)) + { + return 0; + } + + var rname = info.fetch(1); + var pref = vinfo.fetch(1); + + add_push_ref(@"refs/remotes/$rname/$pref"); + return 0; + }); + + } catch { return; } + } + + private void add_branch_same_name_push(Ggit.Config cfg) + { + string remote; + + try + { + remote = cfg.get_string(@"branch.$(parsed_name.shortname).remote"); + } catch { return; } + + add_push_ref(@"refs/remotes/$remote/$(parsed_name.shortname)"); + } + + private void compose_pushes() + { + d_pushes = new List(); + + Ggit.Config cfg; + + try + { + cfg = get_owner().get_config(); + } catch { return; } + + /* The possible refspecs of a local $ref (branch) are resolved in the + * following order (duplicates are removed automatically): + * + * 1) Branch configured remote and merge (git push): + * + * Remote: branch..remote + * Spec: branch..merge + * + * 2) Remote configured matching push refspec: + * For each remote..push matching ${ref.name}: + * + * Remote: + * Spec: + * + * 3) Remote branch with the same name + * + * Remote: branch..remote + * Spec: ${ref.name} + */ + + // Branch configured remote and merge + add_branch_configured_push(cfg); + + // Remote configured push spec + add_remote_configured_push(cfg); + + // Same name push + add_branch_same_name_push(cfg); + } + + public List pushes + { + get + { + if (d_pushes == null) + { + compose_pushes(); + } + + return d_pushes; + } + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-repository.c b/libgitg/gitg-repository.c deleted file mode 100644 index f1d1b188..00000000 --- a/libgitg/gitg-repository.c +++ /dev/null @@ -1,2081 +0,0 @@ -/* - * gitg-repository.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-repository.h" -#include "gitg-hash.h" -#include "gitg-i18n.h" -#include "gitg-lanes.h" -#include "gitg-ref.h" -#include "gitg-config.h" -#include "gitg-shell.h" - -#include -#include -#include -#include - -#define GITG_REPOSITORY_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_REPOSITORY, GitgRepositoryPrivate)) - -static void gitg_repository_tree_model_iface_init (GtkTreeModelIface *iface); - -G_DEFINE_TYPE_EXTENDED (GitgRepository, gitg_repository, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, gitg_repository_tree_model_iface_init)); - -/* Properties */ -enum -{ - PROP_0, - PROP_WORK_TREE, - PROP_GIT_DIR, - PROP_PATH, - PROP_LOADER, - PROP_SHOW_STAGED, - PROP_SHOW_UNSTAGED, - PROP_SHOW_STASH, - PROP_TOPO_ORDER, - PROP_INACTIVE_MAX, - PROP_INACTIVE_COLLAPSE, - PROP_INACTIVE_GAP, - PROP_INACTIVE_ENABLED -}; - -/* Signals */ -enum -{ - LOAD, - LOADED, - LAST_SIGNAL -}; - -static guint repository_signals[LAST_SIGNAL] = { 0 }; - -enum -{ - OBJECT_COLUMN, - SUBJECT_COLUMN, - AUTHOR_COLUMN, - DATE_COLUMN, - N_COLUMNS -}; - -typedef enum -{ - LOAD_STAGE_NONE = 0, - LOAD_STAGE_STASH, - LOAD_STAGE_STAGED, - LOAD_STAGE_UNSTAGED, - LOAD_STAGE_COMMITS, - LOAD_STAGE_LAST -} LoadStage; - -struct _GitgRepositoryPrivate -{ - GFile *git_dir; - GFile *work_tree; - - GitgShell *loader; - GHashTable *hashtable; - gint stamp; - GType column_types[N_COLUMNS]; - - GHashTable *ref_pushes; - GHashTable *ref_names; - - GitgRevision **storage; - GitgLanes *lanes; - GHashTable *refs; - GitgRef *current_ref; - GitgRef *working_ref; - - gulong size; - gulong allocated; - gint grow_size; - - gchar **last_args; - gchar **selection; - - guint idle_relane_id; - - LoadStage load_stage; - - GFileMonitor *monitor; - - guint show_staged : 1; - guint show_unstaged : 1; - guint show_stash : 1; - guint topoorder : 1; -}; - -static gboolean repository_relane (GitgRepository *repository); -static void build_log_args (GitgRepository *self, - gint argc, - gchar const **av); - -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 -tree_model_get_column_type (GtkTreeModel *tree_model, - gint index) -{ - 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); - - 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) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (tree_model), FALSE); - - gint *indices; - gint depth; - - indices = gtk_tree_path_get_indices (path); - depth = gtk_tree_path_get_depth (path); - - GitgRepository *rp = GITG_REPOSITORY (tree_model); - - g_return_val_if_fail (depth == 1, FALSE); - - if (indices[0] < 0 || indices[0] >= rp->priv->size) - return FALSE; - - fill_iter (rp, indices[0], iter); - - return TRUE; -} - -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 void -tree_model_get_value (GtkTreeModel *tree_model, - GtkTreeIter *iter, - gint column, - GValue *value) -{ - g_return_if_fail (GITG_IS_REPOSITORY (tree_model)); - g_return_if_fail (column >= 0 && column < N_COLUMNS); - - GitgRepository *rp = GITG_REPOSITORY (tree_model); - g_return_if_fail (iter->stamp == rp->priv->stamp); - - 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: - g_value_set_boxed (value, rv); - break; - case SUBJECT_COLUMN: - 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, gitg_revision_get_author_date_for_display (rv)); - break; - default: - g_assert_not_reached (); - break; - } -} - -static gboolean -tree_model_iter_next (GtkTreeModel *tree_model, - GtkTreeIter *iter) -{ - 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); - - 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); - fill_iter (rp, 0, iter); - - 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); - - fill_iter (rp, n, iter); - - 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 void -gitg_repository_tree_model_iface_init (GtkTreeModelIface *iface) -{ - 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 -do_clear (GitgRepository *repository, - gboolean emit) -{ - gint i; - GtkTreePath *path = gtk_tree_path_new_from_indices (repository->priv->size - 1, -1); - - for (i = repository->priv->size - 1; i >= 0; --i) - { - if (emit) - { - 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); - gitg_revision_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; - - gitg_ref_free (repository->priv->current_ref); - repository->priv->current_ref = NULL; - - /* clear hash tables */ - g_hash_table_remove_all (repository->priv->hashtable); - g_hash_table_remove_all (repository->priv->refs); - g_hash_table_remove_all (repository->priv->ref_names); - g_hash_table_remove_all (repository->priv->ref_pushes); - - gitg_color_reset (); -} - -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 void -gitg_repository_finalize (GObject *object) -{ - GitgRepository *rp = GITG_REPOSITORY (object); - - /* Make sure to cancel the loader */ - gitg_io_cancel (GITG_IO (rp->priv->loader)); - g_object_unref (rp->priv->loader); - - g_object_unref (rp->priv->lanes); - - /* Clear the model to remove all revision objects */ - do_clear (rp, FALSE); - - if (rp->priv->work_tree) - { - g_object_unref (rp->priv->work_tree); - } - - if (rp->priv->git_dir) - { - g_object_unref (rp->priv->git_dir); - } - - /* Free the hash */ - g_hash_table_destroy (rp->priv->hashtable); - g_hash_table_destroy (rp->priv->refs); - g_hash_table_destroy (rp->priv->ref_names); - g_hash_table_destroy (rp->priv->ref_pushes); - - /* Free cached args */ - g_strfreev (rp->priv->last_args); - g_strfreev (rp->priv->selection); - - if (rp->priv->idle_relane_id) - { - g_source_remove (rp->priv->idle_relane_id); - } - - if (rp->priv->current_ref) - { - gitg_ref_free (rp->priv->current_ref); - } - - if (rp->priv->working_ref) - { - gitg_ref_free (rp->priv->working_ref); - } - - if (rp->priv->monitor) - { - g_file_monitor_cancel (rp->priv->monitor); - g_object_unref (rp->priv->monitor); - } - - 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_WORK_TREE: - if (self->priv->work_tree) - { - g_object_unref (self->priv->work_tree); - } - - self->priv->work_tree = g_value_dup_object (value); - break; - case PROP_GIT_DIR: - if (self->priv->git_dir) - { - g_object_unref (self->priv->git_dir); - } - - self->priv->git_dir = g_value_dup_object (value); - break; - case PROP_SHOW_STAGED: - self->priv->show_staged = g_value_get_boolean (value); - gitg_repository_reload (self); - break; - case PROP_SHOW_UNSTAGED: - self->priv->show_unstaged = g_value_get_boolean (value); - gitg_repository_reload (self); - break; - case PROP_SHOW_STASH: - self->priv->show_stash = g_value_get_boolean (value); - gitg_repository_reload (self); - break; - case PROP_TOPO_ORDER: - self->priv->topoorder = g_value_get_boolean (value); - - if (self->priv->selection != NULL) - { - build_log_args (self, - g_strv_length (self->priv->selection), - (gchar const **)self->priv->selection); - } - - gitg_repository_reload (self); - break; - case PROP_INACTIVE_MAX: - g_object_set_property (G_OBJECT (self->priv->lanes), - "inactive-max", - value); - prepare_relane (self); - break; - case PROP_INACTIVE_COLLAPSE: - g_object_set_property (G_OBJECT (self->priv->lanes), - "inactive-collapse", - value); - prepare_relane (self); - break; - case PROP_INACTIVE_GAP: - g_object_set_property (G_OBJECT (self->priv->lanes), - "inactive-gap", - value); - prepare_relane (self); - break; - case PROP_INACTIVE_ENABLED: - g_object_set_property (G_OBJECT (self->priv->lanes), - "inactive-enabled", - value); - prepare_relane (self); - 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_WORK_TREE: - g_value_set_object (value, self->priv->work_tree); - break; - case PROP_GIT_DIR: - g_value_set_object (value, self->priv->git_dir); - break; - case PROP_LOADER: - g_value_set_object (value, self->priv->loader); - break; - case PROP_SHOW_STAGED: - g_value_set_boolean (value, self->priv->show_staged); - break; - case PROP_SHOW_UNSTAGED: - g_value_set_boolean (value, self->priv->show_unstaged); - break; - case PROP_SHOW_STASH: - g_value_set_boolean (value, self->priv->show_stash); - break; - case PROP_TOPO_ORDER: - g_value_set_boolean (value, self->priv->topoorder); - break; - case PROP_INACTIVE_MAX: - g_object_get_property (G_OBJECT (self->priv->lanes), - "inactive-max", - value); - break; - case PROP_INACTIVE_COLLAPSE: - g_object_get_property (G_OBJECT (self->priv->lanes), - "inactive-collapse", - value); - break; - case PROP_INACTIVE_GAP: - g_object_get_property (G_OBJECT (self->priv->lanes), - "inactive-gap", - value); - break; - case PROP_INACTIVE_ENABLED: - g_object_get_property (G_OBJECT (self->priv->lanes), - "inactive-enabled", - value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static gchar * -parse_ref_intern (GitgRepository *repository, - gchar const *ref, - gboolean symbolic) -{ - gchar **ret; - gboolean retval; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (repository, - "rev-parse", - "--verify", - symbolic ? "--symbolic-full-name" : ref, - symbolic ? ref : NULL, - NULL), - FALSE, - &ret, - NULL); - - if (!retval || !ret) - { - g_strfreev (ret); - return NULL; - } - - gchar *r = g_strdup (*ret); - g_strfreev (ret); - - return r; -} - -static GitgRef * -get_current_working_ref (GitgRepository *repository) -{ - GitgRef *ret = NULL; - - gchar *hash = parse_ref_intern (repository, "HEAD", FALSE); - gchar *name = parse_ref_intern (repository, "HEAD", TRUE); - - if (hash && name) - { - ret = gitg_ref_new (hash, name); - gitg_ref_set_working (ret, TRUE); - } - - g_free (hash); - g_free (name); - - return ret; -} - -static void -on_head_changed (GFileMonitor *monitor, - GFile *file, - GFile *otherfile, - GFileMonitorEvent event, - GitgRepository *repository) -{ - switch (event) - { - case G_FILE_MONITOR_EVENT_CHANGED: - case G_FILE_MONITOR_EVENT_CREATED: - { - GitgRef *current = get_current_working_ref (repository); - - if (!gitg_ref_equal (current, repository->priv->working_ref)) - { - gitg_repository_reload (repository); - } - - gitg_ref_free (current); - } - break; - default: - break; - } -} - -static void -install_head_monitor (GitgRepository *repository) -{ - GFile *file = g_file_get_child (repository->priv->git_dir, "HEAD"); - - repository->priv->monitor = g_file_monitor_file (file, - G_FILE_MONITOR_NONE, - NULL, - NULL); - - g_signal_connect (repository->priv->monitor, - "changed", - G_CALLBACK (on_head_changed), - repository); - - g_object_unref (file); -} - -static void -gitg_repository_constructed (GObject *object) -{ - GitgRepository *repository = GITG_REPOSITORY (object); - - if (repository->priv->git_dir == NULL && - repository->priv->work_tree == NULL) - { - return; - } - - if (repository->priv->git_dir == NULL) - { - repository->priv->git_dir = g_file_get_child (repository->priv->work_tree, - ".git"); - } - else if (repository->priv->work_tree == NULL) - { - repository->priv->work_tree = g_file_get_parent (repository->priv->git_dir); - } - - install_head_monitor (repository); - - G_OBJECT_CLASS (gitg_repository_parent_class)->constructed (object); -} - -static void -gitg_repository_class_init (GitgRepositoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->finalize = gitg_repository_finalize; - - object_class->set_property = gitg_repository_set_property; - object_class->get_property = gitg_repository_get_property; - - object_class->constructed = gitg_repository_constructed; - - g_object_class_install_property (object_class, - PROP_GIT_DIR, - g_param_spec_object ("git-dir", - "GIT_DIR", - "The repository .git directory", - G_TYPE_FILE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (object_class, - PROP_WORK_TREE, - g_param_spec_object ("work-tree", - "WORK_TREE", - "The work tree directory", - G_TYPE_FILE, - 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_SHELL, - G_PARAM_READABLE)); - - g_object_class_install_property (object_class, - PROP_SHOW_STAGED, - g_param_spec_boolean ("show-staged", - "Show Staged", - "Show staged", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SHOW_UNSTAGED, - g_param_spec_boolean ("show-unstaged", - "Show Unstaged", - "Show unstaged", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SHOW_STASH, - g_param_spec_boolean ("show-stash", - "Show Stash", - "Show stash", - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_TOPO_ORDER, - g_param_spec_boolean ("topo-order", - "Topo order", - "Show in topological order", - FALSE, - G_PARAM_READWRITE)); - - /* FIXME: gitg-lanes shouldn't be an object? */ - 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_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_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_object_class_install_property (object_class, - PROP_INACTIVE_ENABLED, - g_param_spec_boolean ("inactive-enabled", - "INACTIVE_ENABLED", - "Lane collapsing enabled", - TRUE, - G_PARAM_READWRITE)); - - repository_signals[LOAD] = - g_signal_new ("load", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgRepositoryClass, - load), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - repository_signals[LOADED] = - g_signal_new ("loaded", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgRepositoryClass, - loaded), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - g_type_class_add_private (object_class, sizeof (GitgRepositoryPrivate)); -} - -static void -append_revision (GitgRepository *repository, - GitgRevision *rv) -{ - GSList *lanes; - gint8 mylane = 0; - - if (repository->priv->size == 0) - { - gitg_lanes_reset (repository->priv->lanes); - } - - lanes = gitg_lanes_next (repository->priv->lanes, rv, &mylane); - gitg_revision_set_lanes (rv, lanes, mylane); - - gitg_repository_add (repository, rv, NULL); - gitg_revision_unref (rv); -} - -static void -add_dummy_commit (GitgRepository *repository, - gboolean staged) -{ - GitgRevision *revision; - gchar const *subject; - struct timeval tv; - - gettimeofday (&tv, NULL); - - if (staged) - { - subject = _ ("Staged changes"); - } - else - { - subject = _ ("Unstaged changes"); - } - - revision = gitg_revision_new ("0000000000000000000000000000000000000000", - "", - "", - tv.tv_sec, - "", - "", - -1, - subject, - NULL); - gitg_revision_set_sign (revision, staged ? 't' : 'u'); - - append_revision (repository, revision); -} - -static void -on_loader_end_loading (GitgShell *object, - GError *error, - GitgRepository *repository) -{ - if (gitg_io_get_cancelled (GITG_IO (object))) - { - g_signal_emit (repository, repository_signals[LOADED], 0); - return; - } - - LoadStage current = repository->priv->load_stage++; - gboolean show_unstaged; - gboolean show_staged; - - show_unstaged = repository->priv->show_unstaged; - show_staged = repository->priv->show_staged; - - switch (current) - { - case LOAD_STAGE_STASH: - case LOAD_STAGE_STAGED: - { - /* Check if there are staged changes */ - gchar *head = gitg_repository_parse_head (repository); - const gchar *cached = NULL; - - if (current == LOAD_STAGE_STAGED) - { - /* Check if there are unstaged changes */ - if (show_staged && gitg_io_get_exit_status (GITG_IO (object)) != 0) - { - add_dummy_commit (repository, TRUE); - } - } - else - { - cached = "--cached"; - } - - gitg_shell_run (object, - gitg_command_new (repository, - "diff-index", - "--no-ext-diff", - "--quiet", - head, - cached, - NULL), - NULL); - - g_free (head); - } - break; - case LOAD_STAGE_UNSTAGED: - if (show_unstaged && gitg_io_get_exit_status (GITG_IO (object)) != 0) - { - add_dummy_commit (repository, FALSE); - } - - gitg_shell_run (object, - gitg_command_newv (repository, - (gchar const * const *)repository->priv->last_args), - NULL); - break; - default: - break; - } - - if (repository->priv->load_stage == LOAD_STAGE_LAST) - { - g_signal_emit (repository, repository_signals[LOADED], 0); - } -} - -static gint -find_ref_custom (GitgRef *first, - GitgRef *second) -{ - return gitg_ref_equal (first, second) ? 0 : 1; -} - -static GitgRef * -add_ref (GitgRepository *self, - gchar const *sha1, - gchar const *name) -{ - GitgRef *ref = gitg_ref_new (sha1, name); - GSList *refs = (GSList *)g_hash_table_lookup (self->priv->refs, - gitg_ref_get_hash (ref)); - - g_hash_table_insert (self->priv->ref_names, - (gpointer)gitg_ref_get_name (ref), - ref); - - if (refs == NULL) - { - g_hash_table_insert (self->priv->refs, - (gpointer)gitg_ref_get_hash (ref), - g_slist_append (NULL, ref)); - } - else - { - if (!g_slist_find_custom (refs, ref, (GCompareFunc)find_ref_custom)) - { - refs = g_slist_append (refs, ref); - } - else - { - gitg_ref_free (ref); - } - } - - return ref; -} - -static void -loader_update_stash (GitgRepository *repository, - gchar **buffer) -{ - gchar *line; - gboolean show_stash; - - show_stash = repository->priv->show_stash; - - if (!show_stash) - { - return; - } - - while ((line = *buffer++) != NULL) - { - gchar **components = g_strsplit (line, "\01", 0); - guint len = g_strv_length (components); - - if (len < 5) - { - g_strfreev (components); - continue; - } - - /* components -> [hash, author, author email, author date, - committer, committer email, committer date, - subject, parents, left-right] */ - gint64 author_date = g_ascii_strtoll (components[3], NULL, 0); - - GitgRevision *rv = gitg_revision_new (components[0], - components[1], - components[2], - author_date, - NULL, - NULL, - -1, - components[4], - NULL); - - add_ref (repository, components[0], "refs/stash"); - - gitg_revision_set_sign (rv, 's'); - append_revision (repository, rv); - g_strfreev (components); - } -} - -static void -loader_update_commits (GitgRepository *self, - gchar **buffer) -{ - gchar *line; - - while ( (line = *buffer++) != NULL) - { - /* new line is read */ - gchar **components = g_strsplit (line, "\01", 0); - guint len = g_strv_length (components); - - if (len < 9) - { - g_strfreev (components); - continue; - } - - /* components -> [hash, author, subject, parents ([1 2 3]), timestamp[, leftright]] */ - gint64 author_date = g_ascii_strtoll (components[3], NULL, 0); - gint64 committer_date = g_ascii_strtoll (components[6], NULL, 0); - - GitgRevision *rv = gitg_revision_new (components[0], - components[1], - components[2], - author_date, - components[4], - components[5], - committer_date, - components[7], - components[8]); - - if (len > 9 && strlen (components[9]) == 1 && strchr ("<>-^", *components[9]) != NULL) - { - gitg_revision_set_sign (rv, *components[9]); - } - - append_revision (self, rv); - g_strfreev (components); - } -} - -static void -on_loader_update (GitgShell *object, - gchar **buffer, - GitgRepository *repository) -{ - switch (repository->priv->load_stage) - { - case LOAD_STAGE_STASH: - loader_update_stash (repository, buffer); - break; - case LOAD_STAGE_STAGED: - break; - case LOAD_STAGE_UNSTAGED: - break; - case LOAD_STAGE_COMMITS: - loader_update_commits (repository, buffer); - break; - default: - break; - } -} - -static void -free_refs (GSList *refs) -{ - g_slist_free_full (refs, (GDestroyNotify)gitg_ref_free); -} - -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) - { - gint8 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 gchar ** -copy_strv (gchar const **ptr, - gint argc) -{ - GPtrArray *ret = g_ptr_array_new (); - gint i = 0; - - while (ptr && ( (argc >= 0 && i < argc) || (argc < 0 && ptr[i]))) - { - g_ptr_array_add (ret, g_strdup (ptr[i])); - ++i; - } - - g_ptr_array_add (ret, NULL); - return (gchar **)g_ptr_array_free (ret, FALSE); -} - -static gboolean -has_left_right (gchar const **av, - int argc) -{ - int i; - - for (i = 0; i < argc; ++i) - { - if (strcmp (av[i], "--left-right") == 0) - { - return TRUE; - } - } - - return FALSE; -} - -static void -build_log_args (GitgRepository *self, - gint argc, - gchar const **av) -{ - gboolean topoorder; - - topoorder = self->priv->topoorder; - - gchar **argv = g_new0 (gchar *, 6 + topoorder + (argc > 0 ? argc - 1 : 0)); - - argv[0] = g_strdup ("log"); - - if (has_left_right (av, argc)) - { - argv[1] = g_strdup ("--pretty=format:%H\x01%an\x01%ae\x01%at\x01%cn\x01%ce\x01%ct\x01%s\x01%P\x01%m"); - } - else - { - argv[1] = g_strdup ("--pretty=format:%H\x01%an\x01%ae\x01%at\x01%cn\x01%ce\x01%ct\x01%s\x01%P"); - } - - argv[2] = g_strdup ("--encoding=UTF-8"); - gint start = 3; - - if (topoorder) - { - argv[3] = g_strdup ("--topo-order"); - ++start; - } - - gchar *head = NULL; - - if (argc <= 0) - { - head = gitg_repository_parse_ref (self, "HEAD"); - - if (head) - { - argv[start] = g_strdup ("HEAD"); - } - - g_free (head); - } - else - { - int i; - - for (i = 0; i < argc; ++i) - { - argv[start + i] = g_strdup (av[i]); - } - } - - g_strfreev (self->priv->last_args); - self->priv->last_args = argv; - - gchar **newselection = copy_strv (av, argc); - - g_strfreev (self->priv->selection); - self->priv->selection = newselection; -} - -static void -gitg_repository_init (GitgRepository *object) -{ - object->priv = GITG_REPOSITORY_GET_PRIVATE (object); - - object->priv->hashtable = g_hash_table_new (gitg_hash_hash, - gitg_hash_hash_equal); - - object->priv->ref_pushes = g_hash_table_new (gitg_hash_hash, - gitg_hash_hash_equal); - - object->priv->ref_names = g_hash_table_new (g_str_hash, g_str_equal); - - 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->lanes = gitg_lanes_new (); - object->priv->grow_size = 1000; - object->priv->stamp = g_random_int (); - - object->priv->refs = g_hash_table_new_full (gitg_hash_hash, - gitg_hash_hash_equal, - NULL, - (GDestroyNotify)free_refs); - - object->priv->loader = gitg_shell_new (10000); - gitg_io_set_auto_utf8 (GITG_IO (object->priv->loader), FALSE); - - g_signal_connect (object->priv->loader, - "update", - G_CALLBACK (on_loader_update), - object); - - g_signal_connect (object->priv->loader, - "end", - G_CALLBACK (on_loader_end_loading), - 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); - - gint 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 (GFile *git_dir, - GFile *work_tree) -{ - return g_object_new (GITG_TYPE_REPOSITORY, - "git-dir", git_dir, - "work-tree", work_tree, - NULL); -} - -GFile * -gitg_repository_get_work_tree (GitgRepository *self) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (self), NULL); - - return g_file_dup (self->priv->work_tree); -} - -GFile * -gitg_repository_get_git_dir (GitgRepository *self) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (self), NULL); - - return g_file_dup (self->priv->git_dir); -} - -GitgShell * -gitg_repository_get_loader (GitgRepository *self) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (self), NULL); - return GITG_SHELL (g_object_ref (self->priv->loader)); -} - -static gboolean -reload_revisions (GitgRepository *repository, - GError **error) -{ - if (repository->priv->working_ref) - { - gitg_ref_free (repository->priv->working_ref); - repository->priv->working_ref = NULL; - } - - g_signal_emit (repository, repository_signals[LOAD], 0); - - repository->priv->load_stage = LOAD_STAGE_STASH; - - return gitg_shell_run (repository->priv->loader, - gitg_command_new (repository, - "log", - "--pretty=format:%H\x01%an\x01%ae\x01%at\x01%s", - "--encoding=UTF-8", - "-g", - "refs/stash", - NULL), - error); -} - -static gchar * -load_current_ref (GitgRepository *self) -{ - gchar **out; - gchar *ret = NULL; - gint i; - gint numargs; - gboolean retval; - - if (self->priv->last_args == NULL) - { - return NULL; - } - - numargs = g_strv_length (self->priv->last_args); - - gchar const **argv = g_new0 (gchar const *, numargs + 3); - - argv[0] = "rev-parse"; - argv[1] = "--no-flags"; - argv[2] = "--symbolic-full-name"; - - for (i = 1; i < numargs; ++i) - { - argv[2 + i] = self->priv->last_args[i]; - } - - retval = gitg_shell_run_sync_with_output (gitg_command_newv (self, argv), - FALSE, - &out, - NULL); - - if (!retval || !out) - { - g_strfreev (out); - return NULL; - } - - if (*out && !*(out + 1)) - { - ret = g_strdup (*out); - } - - g_strfreev (out); - return ret; -} - -static void -load_refs (GitgRepository *self) -{ - gchar **refs; - gboolean retval; - - retval = gitg_shell_run_sync_with_output (gitg_command_new (self, - "for-each-ref", - "--format=%(refname) %(objectname) %(*objectname)", - "refs", - NULL), - FALSE, - &refs, - NULL); - - if (!retval || !refs) - { - g_strfreev (refs); - return; - } - - gchar **buffer = refs; - gchar *buf; - gchar *current = load_current_ref (self); - - GitgRef *working = gitg_repository_get_current_working_ref (self); - - while (buffer != NULL && (buf = *buffer++) != NULL) - { - // each line will look like - gchar **components = g_strsplit (buf, " ", 3); - guint len = g_strv_length (components); - - if (len == 2 || len == 3) - { - gchar const *obj = len == 3 && *components[2] ? components[2] : components[1]; - GitgRef *ref = add_ref (self, obj, components[0]); - - if (current != NULL && strcmp (gitg_ref_get_name (ref), current) == 0) - { - self->priv->current_ref = gitg_ref_copy (ref); - } - - if (working != NULL && gitg_ref_equal (working, ref)) - { - gitg_ref_set_working (ref, TRUE); - } - } - - g_strfreev (components); - } - - g_strfreev (refs); - g_free (current); -} - -void -gitg_repository_reload (GitgRepository *repository) -{ - g_return_if_fail (GITG_IS_REPOSITORY (repository)); - g_return_if_fail (repository->priv->git_dir != NULL); - - gitg_io_cancel (GITG_IO (repository->priv->loader)); - - repository->priv->load_stage = LOAD_STAGE_NONE; - gitg_repository_clear (repository); - - load_refs (repository); - reload_revisions (repository, NULL); -} - -gboolean -gitg_repository_load (GitgRepository *self, - int argc, - gchar const **av, - GError **error) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (self), FALSE); - - if (self->priv->git_dir == 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_io_cancel (GITG_IO (self->priv->loader)); - gitg_repository_clear (self); - - build_log_args (self, argc, av); - - /* first get the refs */ - load_refs (self); - - /* request log (all the revision) */ - return reload_revisions (self, error); -} - -void -gitg_repository_add (GitgRepository *self, - GitgRevision *obj, - GtkTreeIter *iter) -{ - GtkTreeIter iter1; - - /* validate our parameters */ - g_return_if_fail (GITG_IS_REPOSITORY (self)); - - grow_storage (self, 1); - - /* put this object in our data storage */ - self->priv->storage[self->priv->size++] = gitg_revision_ref (obj); - - 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; - } -} - -void -gitg_repository_clear (GitgRepository *repository) -{ - g_return_if_fail (GITG_IS_REPOSITORY (repository)); - do_clear (repository, TRUE); -} - -GitgRevision * -gitg_repository_lookup (GitgRepository *store, - gchar const *hash) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (store), NULL); - - gpointer result = g_hash_table_lookup (store->priv->hashtable, hash); - - if (!result) - { - return NULL; - } - - return store->priv->storage[GPOINTER_TO_UINT (result)]; -} - -gboolean -gitg_repository_find_by_hash (GitgRepository *store, - gchar const *hash, - GtkTreeIter *iter) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (store), FALSE); - - gpointer result = g_hash_table_lookup (store->priv->hashtable, hash); - - if (!result) - { - return FALSE; - } - - GtkTreePath *path = gtk_tree_path_new_from_indices (GPOINTER_TO_UINT (result), - -1); - gtk_tree_model_get_iter (GTK_TREE_MODEL (store), iter, path); - gtk_tree_path_free (path); - - return TRUE; -} - -gboolean -gitg_repository_find (GitgRepository *store, - GitgRevision *revision, - GtkTreeIter *iter) -{ - return gitg_repository_find_by_hash (store, - gitg_revision_get_hash (revision), - iter); -} - -static gint -ref_compare (GitgRef *a, - GitgRef *b) -{ - GitgRefType t1 = gitg_ref_get_ref_type (a); - GitgRefType t2 = gitg_ref_get_ref_type (b); - - if (t1 != t2) - { - return t1 < t2 ? -1 : 1; - } - else - { - return g_strcmp0 (gitg_ref_get_shortname (a), - gitg_ref_get_shortname (b)); - } -} - -GSList * -gitg_repository_get_refs (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - GList *values = g_hash_table_get_values (repository->priv->refs); - GSList *ret = NULL; - GList *item; - - for (item = values; item; item = item->next) - { - GSList *val; - - for (val = item->data; val; val = val->next) - { - ret = g_slist_insert_sorted (ret, - gitg_ref_copy (val->data), - (GCompareFunc)ref_compare); - } - } - - g_list_free (values); - - return ret; -} - -GSList * -gitg_repository_get_refs_for_hash (GitgRepository *repository, - gchar const *hash) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - return g_slist_copy ( (GSList *)g_hash_table_lookup (repository->priv->refs, hash)); -} - -GitgRef * -gitg_repository_get_current_ref (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - return repository->priv->current_ref; -} - -gchar * -gitg_repository_relative (GitgRepository *repository, - GFile *file) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - g_return_val_if_fail (repository->priv->work_tree != NULL, NULL); - - return g_file_get_relative_path (repository->priv->work_tree, file); -} - -gchar * -gitg_repository_parse_ref (GitgRepository *repository, - gchar const *ref) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - return parse_ref_intern (repository, ref, FALSE); -} - -gchar * -gitg_repository_parse_head (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - gchar *ret = gitg_repository_parse_ref (repository, "HEAD"); - - if (!ret) - { - ret = g_strdup ("4b825dc642cb6eb9a060e54bf8d69288fbee4904"); - } - - return ret; -} - -GitgRef * -gitg_repository_get_current_working_ref (GitgRepository *repository) -{ - if (repository->priv->working_ref) - { - return repository->priv->working_ref; - } - - repository->priv->working_ref = get_current_working_ref (repository); - return repository->priv->working_ref; -} - -gchar ** -gitg_repository_get_remotes (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - GitgConfig *config = gitg_config_new (repository); - gchar *ret = gitg_config_get_value_regex (config, "remote\\..*\\.url", NULL); - - GPtrArray *remotes = g_ptr_array_new (); - - if (!ret) - { - g_ptr_array_add (remotes, NULL); - g_object_unref (config); - - return (gchar **)g_ptr_array_free (remotes, FALSE); - } - - gchar **lines = g_strsplit (ret, "\n", -1); - gchar **ptr = lines; - - g_free (ret); - - GRegex *regex = g_regex_new ("remote\\.(.+?)\\.url\\s+(.*)", 0, 0, NULL); - - while (*ptr) - { - GMatchInfo *info = NULL; - - if (g_regex_match (regex, *ptr, 0, &info)) - { - gchar *name = g_match_info_fetch (info, 1); - - g_ptr_array_add (remotes, name); - } - - g_match_info_free (info); - ++ptr; - } - - /* NULL terminate */ - g_ptr_array_add (remotes, NULL); - g_object_unref (config); - g_strfreev (lines); - - return (gchar **)g_ptr_array_free (remotes, FALSE); -} - -GSList const * -gitg_repository_get_ref_pushes (GitgRepository *repository, GitgRef *ref) - -{ - gpointer ret; - GitgRef *my_ref; - - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - my_ref = g_hash_table_lookup (repository->priv->ref_names, - gitg_ref_get_name (ref)); - - if (!my_ref) - { - return NULL; - } - - if (g_hash_table_lookup_extended (repository->priv->ref_pushes, - my_ref, - NULL, - &ret)) - { - return ret; - } - - GitgConfig *config = gitg_config_new (repository); - gchar *escaped = g_regex_escape_string (gitg_ref_get_name (my_ref), -1); - gchar *value_regex = g_strdup_printf ("^%s:", escaped); - - gchar *pushes = gitg_config_get_value_regex (config, - "remote\\..*\\.push", - value_regex); - - g_free (escaped); - g_free (value_regex); - - if (!pushes || !*pushes) - { - g_object_unref (config); - g_free (pushes); - - g_hash_table_insert (repository->priv->ref_pushes, - my_ref, - NULL); - - return NULL; - } - - gchar **lines = g_strsplit (pushes, "\n", -1); - gchar **ptr = lines; - - g_free (pushes); - - GRegex *regex = g_regex_new ("remote\\(.+?)\\.push\\s+.*:refs/heads/(.*)", 0, 0, NULL); - GSList *refs = NULL; - - while (*ptr) - { - GMatchInfo *info = NULL; - - if (g_regex_match (regex, *ptr, 0, &info)) - { - gchar *remote = g_match_info_fetch (info, 1); - gchar *branch = g_match_info_fetch (info, 2); - - gchar *rr = g_strconcat ("refs/remotes/", remote, "/", branch, NULL); - - GitgRef *remref = g_hash_table_lookup (repository->priv->ref_names, - rr); - - g_free (rr); - g_free (remote); - g_free (branch); - - if (remref) - { - refs = g_slist_prepend (refs, remref); - } - } - - g_match_info_free (info); - ++ptr; - } - - g_object_unref (config); - g_strfreev (lines); - - refs = g_slist_reverse (refs); - - g_hash_table_insert (repository->priv->ref_pushes, - my_ref, - refs); - - return refs; -} - -gboolean -gitg_repository_get_loaded (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE); - - return repository->priv->load_stage == LOAD_STAGE_LAST && - !gitg_io_get_running (GITG_IO (repository->priv->loader)); -} - -gchar const ** -gitg_repository_get_current_selection (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), NULL); - - return (gchar const **)repository->priv->selection; -} - -gboolean -gitg_repository_exists (GitgRepository *repository) -{ - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE); - - if (repository->priv->git_dir == NULL) - { - return FALSE; - } - - return g_file_query_exists (repository->priv->git_dir, NULL) && - g_file_query_exists (repository->priv->work_tree, NULL); -} - -static void -collect_update (GitgShell *shell, - gchar const * const *lines, - GPtrArray *ret) -{ - while (lines && *lines) - { - g_ptr_array_add (ret, g_strdup (*lines++)); - } -} - -gboolean -gitg_repository_run_hook (GitgRepository *repository, - gchar const *name, - GError **error, - ...) -{ - GFile *hooksdir; - GFile *hookfile; - GitgCommand *command; - gchar *path; - GPtrArray *args; - gchar **argsv; - gchar **ret; - va_list ap; - gchar const *arg; - GFileInfo *info; - gboolean canexec; - gboolean retval; - GitgShell *shell; - GPtrArray *ptrar; - GFile *index_file; - - g_return_val_if_fail (GITG_IS_REPOSITORY (repository), FALSE); - - if (repository->priv->git_dir == NULL) - { - return FALSE; - } - - hooksdir = g_file_get_child (repository->priv->git_dir, "hooks"); - hookfile = g_file_get_child (hooksdir, name); - g_object_unref (hooksdir); - - info = g_file_query_info (hookfile, - G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, - G_FILE_QUERY_INFO_NONE, - NULL, - NULL); - - canexec = info && - g_file_info_get_attribute_boolean (info, - G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE); - - if (info) - { - g_object_unref (info); - } - - if (!canexec) - { - /* It's considered a success if the hook cannot be executed */ - g_object_unref (hookfile); - return TRUE; - } - - path = g_file_get_path (hookfile); - g_object_unref (hookfile); - - args = g_ptr_array_new (); - g_ptr_array_add (args, path); - - va_start (ap, error); - - while ((arg = va_arg (ap, gchar const *)) != NULL) - { - g_ptr_array_add (args, g_strdup (arg)); - } - - va_end (ap); - - g_ptr_array_add (args, NULL); - argsv = (gchar **)g_ptr_array_free (args, FALSE); - - command = gitg_command_newv (NULL, - (gchar const * const *)argsv); - - gitg_command_set_working_directory (command, repository->priv->work_tree); - - path = g_file_get_path (repository->priv->git_dir); - gitg_command_add_environment (command, "GIT_DIR", path, NULL); - g_free (path); - - index_file = g_file_get_child (repository->priv->git_dir, "index"); - path = g_file_get_path (index_file); - g_object_unref (index_file); - - gitg_command_add_environment (command, "GIT_INDEX_FILE", path, NULL); - g_free (path); - - g_strfreev (argsv); - - shell = gitg_shell_new_synchronized (1000); - - gitg_io_set_stderr_to_stdout (GITG_IO (shell), TRUE); - gitg_shell_set_preserve_line_endings (shell, TRUE); - - ptrar = g_ptr_array_sized_new (100); - - g_signal_connect (shell, - "update", - G_CALLBACK (collect_update), - ptrar); - - retval = gitg_shell_run (shell, command, error) && - gitg_io_get_exit_status (GITG_IO (shell)) == 0; - - g_ptr_array_add (ptrar, NULL); - ret = (gchar **)g_ptr_array_free (ptrar, FALSE); - - if (!retval) - { - if (error) - { - gchar *joined; - - joined = g_strjoinv ("", ret); - - if (*error) - { - g_prefix_error (error, - "Hook `%s' failed: %s", - name, - joined); - } - else - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Hook `%s' failed: %s", - name, - joined); - } - - g_free (joined); - } - } - - g_strfreev (ret); - - return retval; -} diff --git a/libgitg/gitg-repository.h b/libgitg/gitg-repository.h deleted file mode 100644 index aebe8152..00000000 --- a/libgitg/gitg-repository.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * gitg-repository.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REPOSITORY_H__ -#define __GITG_REPOSITORY_H__ - -#include - -#include -#include - -G_BEGIN_DECLS - -#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 _GitgRepository GitgRepository; -typedef struct _GitgRepositoryClass GitgRepositoryClass; -typedef struct _GitgRepositoryPrivate GitgRepositoryPrivate; - -struct _GitgShell; - -typedef enum -{ - GITG_REPOSITORY_NO_ERROR = 0, - GITG_REPOSITORY_ERROR_NOT_FOUND -} GitgRepositoryError; - -struct _GitgRepository -{ - GObject parent; - - GitgRepositoryPrivate *priv; -}; - -struct _GitgRepositoryClass -{ - GObjectClass parent_class; - - void (*load) (GitgRepository *repository); - void (*loaded) (GitgRepository *repository); -}; - -GType gitg_repository_get_type (void) G_GNUC_CONST; - -GitgRepository *gitg_repository_new (GFile *git_dir, - GFile *work_tree); - -GFile *gitg_repository_get_work_tree (GitgRepository *repository); -GFile *gitg_repository_get_git_dir (GitgRepository *repository); - -gboolean gitg_repository_exists (GitgRepository *repository); - -gboolean gitg_repository_load(GitgRepository *repository, int argc, gchar const **argv, GError **error); -gboolean gitg_repository_get_loaded(GitgRepository *repository); - -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); -GitgRevision *gitg_repository_lookup(GitgRepository *store, gchar const *hash); - -GSList *gitg_repository_get_refs(GitgRepository *repository); -GSList *gitg_repository_get_refs_for_hash(GitgRepository *repository, gchar const *hash); -GitgRef *gitg_repository_get_current_ref(GitgRepository *repository); -GitgRef *gitg_repository_get_current_working_ref(GitgRepository *repository); - -gchar *gitg_repository_relative(GitgRepository *repository, GFile *file); - -gchar *gitg_repository_parse_ref(GitgRepository *repository, gchar const *ref); -gchar *gitg_repository_parse_head(GitgRepository *repository); - -void gitg_repository_reload(GitgRepository *repository); - -struct _GitgShell *gitg_repository_get_loader (GitgRepository *repository); - -gchar **gitg_repository_get_remotes (GitgRepository *repository); -GSList const *gitg_repository_get_ref_pushes (GitgRepository *repository, GitgRef *ref); -gchar const **gitg_repository_get_current_selection (GitgRepository *repository); - -gboolean gitg_repository_run_hook (GitgRepository *repository, - gchar const *name, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -G_END_DECLS - -#endif /* __GITG_REPOSITORY_H__ */ diff --git a/libgitg/gitg-repository.vala b/libgitg/gitg-repository.vala new file mode 100644 index 00000000..927f878b --- /dev/null +++ b/libgitg/gitg-repository.vala @@ -0,0 +1,38 @@ +namespace Gitg +{ + +public class Repository : Ggit.Repository +{ + public Repository(File location, File? workdir) throws Error + { + Object(location: location, + workdir: workdir); + + ((Initable)this).init(null); + } + + // Wrappers for Gitg.Ref + public new Ref lookup_reference(string name) throws Error + { + return base.lookup_reference(name) as Ref; + } + + public new Ref create_reference(string name, Ggit.OId oid) throws Error + { + return base.create_reference(name, oid) as Ref; + } + + public new Ref create_symbolic_reference(string name, string target) throws Error + { + return base.create_symbolic_reference(name, target) as Ref; + } + + public new Gitg.Ref get_head() throws Error + { + return base.get_head() as Ref; + } +} + +} + +// ex:set ts=4 noet diff --git a/libgitg/gitg-revision.c b/libgitg/gitg-revision.c deleted file mode 100644 index 579c8781..00000000 --- a/libgitg/gitg-revision.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * gitg-revision.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-convert.h" -#include "gitg-revision.h" -#include "gitg-hash.h" - -struct _GitgRevision -{ - gint refcount; - - GitgHash hash; - - gchar *author; - gchar *author_email; - gint64 author_date; - - gchar *committer; - gchar *committer_email; - gint64 committer_date; - - gchar *subject; - - GitgHash *parents; - guint num_parents; - char sign; - - GSList *lanes; - gint8 mylane; -}; - -G_DEFINE_BOXED_TYPE (GitgRevision, gitg_revision, gitg_revision_ref, gitg_revision_unref) - -static void -free_lanes (GitgRevision *rv) -{ - g_slist_free_full (rv->lanes, (GDestroyNotify)gitg_lane_free); - rv->lanes = NULL; -} - -static void -gitg_revision_finalize (GitgRevision *revision) -{ - g_free (revision->author); - g_free (revision->author_email); - - g_free (revision->committer); - g_free (revision->committer_email); - - g_free (revision->subject); - g_free (revision->parents); - - free_lanes (revision); - - g_slice_free (GitgRevision, revision); -} - -GitgRevision * -gitg_revision_ref (GitgRevision *revision) -{ - if (revision == NULL) - { - return NULL; - } - - g_atomic_int_inc (&revision->refcount); - return revision; -} - -void -gitg_revision_unref (GitgRevision *revision) -{ - if (revision == NULL) - { - return; - } - - if (!g_atomic_int_dec_and_test (&revision->refcount)) - { - return; - } - - gitg_revision_finalize (revision); -} - -GitgRevision * -gitg_revision_new (gchar const *sha, - gchar const *author, - gchar const *author_email, - gint64 author_date, - gchar const *committer, - gchar const *committer_email, - gint64 committer_date, - gchar const *subject, - gchar const *parents) -{ - GitgRevision *rv = g_slice_new0 (GitgRevision); - - rv->refcount = 1; - - gitg_hash_sha1_to_hash (sha, rv->hash); - - rv->author = g_strdup (author); - rv->author_email = g_strdup (author_email); - rv->author_date = author_date; - - rv->committer = g_strdup (committer); - rv->committer_email = g_strdup (committer_email); - rv->committer_date = committer_date; - - rv->subject = g_strdup (subject); - - if (parents) - { - gchar **shas = g_strsplit (parents, " ", 0); - gint num = g_strv_length (shas); - rv->parents = g_new (GitgHash, num + 1); - - gint i; - - for (i = 0; i < num; ++i) - { - gitg_hash_sha1_to_hash (shas[i], rv->parents[i]); - } - - g_strfreev (shas); - rv->num_parents = num; - } - - return rv; -} - -gchar const * -gitg_revision_get_author (GitgRevision *revision) -{ - return revision->author; -} - -gchar const * -gitg_revision_get_author_email (GitgRevision *revision) -{ - return revision->author_email; -} - -gint64 -gitg_revision_get_author_date (GitgRevision *revision) -{ - return revision->author_date; -} - -gchar const * -gitg_revision_get_committer (GitgRevision *revision) -{ - return revision->committer; -} - -gchar const * -gitg_revision_get_committer_email (GitgRevision *revision) -{ - return revision->committer_email; -} - -gint64 -gitg_revision_get_committer_date (GitgRevision *revision) -{ - return revision->committer_date; -} - -gchar const * -gitg_revision_get_subject (GitgRevision *revision) -{ - return revision->subject; -} - -gchar const * -gitg_revision_get_hash (GitgRevision *revision) -{ - return revision->hash; -} - -gchar * -gitg_revision_get_sha1 (GitgRevision *revision) -{ - char res[GITG_HASH_SHA_SIZE]; - gitg_hash_hash_to_sha1 (revision->hash, res); - - return g_strndup (res, GITG_HASH_SHA_SIZE); -} - -GitgHash * -gitg_revision_get_parents_hash (GitgRevision *revision, - guint *num_parents) -{ - if (num_parents) - { - *num_parents = revision->num_parents; - } - - return revision->parents; -} - -gchar ** -gitg_revision_get_parents (GitgRevision *revision) -{ - gchar **ret = g_new (gchar *, revision->num_parents + 1); - - gint i; - - for (i = 0; i < revision->num_parents; ++i) - { - ret[i] = g_new (gchar, GITG_HASH_SHA_SIZE + 1); - gitg_hash_hash_to_sha1 (revision->parents[i], ret[i]); - - ret[i][GITG_HASH_SHA_SIZE] = '\0'; - } - - ret[revision->num_parents] = NULL; - - return ret; -} - -GSList * -gitg_revision_get_lanes (GitgRevision *revision) -{ - return revision->lanes; -} - -GSList * -gitg_revision_remove_lane (GitgRevision *revision, - GitgLane *lane) -{ - revision->lanes = g_slist_remove (revision->lanes, lane); - gitg_lane_free (lane); - - return revision->lanes; -} - -GSList * -gitg_revision_insert_lane (GitgRevision *revision, - GitgLane *lane, - gint index) -{ - revision->lanes = g_slist_insert (revision->lanes, lane, index); - - return revision->lanes; -} - -static void -update_lane_type (GitgRevision *revision) -{ - GitgLane *lane = (GitgLane *)g_slist_nth_data (revision->lanes, revision->mylane); - - if (lane == NULL) - { - return; - } - - lane->type &= ~ (GITG_LANE_SIGN_LEFT | - GITG_LANE_SIGN_RIGHT | - GITG_LANE_SIGN_STASH | - GITG_LANE_SIGN_STAGED | - GITG_LANE_SIGN_UNSTAGED); - - switch (revision->sign) - { - case '<': - lane->type |= GITG_LANE_SIGN_LEFT; - break; - case '>': - lane->type |= GITG_LANE_SIGN_RIGHT; - break; - case 's': - lane->type |= GITG_LANE_SIGN_STASH; - break; - case 't': - lane->type |= GITG_LANE_SIGN_STAGED; - break; - case 'u': - lane->type |= GITG_LANE_SIGN_UNSTAGED; - break; - } -} - -void -gitg_revision_set_lanes (GitgRevision *revision, - GSList *lanes, - gint8 mylane) -{ - free_lanes (revision); - revision->lanes = lanes; - - if (mylane >= 0) - { - revision->mylane = mylane; - } - - update_lane_type (revision); -} - -gint8 -gitg_revision_get_mylane (GitgRevision *revision) -{ - return revision->mylane; -} - -void -gitg_revision_set_mylane (GitgRevision *revision, - gint8 mylane) -{ - g_return_if_fail (mylane >= 0); - - revision->mylane = mylane; - update_lane_type (revision); -} - -void -gitg_revision_set_sign (GitgRevision *revision, - char sign) -{ - revision->sign = sign; -} - -char -gitg_revision_get_sign (GitgRevision *revision) -{ - return revision->sign; -} - -GitgLane * -gitg_revision_get_lane (GitgRevision *revision) -{ - return (GitgLane *)g_slist_nth_data (revision->lanes, revision->mylane); -} - -gchar * -gitg_revision_get_format_patch_name (GitgRevision *revision) -{ - GString *ret; - gboolean lastisspace = FALSE; - gchar const *ptr; - - ret = g_string_new (""); - ptr = revision->subject; - - do - { - gunichar c; - - c = g_utf8_get_char (ptr); - - if (c == ' ' || c == '/') - { - if (!lastisspace) - { - g_string_append_c (ret, '-'); - lastisspace = TRUE; - } - } - else - { - g_string_append_unichar (ret, c); - } - } while (*(ptr = g_utf8_next_char (ptr))); - - return g_string_free (ret, FALSE); -} - -static gchar * -date_for_display (gint64 date) -{ - if (date < 0) - { - return g_strdup (""); - } - - time_t t = date; - struct tm *tms = localtime (&t); - gchar buf[255]; - - strftime (buf, 254, "%c", tms); - return gitg_convert_utf8 (buf, -1); -} - -gchar * -gitg_revision_get_author_date_for_display (GitgRevision *revision) -{ - return date_for_display (gitg_revision_get_author_date (revision)); -} - -gchar * -gitg_revision_get_committer_date_for_display (GitgRevision *revision) -{ - return date_for_display (gitg_revision_get_committer_date (revision)); -} diff --git a/libgitg/gitg-revision.h b/libgitg/gitg-revision.h deleted file mode 100644 index e01a141b..00000000 --- a/libgitg/gitg-revision.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * gitg-revision.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_REVISION_H__ -#define __GITG_REVISION_H__ - -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_REVISION (gitg_revision_get_type ()) -#define GITG_REVISION(obj) ((GitgRevision *)obj) -#define GITG_REVISION_CONST(obj) ((GitgRevision const *)obj) - -typedef struct _GitgRevision GitgRevision; - -GType gitg_revision_get_type (void) G_GNUC_CONST; - -GitgRevision *gitg_revision_new (gchar const *hash, - gchar const *author, - gchar const *author_email, - gint64 author_date, - gchar const *committer, - gchar const *committer_email, - gint64 committer_date, - gchar const *subject, - gchar const *parents); - -inline gchar const *gitg_revision_get_author (GitgRevision *revision); -inline gchar const *gitg_revision_get_author_email (GitgRevision *revision); -inline gint64 gitg_revision_get_author_date (GitgRevision *revision); - -inline gchar const *gitg_revision_get_committer (GitgRevision *revision); -inline gchar const *gitg_revision_get_committer_email (GitgRevision *revision); -inline gint64 gitg_revision_get_committer_date (GitgRevision *revision); - -inline gchar const *gitg_revision_get_subject (GitgRevision *revision); - -inline gchar const *gitg_revision_get_hash (GitgRevision *revision); -inline GitgHash *gitg_revision_get_parents_hash (GitgRevision *revision, guint *num_parents); - -gchar *gitg_revision_get_sha1 (GitgRevision *revision); -gchar **gitg_revision_get_parents (GitgRevision *revision); - -GSList *gitg_revision_get_lanes (GitgRevision *revision); -GitgLane *gitg_revision_get_lane (GitgRevision *revision); -void gitg_revision_set_lanes (GitgRevision *revision, GSList *lanes, gint8 mylane); - -GSList *gitg_revision_remove_lane (GitgRevision *revision, GitgLane *lane); -GSList *gitg_revision_insert_lane (GitgRevision *revision, GitgLane *lane, gint index); - -gint8 gitg_revision_get_mylane (GitgRevision *revision); -void gitg_revision_set_mylane (GitgRevision *revision, gint8 mylane); - -void gitg_revision_set_sign(GitgRevision *revision, char sign); -char gitg_revision_get_sign(GitgRevision *revision); - -GitgRevision *gitg_revision_ref (GitgRevision *revision); -void gitg_revision_unref (GitgRevision *revision); - -gchar *gitg_revision_get_format_patch_name (GitgRevision *revision); - -gchar *gitg_revision_get_author_date_for_display (GitgRevision *revision); -gchar *gitg_revision_get_committer_date_for_display (GitgRevision *revision); - -G_END_DECLS - -#endif /* __GITG_REVISION_H__ */ diff --git a/libgitg/gitg-runner.c b/libgitg/gitg-runner.c deleted file mode 100644 index 1800415e..00000000 --- a/libgitg/gitg-runner.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * gitg-runner.c - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "gitg-runner.h" -#include "gitg-debug.h" - -#include "gitg-smart-charset-converter.h" - -#define GITG_RUNNER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_RUNNER, GitgRunnerPrivate)) - -struct _GitgRunnerPrivate -{ - GitgCommand *command; - - GInputStream *g_stdout; - GOutputStream *g_stdin; - - GCancellable *cancellable; - gboolean cancelled; - - GPid pid; - guint watch_id; -}; - -G_DEFINE_TYPE (GitgRunner, gitg_runner, GITG_TYPE_IO) - -enum -{ - PROP_0, - PROP_COMMAND -}; - -typedef struct -{ - GitgRunner *runner; - GCancellable *cancellable; -} AsyncData; - -static AsyncData * -async_data_new (GitgRunner *runner) -{ - AsyncData *data; - - data = g_slice_new (AsyncData); - - data->runner = runner; - data->cancellable = g_object_ref (runner->priv->cancellable); - - return data; -} - -static void -async_data_free (AsyncData *data) -{ - g_object_unref (data->cancellable); - g_slice_free (AsyncData, data); -} - -static void -gitg_runner_finalize (GObject *object) -{ - G_OBJECT_CLASS (gitg_runner_parent_class)->finalize (object); -} - -static void -close_streams (GitgRunner *runner) -{ - if (runner->priv->cancellable) - { - g_cancellable_cancel (runner->priv->cancellable); - } - - if (runner->priv->g_stdin != NULL) - { - g_output_stream_close (runner->priv->g_stdin, NULL, NULL); - g_object_unref (runner->priv->g_stdin); - - runner->priv->g_stdin = NULL; - } - - if (runner->priv->g_stdout != NULL) - { - g_input_stream_close (runner->priv->g_stdout, NULL, NULL); - g_object_unref (runner->priv->g_stdout); - - runner->priv->g_stdout = NULL; - } - - gitg_io_close (GITG_IO (runner)); -} - -static void -gitg_runner_dispose (GObject *object) -{ - GitgRunner *runner; - - runner = GITG_RUNNER (object); - - if (runner->priv->command != NULL) - { - g_object_unref (runner->priv->command); - runner->priv->command = NULL; - } - - gitg_io_cancel (GITG_IO (runner)); - - close_streams (runner); - - G_OBJECT_CLASS (gitg_runner_parent_class)->dispose (object); -} - -static void -gitg_runner_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgRunner *self = GITG_RUNNER (object); - - switch (prop_id) - { - case PROP_COMMAND: - gitg_runner_set_command (self, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_runner_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgRunner *self = GITG_RUNNER (object); - - switch (prop_id) - { - case PROP_COMMAND: - g_value_set_object (value, self->priv->command); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dummy_cb (GPid pid, - gint status, - gpointer data) -{ -} - -static void -kill_process (GitgRunner *runner) -{ - if (runner->priv->pid == 0) - { - return; - } - - /* We remove our handler for the process here and install a dummy - handler later so it will still be properly reaped */ - g_source_remove (runner->priv->watch_id); - kill (runner->priv->pid, SIGTERM); - - g_child_watch_add (runner->priv->pid, dummy_cb, NULL); - - runner->priv->pid = 0; - - gitg_io_set_exit_status (GITG_IO (runner), EXIT_FAILURE); -} - -static void -runner_done (GitgRunner *runner, - GError *error) -{ - close_streams (runner); - kill_process (runner); - - if (!error && gitg_io_get_exit_status (GITG_IO (runner)) != 0) - { - GError *err; - - err = g_error_new (G_IO_ERROR, - G_IO_ERROR_FAILED, - "Process exited with non-zero exit code: %d", - gitg_io_get_exit_status (GITG_IO (runner))); - - gitg_io_end (GITG_IO (runner), err); - g_error_free (err); - } - else - { - gitg_io_end (GITG_IO (runner), error); - } -} - -static void -gitg_runner_cancel (GitgIO *io) -{ - gboolean was_running; - GitgRunner *runner; - - runner = GITG_RUNNER (io); - - if (runner->priv->cancellable) - { - g_cancellable_cancel (runner->priv->cancellable); - - g_object_unref (runner->priv->cancellable); - runner->priv->cancellable = NULL; - } - - was_running = gitg_io_get_running (GITG_IO (runner)); - - GITG_IO_CLASS (gitg_runner_parent_class)->cancel (GITG_IO (runner)); - - if (was_running) - { - runner_done (runner, NULL); - } -} - -static void -gitg_runner_class_init (GitgRunnerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GitgIOClass *io_class = GITG_IO_CLASS (klass); - - object_class->finalize = gitg_runner_finalize; - object_class->dispose = gitg_runner_dispose; - - object_class->get_property = gitg_runner_get_property; - object_class->set_property = gitg_runner_set_property; - - io_class->cancel = gitg_runner_cancel; - - g_type_class_add_private (object_class, sizeof(GitgRunnerPrivate)); - - g_object_class_install_property (object_class, - PROP_COMMAND, - g_param_spec_object ("command", - "Command", - "Command", - GITG_TYPE_COMMAND, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -} - -static void -gitg_runner_init (GitgRunner *self) -{ - self->priv = GITG_RUNNER_GET_PRIVATE (self); -} - -GitgRunner * -gitg_runner_new (GitgCommand *command) -{ - return g_object_new (GITG_TYPE_RUNNER, - "command", command, - NULL); -} - -static void -splice_input_ready_cb (GOutputStream *source, - GAsyncResult *result, - AsyncData *data) -{ - GError *error = NULL; - gboolean ret; - - ret = g_output_stream_splice_finish (source, result, &error); - - if (g_cancellable_is_cancelled (data->cancellable)) - { - if (error) - { - g_error_free (error); - } - - async_data_free (data); - return; - } - - if (!ret) - { - runner_done (data->runner, error); - } - - if (error) - { - g_error_free (error); - } - - async_data_free (data); -} - -static void -splice_output_ready_cb (GOutputStream *source, - GAsyncResult *result, - AsyncData *data) -{ - GError *error = NULL; - gboolean ret; - - ret = g_output_stream_splice_finish (source, result, &error); - - if (g_cancellable_is_cancelled (data->cancellable)) - { - if (error) - { - g_error_free (error); - } - - async_data_free (data); - return; - } - - if (!ret) - { - runner_done (data->runner, error); - } - else if (data->runner->priv->pid == 0) - { - runner_done (data->runner, NULL); - } - - if (error) - { - g_error_free (error); - } - - async_data_free (data); -} - -void -gitg_runner_stream_close (GitgRunner *runner, - GError *error) -{ - g_return_if_fail (GITG_IS_RUNNER (runner)); - - if (runner->priv->pid == 0 || error) - { - runner_done (runner, error); - } - else - { - g_input_stream_close (runner->priv->g_stdout, NULL, NULL); - } -} - -static void -process_watch_cb (GPid pid, - gint status, - GitgRunner *runner) -{ - runner->priv->pid = 0; - - if (WIFEXITED (status)) - { - gitg_io_set_exit_status (GITG_IO (runner), WEXITSTATUS (status)); - } - else - { - gitg_io_set_exit_status (GITG_IO (runner), 0); - } - - /* Note that we don't emit 'done' here because the streams might not - yet be ready with all their writing/reading */ - if (runner->priv->cancellable) - { - g_object_unref (runner->priv->cancellable); - runner->priv->cancellable = NULL; - } - - runner->priv->watch_id = 0; - - if (runner->priv->g_stdout == NULL || g_input_stream_is_closed (runner->priv->g_stdout)) - { - runner_done (runner, NULL); - } -} - -static void -debug_runner_command (GitgRunner *runner) -{ - gchar *argstr; - gchar const * const *envs; - GFile *wd; - - argstr = g_strjoinv (" ", (gchar **)gitg_command_get_arguments (runner->priv->command)); - - gitg_debug (GITG_DEBUG_SHELL, - "Running command: %s", argstr); - - g_free (argstr); - - envs = gitg_command_get_environment (runner->priv->command); - - if (envs) - { - gchar *environment; - environment = g_strjoinv (", ", (gchar **)envs); - - gitg_debug (GITG_DEBUG_SHELL, - "Environment: %s", environment); - - g_free (environment); - } - else - { - gitg_debug (GITG_DEBUG_SHELL, - "Environment: None"); - } - - wd = gitg_command_get_working_directory (runner->priv->command); - - if (wd) - { - gchar *path; - - path = g_file_get_path (wd); - - gitg_debug (GITG_DEBUG_SHELL, "CWD: %s", path); - - g_free (path); - g_object_unref (wd); - } - else - { - gitg_debug (GITG_DEBUG_SHELL, "CWD: None\n"); - } -} - -static void -setup_dup_stderr_to_stdout () -{ - dup2 (1, 2); -} - -void -gitg_runner_run (GitgRunner *runner) -{ - gboolean ret; - gint stdinf; - gint g_stdoutf; - GFile *working_directory; - gchar *wd_path = NULL; - GInputStream *start_input; - GOutputStream *end_output; - GInputStream *output; - GitgSmartCharsetConverter *smart; - GError *error = NULL; - GSpawnFlags flags = 0; - gboolean redirect_stderr; - GSpawnChildSetupFunc setup_func = NULL; - - g_return_if_fail (GITG_IS_RUNNER (runner)); - - gitg_io_cancel (GITG_IO (runner)); - - runner->priv->cancelled = FALSE; - - working_directory = gitg_command_get_working_directory (runner->priv->command); - - if (working_directory) - { - wd_path = g_file_get_path (working_directory); - g_object_unref (working_directory); - } - - start_input = gitg_io_get_input (GITG_IO (runner)); - - if (gitg_debug_enabled (GITG_DEBUG_SHELL)) - { - debug_runner_command (runner); - } - - redirect_stderr = gitg_io_get_stderr_to_stdout (GITG_IO (runner)); - - if (!redirect_stderr && !gitg_debug_enabled (GITG_DEBUG_SHELL)) - { - flags = G_SPAWN_STDERR_TO_DEV_NULL; - } - - if (redirect_stderr) - { - setup_func = (GSpawnChildSetupFunc)setup_dup_stderr_to_stdout; - } - - ret = g_spawn_async_with_pipes (wd_path, - (gchar **)gitg_command_get_arguments (runner->priv->command), - (gchar **)gitg_command_get_environment (runner->priv->command), - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | - flags, - setup_func, - NULL, - &(runner->priv->pid), - start_input ? &stdinf : NULL, - &g_stdoutf, - NULL, - &error); - - g_free (wd_path); - - gitg_io_begin (GITG_IO (runner)); - - if (!ret) - { - runner_done (runner, error); - g_error_free (error); - return; - } - - runner->priv->watch_id = g_child_watch_add (runner->priv->pid, - (GChildWatchFunc)process_watch_cb, - runner); - - if (start_input) - { - AsyncData *data; - - runner->priv->cancellable = g_cancellable_new (); - - runner->priv->g_stdin = - G_OUTPUT_STREAM (g_unix_output_stream_new (stdinf, - TRUE)); - - data = async_data_new (runner); - - /* Splice the supplied input to g_stdin of the process */ - g_output_stream_splice_async (runner->priv->g_stdin, - start_input, - G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | - G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, - G_PRIORITY_DEFAULT, - runner->priv->cancellable, - (GAsyncReadyCallback)splice_input_ready_cb, - data); - } - - output = G_INPUT_STREAM (g_unix_input_stream_new (g_stdoutf, - TRUE)); - - if (gitg_io_get_auto_utf8 (GITG_IO (runner))) - { - smart = gitg_smart_charset_converter_new (gitg_encoding_get_candidates ()); - - runner->priv->g_stdout = g_converter_input_stream_new (output, - G_CONVERTER (smart)); - - g_object_unref (smart); - g_object_unref (output); - } - else - { - runner->priv->g_stdout = output; - } - - end_output = gitg_io_get_output (GITG_IO (runner)); - - if (end_output) - { - AsyncData *data; - - if (runner->priv->cancellable == NULL) - { - runner->priv->cancellable = g_cancellable_new (); - } - - data = async_data_new (runner); - - /* Splice output of the process into the provided stream */ - g_output_stream_splice_async (end_output, - runner->priv->g_stdout, - G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | - G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, - G_PRIORITY_DEFAULT, - runner->priv->cancellable, - (GAsyncReadyCallback)splice_output_ready_cb, - data); - } -} - -GInputStream * -gitg_runner_get_stream (GitgRunner *runner) -{ - g_return_val_if_fail (GITG_IS_RUNNER (runner), NULL); - - return runner->priv->g_stdout; -} - -void -gitg_runner_set_command (GitgRunner *runner, GitgCommand *command) -{ - g_return_if_fail (GITG_IS_RUNNER (runner)); - g_return_if_fail (GITG_IS_COMMAND (command)); - - if (runner->priv->command) - { - g_object_unref (runner->priv->command); - } - - runner->priv->command = g_object_ref_sink (command); - g_object_notify (G_OBJECT (runner), "command"); -} - -GitgCommand * -gitg_runner_get_command (GitgRunner *runner) -{ - g_return_val_if_fail (GITG_IS_RUNNER (runner), NULL); - - return runner->priv->command; -} diff --git a/libgitg/gitg-runner.h b/libgitg/gitg-runner.h deleted file mode 100644 index d6ba1d34..00000000 --- a/libgitg/gitg-runner.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * gitg-runner.h - * This file is part of gitg - * - * Copyright (C) 2010 - Jesse van den Kieboom - * - * gitg 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. - * - * gitg 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 gitg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_RUNNER_H__ -#define __GITG_RUNNER_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_RUNNER (gitg_runner_get_type ()) -#define GITG_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RUNNER, GitgRunner)) -#define GITG_RUNNER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_RUNNER, GitgRunner const)) -#define GITG_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_RUNNER, GitgRunnerClass)) -#define GITG_IS_RUNNER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_RUNNER)) -#define GITG_IS_RUNNER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_RUNNER)) -#define GITG_RUNNER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_RUNNER, GitgRunnerClass)) - -typedef struct _GitgRunner GitgRunner; -typedef struct _GitgRunnerClass GitgRunnerClass; -typedef struct _GitgRunnerPrivate GitgRunnerPrivate; - -struct _GitgRunner -{ - /*< private >*/ - GitgIO parent; - - GitgRunnerPrivate *priv; - - /*< public >*/ -}; - -struct _GitgRunnerClass -{ - /*< private >*/ - GitgIOClass parent_class; - - /*< public >*/ -}; - -GType gitg_runner_get_type (void) G_GNUC_CONST; -GitgRunner *gitg_runner_new (GitgCommand *command); - -void gitg_runner_run (GitgRunner *runner); - -GitgCommand *gitg_runner_get_command (GitgRunner *runner); -void gitg_runner_set_command (GitgRunner *runner, GitgCommand *command); - -GInputStream *gitg_runner_get_stream (GitgRunner *runner); -void gitg_runner_stream_close (GitgRunner *runner, GError *error); - -G_END_DECLS - -#endif /* __GITG_RUNNER_H__ */ diff --git a/libgitg/gitg-shell.c b/libgitg/gitg-shell.c deleted file mode 100644 index 56a31e64..00000000 --- a/libgitg/gitg-shell.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * gitg-shell.c - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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 "gitg-convert.h" -#include "gitg-debug.h" -#include "gitg-shell.h" -#include "gitg-smart-charset-converter.h" -#include "gitg-runner.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "gitg-line-parser.h" - -#define GITG_SHELL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_SHELL, GitgShellPrivate)) - -/* Signals */ -enum -{ - UPDATE, - LAST_SIGNAL -}; - -static guint shell_signals[LAST_SIGNAL] = { 0 }; - -/* Properties */ -enum -{ - PROP_0, - - PROP_BUFFER_SIZE, - PROP_SYNCHRONIZED, - PROP_PRESERVE_LINE_ENDINGS -}; - -struct _GitgShellPrivate -{ - GSList *runners; - - GCancellable *cancellable; - GError *error; - - GMainLoop *main_loop; - GitgRunner *last_runner; - - guint buffer_size; - GitgLineParser *line_parser; - - guint synchronized : 1; - guint preserve_line_endings : 1; - guint cancelled : 1; - guint read_done : 1; -}; - -static void shell_done (GitgShell *shell, GError *error); - -G_DEFINE_TYPE (GitgShell, gitg_shell, GITG_TYPE_IO) - -static void -runner_end (GitgRunner *runner, - GError *error, - GitgShell *shell) -{ - if (!shell->priv->runners) - { - return; - } - - if ((runner == shell->priv->last_runner && shell->priv->read_done) || error) - { - shell_done (shell, error); - } -} - -static void -close_runners (GitgShell *shell) -{ - GSList *item; - - for (item = shell->priv->runners; item; item = g_slist_next (item)) - { - GitgRunner *runner = item->data; - - g_signal_handlers_disconnect_by_func (runner, - runner_end, - shell); - - gitg_io_close (GITG_IO (runner)); - g_object_unref (runner); - } - - g_slist_free (shell->priv->runners); - shell->priv->runners = NULL; - - if (shell->priv->line_parser) - { - g_object_unref (shell->priv->line_parser); - shell->priv->line_parser = NULL; - } - - shell->priv->last_runner = NULL; -} - -static void -gitg_shell_finalize (GObject *object) -{ - GitgShell *shell = GITG_SHELL (object); - - /* Cancel possible running */ - gitg_io_cancel (GITG_IO (shell)); - - if (shell->priv->cancellable) - { - g_object_unref (shell->priv->cancellable); - } - - G_OBJECT_CLASS (gitg_shell_parent_class)->finalize (object); -} - -static void -gitg_shell_dispose (GObject *object) -{ - GitgShell *shell; - - shell = GITG_SHELL (object); - - close_runners (shell); -} - -static void -gitg_shell_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GitgShell *shell = GITG_SHELL (object); - - switch (prop_id) - { - case PROP_BUFFER_SIZE: - g_value_set_uint (value, shell->priv->buffer_size); - break; - case PROP_SYNCHRONIZED: - g_value_set_boolean (value, shell->priv->synchronized); - break; - case PROP_PRESERVE_LINE_ENDINGS: - g_value_set_boolean (value, shell->priv->preserve_line_endings); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_shell_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GitgShell *shell = GITG_SHELL (object); - - switch (prop_id) - { - case PROP_BUFFER_SIZE: - shell->priv->buffer_size = g_value_get_uint (value); - break; - case PROP_SYNCHRONIZED: - shell->priv->synchronized = g_value_get_boolean (value); - break; - case PROP_PRESERVE_LINE_ENDINGS: - shell->priv->preserve_line_endings = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gitg_shell_cancel (GitgIO *io) -{ - gboolean was_running; - GitgShell *shell; - - shell = GITG_SHELL (io); - - if (shell->priv->line_parser) - { - g_object_unref (shell->priv->line_parser); - shell->priv->line_parser = NULL; - } - - was_running = gitg_io_get_running (io); - - GITG_IO_CLASS (gitg_shell_parent_class)->cancel (io); - - if (was_running) - { - shell_done (GITG_SHELL (io), NULL); - } -} - -static void -gitg_shell_class_init (GitgShellClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GitgIOClass *io_class = GITG_IO_CLASS (klass); - - object_class->finalize = gitg_shell_finalize; - object_class->dispose = gitg_shell_dispose; - - object_class->get_property = gitg_shell_get_property; - object_class->set_property = gitg_shell_set_property; - - io_class->cancel = gitg_shell_cancel; - - g_object_class_install_property (object_class, PROP_BUFFER_SIZE, - g_param_spec_uint ("buffer_size", - "BUFFER SIZE", - "The shells buffer size", - 1, - G_MAXUINT, - 1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_SYNCHRONIZED, - g_param_spec_boolean ("synchronized", - "SYNCHRONIZED", - "Whether the command is ran synchronized", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, - PROP_PRESERVE_LINE_ENDINGS, - g_param_spec_boolean ("preserve-line-endings", - "Preserve Line Endings", - "preserve line endings", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - shell_signals[UPDATE] = - g_signal_new ("update", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GitgShellClass, update), - NULL, - NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - g_type_class_add_private (object_class, sizeof (GitgShellPrivate)); -} - -static void -gitg_shell_init (GitgShell *self) -{ - self->priv = GITG_SHELL_GET_PRIVATE (self); - - self->priv->cancellable = g_cancellable_new (); -} - -GitgShell * -gitg_shell_new (guint buffer_size) -{ - g_assert (buffer_size > 0); - - return GITG_SHELL (g_object_new (GITG_TYPE_SHELL, - "buffer_size", - buffer_size, - "synchronized", - FALSE, - NULL)); -} - -GitgShell * -gitg_shell_new_synchronized (guint buffer_size) -{ - g_assert (buffer_size > 0); - - return GITG_SHELL (g_object_new (GITG_TYPE_SHELL, - "buffer_size", - buffer_size, - "synchronized", - TRUE, - NULL)); -} - -void -gitg_shell_set_preserve_line_endings (GitgShell *shell, - gboolean preserve_line_endings) -{ - g_return_if_fail (GITG_IS_SHELL (shell)); - - shell->priv->preserve_line_endings = preserve_line_endings; - g_object_notify (G_OBJECT (shell), "preserve-line-endings"); -} - -gboolean -gitg_shell_get_preserve_line_endings (GitgShell *shell) -{ - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - - return shell->priv->preserve_line_endings; -} - -static void -shell_done (GitgShell *shell, - GError *error) -{ - if (shell->priv->error) - { - g_error_free (shell->priv->error); - shell->priv->error = NULL; - } - - if (error) - { - shell->priv->error = g_error_copy (error); - gitg_io_set_exit_status (GITG_IO (shell), EXIT_FAILURE); - } - - if (shell->priv->main_loop) - { - g_main_loop_quit (shell->priv->main_loop); - g_main_loop_unref (shell->priv->main_loop); - - shell->priv->main_loop = NULL; - } - - if (shell->priv->runners == NULL) - { - return; - } - - if (shell->priv->cancellable) - { - g_cancellable_cancel (shell->priv->cancellable); - g_object_unref (shell->priv->cancellable); - - shell->priv->cancellable = NULL; - } - - /* Take over the exit code of the last runner */ - if (!error) - { - gitg_io_set_exit_status (GITG_IO (shell), - gitg_io_get_exit_status (GITG_IO (shell->priv->last_runner))); - } - - close_runners (shell); - gitg_io_close (GITG_IO (shell)); - - gitg_io_end (GITG_IO (shell), error); -} - -static gboolean -run_sync (GitgShell *shell, - GError **error) -{ - g_main_loop_run (shell->priv->main_loop); - - if (shell->priv->error) - { - g_propagate_error (error, shell->priv->error); - shell->priv->error = NULL; - - return FALSE; - } - - return gitg_io_get_exit_status (GITG_IO (shell)) == 0; -} - -static void -on_lines_done_cb (GitgLineParser *parser, - GError *error, - GitgShell *shell) -{ - if (!shell->priv->read_done) - { - shell->priv->read_done = TRUE; - - if (shell->priv->last_runner == NULL) - { - shell_done (shell, error); - } - else - { - gitg_runner_stream_close (shell->priv->last_runner, NULL); - } - } -} - -static void -on_lines_cb (GitgLineParser *parser, - gchar **lines, - GitgShell *shell) -{ - g_signal_emit (shell, shell_signals[UPDATE], 0, lines); -} - -static void -run_stream (GitgShell *shell, - GInputStream *stream) -{ - shell->priv->cancellable = g_cancellable_new (); - - shell->priv->read_done = FALSE; - - shell->priv->line_parser = gitg_line_parser_new (shell->priv->buffer_size, - shell->priv->preserve_line_endings); - - g_signal_connect (shell->priv->line_parser, - "lines", - G_CALLBACK (on_lines_cb), - shell); - - g_signal_connect (shell->priv->line_parser, - "done", - G_CALLBACK (on_lines_done_cb), - shell); - - gitg_line_parser_parse (shell->priv->line_parser, - stream, - shell->priv->cancellable); -} - -static gboolean -run_commands (GitgShell *shell, - GitgCommand **commands, - GError **error) -{ - GitgIO *io; - GitgRunner *prev = NULL; - GOutputStream *output; - gboolean ret = TRUE; - GitgCommand **ptr; - - io = GITG_IO (shell); - output = gitg_io_get_output (io); - - shell->priv->read_done = TRUE; - - gitg_io_cancel (GITG_IO (shell)); - - gitg_io_begin (GITG_IO (shell)); - - /* Ref sink all commands */ - for (ptr = commands; *ptr; ++ptr) - { - g_object_ref_sink (*ptr); - } - - if (shell->priv->synchronized) - { - shell->priv->main_loop = g_main_loop_new (NULL, FALSE); - } - - /* Setup runners */ - for (ptr = commands; *ptr; ++ptr) - { - GitgRunner *runner; - - runner = gitg_runner_new (*ptr); - - if (gitg_io_get_stderr_to_stdout (GITG_IO (shell))) - { - gitg_io_set_stderr_to_stdout (GITG_IO (runner), TRUE); - } - - g_signal_connect (runner, - "end", - G_CALLBACK (runner_end), - shell); - - if (ptr == commands) - { - /* Copy input set on the shell to the first runner */ - GInputStream *input; - - input = gitg_io_get_input (io); - - if (input != NULL) - { - gitg_io_set_input (GITG_IO (runner), input); - } - } - else - { - /* Set output of the previous runner to the input of - this runner */ - gitg_io_set_input (GITG_IO (runner), - gitg_runner_get_stream (prev)); - } - - if (!*(ptr + 1)) - { - shell->priv->last_runner = runner; - - /* Copy output set on the shell to the last runner */ - if (output != NULL) - { - gitg_io_set_output (GITG_IO (runner), output); - } - } - - shell->priv->runners = g_slist_append (shell->priv->runners, - runner); - - /* Start the runner */ - gitg_runner_run (runner); - - if (shell->priv->runners == NULL) - { - /* This means it there was an error */ - if (error && shell->priv->error) - { - *error = g_error_copy (shell->priv->error); - } - - if (shell->priv->error) - { - g_error_free (shell->priv->error); - shell->priv->error = NULL; - } - - ret = FALSE; - goto cleanup; - } - - prev = runner; - } - - /* Setup line reader if necessary in async mode */ - if (output == NULL) - { - run_stream (shell, gitg_runner_get_stream (shell->priv->last_runner)); - } - - if (shell->priv->synchronized) - { - return run_sync (shell, error); - } - -cleanup: - for (ptr = commands; *ptr; ++ptr) - { - g_object_unref (*ptr); - } - - if (shell->priv->main_loop) - { - g_main_loop_unref (shell->priv->main_loop); - shell->priv->main_loop = NULL; - } - - return ret; -} - -gboolean -gitg_shell_run (GitgShell *shell, - GitgCommand *command, - GError **error) -{ - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE); - - return gitg_shell_runv (shell, error, command, NULL); -} - -gboolean -gitg_shell_run_list (GitgShell *shell, - GitgCommand **commands, - GError **error) -{ - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - - return run_commands (shell, commands, error); -} - -gboolean -gitg_shell_runva (GitgShell *shell, - va_list ap, - GError **error) -{ - GPtrArray *ptr; - GitgCommand **commands; - GitgCommand *command; - gboolean ret; - guint num = 0; - - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - - ptr = g_ptr_array_new (); - - while ((command = va_arg (ap, GitgCommand *)) != NULL) - { - g_ptr_array_add (ptr, command); - ++num; - } - - if (num == 0) - { - g_ptr_array_free (ptr, TRUE); - return FALSE; - } - - g_ptr_array_add (ptr, NULL); - - commands = (GitgCommand **)g_ptr_array_free (ptr, FALSE); - - ret = gitg_shell_run_list (shell, commands, error); - - g_free (commands); - - return ret; -} - -gboolean -gitg_shell_runv (GitgShell *shell, - GError **error, - ...) -{ - va_list ap; - gboolean ret; - - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - - va_start (ap, error); - ret = gitg_shell_runva (shell, ap, error); - va_end (ap); - - return ret; -} - -guint -gitg_shell_get_buffer_size (GitgShell *shell) -{ - g_return_val_if_fail (GITG_IS_SHELL (shell), 0); - return shell->priv->buffer_size; -} - -gboolean -gitg_shell_run_sync_with_output (GitgCommand *command, - gboolean preserve_line_endings, - gchar ***output, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE); - - return gitg_shell_run_sync_with_outputv (preserve_line_endings, - output, - error, - command, - NULL); -} - -static void -collect_update (GitgShell *shell, - gchar const * const *lines, - GPtrArray *ret) -{ - while (lines && *lines) - { - g_ptr_array_add (ret, g_strdup (*lines++)); - } -} - -gboolean -gitg_shell_run_sync_with_input_and_output_list (GitgCommand **commands, - gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error) -{ - GitgShell *shell; - GPtrArray *ret; - gboolean res; - gchar **out; - - if (output) - { - *output = NULL; - } - - shell = gitg_shell_new_synchronized (1000); - - gitg_shell_set_preserve_line_endings (shell, preserve_line_endings); - - ret = g_ptr_array_sized_new (100); - - g_signal_connect (shell, - "update", - G_CALLBACK (collect_update), - ret); - - if (input) - { - GInputStream *stream; - - stream = g_memory_input_stream_new_from_data (g_strdup (input), - -1, - (GDestroyNotify)g_free); - - gitg_io_set_input (GITG_IO (shell), stream); - g_object_unref (stream); - } - - res = gitg_shell_run_list (shell, commands, error); - g_ptr_array_add (ret, NULL); - out = (gchar **)g_ptr_array_free (ret, FALSE); - - if (output) - { - *output = out; - } - else - { - g_strfreev (out); - } - - if (!res || gitg_io_get_exit_status (GITG_IO (shell)) != 0) - { - g_object_unref (shell); - - return FALSE; - } - - g_object_unref (shell); - - return TRUE; -} - -static gboolean -gitg_shell_run_sync_with_input_and_outputva (gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - va_list ap, - GError **error) -{ - GPtrArray *commands; - GitgCommand *cmd; - GitgCommand **cmds; - gboolean ret; - - commands = g_ptr_array_new (); - - while ((cmd = va_arg (ap, GitgCommand *))) - { - g_ptr_array_add (commands, cmd); - } - - g_ptr_array_add (commands, NULL); - cmds = (GitgCommand **)g_ptr_array_free (commands, FALSE); - - ret = gitg_shell_run_sync_with_input_and_output_list (cmds, - preserve_line_endings, - input, - output, - error); - - g_free (cmds); - return ret; -} - -static gboolean -gitg_shell_run_sync_with_outputva (gboolean preserve_line_endings, - gchar ***output, - va_list ap, - GError **error) -{ - return gitg_shell_run_sync_with_input_and_outputva (preserve_line_endings, - NULL, - output, - ap, - error); -} - -gboolean -gitg_shell_run_sync_with_output_list (GitgCommand **commands, - gboolean preserve_line_endings, - gchar ***output, - GError **error) -{ - return gitg_shell_run_sync_with_input_and_output_list (commands, - preserve_line_endings, - NULL, - output, - error); -} - -gboolean -gitg_shell_run_sync_with_outputv (gboolean preserve_line_endings, - gchar ***output, - GError **error, - ...) -{ - va_list ap; - gboolean ret; - - va_start (ap, error); - ret = gitg_shell_run_sync_with_outputva (preserve_line_endings, - output, - ap, - error); - va_end (ap); - - return ret; -} - -gboolean -gitg_shell_run_sync (GitgCommand *command, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE); - - return gitg_shell_run_syncv (error, command, NULL); -} - -gboolean -gitg_shell_run_sync_list (GitgCommand **commands, - GError **error) -{ - return gitg_shell_run_sync_with_output_list (commands, FALSE, NULL, error); -} - -gboolean -gitg_shell_run_syncv (GError **error, - ...) -{ - va_list ap; - gboolean res; - - va_start (ap, error); - res = gitg_shell_run_sync_with_outputva (FALSE, NULL, ap, error); - va_end (ap); - - return res; -} - -gboolean -gitg_shell_run_sync_with_input (GitgCommand *command, - const gchar *input, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE); - - return gitg_shell_run_sync_with_inputv (input, error, command, NULL); -} - -gboolean -gitg_shell_run_sync_with_input_list (GitgCommand **commands, - const gchar *input, - GError **error) -{ - return gitg_shell_run_sync_with_input_and_output_list (commands, - FALSE, - input, - NULL, - error); -} - -gboolean -gitg_shell_run_sync_with_inputv (const gchar *input, - GError **error, - ...) -{ - va_list ap; - gboolean ret; - - va_start (ap, error); - ret = gitg_shell_run_sync_with_input_and_outputva (FALSE, - input, - NULL, - ap, - error); - va_end (ap); - - return ret; -} - -gboolean -gitg_shell_run_sync_with_input_and_output (GitgCommand *command, - gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error) -{ - g_return_val_if_fail (GITG_IS_COMMAND (command), FALSE); - - return gitg_shell_run_sync_with_input_and_outputv (preserve_line_endings, - input, - output, - error, - command, - NULL); -} - -gboolean -gitg_shell_run_sync_with_input_and_outputv (gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error, - ...) -{ - va_list ap; - gboolean ret; - - va_start (ap, error); - ret = gitg_shell_run_sync_with_input_and_outputva (preserve_line_endings, - input, - output, - ap, - error); - va_end (ap); - - return ret; -} - -GitgCommand ** -gitg_shell_parse_commands (GitgRepository *repository, - const gchar *cmdstr, - GError **error) -{ - gint argc; - gchar **argv; - GitgCommand *cmd = NULL; - gint i; - GPtrArray *commands; - gboolean canenv = TRUE; - guint num = 0; - - g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), NULL); - g_return_val_if_fail (cmdstr != NULL, NULL); - - if (!g_shell_parse_argv (cmdstr, &argc, &argv, error)) - { - return FALSE; - } - - commands = g_ptr_array_new (); - - for (i = 0; i < argc; ++i) - { - gchar *pos; - - if (cmd == NULL) - { - cmd = gitg_command_new (repository, NULL); - g_ptr_array_add (commands, cmd); - - canenv = TRUE; - ++num; - } - - if (strcmp (argv[i], "|") == 0) - { - cmd = NULL; - } - else if (canenv && (pos = g_utf8_strchr (argv[i], -1, '='))) - { - *pos = '\0'; - gitg_command_add_environment (cmd, argv[i], pos + 1, NULL); - } - else - { - canenv = FALSE; - gitg_command_add_arguments (cmd, argv[i], NULL); - } - } - - g_strfreev (argv); - g_ptr_array_add (commands, NULL); - - return (GitgCommand **)g_ptr_array_free (commands, FALSE); -} - -gboolean -gitg_shell_run_parse (GitgShell *shell, - GitgRepository *repository, - const gchar *cmdstr, - GError **error) - -{ - gboolean ret; - GitgCommand **commands; - - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - g_return_val_if_fail (cmdstr != NULL, FALSE); - g_return_val_if_fail (repository == NULL || GITG_IS_REPOSITORY (repository), FALSE); - - commands = gitg_shell_parse_commands (repository, cmdstr, error); - - if (!commands) - { - return FALSE; - } - - ret = run_commands (shell, commands, error); - g_free (commands); - - return ret; -} - -gboolean -gitg_shell_run_stream (GitgShell *shell, - GInputStream *stream, - GError **error) -{ - g_return_val_if_fail (GITG_IS_SHELL (shell), FALSE); - g_return_val_if_fail (G_IS_INPUT_STREAM (stream), FALSE); - - gitg_io_cancel (GITG_IO (shell)); - - run_stream (shell, stream); - return TRUE; -} diff --git a/libgitg/gitg-shell.h b/libgitg/gitg-shell.h deleted file mode 100644 index 2412ff36..00000000 --- a/libgitg/gitg-shell.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * gitg-shell.h - * This file is part of gitg - git repository viewer - * - * Copyright (C) 2009 - Jesse van den Kieboom - * - * 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_SHELL_H__ -#define __GITG_SHELL_H__ - -#include -#include -#include -#include - -G_BEGIN_DECLS - -#define GITG_TYPE_SHELL (gitg_shell_get_type ()) -#define GITG_SHELL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SHELL, GitgShell)) -#define GITG_SHELL_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SHELL, GitgShell const)) -#define GITG_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_SHELL, GitgShellClass)) -#define GITG_IS_SHELL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_SHELL)) -#define GITG_IS_SHELL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_SHELL)) -#define GITG_SHELL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_SHELL, GitgShellClass)) - -#define GITG_SHELL_ERROR (gitg_shell_error_quark()) - -typedef struct _GitgShell GitgShell; -typedef struct _GitgShellClass GitgShellClass; -typedef struct _GitgShellPrivate GitgShellPrivate; - -struct _GitgShell -{ - GitgIO parent; - - GitgShellPrivate *priv; -}; - -struct _GitgShellClass -{ - GitgIOClass parent_class; - - /* signals */ - void (* update) (GitgShell *shell, - gchar const * const *buffer); -}; - -GType gitg_shell_get_type (void) G_GNUC_CONST; - -GitgShell *gitg_shell_new (guint buffer_size); -GitgShell *gitg_shell_new_synchronized (guint buffer_size); - -void gitg_shell_set_preserve_line_endings (GitgShell *shell, - gboolean preserve_line_endings); -gboolean gitg_shell_get_preserve_line_endings (GitgShell *shell); - -guint gitg_shell_get_buffer_size (GitgShell *shell); - -GitgCommand **gitg_shell_parse_commands (GitgRepository *repository, - const gchar *cmdstr, - GError **error); - -gboolean gitg_shell_run_parse (GitgShell *shell, - GitgRepository *repository, - const gchar *cmd, - GError **error); - -gboolean gitg_shell_runva (GitgShell *shell, - va_list ap, - GError **error); - -gboolean gitg_shell_run_stream (GitgShell *shell, - GInputStream *stream, - GError **error); - -gboolean gitg_shell_run (GitgShell *shell, - GitgCommand *command, - GError **error); - -gboolean gitg_shell_run_list (GitgShell *shell, - GitgCommand **commands, - GError **error); - -gboolean gitg_shell_runv (GitgShell *shell, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -gboolean gitg_shell_run_sync_with_output (GitgCommand *command, - gboolean preserve_line_endings, - gchar ***output, - GError **error); - -gboolean gitg_shell_run_sync_with_output_list (GitgCommand **commands, - gboolean preserve_line_endings, - gchar ***output, - GError **error); - -gboolean gitg_shell_run_sync_with_outputv (gboolean preserve_line_endings, - gchar ***output, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -gboolean gitg_shell_run_sync (GitgCommand *command, - GError **error); - -gboolean gitg_shell_run_sync_list (GitgCommand **commands, - GError **error); - -gboolean gitg_shell_run_syncv (GError **error, - ...) G_GNUC_NULL_TERMINATED; - -gboolean gitg_shell_run_sync_with_input (GitgCommand *command, - const gchar *input, - GError **error); - -gboolean gitg_shell_run_sync_with_input_list (GitgCommand **commands, - const gchar *input, - GError **error); - -gboolean gitg_shell_run_sync_with_inputv (const gchar *input, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -gboolean gitg_shell_run_sync_with_input_and_output (GitgCommand *command, - gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error); - -gboolean gitg_shell_run_sync_with_input_and_output_list (GitgCommand **commands, - gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error); - -gboolean gitg_shell_run_sync_with_input_and_outputv (gboolean preserve_line_endings, - const gchar *input, - gchar ***output, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -G_END_DECLS - -#endif /* __GITG_SHELL_H__ */ diff --git a/libgitg/gitg-smart-charset-converter.c b/libgitg/gitg-smart-charset-converter.c deleted file mode 100644 index dc07c250..00000000 --- a/libgitg/gitg-smart-charset-converter.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * gedit-smart-charset-converter.c - * This file is part of gedit - * - * Copyright (C) 2009 - Ignacio Casal Quinteiro - * - * gedit 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. - * - * gedit 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 gedit; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#include "gitg-smart-charset-converter.h" -#include "gitg-debug.h" - -#include -#include - -#define GITG_SMART_CHARSET_CONVERTER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_SMART_CHARSET_CONVERTER, GitgSmartCharsetConverterPrivate)) - -struct _GitgSmartCharsetConverterPrivate -{ - GCharsetConverter *charset_conv; - - GSList *encodings; - GSList *current_encoding; - - guint is_utf8 : 1; - guint use_first : 1; -}; - -static void gitg_smart_charset_converter_iface_init (GConverterIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GitgSmartCharsetConverter, gitg_smart_charset_converter, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER, - gitg_smart_charset_converter_iface_init)) - -GQuark -gitg_charset_conversion_error_quark (void) -{ - static GQuark ret = 0; - - if (G_UNLIKELY (ret == 0)) - { - ret = g_quark_from_static_string ("GitgCharsetConversionError"); - } - - return ret; -} - -static void -gitg_smart_charset_converter_finalize (GObject *object) -{ - GitgSmartCharsetConverter *smart = GITG_SMART_CHARSET_CONVERTER (object); - - g_slist_free (smart->priv->encodings); - - G_OBJECT_CLASS (gitg_smart_charset_converter_parent_class)->finalize (object); -} - -static void -gitg_smart_charset_converter_dispose (GObject *object) -{ - GitgSmartCharsetConverter *smart = GITG_SMART_CHARSET_CONVERTER (object); - - if (smart->priv->charset_conv != NULL) - { - g_object_unref (smart->priv->charset_conv); - smart->priv->charset_conv = NULL; - } - - G_OBJECT_CLASS (gitg_smart_charset_converter_parent_class)->dispose (object); -} - -static void -gitg_smart_charset_converter_class_init (GitgSmartCharsetConverterClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gitg_smart_charset_converter_finalize; - object_class->dispose = gitg_smart_charset_converter_dispose; - - g_type_class_add_private (object_class, sizeof (GitgSmartCharsetConverterPrivate)); -} - -static void -gitg_smart_charset_converter_init (GitgSmartCharsetConverter *smart) -{ - smart->priv = GITG_SMART_CHARSET_CONVERTER_GET_PRIVATE (smart); - - smart->priv->charset_conv = NULL; - smart->priv->encodings = NULL; - smart->priv->current_encoding = NULL; - smart->priv->is_utf8 = FALSE; - smart->priv->use_first = FALSE; -} - -static const GitgEncoding * -get_encoding (GitgSmartCharsetConverter *smart) -{ - if (smart->priv->current_encoding == NULL) - { - smart->priv->current_encoding = smart->priv->encodings; - } - else - { - smart->priv->current_encoding = g_slist_next (smart->priv->current_encoding); - } - - if (smart->priv->current_encoding != NULL) - return (const GitgEncoding *)smart->priv->current_encoding->data; - -#if 0 - FIXME: uncomment this when using fallback - /* If we tried all encodings, we return the first encoding */ - smart->priv->use_first = TRUE; - smart->priv->current_encoding = smart->priv->encodings; - - return (const GitgEncoding *)smart->priv->current_encoding->data; -#endif - return NULL; -} - -static gboolean -try_convert (GCharsetConverter *converter, - const void *inbuf, - gsize inbuf_size) -{ - GError *err; - gsize bytes_read, nread; - gsize bytes_written, nwritten; - GConverterResult res; - gchar *out; - gboolean ret; - gsize out_size; - - if (inbuf == NULL || inbuf_size == 0) - { - return FALSE; - } - - err = NULL; - nread = 0; - nwritten = 0; - out_size = inbuf_size * 4; - out = g_malloc (out_size); - - do - { - res = g_converter_convert (G_CONVERTER (converter), - (gchar *)inbuf + nread, - inbuf_size - nread, - (gchar *)out + nwritten, - out_size - nwritten, - G_CONVERTER_INPUT_AT_END, - &bytes_read, - &bytes_written, - &err); - - nread += bytes_read; - nwritten += bytes_written; - } while (res != G_CONVERTER_FINISHED && res != G_CONVERTER_ERROR && err == NULL); - - if (err != NULL) - { - if (err->code == G_CONVERT_ERROR_PARTIAL_INPUT) - { - /* FIXME We can get partial input while guessing the - encoding because we just take some amount of text - to guess from. */ - ret = TRUE; - } - else - { - ret = FALSE; - } - - g_error_free (err); - } - else - { - ret = TRUE; - } - - /* FIXME: Check the remainder? */ - if (ret == TRUE && !g_utf8_validate (out, nwritten, NULL)) - { - ret = FALSE; - } - - g_free (out); - - return ret; -} - -static GCharsetConverter * -guess_encoding (GitgSmartCharsetConverter *smart, - const void *inbuf, - gsize inbuf_size) -{ - GCharsetConverter *conv = NULL; - - if (inbuf == NULL || inbuf_size == 0) - { - smart->priv->is_utf8 = TRUE; - return NULL; - } - - if (smart->priv->encodings != NULL && - smart->priv->encodings->next == NULL) - { - smart->priv->use_first = TRUE; - } - - /* We just check the first block */ - while (TRUE) - { - const GitgEncoding *enc; - - if (conv != NULL) - { - g_object_unref (conv); - conv = NULL; - } - - /* We get an encoding from the list */ - enc = get_encoding (smart); - - /* if it is NULL we didn't guess anything */ - if (enc == NULL) - { - break; - } - - if (enc == gitg_encoding_get_utf8 ()) - { - gsize remainder; - const gchar *end; - - if (g_utf8_validate (inbuf, inbuf_size, &end) || - smart->priv->use_first) - { - smart->priv->is_utf8 = TRUE; - break; - } - - /* Check if the end is less than one char */ - remainder = inbuf_size - (end - (gchar *)inbuf); - if (remainder < 6) - { - smart->priv->is_utf8 = TRUE; - break; - } - - continue; - } - - conv = g_charset_converter_new ("UTF-8", - gitg_encoding_get_charset (enc), - NULL); - - /* If we tried all encodings we use the first one */ - if (smart->priv->use_first) - { - break; - } - - /* Try to convert */ - if (try_convert (conv, inbuf, inbuf_size)) - { - gitg_debug (GITG_DEBUG_CHARSET_CONVERSION, - "Guessed %s conversion", - gitg_encoding_get_charset (enc)); - break; - } - } - - if (smart->priv->is_utf8) - { - gitg_debug (GITG_DEBUG_CHARSET_CONVERSION, "Guessed UTF8 conversion"); - } - - if (conv != NULL) - { - g_converter_reset (G_CONVERTER (conv)); - - /* FIXME: uncomment this when we want to use the fallback - g_charset_converter_set_use_fallback (conv, TRUE);*/ - } - - return conv; -} - -static GConverterResult -gitg_smart_charset_converter_convert (GConverter *converter, - const void *inbuf, - gsize inbuf_size, - void *outbuf, - gsize outbuf_size, - GConverterFlags flags, - gsize *bytes_read, - gsize *bytes_written, - GError **error) -{ - GitgSmartCharsetConverter *smart = GITG_SMART_CHARSET_CONVERTER (converter); - - /* Guess the encoding if we didn't make it yet */ - if (smart->priv->charset_conv == NULL && !smart->priv->is_utf8) - { - smart->priv->charset_conv = guess_encoding (smart, inbuf, inbuf_size); - - /* If we still have the previous case is that we didn't guess - anything */ - if (smart->priv->charset_conv == NULL && !smart->priv->is_utf8) - { - g_set_error_literal (error, GITG_CHARSET_CONVERSION_ERROR, - GITG_CHARSET_CONVERSION_ERROR_ENCODING_AUTO_DETECTION_FAILED, - _("It is not possible to detect the encoding automatically")); - - return G_CONVERTER_ERROR; - } - } - - /* Now if the encoding is utf8 just redirect the input to the output */ - if (smart->priv->is_utf8) - { - gsize size; - GConverterResult ret; - - size = MIN (inbuf_size, outbuf_size); - - memcpy (outbuf, inbuf, size); - *bytes_read = size; - *bytes_written = size; - - ret = G_CONVERTER_CONVERTED; - - if (flags & G_CONVERTER_INPUT_AT_END) - { - ret = G_CONVERTER_FINISHED; - } - else if (flags & G_CONVERTER_FLUSH) - { - ret = G_CONVERTER_FLUSHED; - } - - return ret; - } - - /* If we reached here is because we need to convert the text so, we - convert it with the charset converter */ - return g_converter_convert (G_CONVERTER (smart->priv->charset_conv), - inbuf, - inbuf_size, - outbuf, - outbuf_size, - flags, - bytes_read, - bytes_written, - error); -} - -static void -gitg_smart_charset_converter_reset (GConverter *converter) -{ - GitgSmartCharsetConverter *smart = GITG_SMART_CHARSET_CONVERTER (converter); - - smart->priv->current_encoding = NULL; - smart->priv->is_utf8 = FALSE; - - if (smart->priv->charset_conv != NULL) - { - g_object_unref (smart->priv->charset_conv); - smart->priv->charset_conv = NULL; - } -} - -static void -gitg_smart_charset_converter_iface_init (GConverterIface *iface) -{ - iface->convert = gitg_smart_charset_converter_convert; - iface->reset = gitg_smart_charset_converter_reset; -} - -GitgSmartCharsetConverter * -gitg_smart_charset_converter_new (GSList *candidate_encodings) -{ - GitgSmartCharsetConverter *smart; - - g_return_val_if_fail (candidate_encodings != NULL, NULL); - - smart = g_object_new (GITG_TYPE_SMART_CHARSET_CONVERTER, NULL); - - smart->priv->encodings = g_slist_copy (candidate_encodings); - - return smart; -} - -const GitgEncoding * -gitg_smart_charset_converter_get_guessed (GitgSmartCharsetConverter *smart) -{ - g_return_val_if_fail (GITG_IS_SMART_CHARSET_CONVERTER (smart), NULL); - - if (smart->priv->current_encoding != NULL) - { - return (const GitgEncoding *)smart->priv->current_encoding->data; - } - else if (smart->priv->is_utf8) - { - return gitg_encoding_get_utf8 (); - } - - return NULL; -} - -guint -gitg_smart_charset_converter_get_num_fallbacks (GitgSmartCharsetConverter *smart) -{ - g_return_val_if_fail (GITG_IS_SMART_CHARSET_CONVERTER (smart), FALSE); - - if (smart->priv->charset_conv == NULL) - return FALSE; - - return g_charset_converter_get_num_fallbacks (smart->priv->charset_conv) != 0; -} - -/* ex:ts=8:noet: */ diff --git a/libgitg/gitg-smart-charset-converter.h b/libgitg/gitg-smart-charset-converter.h deleted file mode 100644 index 64d7aff1..00000000 --- a/libgitg/gitg-smart-charset-converter.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * gedit-smart-charset-converter.h - * This file is part of gedit - * - * Copyright (C) 2009 - Ignacio Casal Quinteiro - * - * gedit 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. - * - * gedit 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 gedit; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301 USA - */ - -#ifndef __GITG_SMART_CHARSET_CONVERTER_H__ -#define __GITG_SMART_CHARSET_CONVERTER_H__ - -#include - -#include "gitg-encodings.h" - -G_BEGIN_DECLS - -#define GITG_TYPE_SMART_CHARSET_CONVERTER (gitg_smart_charset_converter_get_type ()) -#define GITG_SMART_CHARSET_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SMART_CHARSET_CONVERTER, GitgSmartCharsetConverter)) -#define GITG_SMART_CHARSET_CONVERTER_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GITG_TYPE_SMART_CHARSET_CONVERTER, GitgSmartCharsetConverter const)) -#define GITG_SMART_CHARSET_CONVERTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GITG_TYPE_SMART_CHARSET_CONVERTER, GitgSmartCharsetConverterClass)) -#define GITG_IS_SMART_CHARSET_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GITG_TYPE_SMART_CHARSET_CONVERTER)) -#define GITG_IS_SMART_CHARSET_CONVERTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GITG_TYPE_SMART_CHARSET_CONVERTER)) -#define GITG_SMART_CHARSET_CONVERTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GITG_TYPE_SMART_CHARSET_CONVERTER, GitgSmartCharsetConverterClass)) - -typedef struct _GitgSmartCharsetConverter GitgSmartCharsetConverter; -typedef struct _GitgSmartCharsetConverterClass GitgSmartCharsetConverterClass; -typedef struct _GitgSmartCharsetConverterPrivate GitgSmartCharsetConverterPrivate; - -#define GITG_CHARSET_CONVERSION_ERROR (gitg_charset_conversion_error_quark ()) - -typedef enum -{ - GITG_CHARSET_CONVERSION_ERROR_ENCODING_AUTO_DETECTION_FAILED -} GitgCharserConversionError; - -struct _GitgSmartCharsetConverter -{ - GObject parent; - - GitgSmartCharsetConverterPrivate *priv; -}; - -struct _GitgSmartCharsetConverterClass -{ - GObjectClass parent_class; -}; - -GType gitg_smart_charset_converter_get_type (void) G_GNUC_CONST; -GQuark gitg_charset_conversion_error_quark (void); - -GitgSmartCharsetConverter *gitg_smart_charset_converter_new (GSList *candidate_encodings); - -const GitgEncoding *gitg_smart_charset_converter_get_guessed (GitgSmartCharsetConverter *smart); - -guint gitg_smart_charset_converter_get_num_fallbacks(GitgSmartCharsetConverter *smart); - -G_END_DECLS - -#endif /* __GITG_SMART_CHARSET_CONVERTER_H__ */ - -/* ex:ts=8:noet: */ diff --git a/libgitg/libgitg-1.0.pc.in b/libgitg/libgitg-1.0.pc.in new file mode 100644 index 00000000..59ff1fe8 --- /dev/null +++ b/libgitg/libgitg-1.0.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: gitg library +Version: @PACKAGE_VERSION@ +Requires: libgit2-glib-1.0 glib-2.0 gobject-2.0 gmodule-2.0 gio-2.0 gio-unix-2.0 gthread-2.0 +Libs: -L${libdir} -lgitg-1.0 +Cflags: -I${includedir}/libgitg-1.0 diff --git a/plugins/Makefile.am b/plugins/Makefile.am new file mode 100644 index 00000000..32e0a3a1 --- /dev/null +++ b/plugins/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = dash history + +-include $(top_srcdir)/git.mk diff --git a/plugins/dash/Makefile.am b/plugins/dash/Makefile.am new file mode 100644 index 00000000..33518471 --- /dev/null +++ b/plugins/dash/Makefile.am @@ -0,0 +1,52 @@ +INCLUDES = \ + -I$(top_srcdir) \ + -I$(srcdir) \ + $(GITG_PLUGIN_CFLAGS) \ + $(WARN_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + -DLIBDIR=\""$(libdir)"\" + +plugindir = $(GITG_PLUGIN_LIBDIR) +plugin_LTLIBRARIES = libdash.la +plugin_DATA = dash.plugin + +VALAFLAGS = $(GITG_PLUGIN_VALAFLAGS) +VALA_SOURCES = \ + gitg-dash.vala \ + gitg-dash-navigation.vala + +libdash_la_LDFLAGS = $(GITG_PLUGIN_LIBTOOL_FLAGS) + +libdash_la_LIBADD = $(GITG_PLUGIN_LIBS) +libdash_la_CFLAGS = -w + +libdash_la_SOURCES = \ + $(VALA_SOURCES) \ + gitg-dash-resources.c + +BUILT_SOURCES = \ + gitg-dash-resources.c \ + gitg-dash-resources.h + +gitg-dash-resources.c: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-source \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +gitg-dash-resources.h: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-header \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +EXTRA_DIST = $(plugin_DATA) \ + resources/resources.xml \ + $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + +CLEANFILES = \ + $(VALA_SOURCES:.vala=.c) \ + $(BUILT_SOURCES) + +install-data-hook: + rm -f $(GITG_PLUGIN_LIBDIR)/libdash.la + +-include $(top_srcdir)/git.mk diff --git a/plugins/dash/dash.plugin b/plugins/dash/dash.plugin new file mode 100644 index 00000000..dad39a66 --- /dev/null +++ b/plugins/dash/dash.plugin @@ -0,0 +1,11 @@ +[Plugin] +Loader=C +Module=dash +Name=Dash +Description=gitg Dash +Authors=Jesse van den Kieboom +Copyright=Copyright © 2012 Jesse van den Kieboom +Website= +Hidden=1 +Builtin=1 +Version=1.0 diff --git a/plugins/dash/gitg-dash-navigation.vala b/plugins/dash/gitg-dash-navigation.vala new file mode 100644 index 00000000..e74049dc --- /dev/null +++ b/plugins/dash/gitg-dash-navigation.vala @@ -0,0 +1,93 @@ +namespace GitgDash +{ + private class Navigation : Object, GitgExt.Navigation + { + public GitgExt.Application? application { owned get; construct; } + + public signal void show_open(); + public signal void show_create(); + public signal void show_recent(string uri); + public signal void activate_recent(string uri); + + public Navigation(GitgExt.Application app) + { + Object(application: app); + } + + public void populate(GitgExt.NavigationTreeModel model) + { + model.begin_header("Repository", null) + .append_default("Open", "document-open-symbolic", (c) => { show_open(); }) + .append("Create", "list-add-symbolic", (c) => { show_create(); }) + .end_header(); + + model.begin_header("Recent", null); + + var manager = Gtk.RecentManager.get_default(); + var list = new List(); + + Gee.HashSet uris = new Gee.HashSet(); + + foreach (var item in manager.get_items()) + { + if (!item.has_application("gitg") || + !item.exists()) + { + continue; + } + + if (uris.add(item.get_uri())) + { + list.prepend(item); + } + } + + list.sort((a, b) => { + if (a.get_visited() < b.get_visited()) + { + return 1; + } + else if (a.get_visited() > b.get_visited()) + { + return -1; + } + else + { + return 0; + } + }); + + foreach (var item in list) + { + string uri = item.get_uri(); + + model.append(item.get_display_name(), + null, + (c) => { + if (c == 1) + { + show_recent(uri); + } + else + { + activate_recent(uri); + } + }); + } + + model.end_header(); + } + + public GitgExt.NavigationSide navigation_side + { + get { return GitgExt.NavigationSide.LEFT; } + } + + public bool available + { + get { return true; } + } + } +} + +// ex: ts=4 noet diff --git a/plugins/dash/gitg-dash.vala b/plugins/dash/gitg-dash.vala new file mode 100644 index 00000000..668a776f --- /dev/null +++ b/plugins/dash/gitg-dash.vala @@ -0,0 +1,285 @@ +namespace GitgDash +{ + // Do this to pull in config.h before glib.h (for gettext...) + private const string version = Gitg.Config.VERSION; + + public class View : Object, GitgExt.View + { + public GitgExt.Application? application { owned get; construct; } + private Gtk.Notebook d_main; + + private Gtk.Widget? d_open; + private int d_openidx; + + private Gtk.Widget? d_create; + private int d_createidx; + + private Gtk.Widget? d_recent; + private Gtk.Label? d_recent_path; + private Gtk.Label? d_recent_last_used; + private Gtk.Label? d_recent_current_branch; + private File? d_recent_current_file; + private int d_recentidx; + + private HashTable d_repos; + + private File? d_open_folder; + + construct + { + d_main = new Gtk.Notebook(); + d_main.set_show_tabs(false); + d_main.show(); + + d_repos = new HashTable(File.hash, File.equal); + } + + public string id + { + owned get { return "/org/gnome/gitg/Views/Dash"; } + } + + public bool is_available() + { + // The dash is always available + return true; + } + + public string display_name + { + owned get { return "Dashboard"; } + } + + public Icon? icon + { + owned get + { + return new ThemedIcon("document-open-recent-symbolic"); + } + } + + public Gtk.Widget? widget + { + owned get + { + return d_main; + } + } + + public GitgExt.Navigation? navigation + { + owned get + { + var ret = new Navigation(application); + + ret.show_open.connect(show_open); + ret.show_create.connect(show_create); + ret.show_recent.connect(show_recent); + ret.activate_recent.connect(activate_recent); + + return ret; + } + } + + public bool is_default_for(GitgExt.ViewAction action) + { + return application.repository == null; + } + + private Gee.HashMap? from_builder(string path, string[] ids) + { + var builder = new Gtk.Builder(); + + try + { + builder.add_from_resource("/org/gnome/gitg/dash/" + path); + } + catch (Error e) + { + warning("Failed to load ui: %s", e.message); + return null; + } + + Gee.HashMap ret = new Gee.HashMap(); + + foreach (string id in ids) + { + ret[id] = builder.get_object(id); + } + + return ret; + } + + private void connect_chooser_folder(Gtk.FileChooser ch) + { + if (d_open_folder == null) + { + var path = Environment.get_home_dir(); + d_open_folder = File.new_for_path(path); + } + + ch.unmap.connect((w) => { + d_open_folder = ch.get_current_folder_file(); + }); + + ch.map.connect((w) => { + if (d_open_folder != null) + { + try + { + ch.set_current_folder_file(d_open_folder); + } catch {}; + } + }); + } + + public void show_open() + { + if (d_open == null) + { + var ret = from_builder("view-open.ui", {"view", + "file_chooser", + "button_open"}); + + d_open = ret["view"] as Gtk.Widget; + + var ch = ret["file_chooser"] as Gtk.FileChooser; + connect_chooser_folder(ch); + + (ret["button_open"] as Gtk.Button).clicked.connect((b) => { + application.open(ch.get_current_folder_file()); + }); + + d_openidx = d_main.append_page(d_open, null); + } + + d_main.set_current_page(d_openidx); + } + + public void show_create() + { + if (d_create == null) + { + var ret = from_builder("view-create.ui", {"view", + "file_chooser", + "button_create"}); + + d_create = ret["view"] as Gtk.Widget; + + var ch = ret["file_chooser"] as Gtk.FileChooser; + connect_chooser_folder(ch); + + (ret["button_create"] as Gtk.Button).clicked.connect((b) => { + application.create(ch.get_current_folder_file()); + }); + + d_createidx = d_main.append_page(d_create, null); + } + + d_main.set_current_page(d_createidx); + } + + public void show_recent(string uri) + { + var manager = Gtk.RecentManager.get_default(); + Gtk.RecentInfo? info = null; + + foreach (var item in manager.get_items()) + { + if (item.get_uri() == uri && + item.has_application("gitg") && item.exists()) + { + info = item; + break; + } + } + + if (info == null) + { + return; + } + + File f = File.new_for_uri(info.get_uri()); + Gitg.Repository? repo; + + if (!d_repos.lookup_extended(f, null, out repo)) + { + // Try to open the repo + try + { + repo = new Gitg.Repository(f, null); + + d_repos.insert(f, repo); + } + catch + { + return; + } + } + + if (repo == null) + { + return; + } + + if (d_recent == null) + { + var ret = from_builder("view-recent.ui", {"view", + "label_path_i", + "label_last_used_i", + "label_current_branch_i", + "button_open"}); + + d_recent = ret["view"] as Gtk.Widget; + d_recent_path = ret["label_path_i"] as Gtk.Label; + d_recent_last_used = ret["label_last_used_i"] as Gtk.Label; + d_recent_current_branch = ret["label_current_branch_i"] as Gtk.Label; + + (ret["button_open"] as Gtk.Button).clicked.connect((b) => { + application.open(d_recent_current_file); + }); + + d_recentidx = d_main.append_page(d_recent, null); + } + + d_recent_path.label = Filename.display_name(f.get_path()); + d_recent_current_file = f; + + var dt = new DateTime.from_unix_utc(info.get_visited()); + d_recent_last_used.label = dt.format("%c"); + + d_recent_current_branch.label = _("(no branch)"); + + try + { + var r = repo.get_head(); + + if (r != null) + { + d_recent_current_branch.label = r.parsed_name.shortname; + } + } + catch {} + + d_main.set_current_page(d_recentidx); + } + + public void activate_recent(string uri) + { + File f = File.new_for_uri(uri); + + application.open(f); + } + } +} + +[ModuleInit] +public void peas_register_types(TypeModule module) +{ + Peas.ObjectModule mod = module as Peas.ObjectModule; + + mod.register_extension_type(typeof(GitgExt.View), + typeof(GitgDash.View)); +} + +// ex: ts=4 noet diff --git a/plugins/dash/resources/resources.xml b/plugins/dash/resources/resources.xml new file mode 100644 index 00000000..6139db8f --- /dev/null +++ b/plugins/dash/resources/resources.xml @@ -0,0 +1,10 @@ + + + + view-open.ui + view-create.ui + view-recent.ui + + + + diff --git a/plugins/dash/resources/view-create.ui b/plugins/dash/resources/view-create.ui new file mode 100644 index 00000000..c68addbb --- /dev/null +++ b/plugins/dash/resources/view-create.ui @@ -0,0 +1,91 @@ + + + + + + True + 6 + True + True + vertical + + + True + True + Create repository + 0 + + + + 0 + 0 + 1 + 1 + + + + + True + True + Select a folder in which you want to create a new git repository. + 0 + + + + 0 + 1 + 1 + 1 + + + + + True + True + True + True + select-folder + False + + + 0 + 2 + 1 + 1 + + + + + True + True + end + horizontal + + + True + Create + True + + + 0 + 0 + 1 + 1 + + + + + 0 + 3 + 1 + 1 + + + + + + diff --git a/plugins/dash/resources/view-open.ui b/plugins/dash/resources/view-open.ui new file mode 100644 index 00000000..199b9c34 --- /dev/null +++ b/plugins/dash/resources/view-open.ui @@ -0,0 +1,91 @@ + + + + + + True + 6 + True + True + vertical + + + True + True + Open repository + 0 + + + + 0 + 0 + 1 + 1 + + + + + True + True + Select a folder to open the corresponding git repository. + 0 + + + + 0 + 1 + 1 + 1 + + + + + True + True + True + True + select-folder + False + + + 0 + 2 + 1 + 1 + + + + + True + True + end + horizontal + + + True + gtk-open + True + + + 0 + 0 + 1 + 1 + + + + + 0 + 3 + 1 + 1 + + + + + + diff --git a/plugins/dash/resources/view-recent.ui b/plugins/dash/resources/view-recent.ui new file mode 100644 index 00000000..80e824b3 --- /dev/null +++ b/plugins/dash/resources/view-recent.ui @@ -0,0 +1,173 @@ + + + + + True + False + True + True + 6 + 12 + + + True + False + True + 0 + Recent repository + + + + 0 + 0 + 2 + 1 + + + + + True + False + True + 0 + Open a recently used repository. + + + + 0 + 1 + 2 + 1 + + + + + True + False + 0 + Path: + + + + 0 + 2 + 1 + 1 + + + + + True + False + True + 0 + + + + 1 + 2 + 1 + 1 + + + + + True + False + 0 + Last used: + + + + 0 + 3 + 1 + 1 + + + + + True + False + True + 0 + + + + 1 + 3 + 1 + 1 + + + + + True + False + 0 + Current branch: + + + + 0 + 4 + 1 + 1 + + + + + True + False + True + 0 + + + + 1 + 4 + 1 + 1 + + + + + True + True + True + end + end + horizontal + + + True + gtk-open + True + + + 0 + 0 + 1 + 1 + + + + + 0 + 5 + 2 + 1 + + + + diff --git a/plugins/history/Makefile.am b/plugins/history/Makefile.am new file mode 100644 index 00000000..099c1658 --- /dev/null +++ b/plugins/history/Makefile.am @@ -0,0 +1,52 @@ +INCLUDES = \ + -I$(top_srcdir) \ + -I$(srcdir) \ + $(GITG_PLUGIN_CFLAGS) \ + $(WARN_CFLAGS) \ + -DDATADIR=\""$(datadir)"\" \ + -DLIBDIR=\""$(libdir)"\" + +plugindir = $(GITG_PLUGIN_LIBDIR) +plugin_LTLIBRARIES = libhistory.la +plugin_DATA = history.plugin + +VALAFLAGS = $(GITG_PLUGIN_VALAFLAGS) +VALA_SOURCES = \ + gitg-history.vala \ + gitg-history-navigation.vala + +libhistory_la_LDFLAGS = $(GITG_PLUGIN_LIBTOOL_FLAGS) + +libhistory_la_LIBADD = $(GITG_PLUGIN_LIBS) +libhistory_la_CFLAGS = -w + +libhistory_la_SOURCES = \ + $(VALA_SOURCES) \ + gitg-history-resources.c + +BUILT_SOURCES = \ + gitg-history-resources.c \ + gitg-history-resources.h + +gitg-history-resources.c: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-source \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +gitg-history-resources.h: resources/resources.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + $(GLIB_COMPILE_RESOURCES) --generate-header \ + --sourcedir $(srcdir)/resources \ + --target "$@" "$<" + +EXTRA_DIST = $(plugin_DATA) \ + resources/resources.xml \ + $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir)/resources resources/resources.xml) + +CLEANFILES = \ + $(VALA_SOURCES:.vala=.c) \ + $(BUILT_SOURCES) + +install-data-hook: + rm -f $(GITG_PLUGIN_LIBDIR)/libhistory.la + +-include $(top_srcdir)/git.mk diff --git a/plugins/history/gitg-history-navigation.vala b/plugins/history/gitg-history-navigation.vala new file mode 100644 index 00000000..b18753c2 --- /dev/null +++ b/plugins/history/gitg-history-navigation.vala @@ -0,0 +1,123 @@ +namespace GitgHistory +{ + private class Navigation : Object, GitgExt.Navigation + { + public GitgExt.Application? application { owned get; construct; } + + public Navigation(GitgExt.Application app) + { + Object(application: app); + } + + private static int sort_refs(Gitg.Ref a, Gitg.Ref b) + { + return a.parsed_name.shortname.ascii_casecmp(b.parsed_name.shortname); + } + + public void populate(GitgExt.NavigationTreeModel model) + { + var repo = application.repository; + + List branches = new List(); + HashTable> remotes; + List remotenames = new List(); + + remotes = new HashTable>(str_hash, str_equal); + + try + { + repo.references_foreach(Ggit.RefType.LISTALL, (nm) => { + Gitg.Ref? r; + + try + { + r = repo.lookup_reference(nm); + } catch { return 0; } + + if (r.parsed_name.rtype == Gitg.RefType.BRANCH) + { + branches.insert_sorted(r, sort_refs); + } + else if (r.parsed_name.rtype == Gitg.RefType.REMOTE) + { + unowned List lst; + + string rname = r.parsed_name.remote_name; + + if (!remotes.lookup_extended(rname, null, out lst)) + { + List nlst = new List(); + nlst.prepend(r); + + remotes.insert(rname, (owned)nlst); + remotenames.insert_sorted(rname, (a, b) => a.ascii_casecmp(b)); + } + else + { + /*unowned List start = lst; + + lst.insert_sorted(r, sort_refs); + + if (lst != start) + { + remotes.insert(rname, lst.copy()); + }*/ + } + } + + return 0; + }); + } catch {} + + Gitg.Ref? head = null; + + try + { + head = repo.get_head(); + } catch {} + + // Branches + model.begin_header("Branches", null); + + foreach (var item in branches) + { + if (head != null && item.get_id().equal(head.get_id())) + { + model.append_default(item.parsed_name.shortname, + "object-select-symbolic", + null); + } + else + { + model.append(item.parsed_name.shortname, null, null); + } + } + + model.end_header(); + + // Remotes + model.begin_header("Remotes", "network-server-symbolic"); + + foreach (var rname in remotenames) + { + //model.append(item.parsed_name.remote_branch, null, null); + } + + model.end_header(); + + // Tags + } + + public GitgExt.NavigationSide navigation_side + { + get { return GitgExt.NavigationSide.LEFT; } + } + + public bool available + { + get { return true; } + } + } +} + +// ex: ts=4 noet diff --git a/plugins/history/gitg-history.vala b/plugins/history/gitg-history.vala new file mode 100644 index 00000000..8a03455f --- /dev/null +++ b/plugins/history/gitg-history.vala @@ -0,0 +1,103 @@ +namespace GitgHistory +{ + // Do this to pull in config.h before glib.h (for gettext...) + private const string version = Gitg.Config.VERSION; + + public class View : Object, GitgExt.View + { + public GitgExt.Application? application { owned get; construct; } + + private Gtk.Widget d_main; + + public string id + { + owned get { return "/org/gnome/gitg/Views/History"; } + } + + public bool is_available() + { + // The history view is available only when there is a repository + return application.repository != null; + } + + public string display_name + { + owned get { return "History"; } + } + + public Icon? icon + { + owned get { return new ThemedIcon("view-list-symbolic"); } + } + + public Gtk.Widget? widget + { + owned get + { + if (d_main == null) + { + build_ui(); + } + + return d_main; + } + } + + public GitgExt.Navigation? navigation + { + owned get + { + var ret = new Navigation(application); + + return ret; + } + } + + public bool is_default_for(GitgExt.ViewAction action) + { + return application.repository != null && action == GitgExt.ViewAction.HISTORY; + } + + private void build_ui() + { + var ret = from_builder("view-history.ui", {"view"}); + + d_main = ret["view"] as Gtk.Widget; + } + + private Gee.HashMap? from_builder(string path, string[] ids) + { + var builder = new Gtk.Builder(); + + try + { + builder.add_from_resource("/org/gnome/gitg/history/" + path); + } + catch (Error e) + { + warning("Failed to load ui: %s", e.message); + return null; + } + + Gee.HashMap ret = new Gee.HashMap(); + + foreach (string id in ids) + { + ret[id] = builder.get_object(id); + } + + return ret; + } + } +} + +[ModuleInit] +public void peas_register_types(TypeModule module) +{ + Peas.ObjectModule mod = module as Peas.ObjectModule; + + mod.register_extension_type(typeof(GitgExt.View), + typeof(GitgHistory.View)); +} + +// ex: ts=4 noet diff --git a/plugins/history/history.plugin b/plugins/history/history.plugin new file mode 100644 index 00000000..33d800a4 --- /dev/null +++ b/plugins/history/history.plugin @@ -0,0 +1,11 @@ +[Plugin] +Loader=C +Module=history +Name=History +Description=gitg History +Authors=Jesse van den Kieboom +Copyright=Copyright © 2012 Jesse van den Kieboom +Website= +Hidden=1 +Builtin=1 +Version=1.0 diff --git a/plugins/history/resources/resources.xml b/plugins/history/resources/resources.xml new file mode 100644 index 00000000..802c861d --- /dev/null +++ b/plugins/history/resources/resources.xml @@ -0,0 +1,8 @@ + + + + view-history.ui + + + + diff --git a/plugins/history/resources/view-history.ui b/plugins/history/resources/view-history.ui new file mode 100644 index 00000000..c725a0d6 --- /dev/null +++ b/plugins/history/resources/view-history.ui @@ -0,0 +1,13 @@ + + + + + True + 6 + True + True + vertical + + + + diff --git a/vapi/config.vapi b/vapi/config.vapi new file mode 100644 index 00000000..cee9f224 --- /dev/null +++ b/vapi/config.vapi @@ -0,0 +1,13 @@ +[CCode(cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")] +namespace Gitg.Config +{ + public const string GETTEXT_PACKAGE; + public const string PACKAGE_NAME; + public const string PACKAGE_VERSION; + public const string GITG_DATADIR; + public const string GITG_LOCALEDIR; + public const string GITG_LIBDIR; + public const string VERSION; +} + +// ex:ts=4 noet diff --git a/vapi/gobject-introspection-1.0.vapi b/vapi/gobject-introspection-1.0.vapi new file mode 100644 index 00000000..28f7c496 --- /dev/null +++ b/vapi/gobject-introspection-1.0.vapi @@ -0,0 +1,31 @@ +[CCode (cprefix = "GI", lower_case_cprefix = "g_i", cheader_filename = "girepository.h")] +namespace Introspection +{ + [CCode (cprefix = "G_IREPOSITORY_ERROR_")] + public errordomain RepositoryError { + TYPELIB_NOT_FOUND, + NAMESPACE_MISMATCH, + NAMESPACE_VERSION_CONFLICT, + LIBRARY_NOT_FOUND + } + + [CCode (cname="int", cprefix = "G_IREPOSITORY_LOAD_FLAG_")] + public enum RepositoryLoadFlags { + LAZY = 1 + } + + [CCode (ref_function = "", unref_function = "")] + public class Repository { + public static unowned Repository get_default(); + public static void prepend_search_path(string directory); + public static unowned GLib.SList get_search_path(); + + public unowned Typelib? require(string namespace_, string? version = null, RepositoryLoadFlags flags = 0) throws RepositoryError; + } + + [Compact] + [CCode (cname = "GTypelib", cprefix = "g_typelib_", free_function = "g_typelib_free")] + public class Typelib { + public unowned string get_namespace(); + } +}