gtranslator r3602 - in trunk: . data plugins plugins/subversion src



Author: icq
Date: Mon Sep 22 09:38:40 2008
New Revision: 3602
URL: http://svn.gnome.org/viewvc/gtranslator?rev=3602&view=rev

Log:
Merge subversion branch into the master branch to implement the subversion plugin

Added:
   trunk/plugins/subversion/
   trunk/plugins/subversion/Makefile.am
   trunk/plugins/subversion/async-command.c
   trunk/plugins/subversion/async-command.h
   trunk/plugins/subversion/checkout-dialog.c
   trunk/plugins/subversion/checkout-dialog.h
   trunk/plugins/subversion/command.c
   trunk/plugins/subversion/command.h
   trunk/plugins/subversion/commit-dialog.c
   trunk/plugins/subversion/commit-dialog.h
   trunk/plugins/subversion/diff-dialog.c
   trunk/plugins/subversion/diff-dialog.h
   trunk/plugins/subversion/subversion-enum-types.c.template
   trunk/plugins/subversion/subversion-enum-types.h.template
   trunk/plugins/subversion/subversion-plugin.c
   trunk/plugins/subversion/subversion-plugin.h
   trunk/plugins/subversion/subversion-utils.c
   trunk/plugins/subversion/subversion-utils.h
   trunk/plugins/subversion/subversion.glade
   trunk/plugins/subversion/subversion.gtranslator-plugin.desktop.in
   trunk/plugins/subversion/svn-add-command.c
   trunk/plugins/subversion/svn-add-command.h
   trunk/plugins/subversion/svn-cat-command.c
   trunk/plugins/subversion/svn-cat-command.h
   trunk/plugins/subversion/svn-checkout-command.c
   trunk/plugins/subversion/svn-checkout-command.h
   trunk/plugins/subversion/svn-command.c
   trunk/plugins/subversion/svn-command.h
   trunk/plugins/subversion/svn-commit-command.c
   trunk/plugins/subversion/svn-commit-command.h
   trunk/plugins/subversion/svn-diff-command.c
   trunk/plugins/subversion/svn-diff-command.h
   trunk/plugins/subversion/svn-resolve-command.c
   trunk/plugins/subversion/svn-resolve-command.h
   trunk/plugins/subversion/svn-status-command.c
   trunk/plugins/subversion/svn-status-command.h
   trunk/plugins/subversion/svn-status.c
   trunk/plugins/subversion/svn-status.h
   trunk/plugins/subversion/svn-update-command.c
   trunk/plugins/subversion/svn-update-command.h
   trunk/plugins/subversion/update-dialog.c
   trunk/plugins/subversion/update-dialog.h
   trunk/plugins/subversion/vcs-status-tree-view.c
   trunk/plugins/subversion/vcs-status-tree-view.h
Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/data/gtranslator-ui.xml
   trunk/plugins/Makefile.am
   trunk/src/main.c

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Mon Sep 22 09:38:40 2008
@@ -252,6 +252,222 @@
 
 AM_CONDITIONAL(USE_CHARMAP, test x"$have_gucharmap" = "xyes")
 
+dnl  **********************************************************
+dnl  check if we have svn libraries to build subversion plugin
+dnl  (stolen from kdevelop ;-)
+dnl  **********************************************************
+
+AC_MSG_CHECKING(for Subversion svn-config)
+AC_ARG_WITH(subversion-dir,
+		[  --with-subversion-dir=DIR           where Subversion is installed ],
+		[
+				SVNCONFIG="$withval/bin/svn-config"
+		])
+
+if test -z "$SVNCONFIG"; then
+		_SVNCONFIG="`svn-config --prefix 2> /dev/null`"
+		if test -n "$_SVNCONFIG"; then
+				SVNCONFIG="$_SVNCONFIG/bin/svn-config"
+		fi
+fi
+
+AC_SUBST(SVNCONFIG)
+if test -x "$SVNCONFIG"; then
+		SVNLD="`$SVNCONFIG --ldflags 2> /dev/null`"
+		SVN_LIB="`$SVNCONFIG --libs --cflags 2> /dev/null` -lsvn_client-1 -lsvn_subr-1"
+		dnl ugly hack for subversion svn-config problems in 0.14.x, to be removed when svn-config is fixed
+		SVN_INCLUDE="`$SVNCONFIG --includes 2> /dev/null` -I$_SVNCONFIG/include/subversion-1/"
+		AC_MSG_RESULT(yes)
+else
+		AC_MSG_RESULT(not found)
+		
+		dnl just a fallback to debian's config so that it works for me :)
+		AC_ARG_WITH(svn-include,
+								[[  --with-svn-include=DIR   Use the given path to the subversion headers.]],
+								[
+								if test "$withval" != "yes" -a "$withval" != ""; then
+										SVN_INCLUDES=$withval
+								fi
+								])
+		if test -z "$SVN_INCLUDES"; then
+			SVN_INCLUDES="/usr/local/include /usr/include"
+		fi
+		AC_MSG_CHECKING([for Subversion headers])
+		SVN_INCLUDE=""
+		for VALUE in $SVN_INCLUDES ; do
+				if test -f $VALUE/subversion-1/svn_types.h ; then
+						SVN_INCLUDE=$VALUE/subversion-1
+						break
+				fi
+				if test -f $VALUE/svn_types.h ; then
+						SVN_INCLUDE=$VALUE
+						break
+				fi
+		done
+		if test $SVN_INCLUDE ; then
+				AC_MSG_RESULT([found])
+		else
+				AC_MSG_RESULT([not found])
+		fi
+		SVN_LIBS="/usr/local/lib /usr/lib"
+		AC_ARG_WITH(svn-lib,
+						[[  --with-svn-lib=DIR  Use the given path to the subversion libraries.]],
+						[
+							if test "$withval" != "yes" -a "$withval" != ""; then
+								SVN_LIBS=$withval
+							fi
+						])
+		AC_MSG_CHECKING([for Subversion libraries])
+		SVN_LIB=""
+		for VALUE in $SVN_LIBS ; do
+				if ls $VALUE/libsvn_client-1.* 1>/dev/null 2>&1; then
+						SVN_LIB=$VALUE
+						break
+				fi
+		done
+		if test $SVN_LIB ; then
+				AC_MSG_RESULT([found])
+		else
+				AC_MSG_RESULT([not found])
+		fi
+fi
+
+dnl ******************************************************************
+dnl Check for extra libs required by subversion.
+dnl FIXME: This should actually be done by subversion and not by us.
+dnl ******************************************************************
+
+AC_ARG_ENABLE(plugin-subversion,
+  [  --disable-plugin-subversion        Disable subversion support in Anjuta.],
+  [ if test "$enableval" = "no"; then
+        user_disabled_subversion=1
+    fi ],
+  [ user_disabled_subversion=0 ] )
+
+AC_MSG_CHECKING(if subversion support is disabled)
+if test "$user_disabled_subversion" = 1; then
+	AC_MSG_RESULT(yes)
+	SVN_INCLUDE=""
+	SVN_LIB=""
+else
+	AC_MSG_RESULT(no)
+fi
+
+if test -n "$SVN_INCLUDE" ; then
+	dnl ------------------------------------
+	dnl APR. Required by subversion (devel)
+	dnl ------------------------------------
+	
+	APR_CONFIGS="apr-config /usr/local/apr/bin/apr-config/ apr-1-config "
+	AC_ARG_WITH(apr-config,
+	[[  --with-apr-config=FILE    Use the given path to apr-config when determining
+								APR configuration; defaults to "apr-config"]],
+	[
+	if test "$withval" != "yes" -a "$withval" != ""; then
+	  APR_CONFIGS=$withval
+	fi
+	])
+	AC_MSG_CHECKING([for APR])
+	APR_CONFIG=""
+	for VALUE in $APR_CONFIGS ; do
+			if $VALUE --cflags > /dev/null 2>&1 ; then
+					APR_CONFIG=$VALUE
+					break
+			fi
+	done
+	test $VALUE && APR_CONFIG=$VALUE
+	if test $APR_CONFIG ; then
+		AC_MSG_RESULT([found])
+		APR_CFLAGS="`$APR_CONFIG --cflags` `$APR_CONFIG --cppflags`"
+		APR_INCLUDE="`$APR_CONFIG --includes`"
+		APR_LIBS="`$APR_CONFIG --link-ld --libs`"
+	else
+		AC_MSG_RESULT([not found])
+		dnl AC_MSG_ERROR([APR is required. Try --with-apr-config.])
+	fi
+	
+	dnl -----------------------------------------
+	dnl APR util. Required by subversion (devel)
+	dnl------------------------------------------
+	
+	APU_CONFIGS="apu-config /usr/local/apr/bin/apu-config apu-1-config"
+	AC_ARG_WITH(apu-config,
+	[[  --with-apu-config=FILE    Use the given path to apu-config when determining
+								APR util configuration; defaults to "apu-config"]],
+	[
+		if test "$withval" != "yes" -a "$withval" != ""; then
+			APU_CONFIGS=$withval
+		fi
+	])
+	AC_MSG_CHECKING([for APR util])
+	APU_CONFIG=""
+	for VALUE in $APU_CONFIGS ; do
+			if $VALUE --includes > /dev/null 2>&1 ; then
+					APU_CONFIG=$VALUE
+					break
+			fi
+	done
+	if test $APU_CONFIG ; then
+		AC_MSG_RESULT([found])
+		APR_INCLUDE="$APR_INCLUDE `$APU_CONFIG --includes`"
+		APR_LIBS="$APR_LIBS `$APU_CONFIG --link-ld --libs`"
+	else
+		AC_MSG_RESULT([not found])
+	fi
+	
+	dnl -----------------------------------------
+	dnl NEON. Required by subversion (devel)
+	dnl------------------------------------------
+
+	dnl Check for neon. It is required by subversion libs, but for
+	dnl for some strange reason it's not in it's dependencies.
+	dnl subversion plugin will be disabled if neon (devel) is not
+	dnl installed, even if subversion (devel) is installed.
+
+	NEON_CONFIGS="neon-config"
+	AC_ARG_WITH(neon-config,
+	[[  --with-neon-config=FILE    Use the given path to neon-config when determining
+								Neon configuration; defaults to "neon-config"]],
+	[
+		if test "$withval" != "yes" -a "$withval" != ""; then
+			NEON_CONFIGS=$withval
+		fi
+	])
+	AC_MSG_CHECKING([for Neon])
+	NEON_CONFIG=""
+	for VALUE in $NEON_CONFIGS ; do
+			if $VALUE --cflags > /dev/null 2>&1 ; then
+					NEON_CONFIG=$VALUE
+					break
+			fi
+	done
+	if test $NEON_CONFIG ; then
+		AC_MSG_RESULT([found])
+	else
+		AC_MSG_RESULT([not found])
+		SVN_INCLUDE=""
+		SVN_LIB=""
+	fi
+fi
+
+dnl ------------------------------------------
+dnl Finally prepare subversion build flags
+dnl ------------------------------------------
+
+if test -n "$SVN_INCLUDE" ; then
+	SVN_INCLUDE="-I$SVN_INCLUDE $APR_INCLUDE"
+	if test x != "x$SVN_LIB" ; then
+	    SVN_LIB="-L$SVN_LIB $APR_LIBS -lsvn_client-1 -lsvn_subr-1"
+	else
+	    SVN_LIB="$APR_LIBS -lsvn_client-1 -lsvn_subr-1"
+	fi
+	SVN_CFLAGS="$APR_CFLAGS"
+fi
+
+AM_CONDITIONAL(BUILD_SVN, [test -n "$SVN_INCLUDE"])
+AC_SUBST(SVN_INCLUDE)
+AC_SUBST(SVN_LIB)
+AC_SUBST(SVN_CFLAGS)
 
 dnl -------------------------------------------------------------------
 dnl Enable debug builds.
@@ -304,6 +520,7 @@
 plugins/insert-tags/Makefile
 plugins/open-tran/Makefile
 plugins/source-view/Makefile
+plugins/subversion/Makefile
 src/Makefile
 src/dialogs/Makefile
 src/toolbareditor/Makefile
@@ -325,7 +542,18 @@
 debug friendly build	  :	${enable_debug:-no}
 build with deprecation 	  :	${enable_deprecated:-no}
 compilation flags      	  :	${CFLAGS}
-
+------------------------------------------------------------------
+"
+if [ test -n "$SVN_INCLUDE" ]; then
+        echo "Building subversion plugin: ............................YES"
+else
+        echo "Building subversion plugin: ............................NO"
+		echo "        Requires apr (>= 0.9.4); http://subversion.org";
+		echo "        Requires apr-util (>= 0.9.4); http://subversion.org";
+		echo "        Requires neon (>= 0.24.5); http://subversion.org";
+		echo "        Requires subversion (>= 1.0.2); http://subversion.org";
+fi
+echo "
 ------------------------------------------------------------------
 -- For suggestions, problems & bug reports for gtranslator please
     use http://bugzilla.gnome.org/enter_bug.cgi?product=gtranslator

Modified: trunk/data/gtranslator-ui.xml
==============================================================================
--- trunk/data/gtranslator-ui.xml	(original)
+++ trunk/data/gtranslator-ui.xml	Mon Sep 22 09:38:40 2008
@@ -80,6 +80,10 @@
       <menuitem name="SearchReplaceMenu" action="SearchReplace"/>
     </menu>
 
+    <placeholder name="SubversionPlaceholder" />
+
+    <placeholder name="ExtraMenu_1" />
+
     <menu name="HelpMenu" action="Help">
       <menuitem name="HelpContentsMenu" action="HelpContents"/>
       <menuitem name="HelpAboutMenu" action="HelpAbout"/>

Modified: trunk/plugins/Makefile.am
==============================================================================
--- trunk/plugins/Makefile.am	(original)
+++ trunk/plugins/Makefile.am	Mon Sep 22 09:38:40 2008
@@ -15,3 +15,7 @@
 if USE_DICTIONARY
 SUBDIRS += dictionary
 endif
+
+if BUILD_SVN
+SUBDIRS += subversion
+endif

Added: trunk/plugins/subversion/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/Makefile.am	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,96 @@
+# FullScreen plugin
+plugindir = $(libdir)/gtranslator/plugins
+
+INCLUDES = \
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/src				\
+	-I$(top_srcdir)/src/plugin-system		\
+	-I$(top_srcdir)/src/dialogs			\
+	-DDATADIR=\""$(pkgdatadir)"\"                   \
+	$(GTRANSLATOR_CFLAGS) 				\
+	$(SVN_CFLAGS)					\
+        $(SVN_INCLUDE)					\
+	$(WARN_CFLAGS)					\
+	$(DISABLE_DEPRECATED_CFLAGS)			\
+	-DGTR_LOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
+
+plugin_LTLIBRARIES = \
+	libsubversion.la
+
+BUILT_SOURCES = \
+	subversion-enum-types.h \
+	subversion-enum-types.c
+
+NOINST_H_FILES = \
+	subversion-plugin.h \
+	command.h \
+	async-command.h \
+	svn-command.h \
+	svn-commit-command.h \
+	svn-update-command.h \
+	svn-add-command.h \
+	svn-status-command.h \
+	svn-status.h \
+	commit-dialog.h \
+	vcs-status-tree-view.h \
+	subversion-utils.h \
+	svn-diff-command.h \
+	svn-resolve-command.h \
+	svn-cat-command.h \
+	svn-checkout-command.h \
+	update-dialog.h \
+	diff-dialog.h \
+	checkout-dialog.h
+
+libsubversion_la_SOURCES = \
+	$(BUILT_SOURCES) \
+	subversion-plugin.c \
+	command.c \
+	async-command.c \
+	svn-command.c \
+	svn-commit-command.c \
+	svn-update-command.c \
+	svn-add-command.c \
+	svn-status-command.c \
+	svn-status.c \
+	commit-dialog.c \
+	vcs-status-tree-view.c \
+	subversion-utils.c \
+	svn-diff-command.c \
+	svn-resolve-command.c \
+	update-dialog.c \
+	svn-cat-command.c \
+	svn-checkout-command.c \
+	diff-dialog.c \
+	checkout-dialog.c \
+	$(NOINST_H_FILES)
+
+libsubversion_la_LDFLAGS = \
+	$(PLUGIN_LIBTOOL_FLAGS)				\
+	$(GTRANSLATOR_LIBS)				\
+	$(SVN_LIB)
+
+gladedir = $(pkgdatadir)
+
+glade_DATA =  \
+	subversion.glade
+
+subversion-enum-types.h: subversion-enum-types.h.template $(NOINST_H_FILES) $(GLIB_MKENUMS)
+	(cd $(srcdir) && $(GLIB_MKENUMS) --template subversion-enum-types.h.template $(NOINST_H_FILES)) > $@
+
+subversion-enum-types.c: subversion-enum-types.c.template $(NOINST_H_FILES) $(GLIB_MKENUMS)
+	(cd $(srcdir) && $(GLIB_MKENUMS) --template subversion-enum-types.c.template $(NOINST_H_FILES)) > $@
+
+# Plugin Info
+
+plugin_in_files = subversion.gtranslator-plugin.desktop.in
+
+%.gtranslator.plugin: %.gtranslator-plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
+
+plugin_DATA = $(plugin_in_files:.gtranslator-plugin.desktop.in=.gtranslator.plugin)
+
+EXTRA_DIST = $(plugin_in_files)
+
+CLEANFILES = $(plugin_DATA) $(BUILT_SOURCES)
+DISTCLEANFILES = $(plugin_DATA)
+

Added: trunk/plugins/subversion/async-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/async-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,205 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "async-command.h"
+
+/**
+ * SECTION: gtranslator-async-command
+ * @short_description: #GtranslatorCommand subclass that serves as the base for 
+ *					   commands that need to run in another thread.
+ * @include: libgtranslator/gtranslator-async-command.h
+ *
+ * #GtranslatorAsyncCommand provides a simple way for plugins to run tasks that 
+ * are synchronous and usually take several seconds or longer to execute in 
+ * another thread so that such tasks do no block Gtranslator's user interface.
+ *
+ * #GtranslatorAsyncCommand automatically runs and manages the thread when the 
+ * command starts, and destroys it when the command finishes. Aside from 
+ * locking protected data with gtranslator_async_command_lock/unlock, clients, and
+ * even commands themselves need not even be concerned that their tasks are 
+ * rnning on another thread.
+ *
+ * For an example of how #GtranslatorAsyncCommand is used, see the Subversion plugin.
+ */
+
+struct _GtranslatorAsyncCommandPriv
+{
+	GMutex *mutex;
+	guint return_code;
+	gboolean complete;
+	gboolean new_data_arrived;
+};
+
+G_DEFINE_TYPE (GtranslatorAsyncCommand, gtranslator_async_command, GTR_TYPE_COMMAND);
+
+static void
+gtranslator_async_command_init (GtranslatorAsyncCommand *self)
+{
+	self->priv = g_new0 (GtranslatorAsyncCommandPriv, 1);
+	
+	self->priv->mutex = g_mutex_new ();
+}
+
+static void
+gtranslator_async_command_finalize (GObject *object)
+{
+	GtranslatorAsyncCommand *self;
+	
+	self = GTR_ASYNC_COMMAND (object);
+	
+	g_mutex_free (self->priv->mutex);
+	g_idle_remove_by_data (self);
+	
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (gtranslator_async_command_parent_class)->finalize (object);
+}
+
+static gboolean
+gtranslator_async_command_notification_poll (GtranslatorCommand *command)
+{
+	GtranslatorAsyncCommand *self;
+	
+	self = GTR_ASYNC_COMMAND (command);
+	
+	if (self->priv->new_data_arrived &&
+		g_mutex_trylock (self->priv->mutex))
+	{
+		g_signal_emit_by_name (command, "data-arrived");
+		g_mutex_unlock (self->priv->mutex);
+		self->priv->new_data_arrived = FALSE;
+	}
+	
+	if (self->priv->complete)
+	{
+		g_signal_emit_by_name (command, "command-finished", 
+							   self->priv->return_code);
+		return FALSE;
+	}
+	else
+		return TRUE;
+	
+}
+
+static gpointer
+gtranslator_async_command_thread (GtranslatorCommand *command)
+{
+	guint return_code;
+	
+	return_code = GTR_COMMAND_GET_CLASS (command)->run (command);
+	gtranslator_command_notify_complete (command, return_code);
+	return NULL;
+}
+
+static void
+start_command (GtranslatorCommand *command)
+{
+	g_idle_add ((GSourceFunc) gtranslator_async_command_notification_poll, 
+				command);
+	g_thread_create ((GThreadFunc) gtranslator_async_command_thread, 
+					 command, FALSE, NULL);
+}
+
+static void
+notify_data_arrived (GtranslatorCommand *command)
+{
+	GtranslatorAsyncCommand *self;
+	
+	self = GTR_ASYNC_COMMAND (command);
+	
+	self->priv->new_data_arrived = TRUE;
+}
+
+static void
+notify_complete (GtranslatorCommand *command, guint return_code)
+{
+	GtranslatorAsyncCommand *self;
+	
+	self = GTR_ASYNC_COMMAND (command);
+	
+	self->priv->complete = TRUE;
+	self->priv->return_code = return_code;
+}
+
+static void
+gtranslator_async_command_class_init (GtranslatorAsyncCommandClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass* parent_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = gtranslator_async_command_finalize;
+	
+	parent_class->start = start_command;
+	parent_class->notify_data_arrived = notify_data_arrived;
+	parent_class->notify_complete = notify_complete;
+}
+
+void
+gtranslator_async_command_set_error_message (GtranslatorCommand *command, 
+										gchar *error_message)
+{
+	gtranslator_async_command_lock (GTR_ASYNC_COMMAND (command));
+	GTR_COMMAND_GET_CLASS (command)->set_error_message (command, 
+														   error_message);
+	gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (command));
+}
+
+gchar *
+gtranslator_async_command_get_error_message (GtranslatorCommand *command)
+{
+	gchar *error_message;
+	
+	gtranslator_async_command_lock (GTR_ASYNC_COMMAND (command));
+	error_message = GTR_COMMAND_GET_CLASS (command)->get_error_message (command);
+	gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (command));
+	
+	return error_message;
+}
+
+/**
+ * gtranslator_async_command_lock:
+ * @self: GtranslatorAsyncCommand object.
+ *
+ * Locks the command's built-in mutex.
+ */
+void
+gtranslator_async_command_lock (GtranslatorAsyncCommand *self)
+{
+	g_mutex_lock (self->priv->mutex);
+}
+
+/**
+ * gtranslator_async_command_unlock:
+ * @self: GtranslatorAsyncCommand object.
+ *
+ * Unlocks the command's built-in mutex.
+ */
+void
+gtranslator_async_command_unlock (GtranslatorAsyncCommand *self)
+{
+	g_mutex_unlock (self->priv->mutex);
+}

Added: trunk/plugins/subversion/async-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/async-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,70 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _GTR_ASYNC_COMMAND_H_
+#define _GTR_ASYNC_COMMAND_H_
+
+#include <glib-object.h>
+#include "command.h"
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_ASYNC_COMMAND             (gtranslator_async_command_get_type ())
+#define GTR_ASYNC_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTR_TYPE_ASYNC_COMMAND, GtranslatorAsyncCommand))
+#define GTR_ASYNC_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTR_TYPE_ASYNC_COMMAND, GtranslatorAsyncCommandClass))
+#define IS_GTR_ASYNC_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTR_TYPE_ASYNC_COMMAND))
+#define IS_GTR_ASYNC_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTR_TYPE_ASYNC_COMMAND))
+#define GTR_ASYNC_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTR_TYPE_ASYNC_COMMAND, GtranslatorAsyncCommandClass))
+
+typedef struct _GtranslatorAsyncCommandClass GtranslatorAsyncCommandClass;
+typedef struct _GtranslatorAsyncCommand GtranslatorAsyncCommand;
+typedef struct _GtranslatorAsyncCommandPriv GtranslatorAsyncCommandPriv;
+
+struct _GtranslatorAsyncCommandClass
+{
+	GtranslatorCommandClass parent_class;
+};
+
+struct _GtranslatorAsyncCommand
+{
+	GtranslatorCommand parent_instance;
+	
+	GtranslatorAsyncCommandPriv *priv;
+};
+
+GType gtranslator_async_command_get_type (void) G_GNUC_CONST;
+
+void gtranslator_async_command_set_error_message (GtranslatorCommand *command, 
+											 gchar *error_message);
+gchar *gtranslator_async_command_get_error_message (GtranslatorCommand *command);
+
+void gtranslator_async_command_lock (GtranslatorAsyncCommand *self);
+void gtranslator_async_command_unlock (GtranslatorAsyncCommand *self);
+
+G_END_DECLS
+
+#endif /* _GTR_ASYNC_COMMAND_H_ */

Added: trunk/plugins/subversion/checkout-dialog.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/checkout-dialog.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "checkout-dialog.h"
+#include "subversion-plugin.h"
+#include "svn-checkout-command.h"
+#include "utils.h"
+#include "svn-command.h"
+#include "statusbar.h"
+#include "subversion-utils.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+
+#define GTR_CHECKOUT_DIALOG_GET_PRIVATE(object)	(G_TYPE_INSTANCE_GET_PRIVATE ( \
+						 	(object),	\
+						 	GTR_TYPE_CHECKOUT_DIALOG,     \
+						 	GtranslatorCheckoutDialogPrivate))
+
+
+G_DEFINE_TYPE(GtranslatorCheckoutDialog, gtranslator_checkout_dialog, GTK_TYPE_DIALOG)
+
+struct _GtranslatorCheckoutDialogPrivate
+{
+	GtkWidget *main_box;
+	GtkWidget *path_entry;
+	GtkWidget *dir_find_button;
+	GtkWidget *url_entry;
+	
+	GtkListStore *store;
+	GtkWidget *checkout_treeview;
+	
+	GtranslatorWindow *window;
+};
+
+enum 
+{
+	ICON_COLUMN,
+	TEXT_COLUMN,
+	N_COLUMNS
+};
+
+static void
+on_checkout_command_finished (GtranslatorCommand *command,
+			    guint return_code,
+			    GtranslatorCheckoutDialog *dlg)
+{
+	GtranslatorStatusbar *status;
+	
+	status = GTR_STATUSBAR (gtranslator_window_get_statusbar (dlg->priv->window));
+	
+	gtranslator_statusbar_flash_message (status, 0,
+					     _("Subversion: Checkout complete."));
+	
+	subversion_utils_report_errors (dlg->priv->window, 
+					command, return_code);
+	
+	svn_checkout_command_destroy (SVN_CHECKOUT_COMMAND (command));	
+}
+
+static void
+on_checkout_command_info_arrived (GtranslatorCommand *command,
+				GtranslatorCheckoutDialog *dlg)
+{
+	GQueue *info;
+	gchar *message;
+	GtkTreeIter iter;
+	
+	info = svn_command_get_info_queue (SVN_COMMAND (command));
+	
+	while (g_queue_peek_head (info))
+	{
+		message = g_queue_pop_head (info);
+		
+		gtk_list_store_append (dlg->priv->store, &iter);
+		gtk_list_store_set (dlg->priv->store, &iter,
+				    TEXT_COLUMN, message,
+				    -1);
+		
+		g_free (message);
+	}
+}
+
+static void
+dialog_response_handler (GtranslatorCheckoutDialog *dlg, 
+			 gint       res_id)
+{
+	switch (res_id)
+	{
+		case GTK_RESPONSE_APPLY:
+		{
+			const gchar *path, *url;
+			SvnCheckoutCommand *checkout_command;
+			
+			path = gtk_entry_get_text (GTK_ENTRY (dlg->priv->path_entry));
+			if (strcmp ("", path) == 0)
+			{
+				GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (dlg->priv->window),
+									    GTK_DIALOG_DESTROY_WITH_PARENT,
+									    GTK_MESSAGE_WARNING,
+									    GTK_BUTTONS_CLOSE,
+									    _("Please, add a directory path to make the checkout"));
+				gtk_dialog_run (GTK_DIALOG (dialog));
+				gtk_widget_destroy (dialog);
+				break;
+			}
+			
+			url = gtk_entry_get_text (GTK_ENTRY (dlg->priv->url_entry));
+			if (strcmp ("", url) == 0)
+			{
+				GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (dlg->priv->window),
+									    GTK_DIALOG_DESTROY_WITH_PARENT,
+									    GTK_MESSAGE_WARNING,
+									    GTK_BUTTONS_CLOSE,
+									    _("Please, add a Subversion URL"));
+				gtk_dialog_run (GTK_DIALOG (dialog));
+				gtk_widget_destroy (dialog);
+				break;
+			}
+
+			checkout_command = svn_checkout_command_new (url, path);
+			
+			gtk_list_store_clear (dlg->priv->store);
+			
+			g_signal_connect (G_OBJECT (checkout_command), "command-finished",
+					  G_CALLBACK (on_checkout_command_finished),
+					  dlg);
+			
+			g_signal_connect (G_OBJECT (checkout_command), "data-arrived",
+					  G_CALLBACK (on_checkout_command_info_arrived),
+					  dlg);
+
+			gtranslator_command_start (GTR_COMMAND (checkout_command));
+
+			break;
+		}
+		default:
+			gtk_widget_hide (GTK_WIDGET (dlg));
+	}
+}
+
+static void
+on_dir_find_button_clicked (GtkButton *button,
+			    GtranslatorCheckoutDialog *dlg)
+{
+	GtkWidget *dialog;
+	gint res;
+	
+	dialog = gtk_file_chooser_dialog_new (_("Checkout directory"),
+					      GTK_WINDOW (dlg->priv->window),
+					      GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
+					      GTK_STOCK_CANCEL,
+					      GTK_RESPONSE_CANCEL,
+					      GTK_STOCK_OK,
+					      GTK_RESPONSE_OK,
+					      NULL);
+	res = gtk_dialog_run (GTK_DIALOG (dialog));
+	switch (res)
+	{
+		case GTK_RESPONSE_OK: 
+		{
+			gchar *filename;
+			
+			filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+			gtk_entry_set_text (GTK_ENTRY (dlg->priv->path_entry),
+					    filename);
+			g_free (filename);
+			break;
+		}
+		default:
+			break;
+	}
+	gtk_widget_destroy (dialog);
+}
+
+static void
+setup_treeview (GtranslatorCheckoutDialog *dlg)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	
+	dlg->priv->store = gtk_list_store_new (N_COLUMNS,
+					       GDK_TYPE_PIXBUF,
+					       G_TYPE_STRING);
+	
+	gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->checkout_treeview),
+				 GTK_TREE_MODEL (dlg->priv->store));
+	
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dlg->priv->checkout_treeview),
+					   FALSE);
+	
+	column = gtk_tree_view_column_new ();
+	/*
+	 * Icon column
+	 */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (renderer,
+		      "stock-id", GTK_STOCK_INFO,
+		      "stock-size", GTK_ICON_SIZE_MENU,
+		      "xalign", 1.0,
+		      "xpad", 6,
+		      NULL);
+
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	
+	/*
+	 * Text column
+	 */
+	
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_set_attributes (column,
+					     renderer,
+					     "text", TEXT_COLUMN,
+					     NULL);
+
+	gtk_tree_view_column_set_resizable (column, FALSE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->checkout_treeview),
+				     column);
+}
+
+static void
+gtranslator_checkout_dialog_init (GtranslatorCheckoutDialog *dlg)
+{
+	gboolean ret;
+	GtkWidget *error_widget;
+	
+	dlg->priv = GTR_CHECKOUT_DIALOG_GET_PRIVATE (dlg);
+	
+	gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+				GTK_STOCK_REFRESH,
+				GTK_RESPONSE_APPLY,
+				GTK_STOCK_CLOSE,
+				GTK_RESPONSE_CLOSE,
+				NULL);
+	
+	gtk_window_set_title (GTK_WINDOW (dlg), _("Checkout repository"));
+	gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 600);
+	gtk_window_set_resizable (GTK_WINDOW (dlg), TRUE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+	
+	/* HIG defaults */
+	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->vbox), 2); /* 2 * 5 + 2 = 12 */
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->action_area), 4);
+	
+	g_signal_connect (dlg,
+			  "response",
+			  G_CALLBACK (dialog_response_handler),
+			  NULL);
+	
+	/*Glade*/
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+		"checkout_main_box",
+		&error_widget,
+		
+		"checkout_main_box", &dlg->priv->main_box,
+		"path_entry", &dlg->priv->path_entry,
+		"dir_find_button", &dlg->priv->dir_find_button,
+		"url_entry", &dlg->priv->url_entry,
+		"checkout_treeview", &dlg->priv->checkout_treeview,
+		
+		NULL);
+	
+	if(!ret)
+	{
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		
+		return;
+	}
+	
+	setup_treeview (dlg);
+	
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+			    dlg->priv->main_box, TRUE, TRUE, 0);
+	
+	gtk_container_set_border_width (GTK_CONTAINER (dlg->priv->main_box), 5);
+	
+	g_signal_connect (dlg->priv->dir_find_button, "clicked",
+			  G_CALLBACK (on_dir_find_button_clicked), dlg);
+}
+
+static void
+gtranslator_checkout_dialog_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gtranslator_checkout_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_checkout_dialog_class_init (GtranslatorCheckoutDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GtranslatorCheckoutDialogPrivate));
+
+	object_class->finalize = gtranslator_checkout_dialog_finalize;
+}
+
+void
+gtranslator_show_checkout_dialog (GtranslatorWindow *window)
+{
+	static GtranslatorCheckoutDialog *dlg = NULL;
+	
+	g_return_if_fail (GTR_IS_WINDOW (window));
+	
+	if(dlg == NULL)
+	{
+		dlg = g_object_new (GTR_TYPE_CHECKOUT_DIALOG, NULL);
+		
+		gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg),
+						    TRUE);
+		
+		dlg->priv->window = window;
+		
+		g_signal_connect (dlg,
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  &dlg);
+
+		gtk_widget_show (GTK_WIDGET (dlg));
+	}
+	
+	if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (dlg)))
+	{
+		gtk_window_set_transient_for (GTK_WINDOW (dlg),
+					      GTK_WINDOW (window));
+	}
+
+	gtk_window_present (GTK_WINDOW (dlg));
+}

Added: trunk/plugins/subversion/checkout-dialog.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/checkout-dialog.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __CHECKOUT_DIALOG_H__
+#define __CHECKOUT_DIALOG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "window.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTR_TYPE_CHECKOUT_DIALOG		(gtranslator_checkout_dialog_get_type ())
+#define GTR_CHECKOUT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_CHECKOUT_DIALOG, GtranslatorCheckoutDialog))
+#define GTR_CHECKOUT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_CHECKOUT_DIALOG, GtranslatorCheckoutDialogClass))
+#define GTR_IS_CHECKOUT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_CHECKOUT_DIALOG))
+#define GTR_IS_CHECKOUT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_CHECKOUT_DIALOG))
+#define GTR_CHECKOUT_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_CHECKOUT_DIALOG, GtranslatorCheckoutDialogClass))
+
+/* Private structure type */
+typedef struct _GtranslatorCheckoutDialogPrivate	GtranslatorCheckoutDialogPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GtranslatorCheckoutDialog		GtranslatorCheckoutDialog;
+
+struct _GtranslatorCheckoutDialog
+{
+	GtkDialog parent_instance;
+	
+	/*< private > */
+	GtranslatorCheckoutDialogPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtranslatorCheckoutDialogClass	GtranslatorCheckoutDialogClass;
+
+struct _GtranslatorCheckoutDialogClass
+{
+	GtkDialogClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType		 gtranslator_checkout_dialog_get_type               (void) G_GNUC_CONST;
+
+GType		 gtranslator_checkout_dialog_register_type          (GTypeModule * module);
+
+void	     gtranslator_show_checkout_dialog                   (GtranslatorWindow *window);
+
+G_END_DECLS
+
+#endif /* __CHECKOUT_DIALOG_H__ */

Added: trunk/plugins/subversion/command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,217 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "command.h"
+
+/**
+ * SECTION: gtranslator-command
+ * @short_description: System for creating objects that provide a standard 
+ *					   interface to external components (libraries, processes,
+ *					   etc.) 
+ * @see_also: #GtranslatorAsyncCommand
+ * @include libgtranslator/gtranslator-command.h
+ *
+ * #GtranslatorCommand is the base class for objects that are designed to provide 
+ * a layer of abstraction between UI code and some other component, like a 
+ * library or child process. GtranslatorCommand provides a simple and consistent
+ * interface for plugins to interact with these components without needing 
+ * to concern themselves with the exact details of how these components work.
+ * 
+ * To create command objects, plugins derive them from an #GtranslatorCommand 
+ * subclass like #GtranslatorAsyncCommand, which runs commands in another thread.
+ * These classes determine how ::run is called and how signals are emitted.
+ * ::run is responsible for actually doing the work of the command. It is the 
+ * responsiblity of the command object that does a certain task to implement 
+ * ::run to do its job. Everything else is normally implemented by its parent
+ * classes at this point
+ *
+ * For an example of how to use #GtranslatorCommand, see the Subversion plugin.
+ */
+
+struct _GtranslatorCommandPriv
+{
+	gchar *error_message;
+};
+
+enum
+{
+	DATA_ARRIVED,
+	COMMAND_FINISHED,
+
+	LAST_SIGNAL
+};
+
+
+static guint gtranslator_command_signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GtranslatorCommand, gtranslator_command, G_TYPE_OBJECT);
+
+static void
+gtranslator_command_init (GtranslatorCommand *self)
+{
+	self->priv = g_new0 (GtranslatorCommandPriv, 1);
+}
+
+static void
+gtranslator_command_finalize (GObject *object)
+{
+	GtranslatorCommand *self;
+	
+	self = GTR_COMMAND (object);
+	
+	g_free (self->priv->error_message);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (gtranslator_command_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_command_class_init (GtranslatorCommandClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = gtranslator_command_finalize;
+	
+	klass->run = NULL;
+	klass->start = NULL;
+	klass->notify_data_arrived = NULL;
+	klass->notify_complete = NULL;
+	klass->set_error_message = gtranslator_command_set_error_message;
+	klass->get_error_message = gtranslator_command_get_error_message;
+
+	/**
+	 * GtranslatorCommand::data-arrived:
+	 * @command: Command
+	 * 
+	 * Notifies clients that the command has processed data that is ready to 
+	 * be used.
+	 */
+	gtranslator_command_signals[DATA_ARRIVED] =
+		g_signal_new ("data-arrived",
+		              G_OBJECT_CLASS_TYPE (klass),
+		              G_SIGNAL_RUN_FIRST,
+		              0,
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE, 
+					  0);
+
+	/**
+	 * GtranslatorCommand::command-finished:
+	 * @command: Command
+	 * @return_code: The return code of the finished commmand
+	 *
+	 * Indicates that the command has completed. Clients should at least handle
+	 * this signal to unref the command object. 
+	 */
+	gtranslator_command_signals[COMMAND_FINISHED] =
+		g_signal_new ("command-finished",
+		              G_OBJECT_CLASS_TYPE (klass),
+		              G_SIGNAL_RUN_FIRST,
+		              0,
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__UINT ,
+		              G_TYPE_NONE, 1,
+		              G_TYPE_UINT);
+}
+
+/**
+ * gtranslator_command_start:
+ * @self: Command object to start
+ *
+ * Starts a command. Client code can handle data from the command by connecting
+ * to the ::data-arrived signal. 
+ *
+ * #GtranslatorCommand subclasses should override this method to determine how they
+ * call ::run, which actually does the command's legwork. 
+ */
+void
+gtranslator_command_start (GtranslatorCommand *self)
+{
+	GTR_COMMAND_GET_CLASS (self)->start (self);
+}
+
+
+/**
+ * gtranslator_command_notify_data_arrived:
+ * @self: Command object.
+ * 
+ * Used by base classes derived from #GtranslatorCommand to emit the ::data-arrived
+ * signal. This method should not be used by client code or #GtranslatorCommand 
+ * objects that are not base classes. 
+ */
+void
+gtranslator_command_notify_data_arrived (GtranslatorCommand *self)
+{
+	GTR_COMMAND_GET_CLASS (self)->notify_data_arrived (self);
+}
+
+/**
+ * gtranslator_command_notify_complete:
+ * @self: Command object.
+ * 
+ * Used by base classes derived from #GtranslatorCommand to emit the 
+ * ::command-finished signal. This method should not be used by client code or  
+ * #GtranslatorCommand objects that are not base classes. 
+ */
+void
+gtranslator_command_notify_complete (GtranslatorCommand *self, guint return_code)
+{
+	GTR_COMMAND_GET_CLASS (self)->notify_complete (self, return_code);
+}
+
+/**
+ * gtranslator_command_set_error_message:
+ * @self: Command object.
+ * @error_message: Error message.
+ * 
+ * Command objects use this to set error messages when they encounter some kind
+ * of failure. 
+ */
+void
+gtranslator_command_set_error_message (GtranslatorCommand *self, gchar *error_message)
+{
+	if (self->priv->error_message)
+		g_free (error_message);
+	
+	self->priv->error_message = g_strdup (error_message);
+}
+
+/**
+ * gtranslator_command_get_error_message:
+ * @self: Command object.
+ * @error_message: Error message.
+ * 
+ * Get the error message from the command, if there is one. This method is 
+ * normally used from a ::command-finished handler to report errors to the user
+ * when a command finishes. 
+ *
+ * Return value: Error message string that must be freed when no longer needed.
+ * If no error is set, return %NULL.
+ */
+gchar *
+gtranslator_command_get_error_message (GtranslatorCommand *self)
+{
+	return g_strdup (self->priv->error_message);
+}

Added: trunk/plugins/subversion/command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,75 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _GTR_COMMAND_H_
+#define _GTR_COMMAND_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_COMMAND             (gtranslator_command_get_type ())
+#define GTR_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTR_TYPE_COMMAND, GtranslatorCommand))
+#define GTR_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTR_TYPE_COMMAND, GtranslatorCommandClass))
+#define GTR_IS_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTR_TYPE_COMMAND))
+#define GTR_IS_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTR_TYPE_COMMAND))
+#define GTR_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTR_TYPE_COMMAND, GtranslatorCommandClass))
+
+typedef struct _GtranslatorCommandClass GtranslatorCommandClass;
+typedef struct _GtranslatorCommand GtranslatorCommand;
+typedef struct _GtranslatorCommandPriv GtranslatorCommandPriv;
+
+struct _GtranslatorCommandClass
+{
+	GObjectClass parent_class;
+	
+	/* Virtual Methods */
+	guint (*run) (GtranslatorCommand *self);
+	void (*start) (GtranslatorCommand *self);
+	void (*notify_data_arrived) (GtranslatorCommand *self);
+	void (*notify_complete) (GtranslatorCommand *self, guint return_code);
+	void (*set_error_message) (GtranslatorCommand *self, gchar *error_message);
+	gchar * (*get_error_message) (GtranslatorCommand *self);
+
+};
+
+struct _GtranslatorCommand
+{
+	GObject parent_instance;
+	
+	GtranslatorCommandPriv *priv;
+};
+
+GType gtranslator_command_get_type (void) G_GNUC_CONST;
+
+void gtranslator_command_start (GtranslatorCommand *self);
+void gtranslator_command_notify_data_arrived (GtranslatorCommand *self);
+void gtranslator_command_notify_complete (GtranslatorCommand *self, guint return_code);
+
+void gtranslator_command_set_error_message (GtranslatorCommand *self, gchar *error_message);
+gchar *gtranslator_command_get_error_message (GtranslatorCommand *self);
+
+G_END_DECLS
+
+#endif /* _GTR_COMMAND_H_ */

Added: trunk/plugins/subversion/commit-dialog.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/commit-dialog.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,701 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ *
+ *     Based on anjuta subversion plugin.
+ *     Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "commit-dialog.h"
+#include "utils.h"
+#include "subversion-plugin.h"
+#include "svn-status-command.h"
+#include "vcs-status-tree-view.h"
+#include "svn-status.h"
+#include "subversion-utils.h"
+#include "statusbar.h"
+#include "svn-commit-command.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <gconf/gconf-client.h>
+#include <unistd.h>
+
+
+#define GTR_COMMIT_DIALOG_GET_PRIVATE(object)	(G_TYPE_INSTANCE_GET_PRIVATE ( \
+						 	(object),	\
+						 	GTR_TYPE_COMMIT_DIALOG,     \
+						 	GtranslatorCommitDialogPrivate))
+
+#define ADD_CHANGE_LOG_KEY SUBVERSION_BASE_KEY "/add_change_log"
+
+G_DEFINE_TYPE(GtranslatorCommitDialog, gtranslator_commit_dialog, GTK_TYPE_DIALOG)
+
+struct _GtranslatorCommitDialogPrivate
+{
+	GConfClient *gconf_client;
+	
+	GtkWidget *main_box;
+	GtkWidget *changelog_view;
+	GtkWidget *status_view;
+	GtkWidget *select_all_button;
+	GtkWidget *clear_button;
+	GtkWidget *status_progress_bar;
+	GtkWidget *add_log_checkbutton;
+	
+	GtranslatorWindow *window;
+	gchar *dirname;
+};
+
+static void        send_status_command           (GtranslatorCommitDialog *dlg,
+						  GtranslatorWindow *window);
+
+static void
+select_all_status_items (GtkButton *select_all_button,
+			 GtranslatorVcsStatusTreeView *tree_view)
+{
+	gtranslator_vcs_status_tree_view_select_all (tree_view);
+}
+
+static void
+clear_all_status_selections (GtkButton *clear_button,
+			     GtranslatorVcsStatusTreeView *tree_view)
+{
+	gtranslator_vcs_status_tree_view_unselect_all (tree_view);
+}
+
+static gboolean
+pulse_timer (GtkProgressBar *progress_bar)
+{
+	gtk_progress_bar_pulse (progress_bar);
+	return TRUE;
+}
+
+static void
+stop_pulse_timer (gpointer timer_id, GtkProgressBar *progress_bar)
+{
+	g_source_remove (GPOINTER_TO_UINT (timer_id));
+}
+
+static void
+pulse_progress_bar (GtkProgressBar *progress_bar)
+{
+	guint timer_id;
+	
+	timer_id = g_timeout_add (100, (GSourceFunc) pulse_timer, 
+							  progress_bar);
+	g_object_set_data (G_OBJECT (progress_bar), "pulse-timer-id",
+					   GUINT_TO_POINTER (timer_id));
+	
+	g_object_weak_ref (G_OBJECT (progress_bar),
+					   (GWeakNotify) stop_pulse_timer,
+					   GUINT_TO_POINTER (timer_id));
+}
+
+static void
+hide_pulse_progress_bar (GtranslatorCommand *command,
+			 guint return_code,
+			 GtkProgressBar *progress_bar)
+{
+	guint timer_id;
+	
+	/* If the progress bar has already been destroyed, the timer should be 
+	 * stopped by stop_pulse_timer */
+	if (GTK_IS_PROGRESS_BAR (progress_bar))
+	{
+		timer_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (progress_bar),
+								"pulse-timer-id")); 
+		
+		g_source_remove (GPOINTER_TO_UINT (timer_id));
+		gtk_widget_hide (GTK_WIDGET (progress_bar));
+	}
+}
+
+static void
+select_all_files (GtranslatorCommand *command,
+		  guint return_code, 
+		  GtranslatorVcsStatusTreeView *status_view)
+{
+	gtranslator_vcs_status_tree_view_select_all (status_view);
+}
+
+/* This function is normally intended to disconnect stock data-arrived signal
+ * handlers in this file. It is assumed that object is the user data for the 
+ * callback. If you use any of the stock callbacks defined here, make sure 
+ * to weak ref its target with this callback. Make sure to cancel this ref
+ * by connecting cancel_data_arrived_signal_disconnect to the command-finished 
+ * signal so we don't try to disconnect signals on a destroyed command. */
+static void
+disconnect_data_arrived_signals (GtranslatorCommand *command,
+				 GObject *object)
+{
+	guint data_arrived_signal;
+	
+	if (GTR_IS_COMMAND (command))
+	{
+		data_arrived_signal = g_signal_lookup ("data-arrived",
+						       GTR_TYPE_COMMAND);
+		
+		g_signal_handlers_disconnect_matched (command,
+						      G_SIGNAL_MATCH_DATA,
+						      data_arrived_signal,
+						      0,
+						      NULL,
+						      NULL,
+						      object);
+	}
+										  
+}
+
+static void 
+cancel_data_arrived_signal_disconnect (GtranslatorCommand *command, 
+				       guint return_code,
+				       GObject *signal_target)
+{
+	g_object_weak_unref (signal_target, 
+			     (GWeakNotify) disconnect_data_arrived_signals,
+			     command);
+}
+
+static void
+on_status_command_finished (GtranslatorCommand *command,
+			    guint return_code, 
+			    GtranslatorWindow *window)
+{
+	subversion_utils_report_errors (window, command, return_code);
+	
+	svn_status_command_destroy (SVN_STATUS_COMMAND (command));
+}
+
+static void
+on_status_command_data_arrived (GtranslatorCommand *command, 
+				GtranslatorVcsStatusTreeView *tree_view)
+{
+	GQueue *status_queue;
+	SvnStatus *status;
+	gchar *path;
+
+	status_queue = svn_status_command_get_status_queue (SVN_STATUS_COMMAND (command));
+
+	while (g_queue_peek_head (status_queue))
+	{
+		status = g_queue_pop_head (status_queue);
+		path = svn_status_get_path (status);
+		
+		gtranslator_vcs_status_tree_view_add (tree_view, path, 
+						      svn_status_get_vcs_status (status),
+						      FALSE);
+		
+		svn_status_destroy (status);
+		g_free (path);
+	}
+}
+
+static void
+on_commit_command_finished (GtranslatorCommand *command,
+			    guint return_code,
+			    GtranslatorCommitDialog *dlg)
+{
+	GtranslatorStatusbar *status;
+	
+	g_return_if_fail (GTR_IS_WINDOW (dlg->priv->window));
+
+	status = GTR_STATUSBAR (gtranslator_window_get_statusbar (dlg->priv->window));
+	
+	gtranslator_statusbar_flash_message (status, 0,
+					     _("Subversion: Commit complete."));
+	
+	subversion_utils_report_errors (dlg->priv->window,
+					command, return_code);
+	
+	svn_commit_command_destroy (SVN_COMMIT_COMMAND (command));
+}
+
+static void
+on_command_info_arrived (GtranslatorCommand *command,
+			 GtranslatorWindow *window)
+{
+	GQueue *info;
+	gchar *message;
+	GtranslatorStatusbar *status;
+	
+	status = GTR_STATUSBAR (gtranslator_window_get_statusbar (window));
+	info = svn_command_get_info_queue (SVN_COMMAND (command));
+	
+	while (g_queue_peek_head (info))
+	{
+		message = g_queue_pop_head (info);
+		gtranslator_statusbar_flash_message (status, 0,
+						     message);
+		g_free (message);
+	}
+}
+
+static void
+add_changelog_to_text_view (GtkWidget *textview)
+{
+	gchar *log;
+	GtkTextBuffer *buf;
+	
+	buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+	
+	log = g_strdup_printf (" * Updated %s translation",
+	/*
+	 * Translators: Please change LANGUAGE for your language name in ENGLISH.
+	 * This string is used to fill the ChangeLog entry
+	 */
+			       C_("ChangeLog entry", "LANGUAGE"));
+	
+	gtk_text_buffer_set_text (buf, log, -1);
+	g_free (log);
+}
+
+static void
+add_changelog_entry (GtranslatorCommitDialog *dlg)
+{
+	guint tmpfd;
+	GError *error = NULL;
+	gchar *tmp_fname;
+	GFile *tmp_file;
+	gchar *changelog;
+	GFile *changelog_file;
+	GFileInputStream *istream;
+	GFileOutputStream *ostream;
+	gchar *changelog_entry;
+	
+	changelog = g_build_filename (dlg->priv->dirname,
+				      "ChangeLog",
+				      NULL);
+	
+	changelog_file = g_file_new_for_path (changelog);
+	if (!g_file_query_exists (changelog_file, NULL))
+	{
+		g_warning (_("The ChangeLog file '%s' does not exists"),
+			   changelog);
+		g_free (changelog);
+		g_object_unref (changelog_file);
+		return;
+	}
+	g_free (changelog);
+	
+	tmpfd = g_file_open_tmp (".gtranslator-changelog-XXXXXX",
+				 &tmp_fname,
+				 &error);
+	
+	if (tmpfd == -1)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		g_object_unref (changelog_file);
+		
+		/* In this case we don't have to close the file */
+		return;
+	}
+	
+	tmp_file = g_file_new_for_path (tmp_fname);
+	
+	istream = g_file_read (changelog_file, NULL, &error);
+	if (error)
+		goto free;
+	
+	ostream = g_file_append_to (tmp_file, G_FILE_CREATE_NONE,
+				    NULL, &error);
+	if (error)
+		goto free;
+	
+	/*
+	 * We move the current ChangeLog file to the temp file
+	 */
+	subversion_utils_from_file_to_file (G_INPUT_STREAM (istream),
+					    G_OUTPUT_STREAM (ostream));
+	
+	/*
+	 * Then we remove the old changelog_file
+	 */
+	g_file_delete (changelog_file, NULL, &error);
+	if (error)
+		goto free;
+	
+	/*
+	 * We create the new one
+	 */
+	ostream = g_file_create (changelog_file, G_FILE_CREATE_NONE,
+				 NULL, &error);
+	if (error)
+		goto free;
+
+	/*
+	 * Now, adding the new changelog entry
+	 */
+	changelog_entry = subversion_utils_get_changelog_entry_from_view (dlg->priv->changelog_view);
+	
+	g_output_stream_write (G_OUTPUT_STREAM (ostream), changelog_entry,
+			       g_utf8_strlen (changelog_entry, -1),
+			       NULL, &error);
+	if (error)
+		goto free;
+	
+	istream = g_file_read (tmp_file, NULL, &error);
+	if (error)
+		goto free;
+	
+	/* Now, appending from tempfile to ChangeLog file */
+	subversion_utils_from_file_to_file (G_INPUT_STREAM (istream),
+					    G_OUTPUT_STREAM (ostream));
+
+	/*
+	 * Updating the dialog
+	 */
+	gtranslator_vsc_status_tree_view_clear (GTR_VCS_STATUS_TREE_VIEW (dlg->priv->status_view));
+	send_status_command (dlg, dlg->priv->window);
+	
+free:   if (error)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+	}
+	g_object_unref (tmp_file);
+	close (tmpfd);
+	g_free (tmp_fname);
+	g_object_unref (changelog_file);
+}
+
+static void
+dialog_response_handler (GtkDialog *dlg, 
+			 gint       res_id)
+{
+	GtranslatorCommitDialog *commit = GTR_COMMIT_DIALOG (dlg);
+	
+	switch (res_id)
+	{
+		case GTK_RESPONSE_OK:
+		{
+			gchar* log = NULL;
+			GList *selected_paths;
+			SvnCommitCommand *commit_command;
+			//guint pulse_timer_id;
+			
+			log = subversion_utils_get_log_from_textview (commit->priv->changelog_view);
+			if (!g_utf8_strlen (log, -1))
+			{
+				gint result;
+				GtkWidget* dialog = gtk_message_dialog_new (GTK_WINDOW (commit->priv->window), 
+									    GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO,
+									    GTK_BUTTONS_YES_NO, 
+									    _("Are you sure that you want to pass an empty log message?"));
+				result = gtk_dialog_run (GTK_DIALOG (dialog));
+				gtk_widget_destroy (dialog);
+				if (result == GTK_RESPONSE_NO)
+				{
+					g_free (log);
+					break;
+				}
+			}
+			
+			selected_paths = gtranslator_vcs_status_tree_view_get_selected (GTR_VCS_STATUS_TREE_VIEW (commit->priv->status_view));
+
+			if (selected_paths == NULL)
+			{
+				GtkWidget* dialog = gtk_message_dialog_new (GTK_WINDOW (commit->priv->window), 
+									    GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO,
+									    GTK_BUTTONS_CLOSE, 
+									    _("You have to select at least one file to send"));
+				gtk_dialog_run (GTK_DIALOG (dialog));
+				gtk_widget_destroy (dialog);
+				g_free (log);
+				break;
+			}
+			
+			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (commit->priv->add_log_checkbutton)))
+			{
+				gchar *changelog_path;
+				
+				add_changelog_entry (commit);
+				
+				changelog_path = g_build_filename (commit->priv->dirname,
+								   "ChangeLog",
+								   NULL);
+				selected_paths = g_list_append (selected_paths,
+								changelog_path);
+			}
+				    
+			commit_command = svn_commit_command_new (selected_paths, 
+								 log,
+								 FALSE);
+			g_free (log);
+			
+			svn_command_free_path_list (selected_paths);
+		
+			/*pulse_timer_id = status_bar_progress_pulse (data->plugin,
+								    _("Subversion: " 
+								      "Committing changes "
+								      "to the "
+								      "repository..."));
+			
+			g_signal_connect (G_OBJECT (commit_command), "command-finished",
+					  G_CALLBACK (stop_status_bar_progress_pulse),
+					  GUINT_TO_POINTER (pulse_timer_id));*/
+			
+			g_signal_connect (G_OBJECT (commit_command), "command-finished",
+					  G_CALLBACK (on_commit_command_finished),
+					  commit);
+			
+			g_signal_connect (G_OBJECT (commit_command), "data-arrived",
+					  G_CALLBACK (on_command_info_arrived),
+					  commit->priv->window);
+			
+			gtranslator_command_start (GTR_COMMAND (commit_command));
+		
+			gtk_widget_hide (GTK_WIDGET (dlg));
+			break;
+		}
+		default:
+			gtk_widget_destroy (GTK_WIDGET (dlg));
+	}
+}
+
+static void
+send_status_command (GtranslatorCommitDialog *dlg,
+		     GtranslatorWindow *window)
+{
+	SvnStatusCommand *status_command;
+	GtranslatorTab *tab;
+	GtranslatorPo *po;
+	
+	/* Setting up */
+	dlg->priv->window = window;
+	tab = gtranslator_window_get_active_tab (window);
+	po = gtranslator_tab_get_po (tab);
+	g_free (dlg->priv->dirname);
+	dlg->priv->dirname = g_path_get_dirname (gtranslator_po_get_filename (po));
+	
+	status_command = svn_status_command_new (dlg->priv->dirname,
+						 TRUE, TRUE);
+	
+	g_signal_connect (G_OBJECT (status_command), "command-finished",
+			  G_CALLBACK (select_all_files),
+			  dlg->priv->status_view);
+	
+	pulse_progress_bar (GTK_PROGRESS_BAR (dlg->priv->status_progress_bar));
+	
+	g_signal_connect (G_OBJECT (status_command), "command-finished",
+			  G_CALLBACK (cancel_data_arrived_signal_disconnect),
+			  dlg->priv->status_view);
+	
+	g_signal_connect (G_OBJECT (status_command), "command-finished",
+			  G_CALLBACK (hide_pulse_progress_bar),
+			  dlg->priv->status_progress_bar);
+	
+	g_signal_connect (G_OBJECT (status_command), "command-finished",
+			  G_CALLBACK (on_status_command_finished),
+			  dlg->priv->window);
+	
+	g_signal_connect (G_OBJECT (status_command), "data-arrived",
+			  G_CALLBACK (on_status_command_data_arrived),
+			  dlg->priv->status_view);
+	
+	g_object_weak_ref (G_OBJECT (dlg->priv->status_view),
+			   (GWeakNotify) disconnect_data_arrived_signals,
+			   status_command);
+	
+	gtranslator_command_start (GTR_COMMAND (status_command));
+}
+
+static void
+on_add_log_checkbutton_toggled (GtkToggleButton *button,
+				GtranslatorCommitDialog *dlg)
+{
+	g_return_if_fail (GTR_IS_COMMIT_DIALOG (dlg));
+	
+	if (!gconf_client_key_is_writable (dlg->priv->gconf_client,
+					   ADD_CHANGE_LOG_KEY,
+					   NULL))
+		return;
+
+	gconf_client_set_bool (dlg->priv->gconf_client,
+			       ADD_CHANGE_LOG_KEY,
+			       gtk_toggle_button_get_active (button),
+			       NULL);
+}
+
+static void
+gtranslator_commit_dialog_init (GtranslatorCommitDialog *dlg)
+{
+	gboolean ret;
+	GtkWidget *error_widget;
+	GtkWidget *sw_view;
+	gboolean data;
+	
+	dlg->priv = GTR_COMMIT_DIALOG_GET_PRIVATE (dlg);
+	
+	dlg->priv->gconf_client = gconf_client_get_default ();
+	dlg->priv->dirname = NULL;
+	
+	gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+				GTK_STOCK_CANCEL,
+				GTK_RESPONSE_CANCEL,
+				GTK_STOCK_OK,
+				GTK_RESPONSE_OK,
+				NULL);
+	
+	gtk_window_set_title (GTK_WINDOW (dlg), _("Commit Changes"));
+	gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 600);
+	gtk_window_set_resizable (GTK_WINDOW (dlg), TRUE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+	
+	/* HIG defaults */
+	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->vbox), 2); /* 2 * 5 + 2 = 12 */
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->action_area), 4);
+	
+	g_signal_connect (dlg,
+			  "response",
+			  G_CALLBACK (dialog_response_handler),
+			  NULL);
+	
+	/*Glade*/
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+		"commit_main_box",
+		&error_widget,
+		
+		"commit_main_box", &dlg->priv->main_box,
+		"changelog_view", &dlg->priv->changelog_view,
+		"add_log_checkbutton", &dlg->priv->add_log_checkbutton,
+		"select_all_button", &dlg->priv->select_all_button,
+		"clear_button", &dlg->priv->clear_button,
+		"status_progress_bar", &dlg->priv->status_progress_bar,
+		"sw_view", &sw_view,
+		
+		NULL);
+	
+	if(!ret)
+	{
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		
+		return;
+	}
+	
+	/* status view */
+	dlg->priv->status_view = gtranslator_vcs_status_tree_view_new ();
+	gtk_widget_show (dlg->priv->status_view);
+	gtk_container_add (GTK_CONTAINER (sw_view),
+			   dlg->priv->status_view);
+	
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+			    dlg->priv->main_box, TRUE, TRUE, 0);
+	
+	gtk_container_set_border_width (GTK_CONTAINER (dlg->priv->main_box), 5);
+	
+	/*
+	 * We add the ChangeLog
+	 */
+	add_changelog_to_text_view (dlg->priv->changelog_view);
+	
+	g_signal_connect (dlg->priv->add_log_checkbutton, "toggled",
+			  G_CALLBACK (on_add_log_checkbutton_toggled), dlg);
+	
+	g_signal_connect (G_OBJECT (dlg->priv->select_all_button), "clicked",
+			  G_CALLBACK (select_all_status_items),
+			  dlg->priv->status_view);
+	
+	g_signal_connect (G_OBJECT (dlg->priv->clear_button), "clicked",
+			  G_CALLBACK (clear_all_status_selections),
+			  dlg->priv->status_view);
+	
+	/*
+	 * Set add_log_checkbutton value
+	 */
+	data = gconf_client_get_bool (dlg->priv->gconf_client,
+				      ADD_CHANGE_LOG_KEY,
+				      NULL);
+	
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dlg->priv->add_log_checkbutton),
+				      data);
+}
+
+static void
+gtranslator_commit_dialog_finalize (GObject *object)
+{
+	GtranslatorCommitDialog *dlg = GTR_COMMIT_DIALOG (object);
+	
+	gconf_client_suggest_sync (dlg->priv->gconf_client, NULL);
+
+	g_object_unref (G_OBJECT (dlg->priv->gconf_client));
+	
+	g_free (dlg->priv->dirname);
+	
+	G_OBJECT_CLASS (gtranslator_commit_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_commit_dialog_class_init (GtranslatorCommitDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GtranslatorCommitDialogPrivate));
+
+	object_class->finalize = gtranslator_commit_dialog_finalize;
+}
+
+void
+gtranslator_show_commit_dialog (GtranslatorWindow *window)
+{
+	static GtranslatorCommitDialog *dlg = NULL;
+	
+	g_return_if_fail (GTR_IS_WINDOW (window));
+	
+	if(dlg == NULL)
+	{
+		dlg = g_object_new (GTR_TYPE_COMMIT_DIALOG, NULL);
+		
+		gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg),
+						    TRUE);
+
+		send_status_command (dlg, window);
+		
+		g_signal_connect (dlg,
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  &dlg);
+		gtk_widget_show (GTK_WIDGET (dlg));
+	}
+	else
+	{
+		/* We clean the current status treeview and send another
+		 status command */
+		gtranslator_vsc_status_tree_view_clear (GTR_VCS_STATUS_TREE_VIEW (dlg->priv->status_view));
+		send_status_command (dlg, dlg->priv->window);
+	}
+	
+	if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (dlg)))
+	{
+		gtk_window_set_transient_for (GTK_WINDOW (dlg),
+					      GTK_WINDOW (window));
+	}
+
+	gtk_window_present (GTK_WINDOW (dlg));
+}

Added: trunk/plugins/subversion/commit-dialog.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/commit-dialog.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __COMMIT_DIALOG_H__
+#define __COMMIT_DIALOG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "window.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTR_TYPE_COMMIT_DIALOG		(gtranslator_commit_dialog_get_type ())
+#define GTR_COMMIT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_COMMIT_DIALOG, GtranslatorCommitDialog))
+#define GTR_COMMIT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_COMMIT_DIALOG, GtranslatorCommitDialogClass))
+#define GTR_IS_COMMIT_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_COMMIT_DIALOG))
+#define GTR_IS_COMMIT_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_COMMIT_DIALOG))
+#define GTR_COMMIT_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_COMMIT_DIALOG, GtranslatorCommitDialogClass))
+
+/* Private structure type */
+typedef struct _GtranslatorCommitDialogPrivate	GtranslatorCommitDialogPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GtranslatorCommitDialog		GtranslatorCommitDialog;
+
+struct _GtranslatorCommitDialog
+{
+	GtkDialog parent_instance;
+	
+	/*< private > */
+	GtranslatorCommitDialogPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtranslatorCommitDialogClass	GtranslatorCommitDialogClass;
+
+struct _GtranslatorCommitDialogClass
+{
+	GtkDialogClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType		 gtranslator_commit_dialog_get_type               (void) G_GNUC_CONST;
+
+GType		 gtranslator_commit_dialog_register_type          (GTypeModule * module);
+
+void         gtranslator_show_commit_dialog                   (GtranslatorWindow *window);
+
+G_END_DECLS
+
+#endif /* __COMMIT_DIALOG_H__ */

Added: trunk/plugins/subversion/diff-dialog.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/diff-dialog.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "diff-dialog.h"
+#include "subversion-plugin.h"
+#include "svn-diff-command.h"
+#include "svn-cat-command.h"
+#include "utils.h"
+#include "svn-command.h"
+#include "statusbar.h"
+#include "subversion-utils.h"
+#include "subversion-plugin.h"
+#include "tab.h"
+#include "po.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <gconf/gconf-client.h>
+#include <unistd.h>
+
+#define USE_CONFIGURED_PROGRAM_KEY SUBVERSION_BASE_KEY "/use_configured_program"
+#define SAVE_DIFF_KEY SUBVERSION_BASE_KEY "/save_diff"
+
+#define GTR_DIFF_DIALOG_GET_PRIVATE(object)	(G_TYPE_INSTANCE_GET_PRIVATE ( \
+						 	(object),	\
+						 	GTR_TYPE_DIFF_DIALOG,     \
+						 	GtranslatorDiffDialogPrivate))
+
+
+G_DEFINE_TYPE(GtranslatorDiffDialog, gtranslator_diff_dialog, GTK_TYPE_DIALOG)
+
+struct _GtranslatorDiffDialogPrivate
+{
+	GConfClient *gconf_client;
+	
+	GtkWidget *main_box;
+	GtkWidget *use_configured_program;
+	GtkWidget *save_diff;
+	GtkWidget *diff_filename_entry;
+	GtkWidget *diff_find;
+	
+	gchar *filename;
+
+	GtranslatorWindow *window;
+};
+
+static void
+on_diff_command_finished (GtranslatorCommand *command,
+			  guint return_code,
+			  GtranslatorDiffDialog *dlg)
+{
+	GtranslatorStatusbar *status;
+	
+	status = GTR_STATUSBAR (gtranslator_window_get_statusbar (dlg->priv->window));
+	
+	gtranslator_statusbar_flash_message (status, 0,
+					     _("Subversion: Diff complete."));
+	
+	subversion_utils_report_errors (dlg->priv->window, 
+					command, return_code);
+	
+	if (SVN_IS_DIFF_COMMAND (command))
+		svn_diff_command_destroy (SVN_DIFF_COMMAND (command));	
+	else svn_cat_command_destroy (SVN_CAT_COMMAND (command));
+}
+
+static void
+show_in_program (const gchar *program_name,
+		 const gchar *line_arg,
+		 const gchar *path1,
+		 const gchar *path2)
+{
+	gchar *open[5];
+
+	if (g_find_program_in_path (program_name))
+	{
+		open[0] = g_strdup (program_name);
+	}
+	else
+	{
+		GtkWidget *dialog;
+		
+		dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+						 GTK_DIALOG_MODAL,
+						 GTK_BUTTONS_CLOSE,
+						 _("Please, install %s to be able to diff the file"),
+						 program_name);
+		gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+	}
+	
+	open[1] = g_strdup (path1);
+	open[2] = g_strdup (path2);
+	
+	if (strcmp (line_arg, ""))
+	{
+		open[3] = g_strdup_printf ("%s",line_arg);
+		open[4] = NULL;
+	}
+	else open[3] = NULL;
+					
+	gdk_spawn_on_screen (gdk_screen_get_default (),
+			     NULL,
+			     open,
+			     NULL,
+			     G_SPAWN_SEARCH_PATH,
+			     NULL,
+			     NULL, NULL, NULL);
+	g_free (open[0]);
+	g_free (open[1]);
+	g_free (open[2]);
+	g_free (open[3]);
+}
+
+static void
+on_cat_command_info_arrived (GtranslatorCommand *command,
+			     GtranslatorDiffDialog *dlg)
+{
+	GQueue *output;
+	gchar *line;
+	guint tmpfd;
+	GError *error = NULL;
+	gchar *tmp_fname;
+	GFile *tmp_file;
+	GFileOutputStream *ostream;
+	gboolean check;
+	gchar *program_name;
+	gchar *program_arg;
+	
+	output = svn_cat_command_get_output (SVN_CAT_COMMAND (command));
+	
+	tmpfd = g_file_open_tmp (".gtranslator-changelog-XXXXXX",
+				 &tmp_fname,
+				 &error);
+	
+	if (tmpfd == -1)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		
+		/* In this case we don't have to close the file */
+		return;
+	}
+	
+	tmp_file = g_file_new_for_path (tmp_fname);
+		    
+	ostream = g_file_append_to (tmp_file, G_FILE_CREATE_NONE,
+				    NULL, &error);
+	
+	while (g_queue_peek_head (output))
+	{
+		line = g_queue_pop_head (output);
+		
+		g_output_stream_write (G_OUTPUT_STREAM (ostream), line,
+				       strlen (line),
+				       NULL, &error);
+		
+		g_free (line);
+		
+		if (error)
+			break;
+	}
+	
+	if (error)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		error = NULL;
+	}
+	
+	if (!g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &error))
+	{
+		g_warning (error->message);
+		g_error_free (error);
+	}
+	
+	/*
+	 * Check if we have to show it in an external diff program
+	 */
+	check = gconf_client_get_bool (dlg->priv->gconf_client,
+				       USE_CONFIGURED_PROGRAM_KEY,
+				       NULL);
+	
+	if (check)
+	{
+		program_name = gconf_client_get_string (dlg->priv->gconf_client,
+							PROGRAM_NAME_KEY,
+							NULL);
+		program_arg = gconf_client_get_string (dlg->priv->gconf_client,
+						       LINE_ARGUMENT_KEY,
+						       NULL);
+		
+		show_in_program (program_name, program_arg,
+				 tmp_fname, dlg->priv->filename);
+		
+		g_free (program_name);
+		g_free (program_arg);
+	}
+	
+	close (tmpfd);
+	g_free (tmp_fname);
+	g_object_unref (tmp_file);
+}
+
+static void
+on_diff_command_info_arrived (GtranslatorCommand *command,
+			      GtranslatorDiffDialog *dlg)
+{
+	GQueue *output;
+	gchar *line;
+	GError *error = NULL;
+	GFile *tmp_file;
+	const gchar *tmp_fname;
+	GFileOutputStream *ostream;
+	
+	output = svn_diff_command_get_output (SVN_DIFF_COMMAND (command));
+	
+	tmp_fname = gtk_entry_get_text (GTK_ENTRY (dlg->priv->diff_filename_entry));
+	
+	tmp_file = g_file_new_for_path (tmp_fname);
+	
+	if (g_file_query_exists (tmp_file, NULL))
+	{
+		if (!g_file_delete (tmp_file, NULL, &error))
+		{
+			g_warning (error->message);
+			g_error_free (error);
+			
+			g_object_unref (tmp_file);
+			return;
+		}
+	}
+	
+	ostream = g_file_create (tmp_file, G_FILE_CREATE_NONE,
+				 NULL, &error);
+	
+	while (g_queue_peek_head (output))
+	{
+		line = g_queue_pop_head (output);
+		
+		g_output_stream_write (G_OUTPUT_STREAM (ostream), line,
+				       strlen (line),
+				       NULL, &error);
+		
+		g_free (line);
+		
+		if (error)
+			break;
+	}
+	
+	if (error)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		error = NULL;
+	}
+	
+	if (!g_output_stream_close (G_OUTPUT_STREAM (ostream), NULL, &error))
+	{
+		g_warning (error->message);
+		g_error_free (error);
+	}
+	
+	g_object_unref (tmp_file);
+}
+
+static void
+send_diff_command (GtranslatorDiffDialog *dlg)
+{
+	SvnDiffCommand *diff_command;
+	
+	diff_command = svn_diff_command_new (dlg->priv->filename,
+					     SVN_DIFF_REVISION_NONE,
+					     SVN_DIFF_REVISION_NONE,
+					     TRUE);
+	
+	g_signal_connect (G_OBJECT (diff_command), "command-finished",
+			  G_CALLBACK (on_diff_command_finished),
+			  dlg);
+	
+	g_signal_connect (G_OBJECT (diff_command), "data-arrived",
+			  G_CALLBACK (on_diff_command_info_arrived),
+			  dlg);
+	
+	gtranslator_command_start (GTR_COMMAND (diff_command));
+}
+
+static void
+send_cat_command (GtranslatorDiffDialog *dlg)
+{
+	SvnCatCommand *cat_command;
+	
+	cat_command = svn_cat_command_new (dlg->priv->filename,
+					   SVN_DIFF_REVISION_NONE);
+	
+	g_signal_connect (G_OBJECT (cat_command), "command-finished",
+			  G_CALLBACK (on_diff_command_finished),
+			  dlg);
+	
+	g_signal_connect (G_OBJECT (cat_command), "data-arrived",
+			  G_CALLBACK (on_cat_command_info_arrived),
+			  dlg);
+	
+	gtranslator_command_start (GTR_COMMAND (cat_command));
+}
+
+static void
+dialog_response_handler (GtranslatorDiffDialog *dlg, 
+			 gint       res_id)
+{
+	switch (res_id)
+	{
+		case GTK_RESPONSE_OK:
+		{	
+			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dlg->priv->save_diff)))
+				send_diff_command (dlg);
+			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dlg->priv->use_configured_program)))
+				send_cat_command (dlg);
+			gtk_widget_hide (GTK_WIDGET (dlg));
+			break;
+		}
+		default:
+			gtk_widget_hide (GTK_WIDGET (dlg));
+	}
+}
+
+static void
+setup_diff_filename_entry (GtranslatorDiffDialog *dlg)
+{
+	gchar *file;
+	
+	file = g_strdup_printf ("%s.diff", dlg->priv->filename);
+	
+	gtk_entry_set_text (GTK_ENTRY (dlg->priv->diff_filename_entry),
+			    file);
+	g_free (file);
+}
+
+static void
+use_configured_program_toggled (GtkToggleButton *button,
+				GtranslatorDiffDialog *dlg)
+{
+	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
+	
+	if (!gconf_client_key_is_writable (dlg->priv->gconf_client,
+					   USE_CONFIGURED_PROGRAM_KEY,
+					   NULL))
+		return;
+
+	gconf_client_set_bool (dlg->priv->gconf_client,
+			       USE_CONFIGURED_PROGRAM_KEY,
+			       gtk_toggle_button_get_active (button),
+			       NULL);
+}
+
+static void
+save_diff_toggled (GtkToggleButton *button,
+		   GtranslatorDiffDialog *dlg)
+{
+	gboolean active;
+	
+	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button));
+	
+	active = gtk_toggle_button_get_active (button);
+	
+	if (!gconf_client_key_is_writable (dlg->priv->gconf_client,
+					   SAVE_DIFF_KEY,
+					   NULL))
+		return;
+
+	gconf_client_set_bool (dlg->priv->gconf_client,
+			       SAVE_DIFF_KEY,
+			       active,
+			       NULL);
+	
+
+	
+	gtk_widget_set_sensitive (dlg->priv->diff_filename_entry, active);
+	gtk_widget_set_sensitive (dlg->priv->diff_find, active);
+}
+
+static void
+on_diff_find_clicked (GtkButton *button,
+		      GtranslatorDiffDialog *dlg)
+{
+	GtkWidget *dialog;
+	gint res;
+	
+	dialog = gtk_file_chooser_dialog_new (_("Diff file"),
+					      GTK_WINDOW (dlg->priv->window),
+					      GTK_FILE_CHOOSER_ACTION_SAVE,
+					      GTK_STOCK_CANCEL,
+					      GTK_RESPONSE_CANCEL,
+					      GTK_STOCK_OK,
+					      GTK_RESPONSE_OK,
+					      NULL);
+	res = gtk_dialog_run (GTK_DIALOG (dialog));
+	switch (res)
+	{
+		case GTK_RESPONSE_OK: 
+		{
+			gchar *filename;
+			
+			filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+			gtk_entry_set_text (GTK_ENTRY (dlg->priv->diff_filename_entry),
+					    filename);
+			g_free (filename);
+			break;
+		}
+		default:
+			break;
+	}
+	gtk_widget_destroy (dialog);
+}
+
+static void
+set_values (GtranslatorDiffDialog *dlg)
+{
+	gboolean data;
+	
+	/* Use configured program */
+	data = gconf_client_get_bool (dlg->priv->gconf_client,
+				      USE_CONFIGURED_PROGRAM_KEY,
+				      NULL);
+	
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dlg->priv->use_configured_program),
+				      data);
+	
+	/* Save diff */
+	data = gconf_client_get_bool (dlg->priv->gconf_client,
+				      SAVE_DIFF_KEY,
+				      NULL);
+	
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dlg->priv->save_diff),
+				      data);
+}
+
+static void
+gtranslator_diff_dialog_init (GtranslatorDiffDialog *dlg)
+{
+	gboolean ret;
+	GtkWidget *error_widget;
+	gboolean active;
+	
+	dlg->priv = GTR_DIFF_DIALOG_GET_PRIVATE (dlg);
+	
+	dlg->priv->gconf_client = gconf_client_get_default ();
+	dlg->priv->filename = NULL;
+	
+	gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+				GTK_STOCK_CLOSE,
+				GTK_RESPONSE_CLOSE,
+				GTK_STOCK_OK,
+				GTK_RESPONSE_OK,
+				NULL);
+	
+	gtk_window_set_title (GTK_WINDOW (dlg), _("Diff"));
+	gtk_window_set_default_size (GTK_WINDOW (dlg), 500, 300);
+	gtk_window_set_resizable (GTK_WINDOW (dlg), TRUE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+	
+	/* HIG defaults */
+	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->vbox), 2); /* 2 * 5 + 2 = 12 */
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->action_area), 4);
+	
+	g_signal_connect (dlg,
+			  "response",
+			  G_CALLBACK (dialog_response_handler),
+			  NULL);
+	
+	/*Glade*/
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+		"diff_main_box",
+		&error_widget,
+		
+		"diff_main_box", &dlg->priv->main_box,
+		"use_configured_program", &dlg->priv->use_configured_program,
+		"save_diff", &dlg->priv->save_diff,
+		"diff_filename_entry", &dlg->priv->diff_filename_entry,
+		"diff_find", &dlg->priv->diff_find,
+		
+		NULL);
+	
+	if(!ret)
+	{
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		
+		return;
+	}
+	
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+			    dlg->priv->main_box, TRUE, TRUE, 0);
+	
+	gtk_container_set_border_width (GTK_CONTAINER (dlg->priv->main_box), 5);
+	
+	g_signal_connect (dlg->priv->use_configured_program, "toggled",
+			  G_CALLBACK (use_configured_program_toggled), dlg);
+	
+	g_signal_connect (dlg->priv->save_diff, "toggled",
+			  G_CALLBACK (save_diff_toggled), dlg);
+	
+	g_signal_connect (dlg->priv->diff_find, "clicked",
+			  G_CALLBACK (on_diff_find_clicked), dlg);
+	
+	/*
+	 * Set values
+	 */
+	set_values (dlg);
+	
+	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dlg->priv->save_diff));
+	gtk_widget_set_sensitive (dlg->priv->diff_filename_entry, active);
+	gtk_widget_set_sensitive (dlg->priv->diff_find, active);
+}
+
+static void
+gtranslator_diff_dialog_finalize (GObject *object)
+{
+	GtranslatorDiffDialog *dlg = GTR_DIFF_DIALOG (object);
+	
+	gconf_client_suggest_sync (dlg->priv->gconf_client, NULL);
+
+	g_object_unref (G_OBJECT (dlg->priv->gconf_client));
+	
+	g_free (dlg->priv->filename);
+	
+	G_OBJECT_CLASS (gtranslator_diff_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_diff_dialog_class_init (GtranslatorDiffDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GtranslatorDiffDialogPrivate));
+
+	object_class->finalize = gtranslator_diff_dialog_finalize;
+}
+
+void
+gtranslator_show_diff_dialog (GtranslatorWindow *window)
+{
+	static GtranslatorDiffDialog *dlg = NULL;
+	const gchar *filename;
+	GtranslatorTab *tab;
+	GtranslatorPo *po;
+	
+	g_return_if_fail (GTR_IS_WINDOW (window));
+	
+	tab = gtranslator_window_get_active_tab (window);
+	po = gtranslator_tab_get_po (tab);
+	filename = gtranslator_po_get_filename (po);
+	
+	if(dlg == NULL)
+	{
+		dlg = g_object_new (GTR_TYPE_DIFF_DIALOG, NULL);
+		
+		gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg),
+						    TRUE);
+		
+		dlg->priv->window = window;
+		
+		g_signal_connect (dlg,
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  &dlg);
+
+		gtk_widget_show (GTK_WIDGET (dlg));
+	}
+	
+	//As we are not destroying the dialog we have to free the filename
+	g_free (dlg->priv->filename);
+	dlg->priv->filename = g_strdup (filename);
+	setup_diff_filename_entry (dlg);
+	
+	if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (dlg)))
+	{
+		gtk_window_set_transient_for (GTK_WINDOW (dlg),
+					      GTK_WINDOW (window));
+	}
+
+	gtk_window_present (GTK_WINDOW (dlg));
+}

Added: trunk/plugins/subversion/diff-dialog.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/diff-dialog.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __DIFF_DIALOG_H__
+#define __DIFF_DIALOG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "window.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTR_TYPE_DIFF_DIALOG		(gtranslator_diff_dialog_get_type ())
+#define GTR_DIFF_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_DIFF_DIALOG, GtranslatorDiffDialog))
+#define GTR_DIFF_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_DIFF_DIALOG, GtranslatorDiffDialogClass))
+#define GTR_IS_DIFF_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_DIFF_DIALOG))
+#define GTR_IS_DIFF_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_DIFF_DIALOG))
+#define GTR_DIFF_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_DIFF_DIALOG, GtranslatorDiffDialogClass))
+
+/* Private structure type */
+typedef struct _GtranslatorDiffDialogPrivate	GtranslatorDiffDialogPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GtranslatorDiffDialog		GtranslatorDiffDialog;
+
+struct _GtranslatorDiffDialog
+{
+	GtkDialog parent_instance;
+	
+	/*< private > */
+	GtranslatorDiffDialogPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtranslatorDiffDialogClass	GtranslatorDiffDialogClass;
+
+struct _GtranslatorDiffDialogClass
+{
+	GtkDialogClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType		 gtranslator_diff_dialog_get_type               (void) G_GNUC_CONST;
+
+GType		 gtranslator_diff_dialog_register_type          (GTypeModule * module);
+
+void	     gtranslator_show_diff_dialog                   (GtranslatorWindow *window);
+
+G_END_DECLS
+
+#endif /* __DIFF_DIALOG_H__ */

Added: trunk/plugins/subversion/subversion-enum-types.c.template
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-enum-types.c.template	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include "gtranslator-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 ***/

Added: trunk/plugins/subversion/subversion-enum-types.h.template
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-enum-types.h.template	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,26 @@
+/*** BEGIN file-header ***/
+#ifndef __GTR_ENUM_TYPES_H__
+#define __GTR_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define GTR_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 /* __GEDIT_ENUM_TYPES_H__ */
+/*** END file-tail ***/

Added: trunk/plugins/subversion/subversion-plugin.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-plugin.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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
+ *     MERCHANPOILITY 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "subversion-plugin.h"
+#include "subversion-utils.h"
+#include "svn-add-command.h"
+#include "window.h"
+#include "statusbar.h"
+#include "commit-dialog.h"
+#include "update-dialog.h"
+#include "diff-dialog.h"
+#include "checkout-dialog.h"
+#include "utils.h"
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <gconf/gconf-client.h>
+
+#define WINDOW_DATA_KEY "GtranslatorSubversionPluginWindowData"
+
+#define GTR_SUBVERSION_PLUGIN_GET_PRIVATE(object) \
+				(G_TYPE_INSTANCE_GET_PRIVATE ((object),	\
+				GTR_TYPE_SUBVERSION_PLUGIN,		\
+				GtranslatorSubversionPluginPrivate))
+
+GTR_PLUGIN_REGISTER_TYPE(GtranslatorSubversionPlugin, gtranslator_subversion_plugin)
+
+struct _GtranslatorSubversionPluginPrivate
+{
+	GConfClient *gconf_client;
+	
+	/* Dialog stuff */
+	GtkWidget *dialog;
+	
+	GtkWidget *main_box;
+	GtkWidget *program_name_entry;
+	GtkWidget *line_argument_entry;
+};
+
+static void
+on_update_activated (GtkAction *action,
+		     GtranslatorWindow *window)
+{
+	gtranslator_show_update_dialog (window);
+}
+
+static void
+on_commit_activated (GtkAction *action,
+		     GtranslatorWindow *window)
+{
+	gtranslator_show_commit_dialog (window);
+}
+
+static void
+on_add_command_finished (GtranslatorCommand *command,
+			 guint return_code, 
+			 GtranslatorWindow *window)
+{
+	GtranslatorStatusbar *statusbar;
+	
+	statusbar = GTR_STATUSBAR (gtranslator_window_get_statusbar (window));
+	
+	gtranslator_statusbar_flash_message (statusbar, 0,
+					     _("Subversion: File will be added on next "
+					       "commit."));
+
+	subversion_utils_report_errors (window, command, return_code);
+	
+	svn_add_command_destroy (SVN_ADD_COMMAND (command));
+}
+
+static void
+on_add_activated (GtkAction *action,
+		  GtranslatorWindow *window)
+{
+	GtranslatorTab *tab;
+	GtranslatorPo *po;
+	SvnAddCommand *add_command;
+	
+	tab = gtranslator_window_get_active_tab (window);
+	po = gtranslator_tab_get_po (tab);
+
+	add_command = svn_add_command_new ((gchar *)gtranslator_po_get_filename (po),
+					   FALSE,
+					   FALSE);
+
+	g_signal_connect (G_OBJECT (add_command), "command-finished",
+			  G_CALLBACK (on_add_command_finished),
+			  window);
+	
+	gtranslator_command_start (GTR_COMMAND (add_command));
+}
+
+static void
+on_diff_activated (GtkAction *action,
+		   GtranslatorWindow *window)
+{
+	gtranslator_show_diff_dialog (window);
+}
+
+static void
+on_checkout_activated (GtkAction *action,
+		       GtranslatorWindow *window)
+{
+	gtranslator_show_checkout_dialog (window);
+}
+
+static const GtkActionEntry action_entries[] =
+{	
+	{ "SubversionUpdate", GTK_STOCK_REFRESH, N_("_Update"), NULL,
+	 N_("Sync your local copy with the Subversion tree"),
+	 G_CALLBACK (on_update_activated)},
+	
+	{ "SubversionCommit", GTK_STOCK_YES, N_("_Commit"), NULL,
+	 N_("Commit your changes to the Subversion tree"),
+	 G_CALLBACK (on_commit_activated)},
+	
+	{ "SubversionAdd", GTK_STOCK_ADD, N_("_Add"), NULL,
+	 N_("Add a new file/directory to the Subversion tree"),
+	 G_CALLBACK (on_add_activated)},
+	
+	{ "SubversionDiff", GTK_STOCK_ZOOM_100, N_("_Diff"), NULL,
+	 N_("Diff local PO file with repository PO file"),
+	 G_CALLBACK (on_diff_activated)},
+	
+	{ "SubversionCheckout", GTK_STOCK_SAVE, N_("C_heckout"), "",
+	 N_("Get a new repository copy"),
+	 G_CALLBACK (on_checkout_activated)},
+	
+	{ "Subversion", NULL, N_("_Subversion") }
+};
+
+static const gchar submenu[] =
+"<ui>"
+"  <menubar name=\"MainMenu\">"
+"    <placeholder name=\"SubversionPlaceholder\">"
+"      <menu name=\"SubversionMenu\" action=\"Subversion\">"
+"        <menuitem name=\"SubversionUpdateMenu\" action=\"SubversionUpdate\"/>"
+"        <menuitem name=\"SubversionCommitMenu\" action=\"SubversionCommit\"/>"
+"        <separator />"
+"        <menuitem name=\"SubversionAddMenu\" action=\"SubversionAdd\"/>"
+"        <separator />"
+"        <menuitem name=\"SubversionDiffMenu\" action=\"SubversionDiff\"/>"
+"        <separator />"
+"        <menuitem name=\"SubversionCheckoutMenu\" action=\"SubversionCheckout\"/>"
+"      </menu>"
+"    </placeholder>"
+"  </menubar>"
+"</ui>";
+
+typedef struct
+{
+	GtkActionGroup *action_group;
+	guint           ui_id;
+} WindowData;
+
+static void
+free_window_data (WindowData *data)
+{
+	g_return_if_fail (data != NULL);
+
+	g_free (data);
+}
+
+static void
+update_ui_real (GtranslatorWindow *window,
+		WindowData   *data)
+{
+	GList *tabs;
+	GtkAction *action;
+
+	tabs = gtranslator_window_get_all_tabs (window);
+
+	action = gtk_action_group_get_action (data->action_group,
+					      "SubversionAdd");
+	gtk_action_set_sensitive (action,
+				  tabs != NULL);
+	
+	action = gtk_action_group_get_action (data->action_group,
+					      "SubversionUpdate");
+	gtk_action_set_sensitive (action,
+				  tabs != NULL);
+	
+	action = gtk_action_group_get_action (data->action_group,
+					      "SubversionCommit");
+	gtk_action_set_sensitive (action,
+				  tabs != NULL);
+	
+	action = gtk_action_group_get_action (data->action_group,
+					      "SubversionDiff");
+	gtk_action_set_sensitive (action,
+				  tabs != NULL);
+}
+
+static void
+gtranslator_subversion_plugin_init (GtranslatorSubversionPlugin *plugin)
+{
+	plugin->priv = GTR_SUBVERSION_PLUGIN_GET_PRIVATE (plugin);
+
+	plugin->priv->gconf_client = gconf_client_get_default ();
+
+	gconf_client_add_dir (plugin->priv->gconf_client,
+			      SUBVERSION_BASE_KEY,
+			      GCONF_CLIENT_PRELOAD_ONELEVEL,
+			      NULL);
+	
+	apr_initialize ();
+}
+
+static void
+gtranslator_subversion_plugin_finalize (GObject *object)
+{
+	GtranslatorSubversionPlugin *plugin = GTR_SUBVERSION_PLUGIN (object);
+	
+	gconf_client_suggest_sync (plugin->priv->gconf_client, NULL);
+
+	g_object_unref (G_OBJECT (plugin->priv->gconf_client));
+	
+	apr_terminate ();
+	
+	G_OBJECT_CLASS (gtranslator_subversion_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (GtranslatorPlugin *plugin,
+	       GtranslatorWindow *window)
+{
+	GtkUIManager *manager;
+	WindowData *data;
+	GError *error = NULL;
+	
+	g_return_if_fail (GTR_IS_WINDOW (window));
+
+	data = g_new (WindowData, 1);
+
+	manager = gtranslator_window_get_ui_manager (window);
+
+	data->action_group = gtk_action_group_new ("GtranslatorSubversionPluginActions");
+	gtk_action_group_set_translation_domain (data->action_group, 
+						 GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (data->action_group,
+				      action_entries,
+				      G_N_ELEMENTS (action_entries), 
+				      window);
+
+	gtk_ui_manager_insert_action_group (manager, data->action_group, 0);
+
+	g_object_set_data_full (G_OBJECT (window), 
+				WINDOW_DATA_KEY, 
+				data,
+				(GDestroyNotify) free_window_data);
+	
+	data->ui_id = gtk_ui_manager_add_ui_from_string (manager,
+							 submenu,
+							 -1,
+							 &error);
+	
+	if (data->ui_id == 0)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		return;
+	}
+
+	gtk_ui_manager_ensure_update (manager);
+	update_ui_real (window, data);
+}
+
+static void
+impl_deactivate (GtranslatorPlugin *plugin,
+		 GtranslatorWindow *window)
+{
+	GtkUIManager *manager;
+	WindowData *data;
+	
+	manager = gtranslator_window_get_ui_manager (window);
+
+	data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
+	g_return_if_fail (data != NULL);
+
+	gtk_ui_manager_remove_ui (manager, data->ui_id);
+	gtk_ui_manager_remove_action_group (manager, data->action_group);
+
+	g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);	
+}
+
+static void
+impl_update_ui (GtranslatorPlugin *plugin,
+		GtranslatorWindow *window)
+{
+	WindowData *data;
+
+	data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
+	g_return_if_fail (data != NULL);
+
+	update_ui_real (window, data);
+}
+
+static void
+get_program (GtranslatorSubversionPlugin *plugin)
+{
+	gchar *data;
+	
+	/* Program name */
+	data = gconf_client_get_string (plugin->priv->gconf_client,
+					PROGRAM_NAME_KEY,
+					NULL);
+	
+	if (!data)
+		data = g_strdup ("meld");
+	
+	gtk_entry_set_text (GTK_ENTRY (plugin->priv->program_name_entry), data);
+	
+	g_free (data);
+	
+	/* Line argument */
+	data = gconf_client_get_string (plugin->priv->gconf_client,
+					LINE_ARGUMENT_KEY,
+					NULL);
+	
+	if (!data)
+		data = g_strdup ("");
+	
+	gtk_entry_set_text (GTK_ENTRY (plugin->priv->line_argument_entry), data);
+	
+	g_free (data);
+}
+
+static GtkWidget *
+get_configuration_dialog (GtranslatorSubversionPlugin *plugin)
+{
+
+	gboolean ret;
+	GtkWidget *error_widget;
+	
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+						   "settings_dialog",
+						   &error_widget,
+						   "settings_dialog", &plugin->priv->dialog,
+						   "main_box", &plugin->priv->main_box,
+						   "program_name", &plugin->priv->program_name_entry,
+						   "line_argument", &plugin->priv->line_argument_entry,
+						   NULL);
+
+	if(!ret)
+	{
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (plugin->priv->dialog)->vbox),
+					     error_widget);
+		
+		return plugin->priv->dialog;
+	}
+
+	get_program (plugin);
+	
+	return plugin->priv->dialog;
+}
+
+static void
+ok_button_pressed (GtranslatorSubversionPlugin *plugin)
+{
+	const gchar *program_name;
+	const gchar *line_argument;
+	
+	/* We have to get the text from the entries */
+	program_name = gtk_entry_get_text (GTK_ENTRY (plugin->priv->program_name_entry));
+	line_argument = gtk_entry_get_text (GTK_ENTRY (plugin->priv->line_argument_entry));
+	
+	/* Now we store the data in gconf */
+	if (!gconf_client_key_is_writable (plugin->priv->gconf_client,
+					   PROGRAM_NAME_KEY,
+					   NULL))
+		return;
+
+	gconf_client_set_string (plugin->priv->gconf_client,
+				 PROGRAM_NAME_KEY,
+		       		 program_name,
+		       		 NULL);
+	
+	if (!gconf_client_key_is_writable (plugin->priv->gconf_client,
+					   LINE_ARGUMENT_KEY,
+					   NULL))
+		return;
+
+	gconf_client_set_string (plugin->priv->gconf_client,
+				 LINE_ARGUMENT_KEY,
+		       		 line_argument,
+		       		 NULL);
+}
+
+static void
+configure_dialog_response_cb (GtkWidget           *widget,
+			      gint                 response,
+			      GtranslatorSubversionPlugin *plugin)
+{
+	switch (response)
+	{
+		case GTK_RESPONSE_OK:
+		{
+			ok_button_pressed (plugin);
+
+			gtk_widget_destroy (plugin->priv->dialog);
+			break;
+		}
+		case GTK_RESPONSE_CANCEL:
+		{
+			gtk_widget_destroy (plugin->priv->dialog);
+		}
+	}
+}
+
+static GtkWidget *
+impl_create_configure_dialog (GtranslatorPlugin *plugin)
+{
+	GtkWidget *dialog;
+	
+	dialog = get_configuration_dialog (GTR_SUBVERSION_PLUGIN (plugin));
+	
+	g_signal_connect (dialog,
+			  "response",
+			  G_CALLBACK (configure_dialog_response_cb),
+			  GTR_SUBVERSION_PLUGIN (plugin));
+	g_signal_connect (dialog,
+			  "destroy",
+			  G_CALLBACK (gtk_widget_destroy),
+			  &dialog);
+	
+	return dialog;
+}
+
+static void
+gtranslator_subversion_plugin_class_init (GtranslatorSubversionPluginClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorPluginClass *plugin_class = GTR_PLUGIN_CLASS (klass);
+
+	object_class->finalize = gtranslator_subversion_plugin_finalize;
+
+	plugin_class->activate = impl_activate;
+	plugin_class->deactivate = impl_deactivate;
+	plugin_class->update_ui = impl_update_ui;
+	plugin_class->create_configure_dialog = impl_create_configure_dialog;
+	
+	g_type_class_add_private (object_class, sizeof (GtranslatorSubversionPluginPrivate));
+}

Added: trunk/plugins/subversion/subversion-plugin.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-plugin.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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
+ *     MERCHANPOILITY 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __GTR_SUBVERSION_PLUGIN_H__
+#define __GTR_SUBVERSION_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "plugin.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTR_TYPE_SUBVERSION_PLUGIN		(gtranslator_subversion_plugin_get_type ())
+#define GTR_SUBVERSION_PLUGIN(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_SUBVERSION_PLUGIN, GtranslatorSubversionPlugin))
+#define GTR_SUBVERSION_PLUGIN_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_SUBVERSION_PLUGIN, GtranslatorSubversionPluginClass))
+#define GTR_IS_SUBVERSION_PLUGIN(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_SUBVERSION_PLUGIN))
+#define GTR_IS_SUBVERSION_PLUGIN_CLASS(k)		(G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_SUBVERSION_PLUGIN))
+#define GTR_SUBVERSION_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_SUBVERSION_PLUGIN_PLUGIN, GtranslatorSubversionPluginClass))
+
+#define GLADE_FILE DATADIR "/subversion.glade"
+
+/* Gconf keys */
+#define SUBVERSION_BASE_KEY "/apps/gtranslator/plugins/subversion"
+#define PROGRAM_NAME_KEY SUBVERSION_BASE_KEY "/program_name"
+#define LINE_ARGUMENT_KEY SUBVERSION_BASE_KEY "/line_argument"
+
+/* Private structure type */
+typedef struct _GtranslatorSubversionPluginPrivate	GtranslatorSubversionPluginPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GtranslatorSubversionPlugin		GtranslatorSubversionPlugin;
+
+struct _GtranslatorSubversionPlugin
+{
+	GtranslatorPlugin parent_instance;
+
+	GtranslatorSubversionPluginPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtranslatorSubversionPluginClass	GtranslatorSubversionPluginClass;
+
+struct _GtranslatorSubversionPluginClass
+{
+	GtranslatorPluginClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType	gtranslator_subversion_plugin_get_type	(void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_gtranslator_plugin (GTypeModule *module);
+
+G_END_DECLS
+
+#endif /* __GTR_SUBVERSION_PLUGIN_H__ */

Added: trunk/plugins/subversion/subversion-utils.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-utils.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ *
+ *     Based on anjuta subversion plugin.
+ *     Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "command.h"
+#include "subversion-utils.h"
+#include "utils.h"
+#include "statusbar.h"
+#include "svn-command.h"
+#include "application.h"
+#include "profile.h"
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+typedef struct _PulseProgressData
+{
+	GtranslatorStatusbar *status;
+	gchar *text;
+}PulseProgressData;
+
+void
+subversion_utils_report_errors (GtranslatorWindow *window,
+				GtranslatorCommand *command,
+				guint error_code)
+{
+	GtkWidget *dialog;
+	
+	if (error_code)
+	{
+		gchar *message;
+		
+		message = gtranslator_command_get_error_message (command);
+		dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+						 GTK_DIALOG_DESTROY_WITH_PARENT,
+						 GTK_MESSAGE_ERROR,
+						 GTK_BUTTONS_CLOSE,
+						 message);
+		g_free (message);
+		
+		gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+	}
+}
+
+gchar * 
+subversion_utils_get_log_from_textview (GtkWidget* textview)
+{
+	gchar* log;
+	GtkTextBuffer* textbuf;
+	GtkTextIter iterbegin, iterend;
+	gchar* escaped_log;
+	
+	textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
+	gtk_text_buffer_get_start_iter(textbuf, &iterbegin);
+	gtk_text_buffer_get_end_iter(textbuf, &iterend) ;
+	log = gtk_text_buffer_get_text(textbuf, &iterbegin, &iterend, FALSE);
+
+	escaped_log = gtranslator_utils_escape_search_text (log);
+	return escaped_log;
+}
+
+/*guint
+subversion_utils_status_bar_progress_pulse (GtranslatorWindow *window, gchar *text)
+{
+	PulseProgressData *data;
+	
+	data = g_new0 (PulseProgressData, 1);
+	data->status = gtranslator_window_get_statusbar (window);
+	data->text = g_strdup (text);
+	
+	return g_timeout_add_full (G_PRIORITY_DEFAULT, 100,  
+				   (GSourceFunc) status_pulse_timer, data,
+				   (GDestroyNotify) on_pulse_timer_destroyed);
+}*/
+
+void
+subversion_utils_from_file_to_file (GInputStream *istream,
+				    GOutputStream *ostream)
+{
+	gsize bytes = 1;
+	GError *error = NULL;
+	gchar buffer[4096];
+	static gint i = 0;
+	i++;
+	
+	while (bytes != 0 && bytes != -1)
+	{
+		bytes = g_input_stream_read (istream, buffer,
+					     sizeof (buffer),
+					     NULL, &error);
+		if (error)
+			break;
+		g_output_stream_write (ostream, buffer,
+				       sizeof (buffer),
+				       NULL, &error);
+		if (error)
+			break;
+	}
+	
+	if (error)
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		error = NULL;
+	}
+	
+	if (!g_output_stream_close (ostream, NULL, &error))
+	{
+		g_warning (error->message);
+		g_error_free (error);
+		error = NULL;
+	}
+	if (!g_input_stream_close (istream, NULL, &error))
+	{
+		g_warning (error->message);
+		g_error_free (error);
+	}
+}
+
+gchar *
+subversion_utils_get_changelog_entry_from_view (GtkWidget *view)
+{
+	gchar *log;
+	GtranslatorProfile *profile;
+	gchar *name;
+	gchar *email;
+	gchar *changelog_entry;
+	
+	log = subversion_utils_get_log_from_textview (view);
+	
+	profile = gtranslator_application_get_active_profile (GTR_APP);
+	name = gtranslator_profile_get_author_name (profile);
+	email = gtranslator_profile_get_author_email (profile);
+	
+	//FIXME: Is missing the date
+	changelog_entry = g_strdup_printf ("date  %s  <%s>\n"
+					   "\n\t %s\n\n", name, email,
+					   log);
+	g_free (log);
+	//g_free (name);
+	//g_free (email);
+	
+	return changelog_entry;
+}
\ No newline at end of file

Added: trunk/plugins/subversion/subversion-utils.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion-utils.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ *
+ *     Based on anjuta subversion plugin.
+ *     Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef GTR_SUBVERSION_UTILS_H
+#define GTR_SUBVERSION_UTILS_H 1
+
+#include <gtk/gtkwidget.h>
+#include <gtk/gtkwindow.h>
+#include <gio/gio.h>
+#include "window.h"
+#include "command.h"
+
+void        subversion_utils_report_errors         (GtranslatorWindow *window,
+						    GtranslatorCommand *command,
+						    guint error_code);
+
+gchar      *subversion_utils_get_log_from_textview (GtkWidget* textview);
+
+void        subversion_utils_from_file_to_file     (GInputStream *istream,
+						    GOutputStream *ostream);
+
+gchar      *subversion_utils_get_changelog_entry_from_view (GtkWidget *view);
+
+#endif

Added: trunk/plugins/subversion/subversion.glade
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion.glade	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,1169 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Tue Jul 15 15:43:24 2008 -->
+<glade-interface>
+  <widget class="GtkDialog" id="svn_user_auth">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Repository authorization</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label1">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Realm:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="auth_realm">
+                    <property name="visible">True</property>
+                    <property name="label">Realm</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox2">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Username:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="username_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox3">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label4">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Password:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="password_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox4">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="remember_pwd">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Remember Password</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button2">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="svn_server_trust">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkHBox" id="hbox5">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Realm:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="realm_label">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">label</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="server_info_label">
+                <property name="visible">True</property>
+                <property name="xalign">0.10000000149011612</property>
+                <property name="label" translatable="yes">label</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="remember_check">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Remember this decision</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button3">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button4">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-yes</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="commit_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Send Changes</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox3">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="commit_main_box">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label6">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Log Message:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox6">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label5">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTextView" id="changelog_view">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox11">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label22">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="add_log_checkbutton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Add Log Message to ChangeLog file</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label7">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Select files to Commit:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox7">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label8">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkScrolledWindow" id="sw_view">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox17">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label24">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkProgressBar" id="status_progress_bar">
+                    <property name="visible">True</property>
+                    <property name="text" translatable="yes">Retrieving status...</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">5</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox8">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label23">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">  </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="select_all_button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="label" translatable="yes">gtk-select-all</property>
+                    <property name="use_stock">True</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="clear_button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="label" translatable="yes">gtk-clear</property>
+                    <property name="use_stock">True</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">6</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area3">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button6">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button5">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-3</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="update_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Update repository</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox4">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="update_main_box">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Directory to update:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox10">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label12">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkFileChooserButton" id="dir_button">
+                    <property name="visible">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label9">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Information:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox9">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label10">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="update_treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_clickable">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area4">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button8">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-refresh</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button7">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-7</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="settings_dialog">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox5">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="main_box">
+            <property name="visible">True</property>
+            <property name="border_width">12</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label13">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Diff program:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox12">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label14">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label15">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Program name:</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="program_name">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="padding">6</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox13">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label16">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="label17">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">Line argument:</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="line_argument">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area5">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button10">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button9">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-5</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="diff_dialog">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox6">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="diff_main_box">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label18">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Diff options:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox14">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label19">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="use_configured_program">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Use configured program to view the diff</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox15">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label20">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="save_diff">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Save the diff file</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox16">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label21">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">        </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="diff_filename_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="diff_find">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="label" translatable="yes">gtk-find</property>
+                    <property name="use_stock">True</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area6">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button12">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button11">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkDialog" id="checkout_dialog">
+    <property name="border_width">5</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox7">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkVBox" id="checkout_main_box">
+            <property name="visible">True</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label25">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Directory to checkout:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox18">
+                <property name="visible">True</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkLabel" id="label26">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">  </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="path_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkButton" id="dir_find_button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="label" translatable="yes">gtk-find</property>
+                    <property name="use_stock">True</property>
+                    <property name="response_id">0</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label29">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Subversion URL:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox20">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label30">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkEntry" id="url_entry">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="tooltip_text">svn+ssh://[login ]svn gnome org/svn/[module]/trunk</property>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label27">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Information:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="hbox19">
+                <property name="visible">True</property>
+                <child>
+                  <widget class="GtkLabel" id="label28">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">    </property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                    <property name="shadow_type">GTK_SHADOW_IN</property>
+                    <child>
+                      <widget class="GtkTreeView" id="checkout_treeview">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="headers_clickable">True</property>
+                      </widget>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">5</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area7">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="button14">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-apply</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-10</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="button13">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/plugins/subversion/subversion.gtranslator-plugin.desktop.in
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/subversion.gtranslator-plugin.desktop.in	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,8 @@
+[Gtranslator Plugin]
+Module=subversion
+IAge=2
+_Name=Subversion
+_Description=A Subversion client plugin based on libsvn.
+Authors=Ignacio Casal Quinteiro  <nacho resa gmail com>
+Copyright=Copyright @ 2008 Ignacio Casal Quinteiro
+Website=http://gtranslator.sf.net

Added: trunk/plugins/subversion/svn-add-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-add-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,119 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-add-command.h"
+
+struct _SvnAddCommandPriv
+{
+	gchar *path;
+	gboolean force;
+	gboolean recursive;
+};
+
+G_DEFINE_TYPE (SvnAddCommand, svn_add_command, SVN_TYPE_COMMAND);
+
+static void
+svn_add_command_init (SvnAddCommand *self)
+{
+	self->priv = g_new0 (SvnAddCommandPriv, 1);
+}
+
+static void
+svn_add_command_finalize (GObject *object)
+{
+	SvnAddCommand *self;
+	
+	self = SVN_ADD_COMMAND (object);
+	
+	g_free (self->priv->path);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_add_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_add_command_run (GtranslatorCommand *command)
+{
+	SvnAddCommand *self;
+	SvnCommand *svn_command;
+	svn_error_t *error;
+	svn_depth_t depth;
+	
+	self = SVN_ADD_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+
+	if (self->priv->recursive == TRUE)
+		depth = svn_depth_infinity;
+	else depth = svn_depth_empty;
+	
+	error = svn_client_add4 (self->priv->path,
+							 depth,
+							 self->priv->force,
+							 FALSE,
+							 FALSE, 
+							 svn_command_get_client_context (svn_command), 
+							 svn_command_get_pool (svn_command));
+
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	return 0;
+}
+
+static void
+svn_add_command_class_init (SvnAddCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_add_command_finalize;
+	command_class->run = svn_add_command_run;
+}
+
+
+SvnAddCommand *
+svn_add_command_new (gchar *path, gboolean force, gboolean recursive)
+{
+	SvnAddCommand *self;
+	
+	self = g_object_new (SVN_TYPE_ADD_COMMAND, NULL);
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+														path);
+	self->priv->force = force;
+	self->priv->recursive = recursive;
+	
+	return self;
+}
+
+void
+svn_add_command_destroy (SvnAddCommand *self)
+{
+	g_object_unref (self);
+}

Added: trunk/plugins/subversion/svn-add-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-add-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,65 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_ADD_COMMAND_H_
+#define _SVN_ADD_COMMAND_H_
+
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_ADD_COMMAND             (svn_add_command_get_type ())
+#define SVN_ADD_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_ADD_COMMAND, SvnAddCommand))
+#define SVN_ADD_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_ADD_COMMAND, SvnAddCommandClass))
+#define SVN_IS_ADD_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_ADD_COMMAND))
+#define SVN_IS_ADD_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_ADD_COMMAND))
+#define SVN_ADD_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_ADD_COMMAND, SvnAddCommandClass))
+
+typedef struct _SvnAddCommandClass SvnAddCommandClass;
+typedef struct _SvnAddCommand SvnAddCommand;
+typedef struct _SvnAddCommandPriv SvnAddCommandPriv;
+
+struct _SvnAddCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnAddCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnAddCommandPriv *priv;
+};
+
+GType svn_add_command_get_type (void) G_GNUC_CONST;
+SvnAddCommand * svn_add_command_new (gchar *path, gboolean force, gboolean recursive);
+void svn_add_command_destroy (SvnAddCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_ADD_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-cat-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-cat-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,169 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-cat-command.h"
+
+struct _SvnCatCommandPriv
+{
+	gchar *path;
+	glong revision;
+	GQueue *output;
+};
+
+G_DEFINE_TYPE (SvnCatCommand, svn_cat_command, SVN_TYPE_COMMAND);
+
+static void
+svn_cat_command_init (SvnCatCommand *self)
+{
+	self->priv = g_new0 (SvnCatCommandPriv, 1);
+}
+
+static void
+svn_cat_command_finalize (GObject *object)
+{
+	SvnCatCommand *self;
+	GList *current_output;
+	
+	self = SVN_CAT_COMMAND (object);
+	
+	g_free (self->priv->path);
+	
+	current_output = self->priv->output->head;
+	
+	while (current_output)
+	{
+		g_free (current_output->data);
+		current_output = g_list_next (current_output);
+	}
+	
+	g_queue_free (self->priv->output);
+	
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_cat_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_cat_command_run (GtranslatorCommand *command)
+{
+	SvnCatCommand *self;
+	SvnCommand *svn_command;
+	svn_opt_revision_t revision;
+	svn_opt_revision_t peg_revision;
+	svn_stream_t *cat_stream;
+	apr_file_t *cat_input;
+	apr_file_t *cat_output;
+	apr_size_t read_size;
+	gchar *line;
+	svn_error_t *error;
+	apr_status_t apr_error;
+	
+	self = SVN_CAT_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	
+	apr_file_pipe_create (&cat_output, &cat_input, 
+						  svn_command_get_pool (svn_command));
+	apr_file_pipe_timeout_set (cat_output, 0);
+	apr_file_pipe_timeout_set (cat_input, 0);
+	cat_stream = svn_stream_from_aprfile2 (cat_input, FALSE, 
+										   svn_command_get_pool (svn_command));
+	
+	revision.kind = svn_opt_revision_base;
+	revision.value.number = self->priv->revision;
+	peg_revision.kind = svn_opt_revision_unspecified;
+	
+	error = svn_client_cat2 (cat_stream,
+							 self->priv->path,
+							 &peg_revision,
+							 &revision,
+							 svn_command_get_client_context (svn_command),
+							 svn_command_get_pool (svn_command));
+	
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	while (apr_file_eof (cat_output) != APR_EOF)
+	{
+		read_size = 80;
+		line = g_new0 (gchar, (read_size + 1));
+		
+		apr_error = apr_file_read (cat_output, line, &read_size);
+		
+		if (apr_error)
+			break;
+		
+		if (strlen (line))
+		{
+			gtranslator_async_command_lock (GTR_ASYNC_COMMAND (command));
+			g_queue_push_tail (self->priv->output, g_strdup (line));
+			gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (command));
+			
+			g_free (line);
+			
+			gtranslator_command_notify_data_arrived (command);
+		}
+	}
+								 
+	return 0;
+}
+
+static void
+svn_cat_command_class_init (SvnCatCommandClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass* command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_cat_command_finalize;
+	command_class->run = svn_cat_command_run;
+}
+
+
+SvnCatCommand *
+svn_cat_command_new (gchar *path, glong revision)
+{
+	SvnCatCommand *self;
+	
+	self = g_object_new (SVN_TYPE_CAT_COMMAND, NULL);
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+														path);
+	self->priv->revision = revision;
+	self->priv->output = g_queue_new ();
+	
+	return self;
+}
+
+void
+svn_cat_command_destroy (SvnCatCommand *self)
+{
+	g_object_unref (self);
+}
+
+GQueue *
+svn_cat_command_get_output (SvnCatCommand *self)
+{
+	return self->priv->output;
+}

Added: trunk/plugins/subversion/svn-cat-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-cat-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,63 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_CAT_COMMAND_H_
+#define _SVN_CAT_COMMAND_H_
+
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_CAT_COMMAND             (svn_cat_command_get_type ())
+#define SVN_CAT_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_CAT_COMMAND, SvnCatCommand))
+#define SVN_CAT_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_CAT_COMMAND, SvnCatCommandClass))
+#define SVN_IS_CAT_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_CAT_COMMAND))
+#define SVN_IS_CAT_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_CAT_COMMAND))
+#define SVN_CAT_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_CAT_COMMAND, SvnCatCommandClass))
+
+typedef struct _SvnCatCommandClass SvnCatCommandClass;
+typedef struct _SvnCatCommand SvnCatCommand;
+typedef struct _SvnCatCommandPriv SvnCatCommandPriv;
+
+struct _SvnCatCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnCatCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnCatCommandPriv *priv;
+};
+
+GType svn_cat_command_get_type (void) G_GNUC_CONST;
+SvnCatCommand * svn_cat_command_new (gchar *path, glong revision);
+void svn_cat_command_destroy (SvnCatCommand *self);
+GQueue *svn_cat_command_get_output (SvnCatCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_CAT_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-checkout-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-checkout-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "svn-checkout-command.h"
+
+struct _SvnCheckoutCommandPriv
+{
+	gchar *url;
+	gchar *path;
+};
+
+G_DEFINE_TYPE (SvnCheckoutCommand, svn_checkout_command, SVN_TYPE_COMMAND);
+
+static void
+svn_checkout_command_init (SvnCheckoutCommand *self)
+{	
+	self->priv = g_new0 (SvnCheckoutCommandPriv, 1);
+}
+
+static void
+svn_checkout_command_finalize (GObject *object)
+{
+	SvnCheckoutCommand *self;
+	
+	self = SVN_CHECKOUT_COMMAND (object);
+	
+	g_free (self->priv->url);
+	g_free (self->priv->path);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_checkout_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_checkout_command_run (GtranslatorCommand *command)
+{
+	SvnCheckoutCommand *self;
+	SvnCommand *svn_command;
+	svn_opt_revision_t revision;
+	svn_opt_revision_t peg_revision;
+	svn_revnum_t revnum;
+	svn_error_t *error = NULL;
+	svn_revnum_t revision_number;
+	gchar *revision_message;
+	
+	self = SVN_CHECKOUT_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	
+	revision.kind = svn_opt_revision_head;
+	peg_revision.kind = svn_opt_revision_unspecified;
+	
+	error = svn_client_checkout3 (&revnum,
+				      self->priv->url,
+				      self->priv->path,
+				      &peg_revision,
+				      &revision,
+				      svn_depth_unknown,
+				      TRUE,
+				      FALSE,
+				      svn_command_get_client_context (svn_command),
+				      svn_command_get_pool (svn_command));
+	
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	return 0;
+}
+
+static void
+svn_checkout_command_class_init (SvnCheckoutCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_checkout_command_finalize;
+	command_class->run = svn_checkout_command_run;
+}
+
+
+SvnCheckoutCommand *
+svn_checkout_command_new (const gchar *url, const gchar *path)
+{
+	SvnCheckoutCommand *self;
+	
+	self = g_object_new (SVN_TYPE_CHECKOUT_COMMAND, NULL);
+	
+	self->priv->url = svn_command_make_canonical_path (SVN_COMMAND (self),
+							    (gchar*)url);
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+							    (gchar*)path);
+	
+	return self;
+}
+
+void
+svn_checkout_command_destroy (SvnCheckoutCommand *self)
+{
+	g_object_unref (self);
+}

Added: trunk/plugins/subversion/svn-checkout-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-checkout-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _SVN_CHECKOUT_COMMAND_H_
+#define _SVN_CHECKOUT_COMMAND_H_
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_CHECKOUT_COMMAND             (svn_checkout_command_get_type ())
+#define SVN_CHECKOUT_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_CHECKOUT_COMMAND, SvnCheckoutCommand))
+#define SVN_CHECKOUT_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_CHECKOUT_COMMAND, SvnCheckoutCommandClass))
+#define SVN_IS_CHECKOUT_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_CHECKOUT_COMMAND))
+#define SVN_IS_CHECKOUT_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_CHECKOUT_COMMAND))
+#define SVN_CHECKOUT_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_CHECKOUT_COMMAND, SvnCheckoutCommandClass))
+
+typedef struct _SvnCheckoutCommandClass SvnCheckoutCommandClass;
+typedef struct _SvnCheckoutCommand SvnCheckoutCommand;
+typedef struct _SvnCheckoutCommandPriv SvnCheckoutCommandPriv;
+
+struct _SvnCheckoutCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnCheckoutCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnCheckoutCommandPriv *priv;
+};
+
+GType svn_checkout_command_get_type (void) G_GNUC_CONST;
+SvnCheckoutCommand * svn_checkout_command_new (const gchar *url, const gchar *path);
+void svn_checkout_command_destroy (SvnCheckoutCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_CHECKOUT_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,708 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-command.h"
+#include "utils.h"
+#include <glib/gi18n.h>
+
+struct _SvnCommandPriv
+{
+	svn_client_ctx_t *client_context;
+	apr_pool_t *pool;
+	GQueue *info_messages;
+	GMutex *ui_lock;
+	gboolean main_thread_has_ui_lock;
+};
+
+G_DEFINE_TYPE (SvnCommand, svn_command, GTR_TYPE_ASYNC_COMMAND);
+
+static gboolean
+svn_command_acquire_ui_lock (SvnCommand *self)
+{
+	gboolean got_lock;
+	
+	if (!self->priv->main_thread_has_ui_lock)
+	{
+		got_lock = g_mutex_trylock (self->priv->ui_lock);
+		
+		if (got_lock)
+			self->priv->main_thread_has_ui_lock = TRUE;
+		
+		return !got_lock;
+	}
+	else
+		return FALSE;
+}
+
+static gboolean
+svn_command_release_ui_lock (GMutex *ui_lock)
+{
+	g_mutex_unlock (ui_lock);
+	g_mutex_free (ui_lock);
+	
+	return FALSE;
+}
+
+/* Auth functions */
+/* In order to prevent deadlocking when Subversion prompts for something, we
+ * have to make sure that no GTK calls are made from the command threads by way
+ * of the authentication baton. To do this, the dialog code will be called from
+ * idle sources. */
+
+/* svn_auth_simple_prompt_func_cb argumements */
+typedef struct
+{
+	svn_auth_cred_simple_t **cred;
+	void *baton;
+	gchar *realm;
+	gchar *username;
+	svn_boolean_t may_save;
+	apr_pool_t *pool;
+	svn_error_t *error;
+} SimplePromptArgs;
+
+/* svn_auth_ssl_server_trust_prompt_func_cb arguements */
+typedef struct
+{
+	svn_auth_cred_ssl_server_trust_t **cred;
+	void *baton; 
+	gchar *realm;
+	apr_uint32_t failures;
+	svn_auth_ssl_server_cert_info_t *cert_info;
+	svn_boolean_t may_save;
+	apr_pool_t *pool;
+	svn_error_t *error;
+} SSLServerTrustArgs;
+
+static gboolean
+simple_prompt (SimplePromptArgs *args)
+{
+	GtkWidget* svn_user_auth;
+	GtkWidget* auth_realm;
+	GtkWidget* username_entry;
+	GtkWidget* password_entry;
+	GtkWidget* remember_pwd;
+	GtkWidget *error_widget;
+	gboolean ret;
+	svn_error_t *err = NULL;
+	SvnCommand *svn_command;
+
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+											   "svn_user_auth",
+											   &error_widget,
+											   
+											   "svn_user_auth", &svn_user_auth,
+											   "auth_realm", &auth_realm,
+											   "username_entry", &username_entry,
+											   "password_entry", &password_entry,
+											   "remember_pwd", &remember_pwd,
+											   
+											   NULL);
+	
+	if(!ret)
+	{
+		GtkWidget *dlg = gtk_dialog_new ();
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		gtk_dialog_run (GTK_DIALOG (dlg));
+		gtk_widget_destroy (dlg);
+		
+		return FALSE;
+	}
+	
+	gtk_dialog_set_default_response (GTK_DIALOG (svn_user_auth),
+									 GTK_RESPONSE_OK);
+	
+	if (args->realm)
+		gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
+	if (args->username)
+	{
+		gtk_entry_set_text (GTK_ENTRY (username_entry), args->username);
+		gtk_widget_grab_focus (password_entry);
+	}
+	if (!args->may_save)
+		gtk_widget_set_sensitive(remember_pwd, FALSE);
+		
+	/* Then the dialog is prompted to user and when user clicks ok, the
+	 * values entered, i.e username, password and remember password (true
+	 * by default) should be used to initialized the memebers below. If the
+	 * user cancels the dialog, I think we return an error struct
+	 * appropriately initialized. -- naba
+	 */
+	 
+ 	switch (gtk_dialog_run (GTK_DIALOG (svn_user_auth)))
+	{
+		case GTK_RESPONSE_OK:
+		{
+			*args->cred = apr_pcalloc (args->pool, sizeof(*(args->cred)));
+			(*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
+															       (remember_pwd));
+			(*(args->cred))->username = apr_pstrdup (args->pool,
+								 	  gtk_entry_get_text(GTK_ENTRY(username_entry)));
+			(*(args->cred))->password = apr_pstrdup (args->pool,
+								 	  gtk_entry_get_text(GTK_ENTRY(password_entry)));
+															 			
+			err = SVN_NO_ERROR;
+			break;
+		}
+		default:
+			err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
+									_("Authentication canceled"));
+									 
+			break;
+	}
+	gtk_widget_destroy (svn_user_auth);
+	args->error = err;
+	
+	/* Release because main thread should already have the lock */
+	svn_command = SVN_COMMAND (args->baton);
+	svn_command_unlock_ui (svn_command);
+	
+	return FALSE;
+}
+
+static gboolean
+ssl_server_trust_prompt (SSLServerTrustArgs *args)
+{
+	GtkWidget* svn_server_trust;
+	GtkWidget* auth_realm;
+	GtkWidget* server_info;
+	GtkWidget* remember_check;
+	GtkWidget *error_widget;
+	gboolean ret;
+	svn_error_t *err = NULL;
+	gchar* info;
+	SvnCommand *svn_command;
+	
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+											   "svn_server_trust",
+											   &error_widget,
+											   
+											   "svn_server_trust", &svn_server_trust,
+											   "realm_label", &auth_realm,
+											   "server_info_label", &server_info,
+											   "remember_check", &remember_check,
+											   
+											   NULL);
+	
+	if(!ret)
+	{
+		GtkWidget *dlg = gtk_dialog_new ();
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		gtk_dialog_run (GTK_DIALOG (dlg));
+		gtk_widget_destroy (dlg);
+		
+		return FALSE;
+	}
+	
+	if (args->realm)
+		gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
+	
+	info = g_strconcat(_("Hostname: "), args->cert_info->hostname, "\n",
+					   _("Fingerprint: "), args->cert_info->fingerprint, "\n",
+					   _("Valid from: "), args->cert_info->valid_from, "\n",
+					   _("Valid until: "), args->cert_info->valid_until, "\n",
+					   _("Issuer DN: "), args->cert_info->issuer_dname, "\n",
+					   _("DER certificate: "), args->cert_info->ascii_cert, "\n",
+					   NULL);
+	gtk_label_set_text (GTK_LABEL (server_info), info);
+	
+	if (!args->may_save)
+		gtk_widget_set_sensitive(remember_check, FALSE);
+	
+	gtk_dialog_set_default_response (GTK_DIALOG (svn_server_trust), GTK_RESPONSE_YES);
+
+	
+	switch (gtk_dialog_run(GTK_DIALOG(svn_server_trust)))
+	{
+		case GTK_RESPONSE_YES:
+			*args->cred = apr_pcalloc (args->pool, 
+									   sizeof(*(args->cred)));
+			(*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
+															 	   (remember_check));
+			err = SVN_NO_ERROR;
+		/* TODO: Set bitmask for accepted_failures */
+			break;
+		default:
+			err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
+									_("Authentication canceled"));									 
+			break;
+	}
+	gtk_widget_destroy (svn_server_trust);
+	args->error = err;
+	
+	/* Release because main thread should already have the lock */
+	svn_command = SVN_COMMAND (args->baton);
+	svn_command_unlock_ui (svn_command);
+	
+	return FALSE;
+}
+
+/* User authentication prompts handlers */
+static svn_error_t*
+svn_auth_simple_prompt_func_cb (svn_auth_cred_simple_t **cred, void *baton,
+								const char *realm, const char *username,
+								svn_boolean_t may_save, apr_pool_t *pool)
+{
+	SimplePromptArgs *args;
+	SvnCommand *svn_command;
+	svn_error_t *error;
+	
+	args = g_new0 (SimplePromptArgs, 1);
+	args->cred = cred;
+	args->baton = baton;
+	args->realm = g_strdup (realm);
+	args->username = g_strdup (username);
+	args->may_save = may_save;
+	args->pool = pool;
+	
+	svn_command = SVN_COMMAND (baton);
+	
+	g_idle_add ((GSourceFunc) simple_prompt, args);
+	
+	svn_command_lock_ui (svn_command);
+	svn_command_unlock_ui (svn_command);
+	
+	error = args->error;
+	g_free (args->realm);
+	g_free (args->username);
+	g_free (args);
+	
+	return error;
+
+}
+
+static svn_error_t*
+svn_auth_ssl_server_trust_prompt_func_cb (svn_auth_cred_ssl_server_trust_t **cred,
+										  void *baton, const char *realm,
+										  apr_uint32_t failures,
+										  const svn_auth_ssl_server_cert_info_t *cert_info,
+										  svn_boolean_t may_save,
+										  apr_pool_t *pool)
+{
+	SSLServerTrustArgs *args;
+	SvnCommand *svn_command;
+	svn_error_t *error;
+	
+	args = g_new0 (SSLServerTrustArgs, 1);
+	args->cred = cred;
+	args->baton = baton;
+	args->realm = g_strdup (realm);
+	args->failures = failures;
+	args->cert_info = g_memdup (cert_info, 
+								sizeof (svn_auth_ssl_server_cert_info_t));
+	args->may_save = may_save;
+	args->pool = pool;
+	
+	svn_command = SVN_COMMAND (baton);
+	
+	g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+					 (GSourceFunc) ssl_server_trust_prompt, args, NULL);
+	
+	svn_command_lock_ui (svn_command);
+	svn_command_unlock_ui (svn_command);
+	
+	error = args->error;
+	g_free (args->realm);
+	g_free (args->cert_info);
+	g_free (args);
+	
+	return error;
+}
+
+static svn_error_t*
+svn_auth_ssl_client_cert_prompt_func_cb (svn_auth_cred_ssl_client_cert_t **cred,
+										 void *baton, const char *realm,
+										 svn_boolean_t may_save,
+										 apr_pool_t *pool)
+{
+	
+	/* Ask for the file where client certificate of authenticity is.
+	 * I think it is some sort of private key. */
+	return SVN_NO_ERROR;
+}
+
+static svn_error_t*
+svn_auth_ssl_client_cert_pw_prompt_func_cb (svn_auth_cred_ssl_client_cert_pw_t **cred,
+											void *baton, const char *realm,
+											svn_boolean_t may_save,
+											apr_pool_t *pool)
+{
+	
+	/* Prompt for password only. I think it is pass-phrase of the above key. */
+	return SVN_NO_ERROR;;
+}
+
+/* Notification callback to handle notifications from Subversion itself */
+static void
+on_svn_notify (gpointer baton,
+			   const svn_wc_notify_t *notify,
+			   apr_pool_t *pool)
+{
+	SvnCommand *self;
+	gchar *action_message;
+	gchar *state_message;
+	
+	self = SVN_COMMAND (baton);
+	action_message = NULL;
+	state_message = NULL;
+	
+	switch (notify->action)
+	{
+		case svn_wc_notify_delete:
+			action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
+			break;
+		case svn_wc_notify_add:
+			action_message = g_strdup_printf (_("Added: %s"), notify->path);
+			break;
+		case svn_wc_notify_revert:
+			action_message = g_strdup_printf (_("Reverted: %s"), notify->path);
+			break;
+		case svn_wc_notify_failed_revert:
+			action_message = g_strdup_printf (_("Revert failed: %s"), 
+											  notify->path);
+			break;
+		case svn_wc_notify_resolved:
+			action_message = g_strdup_printf (_("Resolved: %s"), notify->path);
+			break;
+		case svn_wc_notify_update_delete:
+			action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
+			break;
+		case svn_wc_notify_update_update:
+			action_message = g_strdup_printf (_("Updated: %s"), notify->path);
+			break;
+		case svn_wc_notify_update_add:
+			action_message = g_strdup_printf (_("Added: %s"), notify->path);
+			break;
+		case svn_wc_notify_update_external:
+			action_message = g_strdup_printf (_("Externally Updated: %s"), 
+									   notify->path);
+			break;
+		case svn_wc_notify_commit_modified:
+			action_message = g_strdup_printf (_("Commit Modified: %s"), 
+											  notify->path);
+			break;
+		case svn_wc_notify_commit_added:
+			action_message = g_strdup_printf (_("Commit Added: %s"), notify->path);
+			break;
+		case svn_wc_notify_commit_deleted:
+			action_message = g_strdup_printf (_("Commit Deleted: %s"), 
+											  notify->path);
+			break;
+		case svn_wc_notify_commit_replaced:
+			action_message = g_strdup_printf (_("Commit Replaced: %s"), 
+											  notify->path);
+			break;
+		case svn_wc_notify_copy:
+			action_message = g_strdup_printf (_("Created File: %s"), notify->path);
+			break;
+		default:
+			break;
+	}
+	
+	if (action_message)
+	{
+		svn_command_push_info (self, action_message);
+		g_free (action_message);
+	}
+	
+	switch (notify->content_state)
+	{
+		case svn_wc_notify_state_changed:
+			state_message = g_strdup_printf (_("Modified: %s"), notify->path);
+			break;
+		case svn_wc_notify_state_merged:
+			state_message = g_strdup_printf (_("Merged: %s"), notify->path);
+			break;
+		case svn_wc_notify_state_conflicted:
+			state_message = g_strdup_printf (_("Conflicted: %s"), 
+											 notify->path);
+			break;
+		case svn_wc_notify_state_missing:
+			state_message = g_strdup_printf (_("Missing: %s"), notify->path);
+			break;
+		case svn_wc_notify_state_obstructed:
+			state_message = g_strdup_printf (_("Obstructed: %s"), notify->path);
+			break;
+		default:
+			break;
+	}
+	
+	if (state_message)
+	{
+		svn_command_push_info (self, state_message);
+		g_free (state_message);
+	}
+}
+
+static void
+svn_command_init (SvnCommand *self)
+{
+	svn_auth_baton_t *auth_baton;
+	apr_array_header_t *providers;
+	svn_auth_provider_object_t *provider;
+	
+	self->priv = g_new0 (SvnCommandPriv, 1);
+
+	self->priv->pool = svn_pool_create (NULL);
+	svn_client_create_context (&self->priv->client_context, self->priv->pool);
+	self->priv->client_context->notify_func2 = on_svn_notify;
+	self->priv->client_context->notify_baton2 = self;
+
+	svn_config_get_config (&(self->priv->client_context)->config,
+						   NULL, /* default dir */
+						   self->priv->pool);
+
+	self->priv->info_messages = g_queue_new ();
+	self->priv->ui_lock = g_mutex_new ();
+
+	/* Make sure that the main thread holds the lock */
+	g_idle_add ((GSourceFunc) svn_command_acquire_ui_lock, self);
+	
+	/* Fill in the auth baton callbacks */
+	providers = apr_array_make (self->priv->pool, 1, 
+								sizeof (svn_auth_provider_object_t *));
+	
+	/* Provider that authenticates username/password from ~/.subversion */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_simple_provider (&provider, self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that authenticates server trust from ~/.subversion */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_server_trust_file_provider (&provider, self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that authenticates client cert from ~/.subversion */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_client_cert_file_provider (&provider, self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that authenticates client cert password from ~/.subversion */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_client_cert_pw_file_provider (&provider, 
+													 self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that prompts for username/password */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_simple_prompt_provider(&provider,
+										  svn_auth_simple_prompt_func_cb,
+										  self, 3, self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that prompts for server trust */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_server_trust_prompt_provider (&provider,
+													 svn_auth_ssl_server_trust_prompt_func_cb,
+													 self, 
+													 self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that prompts for client certificate file */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_client_cert_prompt_provider (&provider,
+													svn_auth_ssl_client_cert_prompt_func_cb,
+													NULL, 3, self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	/* Provider that prompts for client certificate file password */
+	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
+	svn_client_get_ssl_client_cert_pw_prompt_provider (&provider,
+													   svn_auth_ssl_client_cert_pw_prompt_func_cb,
+													   NULL, 3, 
+													   self->priv->pool);
+	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
+	
+	svn_auth_open (&auth_baton, providers, self->priv->pool);
+	self->priv->client_context->auth_baton = auth_baton;
+}
+
+static void
+svn_command_finalize (GObject *object)
+{
+	SvnCommand *self;
+	GList *current_message_line;
+	
+	self = SVN_COMMAND (object);
+	
+	svn_pool_clear (self->priv->pool);
+	
+	current_message_line = self->priv->info_messages->head;
+	
+	while (current_message_line)
+	{
+		g_free (current_message_line->data);
+		current_message_line = g_list_next (current_message_line);
+	}
+	
+	g_idle_add ((GSourceFunc) svn_command_release_ui_lock, self->priv->ui_lock);
+	
+	g_queue_free (self->priv->info_messages);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_command_parent_class)->finalize (object);
+}
+
+static void
+svn_command_class_init (SvnCommandClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = svn_command_finalize;
+}
+
+
+void
+svn_command_push_info (SvnCommand *self, gchar *message)
+{
+	gtranslator_async_command_lock (GTR_ASYNC_COMMAND (self));
+	g_queue_push_tail (self->priv->info_messages, g_strdup (message));
+	gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (self));
+	
+	gtranslator_command_notify_data_arrived (GTR_COMMAND (self));
+}
+
+GQueue *
+svn_command_get_info_queue (SvnCommand *self)
+{
+	return self->priv->info_messages;
+}
+
+void
+svn_command_set_error (SvnCommand *self, svn_error_t *error)
+{
+	GString *error_string;
+	svn_error_t *current_error;
+	gchar *error_c_string;
+	
+	error_string = g_string_new ("");
+	current_error = error;
+	
+	while (current_error)
+	{
+		g_string_append (error_string, current_error->message);
+
+		if (current_error->child)
+			g_string_append_c (error_string, '\n');
+		
+		current_error = current_error->child;
+	}
+	
+	error_c_string = g_string_free (error_string, FALSE);
+	gtranslator_async_command_set_error_message (GTR_COMMAND (self), 
+											error_c_string);
+	
+	g_free (error_c_string);
+}
+
+svn_client_ctx_t *
+svn_command_get_client_context (SvnCommand *self)
+{
+	return self->priv->client_context;
+}
+
+apr_pool_t *
+svn_command_get_pool (SvnCommand *self)
+{
+	return self->priv->pool;
+}
+
+void
+svn_command_lock_ui (SvnCommand *self)
+{
+	g_mutex_lock (self->priv->ui_lock);
+	
+	/* Have the main thread acquire the lock as soon as the other thread is done
+	 * with it. The main thread should *not* acqure the lock, only release 
+	 * it. */
+	self->priv->main_thread_has_ui_lock = FALSE;
+	g_idle_add ((GSourceFunc) svn_command_acquire_ui_lock, self);
+}
+
+void
+svn_command_unlock_ui (SvnCommand *self)
+{
+	g_mutex_unlock (self->priv->ui_lock);
+}
+
+gchar *
+svn_command_make_canonical_path (SvnCommand *self, gchar *path)
+{
+	const gchar *canonical_path;
+	
+	canonical_path = svn_path_canonicalize (path, self->priv->pool);
+	
+	return g_strdup (canonical_path);
+}
+
+svn_opt_revision_t *
+svn_command_get_revision (gchar *revision)
+{
+	svn_opt_revision_t* svn_revision; 
+	
+	svn_revision = g_new0 (svn_opt_revision_t, 1);
+	
+	/* FIXME: Parse the revision string */
+	svn_revision->kind = svn_opt_revision_head;
+	
+	return svn_revision;
+}
+
+GList *
+svn_command_copy_path_list (GList *list)
+{
+	GList *current_path;
+	GList *new_list;
+	
+	new_list = NULL;
+	current_path = list;
+	
+	while (current_path)
+	{
+		new_list = g_list_append (new_list, g_strdup (current_path->data));
+		current_path = g_list_next (current_path);
+	}
+	
+	return new_list;
+}
+
+void
+svn_command_free_path_list (GList *list)
+{
+	GList *current_path;
+	
+	current_path = list;
+	
+	while (current_path)
+	{
+		g_free (current_path->data);
+		current_path = g_list_next (current_path);
+	}
+	
+	g_list_free (list);
+}

Added: trunk/plugins/subversion/svn-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,88 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_COMMAND_H_
+#define _SVN_COMMAND_H_
+
+#include <glib-object.h>
+#include <svn_client.h>
+#include <svn_pools.h>
+#include <svn_config.h>
+#include <svn_path.h>
+#include "subversion-plugin.h"
+#include "async-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_COMMAND             (svn_command_get_type ())
+#define SVN_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_COMMAND, SvnCommand))
+#define SVN_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_COMMAND, SvnCommandClass))
+#define SVN_IS_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_COMMAND))
+#define SVN_IS_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_COMMAND))
+#define SVN_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_COMMAND, SvnCommandClass))
+
+typedef struct _SvnCommandClass SvnCommandClass;
+typedef struct _SvnCommand SvnCommand;
+typedef struct _SvnCommandPriv SvnCommandPriv;
+
+struct _SvnCommandClass
+{
+	GtranslatorAsyncCommandClass parent_class;
+};
+
+struct _SvnCommand
+{
+	GtranslatorAsyncCommand parent_instance;
+	
+	SvnCommandPriv *priv;
+};
+
+GType svn_command_get_type (void) G_GNUC_CONST;
+
+void svn_command_push_info (SvnCommand *self, gchar *message);
+
+GQueue * svn_command_get_info_queue (SvnCommand *self);
+
+void svn_command_set_error (SvnCommand *self, svn_error_t *error);
+
+svn_client_ctx_t *svn_command_get_client_context (SvnCommand *self);
+
+apr_pool_t *svn_command_get_pool (SvnCommand *self);
+
+void svn_command_lock_ui (SvnCommand *self);
+
+void svn_command_unlock_ui (SvnCommand *self);
+
+gchar *svn_command_make_canonical_path (SvnCommand *self, gchar *path);
+
+/* Static methods */
+svn_opt_revision_t *svn_command_get_revision (gchar *revision);
+
+GList *svn_command_copy_path_list (GList *list);
+
+void svn_command_free_path_list (GList *list);
+
+G_END_DECLS
+
+#endif /* _SVN_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-commit-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-commit-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,169 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-commit-command.h"
+
+struct _SvnCommitCommandPriv
+{
+	GList *paths;
+	gchar *log_message;
+	gboolean recursive;
+};
+
+G_DEFINE_TYPE (SvnCommitCommand, svn_commit_command, SVN_TYPE_COMMAND);
+
+static svn_error_t*
+on_log_callback (const char **log_msg,
+				 const char **tmp_file,
+				 apr_array_header_t *commit_items,
+				 void *baton,
+				 apr_pool_t *pool)
+{
+	
+	SvnCommitCommand *self;
+	
+	self = SVN_COMMIT_COMMAND (baton);
+	
+	*log_msg = self->priv->log_message;
+	*tmp_file = NULL;
+	
+	return SVN_NO_ERROR;
+}
+
+static void
+svn_commit_command_init (SvnCommitCommand *self)
+{
+	svn_client_ctx_t *client_context;
+	
+	self->priv = g_new0 (SvnCommitCommandPriv, 1);
+	client_context = svn_command_get_client_context (SVN_COMMAND (self));
+	
+	client_context->log_msg_func = on_log_callback;
+	client_context->log_msg_baton = self;
+	
+}
+
+static void
+svn_commit_command_finalize (GObject *object)
+{
+	SvnCommitCommand *self;
+	
+	self = SVN_COMMIT_COMMAND (object);
+	
+	svn_command_free_path_list (self->priv->paths);
+	g_free (self->priv->log_message);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_commit_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_commit_command_run (GtranslatorCommand *command)
+{
+	SvnCommitCommand *self;
+	SvnCommand *svn_command;
+	GList *current_path;
+	apr_array_header_t *commit_paths;
+	gchar *revision_message;
+	svn_error_t *error;
+	svn_commit_info_t *commit_info;
+	svn_depth_t depth;
+	
+	self = SVN_COMMIT_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	current_path = self->priv->paths;
+	commit_paths = apr_array_make (svn_command_get_pool (svn_command),
+								   g_list_length (self->priv->paths), 
+								   sizeof (char *));
+	
+	while (current_path)
+	{
+		/* I just copied this so don't blame me... */
+		(*((const char **) apr_array_push (commit_paths))) = current_path->data;
+		current_path = g_list_next (current_path);
+	}
+	
+	if (self->priv->recursive == TRUE)
+		depth = svn_depth_infinity;
+	else depth = svn_depth_files;
+	
+	error = svn_client_commit4 (&commit_info, 
+								commit_paths, 
+								depth,
+								TRUE,
+								FALSE,
+								NULL,
+								NULL,
+								svn_command_get_client_context (svn_command), 
+								svn_command_get_pool (svn_command));
+
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	if (commit_info)
+	{
+		revision_message = g_strdup_printf ("Committed revision %ld.", 
+											commit_info->revision);
+		svn_command_push_info (SVN_COMMAND (command), revision_message);
+		g_free (revision_message);
+	}
+	
+	return 0;
+}
+
+static void
+svn_commit_command_class_init (SvnCommitCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_commit_command_finalize;
+	command_class->run = svn_commit_command_run;
+}
+
+SvnCommitCommand *
+svn_commit_command_new (GList *paths, gchar *log_message, 
+						gboolean recursive)
+{
+	SvnCommitCommand *self;
+	
+	self = g_object_new (SVN_TYPE_COMMIT_COMMAND, NULL);
+	self->priv->paths = svn_command_copy_path_list (paths);
+	self->priv->log_message = g_strdup (log_message);
+	self->priv->recursive = recursive;
+	
+	return self;
+}
+
+void
+svn_commit_command_destroy (SvnCommitCommand *self)
+{
+	g_object_unref (self);
+}

Added: trunk/plugins/subversion/svn-commit-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-commit-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_COMMIT_COMMAND_H_
+#define _SVN_COMMIT_COMMAND_H_
+
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_COMMIT_COMMAND             (svn_commit_command_get_type ())
+#define SVN_COMMIT_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_COMMIT_COMMAND, SvnCommitCommand))
+#define SVN_COMMIT_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_COMMIT_COMMAND, SvnCommitCommandClass))
+#define SVN_IS_COMMIT_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_COMMIT_COMMAND))
+#define SVN_IS_COMMIT_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_COMMIT_COMMAND))
+#define SVN_COMMIT_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_COMMIT_COMMAND, SvnCommitCommandClass))
+
+typedef struct _SvnCommitCommandClass SvnCommitCommandClass;
+typedef struct _SvnCommitCommand SvnCommitCommand;
+typedef struct _SvnCommitCommandPriv SvnCommitCommandPriv;
+
+struct _SvnCommitCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnCommitCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnCommitCommandPriv *priv;
+};
+
+GType svn_commit_command_get_type (void) G_GNUC_CONST;
+SvnCommitCommand * svn_commit_command_new (GList *paths, gchar *log_message, 
+										   gboolean recursive);
+void svn_commit_command_destroy (SvnCommitCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_COMMIT_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-diff-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-diff-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,223 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-diff-command.h"
+
+struct _SvnDiffCommandPriv
+{
+	GQueue *output;
+	gchar *path;
+	glong revision1;
+	glong revision2;
+	gboolean recursive;
+};
+
+G_DEFINE_TYPE (SvnDiffCommand, svn_diff_command, SVN_TYPE_COMMAND);
+
+static void
+svn_diff_command_init (SvnDiffCommand *self)
+{
+	self->priv = g_new0 (SvnDiffCommandPriv, 1);
+	self->priv->output = g_queue_new ();
+}
+
+static void
+svn_diff_command_finalize (GObject *object)
+{
+	SvnDiffCommand *self;
+	GList *current_line;
+	
+	self = SVN_DIFF_COMMAND (object);
+	
+	current_line = self->priv->output->head;
+	
+	while (current_line)
+	{
+		g_free (current_line->data);
+		current_line = g_list_next (current_line);
+	}
+	
+	g_queue_free (self->priv->output);
+	g_free (self->priv->path);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_diff_command_parent_class)->finalize (object);
+}
+
+static guint 
+svn_diff_command_run (GtranslatorCommand *command)
+{
+	SvnDiffCommand *self;
+	SvnCommand *svn_command;
+	svn_opt_revision_t revision1;
+	svn_opt_revision_t revision2;
+	apr_array_header_t *options;
+	apr_file_t *diff_file;
+	gchar file_template[] = "gtranslator-svn-diffXXXXXX";
+	apr_size_t read_size;
+	gchar *line;
+	svn_error_t *error;
+	apr_status_t apr_error;
+	apr_off_t offset;
+	svn_depth_t depth;
+	
+	self = SVN_DIFF_COMMAND (command);
+	svn_command = SVN_COMMAND (self);
+	
+	switch (self->priv->revision1)
+	{
+		case SVN_DIFF_REVISION_NONE:
+			/* Treat this as a diff between working copy and base 
+			 * (show only mods made to the revision of this working copy.) */
+			revision1.kind = svn_opt_revision_base;
+			revision2.kind = svn_opt_revision_working;
+			break;
+		case SVN_DIFF_REVISION_PREVIOUS:
+			/* Diff between selected revision and the one before it.
+			 * This is relative to revision2. */
+			revision1.kind = svn_opt_revision_number;
+			revision1.value.number = self->priv->revision2 - 1;
+			revision2.kind = svn_opt_revision_number;
+			revision2.value.number = self->priv->revision2;
+			break;
+		default:
+			/* Diff between two distinct revisions */
+			revision1.kind = svn_opt_revision_number;
+			revision1.value.number = self->priv->revision1;
+			revision2.kind = svn_opt_revision_number;
+			revision2.value.number = self->priv->revision2;
+			break;
+	}
+	
+	options = apr_array_make(svn_command_get_pool (SVN_COMMAND (command)), 
+							 0, sizeof (char *));
+	
+	apr_file_mktemp (&diff_file, file_template, 0, 
+					 svn_command_get_pool (SVN_COMMAND (command)));
+	
+	if (self->priv->recursive == TRUE)
+		depth = svn_depth_infinity;
+	else depth = svn_depth_empty;
+	
+	error = svn_client_diff4 (options,
+							  self->priv->path,
+							  &revision1,
+							  self->priv->path,
+							  &revision2,
+							  NULL,
+							  depth,
+							  FALSE,
+							  FALSE,
+							  FALSE,
+							  SVN_APR_LOCALE_CHARSET,
+							  diff_file,
+							  NULL,
+							  NULL,
+							  svn_command_get_client_context (svn_command),
+							  svn_command_get_pool (svn_command));
+	
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	offset = 0;
+	apr_file_seek (diff_file, APR_SET, &offset);
+	
+	while (apr_file_eof (diff_file) != APR_EOF)
+	{
+		read_size = 80;
+		line = g_new0 (gchar, (read_size + 1));
+		
+		apr_error = apr_file_read (diff_file, line, &read_size);
+
+		if (strlen (line))
+		{
+			gtranslator_async_command_lock (GTR_ASYNC_COMMAND (command));
+			
+			/* Make sure that we only output UTF-8. We could have done this by
+			 * passing in "UTF-8" for header encoding to the diff API, but there
+			 * is the possiblity that an external diff program could be used, in
+			 * which case that arguement wouldn't do anything. As a workaround,
+			 * have the internal diff system return things in the system 
+			 * charset, and make the (hopefully safe) assumption that any 
+			 * external diff program also outputs in the current locale. */
+			g_queue_push_tail (self->priv->output, 
+							   g_locale_to_utf8 (line, read_size, NULL, NULL,
+												 NULL));
+			gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (command));
+			
+			g_free (line);
+			
+			gtranslator_command_notify_data_arrived (command);
+		}
+	}
+	
+	apr_file_close (diff_file);
+	
+	return 0;
+								 
+}
+
+static void
+svn_diff_command_class_init (SvnDiffCommandClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_diff_command_finalize;
+	command_class->run = svn_diff_command_run;
+}
+
+SvnDiffCommand *
+svn_diff_command_new (gchar *path, glong revision1, glong revision2, 
+					  gboolean recursive)
+{
+	SvnDiffCommand *self;
+	
+	self = g_object_new (SVN_TYPE_DIFF_COMMAND, NULL);
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+														path);
+	self->priv->revision1 = revision1;
+	self->priv->revision2 = revision2;
+	self->priv->recursive = recursive;
+	
+	return self;
+}
+
+void
+svn_diff_command_destroy (SvnDiffCommand *self)
+{
+	g_object_unref (self);
+}
+
+GQueue *
+svn_diff_command_get_output (SvnDiffCommand *self)
+{
+	return self->priv->output;
+}

Added: trunk/plugins/subversion/svn-diff-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-diff-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,72 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * anjuta is free software.
+ * 
+ * You may 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.
+ * 
+ * anjuta 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 anjuta.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_DIFF_COMMAND_H_
+#define _SVN_DIFF_COMMAND_H_
+
+#include <glib-object.h>
+#include <svn_utf.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_DIFF_COMMAND             (svn_diff_command_get_type ())
+#define SVN_DIFF_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_DIFF_COMMAND, SvnDiffCommand))
+#define SVN_DIFF_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_DIFF_COMMAND, SvnDiffCommandClass))
+#define SVN_IS_DIFF_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_DIFF_COMMAND))
+#define SVN_IS_DIFF_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_DIFF_COMMAND))
+#define SVN_DIFF_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_DIFF_COMMAND, SvnDiffCommandClass))
+
+typedef struct _SvnDiffCommandClass SvnDiffCommandClass;
+typedef struct _SvnDiffCommand SvnDiffCommand;
+typedef struct _SvnDiffCommandPriv SvnDiffCommandPriv;
+
+struct _SvnDiffCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnDiffCommand
+{
+	SvnCommandClass parent_instance;
+	
+	SvnDiffCommandPriv *priv;
+};
+
+enum
+{
+	SVN_DIFF_REVISION_PREVIOUS = -1,
+	SVN_DIFF_REVISION_NONE = 0
+}; 
+
+GType svn_diff_command_get_type (void) G_GNUC_CONST;
+SvnDiffCommand *svn_diff_command_new (gchar *path, glong revision1,
+									  glong revision2, gboolean recursive);
+void svn_diff_command_destroy (SvnDiffCommand *self);
+
+GQueue *svn_diff_command_get_output (SvnDiffCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_DIFF_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-resolve-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-resolve-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,112 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-resolve-command.h"
+
+struct _SvnResolveCommandPriv
+{
+	GList *paths;
+	gboolean recursive;
+};
+
+G_DEFINE_TYPE (SvnResolveCommand, svn_resolve_command, SVN_TYPE_COMMAND);
+
+static void
+svn_resolve_command_init (SvnResolveCommand *self)
+{	
+	self->priv = g_new0 (SvnResolveCommandPriv, 1);
+}
+
+static void
+svn_resolve_command_finalize (GObject *object)
+{
+	SvnResolveCommand *self;
+	
+	self = SVN_RESOLVE_COMMAND (object);
+	
+	svn_command_free_path_list (self->priv->paths);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_resolve_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_resolve_command_run (GtranslatorCommand *command)
+{
+	SvnResolveCommand *self;
+	SvnCommand *svn_command;
+	GList *current_path;
+	svn_error_t *error;
+	
+	self = SVN_RESOLVE_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	current_path = self->priv->paths;
+	
+	while (current_path)
+	{
+		error = svn_client_resolved (current_path->data, 
+									 self->priv->recursive,
+									 svn_command_get_client_context (svn_command), 
+									 svn_command_get_pool (svn_command));
+
+		if (error)
+		{
+			svn_command_set_error (svn_command, error);
+			return 1;
+		}
+		
+		current_path = g_list_next (current_path);
+	}
+	
+	return 0;
+}
+
+static void
+svn_resolve_command_class_init (SvnResolveCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_resolve_command_finalize;
+	command_class->run = svn_resolve_command_run;
+}
+
+
+SvnResolveCommand *
+svn_resolve_command_new (GList *paths, gboolean recursive)
+{
+	SvnResolveCommand *self;
+	
+	self = g_object_new (SVN_TYPE_RESOLVE_COMMAND, NULL);
+	self->priv->paths = svn_command_copy_path_list (paths);
+	self->priv->recursive = recursive;
+	
+	return self;
+}
+
+void
+svn_resolve_command_destroy (SvnResolveCommand *self)
+{
+	g_object_unref (self);
+}

Added: trunk/plugins/subversion/svn-resolve-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-resolve-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,62 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * anjuta is free software.
+ * 
+ * You may 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.
+ * 
+ * anjuta 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 anjuta.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_RESOLVE_COMMAND_H_
+#define _SVN_RESOLVE_COMMAND_H_
+
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_RESOLVE_COMMAND             (svn_resolve_command_get_type ())
+#define SVN_RESOLVE_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_RESOLVE_COMMAND, SvnResolveCommand))
+#define SVN_RESOLVE_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_RESOLVE_COMMAND, SvnResolveCommandClass))
+#define SVN_IS_RESOLVE_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_RESOLVE_COMMAND))
+#define SVN_IS_RESOLVE_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_RESOLVE_COMMAND))
+#define SVN_RESOLVE_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_RESOLVE_COMMAND, SvnResolveCommandClass))
+
+typedef struct _SvnResolveCommandClass SvnResolveCommandClass;
+typedef struct _SvnResolveCommand SvnResolveCommand;
+typedef struct _SvnResolveCommandPriv SvnResolveCommandPriv;
+
+struct _SvnResolveCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnResolveCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnResolveCommandPriv *priv;
+};
+
+GType svn_resolve_command_get_type (void) G_GNUC_CONST;
+SvnResolveCommand *svn_resolve_command_new (GList *paths, gboolean recursive);
+void svn_resolve_command_destroy (SvnResolveCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_RESOLVE_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-status-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-status-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,173 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-status-command.h"
+
+struct _SvnStatusCommandPriv
+{
+	gchar *path;
+	gboolean recursive;
+	gboolean get_all_items;
+	GQueue *status_queue;
+};
+
+G_DEFINE_TYPE (SvnStatusCommand, svn_status_command, SVN_TYPE_COMMAND);
+
+static void
+svn_status_command_init (SvnStatusCommand *self)
+{	
+	self->priv = g_new0 (SvnStatusCommandPriv, 1);
+	self->priv->status_queue = g_queue_new ();	
+}
+
+static void
+svn_status_command_finalize (GObject *object)
+{
+	SvnStatusCommand *self;
+	GList *current_status;
+	
+	self = SVN_STATUS_COMMAND (object);
+	current_status = self->priv->status_queue->head;
+	
+	g_free (self->priv->path);
+	
+	while (current_status)
+	{
+		svn_status_destroy (current_status->data);
+		current_status = g_list_next (current_status);
+	}
+	
+	g_queue_free (self->priv->status_queue);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_status_command_parent_class)->finalize (object);
+}
+
+static void
+on_svn_status_notify (void *baton, const char *path, svn_wc_status2_t *status)
+{
+	SvnStatusCommand *self;
+	SvnStatus *status_object;
+	
+	self = SVN_STATUS_COMMAND (baton);
+	
+	/* Right now we only support text status (no properties.) */
+	
+	switch (status->text_status)
+	{
+		case svn_wc_status_modified:
+		case svn_wc_status_added:
+		case svn_wc_status_deleted:
+		case svn_wc_status_conflicted:
+		case svn_wc_status_missing:
+			status_object = svn_status_new ((gchar *) path, 
+											status->text_status);
+		
+			gtranslator_async_command_lock (GTR_ASYNC_COMMAND (self));
+			g_queue_push_tail (self->priv->status_queue, status_object);
+			gtranslator_async_command_unlock (GTR_ASYNC_COMMAND (self));
+		
+			gtranslator_command_notify_data_arrived (GTR_COMMAND (self));
+		
+			break;
+		default:
+			break;
+	}
+}
+
+static guint 
+svn_status_command_run (GtranslatorCommand *command)
+{
+	SvnStatusCommand *self;
+	SvnCommand *svn_command;
+	svn_opt_revision_t revision;
+	svn_error_t *error;
+	svn_depth_t depth;
+	
+	self = SVN_STATUS_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	revision.kind = svn_opt_revision_working;
+	
+	if (self->priv->recursive == TRUE)
+		depth = svn_depth_infinity;
+	else depth = svn_depth_immediates;
+	
+	error = svn_client_status3 (NULL, 
+								self->priv->path, 
+								&revision,
+								on_svn_status_notify, 
+								self, 
+								depth,
+								self->priv->get_all_items, 
+								FALSE, 
+								FALSE,
+								TRUE,
+								NULL,
+								svn_command_get_client_context (svn_command),
+								svn_command_get_pool (svn_command));
+	
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	return 0;
+}
+
+static void
+svn_status_command_class_init (SvnStatusCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	command_class->run = svn_status_command_run;
+	object_class->finalize = svn_status_command_finalize;
+}
+
+SvnStatusCommand *
+svn_status_command_new (gchar *path, gboolean recursive, gboolean get_all_items)
+{
+	SvnStatusCommand *self;
+	
+	self = g_object_new (SVN_TYPE_STATUS_COMMAND, NULL);
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+														path);
+	self->priv->recursive = recursive;
+	self->priv->get_all_items = get_all_items;
+	
+	return self;
+}
+
+void
+svn_status_command_destroy (SvnStatusCommand *self)
+{
+	g_object_unref (self);
+}
+
+GQueue *
+svn_status_command_get_status_queue (SvnStatusCommand *self)
+{
+	return self->priv->status_queue;
+}

Added: trunk/plugins/subversion/svn-status-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-status-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,65 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * anjuta is free software.
+ * 
+ * You may 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.
+ * 
+ * anjuta 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 anjuta.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_STATUS_COMMAND_H_
+#define _SVN_STATUS_COMMAND_H_
+
+#include <glib-object.h>
+#include "svn-command.h"
+#include "svn-status.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_STATUS_COMMAND             (svn_status_command_get_type ())
+#define SVN_STATUS_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_STATUS_COMMAND, SvnStatusCommand))
+#define SVN_STATUS_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_STATUS_COMMAND, SvnStatusCommandClass))
+#define SVN_IS_STATUS_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_STATUS_COMMAND))
+#define SVN_IS_STATUS_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_STATUS_COMMAND))
+#define SVN_STATUS_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_STATUS_COMMAND, SvnStatusCommandClass))
+
+typedef struct _SvnStatusCommandClass SvnStatusCommandClass;
+typedef struct _SvnStatusCommand SvnStatusCommand;
+typedef struct _SvnStatusCommandPriv SvnStatusCommandPriv;
+
+struct _SvnStatusCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnStatusCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnStatusCommandPriv *priv;
+};
+
+GType svn_status_command_get_type (void) G_GNUC_CONST;
+SvnStatusCommand *svn_status_command_new (gchar *path, gboolean recursive, 
+										  gboolean get_all_items);
+void svn_status_command_destroy (SvnStatusCommand *self);
+GQueue *svn_status_command_get_status_queue (SvnStatusCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_STATUS_COMMAND_H_ */

Added: trunk/plugins/subversion/svn-status.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-status.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,115 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-status.h"
+
+struct _SvnStatusPriv
+{
+	gchar *path;
+	enum svn_wc_status_kind status;
+};
+
+G_DEFINE_TYPE (SvnStatus, svn_status, G_TYPE_OBJECT);
+
+static void
+svn_status_init (SvnStatus *self)
+{
+	self->priv = g_new0 (SvnStatusPriv, 1);
+}
+
+static void
+svn_status_finalize (GObject *object)
+{
+	SvnStatus *self;
+	
+	self = SVN_STATUS (object);
+	
+	g_free (self->priv->path);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_status_parent_class)->finalize (object);
+}
+
+static void
+svn_status_class_init (SvnStatusClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = svn_status_finalize;
+}
+
+SvnStatus *
+svn_status_new (gchar *path, enum svn_wc_status_kind status)
+{
+	SvnStatus *self;
+	
+	self = g_object_new (SVN_TYPE_STATUS, NULL);
+	
+	self->priv->path = g_strdup (path);
+	self->priv->status = status;
+	
+	return self;
+}
+
+void
+svn_status_destroy (SvnStatus *self)
+{
+	g_object_unref (self);
+}
+
+gchar *
+svn_status_get_path (SvnStatus *self)
+{
+	return g_strdup (self->priv->path);
+}
+
+GtranslatorVcsStatus
+svn_status_get_vcs_status (SvnStatus *self)
+{
+	GtranslatorVcsStatus status;
+	
+	switch (self->priv->status)
+	{
+		case svn_wc_status_modified:
+			status = GTR_VCS_STATUS_MODIFIED;
+			break;
+		case svn_wc_status_added:
+			status = GTR_VCS_STATUS_ADDED;
+			break;
+		case svn_wc_status_deleted:
+			status = GTR_VCS_STATUS_DELETED;
+			break;
+		case svn_wc_status_conflicted:
+			status = GTR_VCS_STATUS_CONFLICTED;
+			break;
+		case svn_wc_status_missing:
+			status = GTR_VCS_STATUS_MISSING;
+			break;
+		default:
+			status = GTR_VCS_STATUS_NONE;
+			break;
+	}
+	
+	return status;
+}

Added: trunk/plugins/subversion/svn-status.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-status.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,65 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * anjuta
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * anjuta is free software.
+ * 
+ * You may 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.
+ * 
+ * anjuta 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 anjuta.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_STATUS_H_
+#define _SVN_STATUS_H_
+
+#include <glib-object.h>
+#include <svn_wc.h>
+#include "vcs-status-tree-view.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_STATUS             (svn_status_get_type ())
+#define SVN_STATUS(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_STATUS, SvnStatus))
+#define SVN_STATUS_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_STATUS, SvnStatusClass))
+#define SVN_IS_STATUS(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_STATUS))
+#define SVN_IS_STATUS_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_STATUS))
+#define SVN_STATUS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_STATUS, SvnStatusClass))
+
+typedef struct _SvnStatusClass SvnStatusClass;
+typedef struct _SvnStatus SvnStatus;
+typedef struct _SvnStatusPriv SvnStatusPriv;
+
+struct _SvnStatusClass
+{
+	GObjectClass parent_class;
+};
+
+struct _SvnStatus
+{
+	GObject parent_instance;
+	
+	SvnStatusPriv *priv;
+};
+
+GType svn_status_get_type (void) G_GNUC_CONST;
+SvnStatus *svn_status_new (gchar *path, enum svn_wc_status_kind status);
+void svn_status_destroy (SvnStatus *self);
+gchar * svn_status_get_path (SvnStatus *self);
+GtranslatorVcsStatus svn_status_get_vcs_status (SvnStatus *self);
+
+G_END_DECLS
+
+#endif /* _SVN_STATUS_H_ */

Added: trunk/plugins/subversion/svn-update-command.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-update-command.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,141 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#include "svn-update-command.h"
+
+struct _SvnUpdateCommandPriv
+{
+	gchar *path;
+	gchar *revision;
+	gboolean recursive;
+};
+
+G_DEFINE_TYPE (SvnUpdateCommand, svn_update_command, SVN_TYPE_COMMAND);
+
+static void
+svn_update_command_init (SvnUpdateCommand *self)
+{	
+	self->priv = g_new0 (SvnUpdateCommandPriv, 1);
+}
+
+static void
+svn_update_command_finalize (GObject *object)
+{
+	SvnUpdateCommand *self;
+	
+	self = SVN_UPDATE_COMMAND (object);
+	
+	g_free (self->priv->path);
+	g_free (self->priv->revision);
+	g_free (self->priv);
+
+	G_OBJECT_CLASS (svn_update_command_parent_class)->finalize (object);
+}
+
+static guint
+svn_update_command_run (GtranslatorCommand *command)
+{
+	SvnUpdateCommand *self;
+	SvnCommand *svn_command;
+	svn_opt_revision_t *revision;
+	apr_array_header_t *update_paths;
+	apr_array_header_t *update_revisions;
+	svn_error_t *error;
+	svn_revnum_t revision_number;
+	gchar *revision_message;
+	svn_depth_t depth;
+	
+	self = SVN_UPDATE_COMMAND (command);
+	svn_command = SVN_COMMAND (command);
+	revision = svn_command_get_revision (self->priv->revision);
+	
+	/* I just copied this so don't blame me... */
+	update_paths = apr_array_make (svn_command_get_pool (svn_command), 1,
+								   sizeof (char *));
+	(*((const char **) apr_array_push (update_paths))) = self->priv->path;
+	
+	if (self->priv->recursive == TRUE)
+		depth = svn_depth_infinity;
+	else depth = svn_depth_files;
+	
+	error = svn_client_update3 (&update_revisions, 
+								update_paths, 
+								revision, 
+								depth,
+								FALSE,
+								FALSE,
+								FALSE,
+								svn_command_get_client_context (svn_command),
+								svn_command_get_pool (svn_command));
+	
+	if (error)
+	{
+		svn_command_set_error (svn_command, error);
+		return 1;
+	}
+	
+	revision_number = (*(svn_revnum_t *) apr_array_pop (update_revisions));
+	
+	revision_message = g_strdup_printf (_("Updated to revision %ld."), 
+										(glong) revision_number);
+	svn_command_push_info (SVN_COMMAND (command), revision_message);
+	g_free (revision_message);
+	
+	return 0;
+}
+
+static void
+svn_update_command_class_init (SvnUpdateCommandClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtranslatorCommandClass *command_class = GTR_COMMAND_CLASS (klass);
+
+	object_class->finalize = svn_update_command_finalize;
+	command_class->run = svn_update_command_run;
+}
+
+
+SvnUpdateCommand *
+svn_update_command_new (gchar *path, gchar *revision, gboolean recursive)
+{
+	SvnUpdateCommand *self;
+	
+	self = g_object_new (SVN_TYPE_UPDATE_COMMAND, NULL);
+	
+	self->priv->path = svn_command_make_canonical_path (SVN_COMMAND (self),
+														path);
+	self->priv->revision = g_strdup (revision);
+	self->priv->recursive = recursive;
+	
+	return self;
+}
+
+void
+svn_update_command_destroy (SvnUpdateCommand *self)
+{
+	g_object_unref (self);
+}

Added: trunk/plugins/subversion/svn-update-command.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/svn-update-command.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,68 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ *
+ * Portions based on the original Subversion plugin 
+ * Copyright (C) Johannes Schmid 2005 
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _SVN_UPDATE_COMMAND_H_
+#define _SVN_UPDATE_COMMAND_H_
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include "svn-command.h"
+
+G_BEGIN_DECLS
+
+#define SVN_TYPE_UPDATE_COMMAND             (svn_update_command_get_type ())
+#define SVN_UPDATE_COMMAND(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), SVN_TYPE_UPDATE_COMMAND, SvnUpdateCommand))
+#define SVN_UPDATE_COMMAND_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), SVN_TYPE_UPDATE_COMMAND, SvnUpdateCommandClass))
+#define SVN_IS_UPDATE_COMMAND(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SVN_TYPE_UPDATE_COMMAND))
+#define SVN_IS_UPDATE_COMMAND_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), SVN_TYPE_UPDATE_COMMAND))
+#define SVN_UPDATE_COMMAND_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), SVN_TYPE_UPDATE_COMMAND, SvnUpdateCommandClass))
+
+typedef struct _SvnUpdateCommandClass SvnUpdateCommandClass;
+typedef struct _SvnUpdateCommand SvnUpdateCommand;
+typedef struct _SvnUpdateCommandPriv SvnUpdateCommandPriv;
+
+struct _SvnUpdateCommandClass
+{
+	SvnCommandClass parent_class;
+};
+
+struct _SvnUpdateCommand
+{
+	SvnCommand parent_instance;
+	
+	SvnUpdateCommandPriv *priv;
+};
+
+GType svn_update_command_get_type (void) G_GNUC_CONST;
+SvnUpdateCommand * svn_update_command_new (gchar *path, gchar *revision, 
+										   gboolean recursive);
+void svn_update_command_destroy (SvnUpdateCommand *self);
+
+G_END_DECLS
+
+#endif /* _SVN_UPDATE_COMMAND_H_ */

Added: trunk/plugins/subversion/update-dialog.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/update-dialog.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "update-dialog.h"
+#include "subversion-plugin.h"
+#include "svn-update-command.h"
+#include "utils.h"
+#include "svn-command.h"
+#include "statusbar.h"
+#include "subversion-utils.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+
+#define GTR_UPDATE_DIALOG_GET_PRIVATE(object)	(G_TYPE_INSTANCE_GET_PRIVATE ( \
+						 	(object),	\
+						 	GTR_TYPE_UPDATE_DIALOG,     \
+						 	GtranslatorUpdateDialogPrivate))
+
+
+G_DEFINE_TYPE(GtranslatorUpdateDialog, gtranslator_update_dialog, GTK_TYPE_DIALOG)
+
+struct _GtranslatorUpdateDialogPrivate
+{
+	GtkWidget *main_box;
+	GtkWidget *dir_button;
+	
+	GtkListStore *store;
+	GtkWidget *update_treeview;
+	
+	GtranslatorWindow *window;
+};
+
+enum 
+{
+	ICON_COLUMN,
+	TEXT_COLUMN,
+	N_COLUMNS
+};
+
+static void
+on_update_command_finished (GtranslatorCommand *command,
+			    guint return_code,
+			    GtranslatorUpdateDialog *dlg)
+{
+	GtranslatorStatusbar *status;
+	
+	status = GTR_STATUSBAR (gtranslator_window_get_statusbar (dlg->priv->window));
+	
+	gtranslator_statusbar_flash_message (status, 0,
+					     _("Subversion: Update complete."));
+	
+	subversion_utils_report_errors (dlg->priv->window, 
+					command, return_code);
+	
+	svn_update_command_destroy (SVN_UPDATE_COMMAND (command));	
+}
+
+static void
+on_update_command_info_arrived (GtranslatorCommand *command,
+				GtranslatorUpdateDialog *dlg)
+{
+	GQueue *info;
+	gchar *message;
+	GtkTreeIter iter;
+	
+	info = svn_command_get_info_queue (SVN_COMMAND (command));
+	
+	while (g_queue_peek_head (info))
+	{
+		message = g_queue_pop_head (info);
+		
+		gtk_list_store_append(dlg->priv->store, &iter);
+		gtk_list_store_set (dlg->priv->store, &iter,
+				    TEXT_COLUMN, message,
+				    -1);
+		
+		g_free (message);
+	}
+}
+
+static void
+dialog_response_handler (GtranslatorUpdateDialog *dlg, 
+			 gint       res_id)
+{
+	switch (res_id)
+	{
+		case GTK_RESPONSE_APPLY:
+		{
+			gchar *filename;
+			SvnUpdateCommand *update_command;
+			
+			filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg->priv->dir_button));
+			
+			update_command = svn_update_command_new ((gchar *) filename,
+								 (gchar *)"", 
+								 TRUE);
+			g_free (filename);
+			
+			gtk_list_store_clear (dlg->priv->store);
+			
+			g_signal_connect (G_OBJECT (update_command), "command-finished",
+					  G_CALLBACK (on_update_command_finished),
+					  dlg);
+			
+			g_signal_connect (G_OBJECT (update_command), "data-arrived",
+					  G_CALLBACK (on_update_command_info_arrived),
+					  dlg);
+			
+			gtranslator_command_start (GTR_COMMAND (update_command));
+			
+			break;
+		}
+		default:
+			gtk_widget_hide (GTK_WIDGET (dlg));
+	}
+}
+
+static void
+setup_treeview (GtranslatorUpdateDialog *dlg)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	
+	dlg->priv->store = gtk_list_store_new (N_COLUMNS,
+					       GDK_TYPE_PIXBUF,
+					       G_TYPE_STRING);
+	
+	gtk_tree_view_set_model (GTK_TREE_VIEW (dlg->priv->update_treeview),
+				 GTK_TREE_MODEL (dlg->priv->store));
+	
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dlg->priv->update_treeview),
+					   FALSE);
+	
+	column = gtk_tree_view_column_new ();
+	/*
+	 * Icon column
+	 */
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	g_object_set (renderer,
+		      "stock-id", GTK_STOCK_INFO,
+		      "stock-size", GTK_ICON_SIZE_MENU,
+		      "xalign", 1.0,
+		      "xpad", 6,
+		      NULL);
+
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	
+	/*
+	 * Text column
+	 */
+	
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_set_attributes (column,
+					     renderer,
+					     "text", TEXT_COLUMN,
+					     NULL);
+
+	gtk_tree_view_column_set_resizable (column, FALSE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (dlg->priv->update_treeview),
+				     column);
+}
+
+static void
+setup_dir (GtranslatorUpdateDialog *dlg)
+{
+	GtranslatorTab *tab;
+	GtranslatorPo *po;
+	gchar *dirname;
+	gchar *dir;
+	GFile *file;
+	
+	tab = gtranslator_window_get_active_tab (dlg->priv->window);
+	po = gtranslator_tab_get_po (tab);
+	dirname = g_path_get_dirname (gtranslator_po_get_filename (po));
+	
+	dir = g_build_filename (dirname, "../", NULL);
+	g_free (dirname);
+	
+	file = g_file_new_for_path (dir);
+	g_free (dir);
+	dir = g_file_get_uri (file);
+	
+	gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (dlg->priv->dir_button),
+				  dir);
+	g_free (dir);
+	g_object_unref (file);
+}
+
+static void
+gtranslator_update_dialog_init (GtranslatorUpdateDialog *dlg)
+{
+	gboolean ret;
+	GtkWidget *error_widget;
+	
+	dlg->priv = GTR_UPDATE_DIALOG_GET_PRIVATE (dlg);
+	
+	gtk_dialog_add_buttons (GTK_DIALOG (dlg),
+				GTK_STOCK_REFRESH,
+				GTK_RESPONSE_APPLY,
+				GTK_STOCK_CLOSE,
+				GTK_RESPONSE_CLOSE,
+				NULL);
+	
+	gtk_window_set_title (GTK_WINDOW (dlg), _("Update repository"));
+	gtk_window_set_default_size (GTK_WINDOW (dlg), 600, 600);
+	gtk_window_set_resizable (GTK_WINDOW (dlg), TRUE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+	gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg), TRUE);
+	
+	/* HIG defaults */
+	gtk_container_set_border_width (GTK_CONTAINER (dlg), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->vbox), 2); /* 2 * 5 + 2 = 12 */
+	gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 5);
+	gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dlg)->action_area), 4);
+	
+	g_signal_connect (dlg,
+			  "response",
+			  G_CALLBACK (dialog_response_handler),
+			  NULL);
+	
+	/*Glade*/
+	ret = gtranslator_utils_get_glade_widgets (GLADE_FILE,
+		"update_main_box",
+		&error_widget,
+		
+		"update_main_box", &dlg->priv->main_box,
+		"dir_button", &dlg->priv->dir_button,
+		"update_treeview", &dlg->priv->update_treeview,
+		
+		NULL);
+	
+	if(!ret)
+	{
+		gtk_widget_show (error_widget);
+		gtk_box_pack_start_defaults (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+					     error_widget);
+		
+		return;
+	}
+	
+	setup_treeview (dlg);
+	
+	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
+			    dlg->priv->main_box, TRUE, TRUE, 0);
+	
+	gtk_container_set_border_width (GTK_CONTAINER (dlg->priv->main_box), 5);
+	
+}
+
+static void
+gtranslator_update_dialog_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gtranslator_update_dialog_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_update_dialog_class_init (GtranslatorUpdateDialogClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (GtranslatorUpdateDialogPrivate));
+
+	object_class->finalize = gtranslator_update_dialog_finalize;
+}
+
+void
+gtranslator_show_update_dialog (GtranslatorWindow *window)
+{
+	static GtranslatorUpdateDialog *dlg = NULL;
+	
+	g_return_if_fail (GTR_IS_WINDOW (window));
+	
+	if(dlg == NULL)
+	{
+		dlg = g_object_new (GTR_TYPE_UPDATE_DIALOG, NULL);
+		
+		gtk_window_set_destroy_with_parent (GTK_WINDOW (dlg),
+						    TRUE);
+		
+		dlg->priv->window = window;
+
+		setup_dir (dlg);
+		
+		g_signal_connect (dlg,
+				  "destroy",
+				  G_CALLBACK (gtk_widget_destroyed),
+				  &dlg);
+
+		gtk_widget_show (GTK_WIDGET (dlg));
+	}
+	
+	if (GTK_WINDOW (window) != gtk_window_get_transient_for (GTK_WINDOW (dlg)))
+	{
+		gtk_window_set_transient_for (GTK_WINDOW (dlg),
+					      GTK_WINDOW (window));
+	}
+
+	gtk_window_present (GTK_WINDOW (dlg));
+}

Added: trunk/plugins/subversion/update-dialog.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/update-dialog.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008  Ignacio Casal Quinteiro <nacho resa gmail com>
+ * 
+ *     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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __UPDATE_DIALOG_H__
+#define __UPDATE_DIALOG_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "window.h"
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define GTR_TYPE_UPDATE_DIALOG		(gtranslator_update_dialog_get_type ())
+#define GTR_UPDATE_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), GTR_TYPE_UPDATE_DIALOG, GtranslatorUpdateDialog))
+#define GTR_UPDATE_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), GTR_TYPE_UPDATE_DIALOG, GtranslatorUpdateDialogClass))
+#define GTR_IS_UPDATE_DIALOG(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), GTR_TYPE_UPDATE_DIALOG))
+#define GTR_IS_UPDATE_DIALOG_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), GTR_TYPE_UPDATE_DIALOG))
+#define GTR_UPDATE_DIALOG_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), GTR_TYPE_UPDATE_DIALOG, GtranslatorUpdateDialogClass))
+
+/* Private structure type */
+typedef struct _GtranslatorUpdateDialogPrivate	GtranslatorUpdateDialogPrivate;
+
+/*
+ * Main object structure
+ */
+typedef struct _GtranslatorUpdateDialog		GtranslatorUpdateDialog;
+
+struct _GtranslatorUpdateDialog
+{
+	GtkDialog parent_instance;
+	
+	/*< private > */
+	GtranslatorUpdateDialogPrivate *priv;
+};
+
+/*
+ * Class definition
+ */
+typedef struct _GtranslatorUpdateDialogClass	GtranslatorUpdateDialogClass;
+
+struct _GtranslatorUpdateDialogClass
+{
+	GtkDialogClass parent_class;
+};
+
+/*
+ * Public methods
+ */
+GType		 gtranslator_update_dialog_get_type               (void) G_GNUC_CONST;
+
+GType		 gtranslator_update_dialog_register_type          (GTypeModule * module);
+
+void	     gtranslator_show_update_dialog                   (GtranslatorWindow *window);
+
+G_END_DECLS
+
+#endif /* __UPDATE_DIALOG_H__ */

Added: trunk/plugins/subversion/vcs-status-tree-view.c
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/vcs-status-tree-view.c	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,395 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+* gtranslator
+* Copyright (C) James Liggett 2007 <jrliggett cox net>
+* 
+* gtranslator is free software.
+* 
+* You may 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.
+* 
+* gtranslator 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 gtranslator.  If not, write to:
+* 	The Free Software Foundation, Inc.,
+* 	51 Franklin Street, Fifth Floor
+* 	Boston, MA  02110-1301, USA.
+*/
+
+#include "vcs-status-tree-view.h"
+#include <string.h>
+#include <glib/gi18n.h>
+
+enum 
+{
+	COL_SELECTED,
+	COL_STATUS,
+	COL_PATH,
+	NUM_COLS
+};
+
+enum
+{
+	GTR_VCS_STATUS_TREE_VIEW_CONSTRUCT_STATUS_CODES = 1,
+	GTR_VCS_STATUS_TREE_VIEW_SHOW_STATUS
+};
+
+struct _GtranslatorVcsStatusTreeViewPriv
+{
+	GtkListStore *store;
+	GHashTable *selected_paths;
+	guint status_codes;
+	gboolean show_status;
+};
+
+G_DEFINE_TYPE (GtranslatorVcsStatusTreeView, gtranslator_vcs_status_tree_view, 
+			   GTK_TYPE_TREE_VIEW);
+
+static void
+on_selected_column_toggled (GtkCellRendererToggle *renderer,
+							gchar *tree_path,
+							GtranslatorVcsStatusTreeView *self)
+{
+	GtkTreeIter iter;
+	gchar *vcs_path;
+	gboolean selected;
+	
+	gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (self->priv->store),
+										 &iter, tree_path);
+	
+	gtk_tree_model_get (GTK_TREE_MODEL (self->priv->store), &iter,
+						COL_PATH, &vcs_path,
+						COL_SELECTED, &selected, -1);
+	
+	gtk_list_store_set (self->priv->store, &iter, 
+						COL_SELECTED, !selected, -1);
+	
+	g_free (vcs_path);
+	
+}
+
+static void
+gtranslator_vcs_status_tree_view_create_columns (GtranslatorVcsStatusTreeView *self)
+{
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	
+	/* Selected column */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_toggle_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (self), column);
+	gtk_tree_view_column_add_attribute (column, renderer, "active",
+										COL_SELECTED);
+	
+	g_signal_connect (G_OBJECT (renderer), "toggled",
+					  G_CALLBACK (on_selected_column_toggled),
+					  self);
+	
+	/* Status column */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (self), column);
+	gtk_tree_view_column_add_attribute (column, renderer, "text",
+										COL_STATUS);
+	
+	/* Path column */
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (self), column);
+	gtk_tree_view_column_add_attribute (column, renderer, "text",
+										COL_PATH);
+	
+	gtk_tree_view_set_model (GTK_TREE_VIEW (self), 
+							 GTK_TREE_MODEL (self->priv->store));
+	g_object_unref (self->priv->store);
+	
+}
+
+static gint
+path_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, 
+		   gpointer user_data)
+{
+	gint compare_value;
+	gchar *path1;
+	gchar *path2;
+	
+	gtk_tree_model_get (model, a, COL_PATH, &path1, -1);
+	gtk_tree_model_get (model, b, COL_PATH, &path2, -1);
+	
+	compare_value = strcmp (path1, path2);
+	
+	g_free (path1);
+	g_free (path2);
+	
+	return compare_value;
+}
+
+static void
+gtranslator_vcs_status_tree_view_init (GtranslatorVcsStatusTreeView *self)
+{
+	GtkTreeSortable *sortable;
+	
+	self->priv = g_new0 (GtranslatorVcsStatusTreeViewPriv, 1);
+	self->priv->store = gtk_list_store_new (NUM_COLS,
+											G_TYPE_BOOLEAN,
+											G_TYPE_STRING,
+											G_TYPE_STRING);
+	self->priv->selected_paths = g_hash_table_new_full (g_str_hash,
+														g_str_equal,
+														g_free,
+														NULL);
+	
+	gtranslator_vcs_status_tree_view_create_columns (self);
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self), FALSE);
+	
+	sortable = GTK_TREE_SORTABLE (self->priv->store);
+	gtk_tree_sortable_set_sort_column_id (sortable, COL_PATH,
+										  GTK_SORT_ASCENDING);
+	gtk_tree_sortable_set_sort_func (sortable, COL_PATH, path_sort, NULL,
+									 NULL);
+}
+
+static void
+gtranslator_vcs_status_tree_view_finalize (GObject *object)
+{
+	GtranslatorVcsStatusTreeView *self;
+	
+	self = GTR_VCS_STATUS_TREE_VIEW (object);
+	
+	g_hash_table_destroy (self->priv->selected_paths);
+	g_free (self->priv);
+	
+	G_OBJECT_CLASS (gtranslator_vcs_status_tree_view_parent_class)->finalize (object);
+}
+
+static void
+gtranslator_vcs_status_tree_view_set_property (GObject *object, guint property_id,
+										  const GValue *value, 
+										  GParamSpec *param_spec)
+{
+	GtranslatorVcsStatusTreeView *self;
+	GtkTreeView *tree_view;
+	GtkTreeViewColumn *column;
+	
+	self = GTR_VCS_STATUS_TREE_VIEW (object);
+	
+	switch (property_id)
+	{
+		case GTR_VCS_STATUS_TREE_VIEW_CONSTRUCT_STATUS_CODES:
+			self->priv->status_codes = g_value_get_flags (value);
+			break;
+		case GTR_VCS_STATUS_TREE_VIEW_SHOW_STATUS:
+			tree_view = GTK_TREE_VIEW (object);
+			column = gtk_tree_view_get_column (tree_view, COL_STATUS);
+			self->priv->show_status = g_value_get_boolean (value);
+		
+			gtk_tree_view_column_set_visible (column, self->priv->show_status);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+			break;
+	}
+}
+
+static void
+gtranslator_vcs_status_tree_view_get_property (GObject *object, guint property_id,
+										  GValue *value, GParamSpec *param_spec)
+{
+	GtranslatorVcsStatusTreeView *self;
+	
+	self = GTR_VCS_STATUS_TREE_VIEW (object);
+	
+	switch (property_id)
+	{
+		case GTR_VCS_STATUS_TREE_VIEW_CONSTRUCT_STATUS_CODES:
+			g_value_set_flags (value, self->priv->status_codes);
+			break;
+		case GTR_VCS_STATUS_TREE_VIEW_SHOW_STATUS:
+			g_value_set_boolean (value, self->priv->show_status);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
+			break;
+	}
+}
+
+static void
+gtranslator_vcs_status_tree_view_class_init (GtranslatorVcsStatusTreeViewClass *klass)
+{
+	GObjectClass* object_class = G_OBJECT_CLASS (klass);
+	GParamSpec *param_spec;
+	
+	object_class->finalize = gtranslator_vcs_status_tree_view_finalize;
+	object_class->get_property = gtranslator_vcs_status_tree_view_get_property;
+	object_class->set_property = gtranslator_vcs_status_tree_view_set_property;
+	
+	param_spec = g_param_spec_flags ("status-codes", "Status codes",
+									 "Control which status codes are shown in "
+									 "the list.",
+									 GTR_TYPE_VCS_STATUS,
+									 GTR_VCS_DEFAULT_STATUS_CODES,
+									 G_PARAM_READWRITE | 
+									 G_PARAM_CONSTRUCT_ONLY);
+	g_object_class_install_property (object_class,
+									 GTR_VCS_STATUS_TREE_VIEW_CONSTRUCT_STATUS_CODES,
+									 param_spec);
+	
+	param_spec = g_param_spec_boolean ("show-status", "Show status",
+									   "Show or hide status description",
+									   TRUE,
+									   G_PARAM_READWRITE);
+	g_object_class_install_property (object_class,
+									 GTR_VCS_STATUS_TREE_VIEW_SHOW_STATUS,
+									 param_spec);
+}
+
+
+GtkWidget *
+gtranslator_vcs_status_tree_view_new (void)
+{
+	return g_object_new (GTR_VCS_TYPE_STATUS_TREE_VIEW, NULL);
+}
+
+void
+gtranslator_vcs_status_tree_view_destroy (GtranslatorVcsStatusTreeView *self)
+{
+	g_object_unref (self);
+}
+
+void
+gtranslator_vcs_status_tree_view_add (GtranslatorVcsStatusTreeView *self, gchar *path, 
+								 GtranslatorVcsStatus status, gboolean selected)
+{
+	GtkTreeIter iter;
+	
+	if (status & self->priv->status_codes)
+	{
+		gtk_list_store_append (self->priv->store, &iter);
+		
+		gtk_list_store_set (self->priv->store, &iter,
+							COL_SELECTED, selected,
+							COL_PATH, path, 
+							-1);
+		
+		if (selected)
+		{
+			g_hash_table_insert (self->priv->selected_paths, g_strdup (path), 
+								 NULL);
+		}
+		
+		switch (status)
+		{
+			case GTR_VCS_STATUS_MODIFIED:
+				gtk_list_store_set (self->priv->store, &iter, COL_STATUS, 
+									_("Modified"), -1);
+			break;
+			case GTR_VCS_STATUS_ADDED:
+				gtk_list_store_set (self->priv->store, &iter, COL_STATUS, 
+									_("Added"), -1);
+			break;
+			case GTR_VCS_STATUS_DELETED:
+				gtk_list_store_set (self->priv->store, &iter, COL_STATUS, 
+									_("Deleted"), -1);
+			break;
+			case GTR_VCS_STATUS_CONFLICTED:
+				gtk_list_store_set (self->priv->store, &iter, COL_STATUS, 
+									_("Conflicted"), -1);
+			break;
+			case GTR_VCS_STATUS_MISSING:
+				gtk_list_store_set (self->priv->store, &iter, COL_STATUS, 
+									_("Missing"), -1);
+			break;
+			case GTR_VCS_STATUS_NONE:
+				default:
+				break;
+			
+		}
+	}
+}
+
+static gboolean
+select_all_paths (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, 
+				  GtranslatorVcsStatusTreeView *self)
+{	
+	gtk_list_store_set (self->priv->store, iter, 
+						COL_SELECTED, TRUE, 
+						-1);
+	
+	return FALSE;
+}
+
+void
+gtranslator_vcs_status_tree_view_select_all (GtranslatorVcsStatusTreeView *self)
+{
+	gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->store),
+						    (GtkTreeModelForeachFunc) select_all_paths,
+							self);
+}
+
+static gboolean 
+unselect_all_paths (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, 
+					GtranslatorVcsStatusTreeView *self)
+{
+	gtk_list_store_set (self->priv->store, iter, 
+						COL_SELECTED, FALSE, 
+						-1);
+	
+	return FALSE;
+}
+
+void
+gtranslator_vcs_status_tree_view_unselect_all (GtranslatorVcsStatusTreeView *self)
+{
+	gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->store),
+							(GtkTreeModelForeachFunc) unselect_all_paths,
+							self);
+}
+
+static gboolean
+create_selected_paths_list (GtkTreeModel *model, GtkTreePath *path,  
+							GtkTreeIter *iter, GList **list)
+{
+	gboolean selected;
+	gchar *file_path;
+	
+	gtk_tree_model_get (model, iter, 
+						COL_SELECTED, &selected,
+						COL_PATH, &file_path, 
+						-1);
+	
+	if (selected)
+		*list = g_list_append (*list, g_strdup (file_path));
+	
+	return FALSE;
+}
+
+GList *
+gtranslator_vcs_status_tree_view_get_selected (GtranslatorVcsStatusTreeView *self)
+{
+	GList *list;
+	
+	list = NULL;
+	
+	gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->store),
+							(GtkTreeModelForeachFunc) create_selected_paths_list,
+							&list);
+	
+	return list;
+}
+
+void
+gtranslator_vsc_status_tree_view_clear (GtranslatorVcsStatusTreeView *self)
+{
+	g_return_if_fail (GTR_VCS_IS_STATUS_TREE_VIEW (self));
+	
+	gtk_list_store_clear (self->priv->store);
+}
\ No newline at end of file

Added: trunk/plugins/subversion/vcs-status-tree-view.h
==============================================================================
--- (empty file)
+++ trunk/plugins/subversion/vcs-status-tree-view.h	Mon Sep 22 09:38:40 2008
@@ -0,0 +1,89 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtranslator
+ * Copyright (C) James Liggett 2007 <jrliggett cox net>
+ * 
+ * gtranslator is free software.
+ * 
+ * You may 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.
+ * 
+ * gtranslator 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 gtranslator.  If not, write to:
+ * 	The Free Software Foundation, Inc.,
+ * 	51 Franklin Street, Fifth Floor
+ * 	Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _GTR_VCS_STATUS_TREE_VIEW_H_
+#define _GTR_VCS_STATUS_TREE_VIEW_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "subversion-enum-types.h"
+
+G_BEGIN_DECLS
+
+#define GTR_VCS_TYPE_STATUS_TREE_VIEW             (gtranslator_vcs_status_tree_view_get_type ())
+#define GTR_VCS_STATUS_TREE_VIEW(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTR_VCS_TYPE_STATUS_TREE_VIEW, GtranslatorVcsStatusTreeView))
+#define GTR_VCS_STATUS_TREE_VIEW_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTR_VCS_TYPE_STATUS_TREE_VIEW, GtranslatorVcsStatusTreeViewClass))
+#define GTR_VCS_IS_STATUS_TREE_VIEW(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTR_VCS_TYPE_STATUS_TREE_VIEW))
+#define GTR_VCS_IS_STATUS_TREE_VIEW_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTR_VCS_TYPE_STATUS_TREE_VIEW))
+#define GTR_VCS_STATUS_TREE_VIEW_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTR_VCS_TYPE_STATUS_TREE_VIEW, GtranslatorVcsStatusTreeViewClass))
+
+/* Show default status codes: Modified, Added, Deleted, and Conflicted */
+#define GTR_VCS_DEFAULT_STATUS_CODES (GTR_VCS_STATUS_MODIFIED | \
+										 GTR_VCS_STATUS_ADDED |    \
+										 GTR_VCS_STATUS_DELETED |  \
+										 GTR_VCS_STATUS_CONFLICTED)
+
+typedef struct _GtranslatorVcsStatusTreeViewClass GtranslatorVcsStatusTreeViewClass;
+typedef struct _GtranslatorVcsStatusTreeView GtranslatorVcsStatusTreeView;
+typedef struct _GtranslatorVcsStatusTreeViewPriv GtranslatorVcsStatusTreeViewPriv;
+
+struct _GtranslatorVcsStatusTreeViewClass
+{
+	GtkTreeViewClass parent_class;
+};
+
+struct _GtranslatorVcsStatusTreeView
+{
+	GtkTreeView parent_instance;
+	
+	GtranslatorVcsStatusTreeViewPriv *priv;
+};
+
+typedef enum
+{
+	/* Unversioned, ignored, or uninteresting items */
+	GTR_VCS_STATUS_NONE = 0, /*< skip >*/
+	
+	GTR_VCS_STATUS_MODIFIED = 1 << 0,
+	GTR_VCS_STATUS_ADDED = 1 << 1,
+	GTR_VCS_STATUS_DELETED = 1 << 2,
+	GTR_VCS_STATUS_CONFLICTED = 1 << 3,
+	GTR_VCS_STATUS_MISSING = 1 << 4,
+} GtranslatorVcsStatus;
+
+GType gtranslator_vcs_status_tree_view_get_type (void) G_GNUC_CONST;
+GtkWidget *gtranslator_vcs_status_tree_view_new (void);
+void gtranslator_vcs_status_tree_view_destroy (GtranslatorVcsStatusTreeView *self);
+void gtranslator_vcs_status_tree_view_add (GtranslatorVcsStatusTreeView *self, 
+									  gchar *path, 
+									  GtranslatorVcsStatus status, 
+									  gboolean selected);
+void gtranslator_vsc_status_tree_view_clear (GtranslatorVcsStatusTreeView *self);
+void gtranslator_vcs_status_tree_view_select_all (GtranslatorVcsStatusTreeView *self);
+void gtranslator_vcs_status_tree_view_unselect_all (GtranslatorVcsStatusTreeView *self);
+GList *gtranslator_vcs_status_tree_view_get_selected (GtranslatorVcsStatusTreeView *self);
+
+G_END_DECLS
+
+#endif /* _GTR_VCS_STATUS_TREE_VIEW_H_ */

Modified: trunk/src/main.c
==============================================================================
--- trunk/src/main.c	(original)
+++ trunk/src/main.c	Mon Sep 22 09:38:40 2008
@@ -129,6 +129,7 @@
 		g_clear_error(&error);
 	}
 
+	if (!g_thread_supported()) g_thread_init(NULL);
 	gtk_init(&argc, &argv);
 	
 	g_option_context_parse(context, &argc, &argv, NULL);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]