summaryrefslogtreecommitdiffstats
path: root/vcs
diff options
context:
space:
mode:
Diffstat (limited to 'vcs')
-rw-r--r--vcs/Makefile.am39
-rw-r--r--vcs/clearcase/Makefile.am18
-rw-r--r--vcs/clearcase/README3
-rw-r--r--vcs/clearcase/README.dox42
-rw-r--r--vcs/clearcase/clearcasefileinfoprovider.cpp66
-rw-r--r--vcs/clearcase/clearcasefileinfoprovider.h50
-rw-r--r--vcs/clearcase/clearcasemanipulator.cpp133
-rw-r--r--vcs/clearcase/clearcasemanipulator.h49
-rw-r--r--vcs/clearcase/clearcasepart.cpp363
-rw-r--r--vcs/clearcase/clearcasepart.h65
-rw-r--r--vcs/clearcase/commentdlg.cpp61
-rw-r--r--vcs/clearcase/commentdlg.h32
-rw-r--r--vcs/clearcase/integrator/Makefile.am13
-rw-r--r--vcs/clearcase/integrator/ccintegratordlg.cpp40
-rw-r--r--vcs/clearcase/integrator/ccintegratordlg.h36
-rw-r--r--vcs/clearcase/integrator/ccintegratordlgbase.ui47
-rw-r--r--vcs/clearcase/integrator/clearcaseintegrator.cpp54
-rw-r--r--vcs/clearcase/integrator/clearcaseintegrator.h39
-rw-r--r--vcs/clearcase/integrator/kdevclearcaseintegrator.desktop44
-rw-r--r--vcs/clearcase/kdevclearcase.desktop82
-rw-r--r--vcs/cvsservice/Makefile.am40
-rw-r--r--vcs/cvsservice/README1
-rw-r--r--vcs/cvsservice/README.dox82
-rw-r--r--vcs/cvsservice/annotatedialog.cpp68
-rw-r--r--vcs/cvsservice/annotatedialog.h65
-rw-r--r--vcs/cvsservice/annotatepage.cpp257
-rw-r--r--vcs/cvsservice/annotatepage.h125
-rw-r--r--vcs/cvsservice/annotateview.cpp221
-rw-r--r--vcs/cvsservice/annotateview.h55
-rw-r--r--vcs/cvsservice/bufferedstringreader.cpp47
-rw-r--r--vcs/cvsservice/bufferedstringreader.h44
-rw-r--r--vcs/cvsservice/buildcvs.sh25
-rw-r--r--vcs/cvsservice/changelog.cpp114
-rw-r--r--vcs/cvsservice/changelog.h45
-rw-r--r--vcs/cvsservice/checkoutdialog.cpp276
-rw-r--r--vcs/cvsservice/checkoutdialog.h90
-rw-r--r--vcs/cvsservice/checkoutdialogbase.ui312
-rw-r--r--vcs/cvsservice/commitdialogbase.ui161
-rw-r--r--vcs/cvsservice/commitdlg.cpp92
-rw-r--r--vcs/cvsservice/commitdlg.h45
-rw-r--r--vcs/cvsservice/cvsdiffpage.cpp134
-rw-r--r--vcs/cvsservice/cvsdiffpage.h55
-rw-r--r--vcs/cvsservice/cvsdir.cpp321
-rw-r--r--vcs/cvsservice/cvsdir.h103
-rw-r--r--vcs/cvsservice/cvsentry.cpp187
-rw-r--r--vcs/cvsservice/cvsentry.h56
-rw-r--r--vcs/cvsservice/cvsfileinfoprovider.cpp314
-rw-r--r--vcs/cvsservice/cvsfileinfoprovider.h79
-rw-r--r--vcs/cvsservice/cvsform.cpp83
-rw-r--r--vcs/cvsservice/cvsform.h37
-rw-r--r--vcs/cvsservice/cvsformbase.ui223
-rw-r--r--vcs/cvsservice/cvslogdialog.cpp113
-rw-r--r--vcs/cvsservice/cvslogdialog.h50
-rw-r--r--vcs/cvsservice/cvslogpage.cpp212
-rw-r--r--vcs/cvsservice/cvslogpage.h63
-rw-r--r--vcs/cvsservice/cvsoptions.cpp288
-rw-r--r--vcs/cvsservice/cvsoptions.h102
-rw-r--r--vcs/cvsservice/cvsoptionswidget.cpp190
-rw-r--r--vcs/cvsservice/cvsoptionswidget.h62
-rw-r--r--vcs/cvsservice/cvsoptionswidgetbase.ui230
-rw-r--r--vcs/cvsservice/cvspart.cpp780
-rw-r--r--vcs/cvsservice/cvspart.h173
-rw-r--r--vcs/cvsservice/cvspartimpl.cpp1012
-rw-r--r--vcs/cvsservice/cvspartimpl.h354
-rw-r--r--vcs/cvsservice/cvsprocesswidget.cpp288
-rw-r--r--vcs/cvsservice/cvsprocesswidget.h77
-rw-r--r--vcs/cvsservice/cvsservicedcopIface.h29
-rw-r--r--vcs/cvsservice/diffdialog.cpp89
-rw-r--r--vcs/cvsservice/diffdialog.h42
-rw-r--r--vcs/cvsservice/diffdialogbase.ui275
-rw-r--r--vcs/cvsservice/diffwidget.cpp331
-rw-r--r--vcs/cvsservice/diffwidget.h103
-rw-r--r--vcs/cvsservice/editorsdialog.cpp134
-rw-r--r--vcs/cvsservice/editorsdialog.h43
-rw-r--r--vcs/cvsservice/editorsdialogbase.ui88
-rw-r--r--vcs/cvsservice/integrator/Makefile.am12
-rw-r--r--vcs/cvsservice/integrator/cvsserviceintegrator.cpp52
-rw-r--r--vcs/cvsservice/integrator/cvsserviceintegrator.h38
-rw-r--r--vcs/cvsservice/integrator/fetcherdlgbase.ui153
-rw-r--r--vcs/cvsservice/integrator/initdlg.ui71
-rw-r--r--vcs/cvsservice/integrator/integratordlg.cpp191
-rw-r--r--vcs/cvsservice/integrator/integratordlg.h48
-rw-r--r--vcs/cvsservice/integrator/integratordlgbase.ui398
-rw-r--r--vcs/cvsservice/integrator/kdevcvsserviceintegrator.desktop45
-rw-r--r--vcs/cvsservice/jobscheduler.cpp55
-rw-r--r--vcs/cvsservice/jobscheduler.h51
-rw-r--r--vcs/cvsservice/kdev_cvs.pngbin0 -> 721 bytes
-rw-r--r--vcs/cvsservice/kdev_cvs.xcfbin0 -> 18033 bytes
-rw-r--r--vcs/cvsservice/kdevcvsservice.desktop77
-rw-r--r--vcs/cvsservice/kdevcvsservicepart.rc36
-rw-r--r--vcs/cvsservice/releaseinputdialog.cpp66
-rw-r--r--vcs/cvsservice/releaseinputdialog.h55
-rw-r--r--vcs/cvsservice/releaseinputdialogbase.ui246
-rw-r--r--vcs/cvsservice/tagdialog.cpp74
-rw-r--r--vcs/cvsservice/tagdialog.h51
-rw-r--r--vcs/cvsservice/tagdialogbase.ui159
-rw-r--r--vcs/perforce/Makefile.am19
-rw-r--r--vcs/perforce/README3
-rw-r--r--vcs/perforce/README.dox15
-rw-r--r--vcs/perforce/commitdlg.cpp161
-rw-r--r--vcs/perforce/commitdlg.h57
-rw-r--r--vcs/perforce/integrator/Makefile.am13
-rw-r--r--vcs/perforce/integrator/kdevperforceintegrator.desktop44
-rw-r--r--vcs/perforce/integrator/perforceintegrator.cpp54
-rw-r--r--vcs/perforce/integrator/perforceintegrator.h39
-rw-r--r--vcs/perforce/integrator/pfintegratordlg.cpp40
-rw-r--r--vcs/perforce/integrator/pfintegratordlg.h36
-rw-r--r--vcs/perforce/integrator/pfintegratordlgbase.ui47
-rw-r--r--vcs/perforce/kdevperforce.desktop82
-rw-r--r--vcs/perforce/kdevperforcepart.rc23
-rw-r--r--vcs/perforce/perforcepart.cpp364
-rw-r--r--vcs/perforce/perforcepart.h79
-rw-r--r--vcs/subversion/Makefile.am38
-rw-r--r--vcs/subversion/README.dox13
-rw-r--r--vcs/subversion/commitdlg.cpp47
-rw-r--r--vcs/subversion/commitdlg.h37
-rw-r--r--vcs/subversion/commitdlgbase.ui111
-rw-r--r--vcs/subversion/configure.in.bot9
-rw-r--r--vcs/subversion/configure.in.in134
-rw-r--r--vcs/subversion/integrator/Makefile.am14
-rw-r--r--vcs/subversion/integrator/kdevsubversionintegrator.desktop45
-rw-r--r--vcs/subversion/integrator/subversionintegrator.cpp54
-rw-r--r--vcs/subversion/integrator/subversionintegrator.h39
-rw-r--r--vcs/subversion/integrator/svnintegratordlg.cpp122
-rw-r--r--vcs/subversion/integrator/svnintegratordlg.h39
-rw-r--r--vcs/subversion/integrator/svnintegratordlgbase.ui190
-rw-r--r--vcs/subversion/kdevpart_subversion.rc31
-rw-r--r--vcs/subversion/kdevsubversion.desktop34
-rw-r--r--vcs/subversion/kdevsvn+file.protocol39
-rw-r--r--vcs/subversion/kdevsvn+http.protocol39
-rw-r--r--vcs/subversion/kdevsvn+https.protocol39
-rw-r--r--vcs/subversion/kdevsvn+ssh.protocol39
-rw-r--r--vcs/subversion/kdevsvn+svn.protocol39
-rw-r--r--vcs/subversion/kdevsvnd.cpp394
-rw-r--r--vcs/subversion/kdevsvnd.desktop31
-rw-r--r--vcs/subversion/kdevsvnd.h50
-rw-r--r--vcs/subversion/kdevsvnd_widgets.cpp70
-rw-r--r--vcs/subversion/kdevsvnd_widgets.h41
-rw-r--r--vcs/subversion/subversion_core.cpp738
-rw-r--r--vcs/subversion/subversion_core.h105
-rw-r--r--vcs/subversion/subversion_fileinfo.cpp507
-rw-r--r--vcs/subversion/subversion_fileinfo.h73
-rw-r--r--vcs/subversion/subversion_global.h56
-rw-r--r--vcs/subversion/subversion_part.cpp569
-rw-r--r--vcs/subversion/subversion_part.h119
-rw-r--r--vcs/subversion/subversion_widget.cpp136
-rw-r--r--vcs/subversion/subversion_widget.h95
-rw-r--r--vcs/subversion/subversiondiff.ui100
-rw-r--r--vcs/subversion/subversionprojectwidget.ui89
-rw-r--r--vcs/subversion/svn_blamewidget.cpp135
-rw-r--r--vcs/subversion/svn_blamewidget.h77
-rw-r--r--vcs/subversion/svn_co.ui335
-rw-r--r--vcs/subversion/svn_commitdlgbase.ui131
-rw-r--r--vcs/subversion/svn_copydlgwidget.ui238
-rw-r--r--vcs/subversion/svn_copywidget.cpp75
-rw-r--r--vcs/subversion/svn_copywidget.h32
-rw-r--r--vcs/subversion/svn_fileselectdlg_commit.cpp163
-rw-r--r--vcs/subversion/svn_fileselectdlg_commit.h52
-rw-r--r--vcs/subversion/svn_kio.cpp2155
-rw-r--r--vcs/subversion/svn_kio.h163
-rw-r--r--vcs/subversion/svn_logviewoptiondlgbase.ui156
-rw-r--r--vcs/subversion/svn_logviewwidget.cpp273
-rw-r--r--vcs/subversion/svn_logviewwidget.h93
-rw-r--r--vcs/subversion/svn_mergeoptiondlgbase.ui374
-rw-r--r--vcs/subversion/svn_mergewidget.cpp99
-rw-r--r--vcs/subversion/svn_mergewidget.h50
-rw-r--r--vcs/subversion/svn_switchdlgbase.ui213
-rw-r--r--vcs/subversion/svn_switchwidget.cpp60
-rw-r--r--vcs/subversion/svn_switchwidget.h31
-rw-r--r--vcs/subversion/svnssltrustpromptbase.ui116
170 files changed, 22461 insertions, 0 deletions
diff --git a/vcs/Makefile.am b/vcs/Makefile.am
new file mode 100644
index 00000000..d1fcb5b0
--- /dev/null
+++ b/vcs/Makefile.am
@@ -0,0 +1,39 @@
+##
+## Do NOT remove the comments that start with "kdevelop:"
+## They are actually directives to the kdevelop plugin system
+##
+## The include_xxxx variables are controlled by configure.in.in
+##
+
+#kdevelop: CERVISIA_SUBDIR = cervisia
+#if include_cervisia
+#CERVISIA_SUBDIR = cervisia
+#endif
+
+#kdevelop: CLEARCASE_SUBDIR = clearcase
+if include_clearcase
+CLEARCASE_SUBDIR = clearcase
+endif
+
+#kdevelop: CVSCLIENT_SUBDIR = cvsclient
+#if include_cvsclient
+#CVSCLIENT_SUBDIR = cvsclient
+#endif
+
+#kdevelop: CVSSERVICE_SUBDIR = cvsservice
+if include_cvsservice
+CVSSERVICE_SUBDIR = cvsservice
+endif
+
+#kdevelop: PERFORCE_SUBDIR = perforce
+if include_perforce
+PERFORCE_SUBDIR = perforce
+endif
+
+#kdevelop: SUBVERSION_SUBDIR = subversion
+if include_subversion
+SUBVERSION_SUBDIR = subversion
+endif
+
+#SUBDIRS = $(CERVISIA_SUBDIR) $(CLEARCASE_SUBDIR) $(CVSSERVICE_SUBDIR) $(PERFORCE_SUBDIR) $(SUBVERSION_SUBDIR)
+SUBDIRS = $(CLEARCASE_SUBDIR) $(CVSSERVICE_SUBDIR) $(PERFORCE_SUBDIR) $(SUBVERSION_SUBDIR)
diff --git a/vcs/clearcase/Makefile.am b/vcs/clearcase/Makefile.am
new file mode 100644
index 00000000..64b70392
--- /dev/null
+++ b/vcs/clearcase/Makefile.am
@@ -0,0 +1,18 @@
+# Here resides the clearcase part
+
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util $(all_includes)
+
+kde_module_LTLIBRARIES = libkdevclearcase.la
+libkdevclearcase_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+libkdevclearcase_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la
+
+libkdevclearcase_la_SOURCES = clearcasepart.cpp commentdlg.cpp \
+ clearcasefileinfoprovider.cpp clearcasemanipulator.cpp
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = kdevclearcase.desktop
+
+SUBDIRS = integrator
diff --git a/vcs/clearcase/README b/vcs/clearcase/README
new file mode 100644
index 00000000..731741e1
--- /dev/null
+++ b/vcs/clearcase/README
@@ -0,0 +1,3 @@
+Please read the on-line, automaticaly updated KDevelop API documentation at:
+http://www.kdevelop.org
+or read the README.dox file.
diff --git a/vcs/clearcase/README.dox b/vcs/clearcase/README.dox
new file mode 100644
index 00000000..74f2678b
--- /dev/null
+++ b/vcs/clearcase/README.dox
@@ -0,0 +1,42 @@
+/** \class ClearcasePart
+Integrates Clearcase configuration management system into KDevelop.
+Based on Perforce (PerforcePart) implementation by Harald Fernengel <harry AT kdevelop.org>
+
+To use clearcase functions, you need to:
+ -# Create a view in which you will keep your project files
+ -# Start the view and open project as a view extended directory.<br>
+ <b>IMPORTANT:</b> If you have a view test_vu and your project is located
+ under /vobs/source/project1 you should open the project
+ from /view/test_vu/vobs/source/project1 rather than
+ inside the view from /vobs/source/project1. File open
+ dialog does not show any files if you do otherwise. Who
+ knows, maybe it will work for you. If so, let me know.
+ -# Clearcase functions appear in the popup menu for an open file just
+ like cvs or perforce.
+ -# Functions supported so far are: checkout, checkin, uncheckout, diff,
+ mkelem, rmname (not rmelem), lshistory, and lsco (list checkouts).
+ -# For mkelem or rmname, you need to make sure that current directory
+ is checked out or the operation will fail.
+ -# For lshistory, the history is printed to the Messages window.
+ -# For lsco, the checkouts are listed recursively from the directory
+ containing the selected file.
+ -# Snapshot views should work.
+ -# To checkout a directory, select directory in file selector part and use
+ popup-menu.
+ -# The Clearcase popup-menu will appear for any file, even if it is not in
+ a VOB. Attempts to perform Clearcase operations on these files will not
+ succeed, and the output can be viewed in the Messages window.
+
+\authors <a href="mailto:ajay_guleria AT yahoo dot com">Ajay Guleria</a>
+\authors <a href="mailto:pnoffke AT bigpond dot com">Patrick Noffke</a>
+\authors <a href="mailto:phil AT hetroy dot org">Philippe Hétroy</a>
+
+\feature Integrates Clearcase configuration management system into KDevelop and displays VCS file information
+\feature Detects the clearcase environment and activates menus
+\feature Provided a dialog for checkout and checkin comments.
+
+
+\todo Update the tree view when a VCS action is done (checkout, checkin...)
+\todo Add a clearcase logging window
+
+*/
diff --git a/vcs/clearcase/clearcasefileinfoprovider.cpp b/vcs/clearcase/clearcasefileinfoprovider.cpp
new file mode 100644
index 00000000..66dec0c8
--- /dev/null
+++ b/vcs/clearcase/clearcasefileinfoprovider.cpp
@@ -0,0 +1,66 @@
+//
+// C++ Implementation: clearcasefileinfoprovider
+//
+// Description:
+//
+//
+// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "clearcasefileinfoprovider.h"
+#include "clearcasepart.h"
+#include "kdevversioncontrol.h"
+
+#include <kprocess.h>
+#include <qapplication.h>
+
+ClearcaseFileinfoProvider::ClearcaseFileinfoProvider(ClearcasePart *parent)
+ : KDevVCSFileInfoProvider( (KDevVersionControl*) parent, "clearcasefileinfoprovider")
+{
+ vcsInfo_ = NULL;
+
+ connect(parent, SIGNAL(statusReady(const VCSFileInfoMap&, void*)), SIGNAL(triggerUpdate(const VCSFileInfoMap&, void*)));
+
+ kdevVCS_ = parent;
+}
+
+
+ClearcaseFileinfoProvider::~ClearcaseFileinfoProvider()
+{
+}
+
+
+const VCSFileInfoMap* ClearcaseFileinfoProvider::status( const QString &dirPath ) {
+
+ if (curDirPath_ == dirPath) return vcsInfo_;
+
+ curDirPath_ = dirPath;
+
+ if (vcsInfo_ != NULL) delete vcsInfo_;
+
+ vcsInfo_ = ccManipulator_.retreiveFilesInfos(dirPath);
+
+ return vcsInfo_;
+}
+
+bool ClearcaseFileinfoProvider::requestStatus( const QString &dirPath, void *callerData, bool recursive, bool checkRepos ) {
+
+ VCSFileInfoMap* vcsDirInfos = ccManipulator_.retreiveFilesInfos(dirPath);
+
+ // update the file tree view
+ emit statusReady(*vcsDirInfos, callerData);
+
+ delete vcsDirInfos;
+ return true;
+}
+
+
+
+QStringList ClearcaseFileinfoProvider::registeredEntryList() const
+{
+ QStringList l;
+ return l;
+}
+
diff --git a/vcs/clearcase/clearcasefileinfoprovider.h b/vcs/clearcase/clearcasefileinfoprovider.h
new file mode 100644
index 00000000..b716d01b
--- /dev/null
+++ b/vcs/clearcase/clearcasefileinfoprovider.h
@@ -0,0 +1,50 @@
+//
+// C++ Interface: clearcasefileinfoprovider
+//
+// Description:
+//
+//
+// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CLEARCASEFILEINFOPROVIDER_H
+#define CLEARCASEFILEINFOPROVIDER_H
+
+#include "clearcasepart.h"
+#include "clearcasemanipulator.h"
+
+
+/**
+@author KDevelop Authors
+*/
+class ClearcaseFileinfoProvider : public KDevVCSFileInfoProvider
+{
+ Q_OBJECT
+public:
+ ClearcaseFileinfoProvider(ClearcasePart *parent);
+
+ virtual ~ClearcaseFileinfoProvider();
+
+ // -- Sync interface
+ const VCSFileInfoMap *status( const QString &dirPath ) ;
+
+ // -- Async interface for requesting data
+ bool requestStatus( const QString &dirPath, void *callerData, bool recursive = true, bool checkRepos = true );
+
+
+private:
+
+ QStringList registeredEntryList() const;
+
+
+private:
+ ClearcaseManipulator ccManipulator_;
+ QString curDirPath_;
+ VCSFileInfoMap* vcsInfo_;
+ ClearcasePart* kdevVCS_;
+
+};
+
+#endif
diff --git a/vcs/clearcase/clearcasemanipulator.cpp b/vcs/clearcase/clearcasemanipulator.cpp
new file mode 100644
index 00000000..c51436ba
--- /dev/null
+++ b/vcs/clearcase/clearcasemanipulator.cpp
@@ -0,0 +1,133 @@
+//
+// C++ Implementation: ClearcaseManipulator
+//
+// Description:
+//
+//
+// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#include "clearcasemanipulator.h"
+
+#include <kprocess.h>
+
+#include <qregexp.h>
+#include <qstring.h>
+
+#include <stdlib.h>
+#include <libgen.h>
+#include <errno.h>
+#ifdef __NetBSD__
+#include <sys/param.h>
+#endif
+
+#if defined(Q_OS_MACX) || defined(MACOSX) || defined(Q_OS_SOLARIS) || defined(Q_OS_FREEBSD) || (defined(__NetBSD__) && (__NetBSD_Version__ < 599001500)) || defined(__DragonFly__)
+//this function is taken from GNU libc
+//it does not exist on macos
+int getline(char **lineptr, size_t *n, FILE *stream)
+{
+ static char line[256];
+ char *ptr;
+ unsigned int len;
+
+ if (lineptr == NULL || n == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (ferror (stream))
+ return -1;
+
+ if (feof(stream))
+ return -1;
+
+ fgets(line,256,stream);
+
+ ptr = strchr(line,'\n');
+ if (ptr)
+ *ptr = '\0';
+
+ len = strlen(line);
+
+ if ((len+1) < 256)
+ {
+ ptr = (char*)realloc(*lineptr, 256);
+ if (ptr == NULL)
+ return(-1);
+ *lineptr = ptr;
+ *n = 256;
+ }
+
+ strcpy(*lineptr,line);
+ return(len);
+}
+#endif
+
+const char ClearcaseManipulator::CT_DESC_SEPARATOR = ';';
+
+
+ClearcaseManipulator::ClearcaseManipulator()
+{
+}
+
+
+ClearcaseManipulator::~ClearcaseManipulator()
+{}
+
+
+bool ClearcaseManipulator::isCCRepository( const QString & directory ) {
+ QString cmd;
+ cmd = "cd " + directory + " && cleartool pwv -root";
+ if ( system(cmd.ascii()) == 0 ) return true;
+
+ return false;
+}
+
+VCSFileInfoMap* ClearcaseManipulator::retreiveFilesInfos(const QString& directory) {
+
+
+ VCSFileInfoMap* fileInfoMap = new VCSFileInfoMap();
+
+ char CCcommand[1024];
+ sprintf(CCcommand, "cleartool desc -fmt \"%%m;%%En;%%Rf;%%Sn;%%PVn\\n\" %s/*", directory.ascii());
+ FILE* outputFile = popen(CCcommand, "r");
+
+ char* line = NULL;
+ size_t numRead;
+ while (!feof(outputFile)) {
+ getline(&line,&numRead,outputFile);
+
+ if (numRead > 0) {
+ int pos = 0;
+ int lastPos = -1;
+
+ QStringList outputList;
+ outputList = outputList.split(CT_DESC_SEPARATOR, QString(line), true );
+ outputList[Name] = QString(basename((char*)outputList[Name].ascii()));
+
+ VCSFileInfo::FileState state;
+ if (outputList[ClearcaseManipulator::State] == "unreserved" || outputList[ClearcaseManipulator::State] == "reserved") {
+ state = VCSFileInfo::Modified;
+ }
+ else if (outputList[ClearcaseManipulator::State] == "") {
+ state = VCSFileInfo::Uptodate;
+ }
+ else {
+ state = VCSFileInfo::Unknown;
+ }
+
+
+ (*fileInfoMap)[outputList[ClearcaseManipulator::Name]] = VCSFileInfo(outputList[ClearcaseManipulator::Name], outputList[ClearcaseManipulator::Version], outputList[ClearcaseManipulator::RepositoryVersion], state);
+ }
+ }
+
+ pclose(outputFile);
+
+ return fileInfoMap;
+}
+
+
+
diff --git a/vcs/clearcase/clearcasemanipulator.h b/vcs/clearcase/clearcasemanipulator.h
new file mode 100644
index 00000000..baa7c17f
--- /dev/null
+++ b/vcs/clearcase/clearcasemanipulator.h
@@ -0,0 +1,49 @@
+//
+// C++ Interface: ClearcaseManipulator
+//
+// Description:
+//
+//
+// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CLEARCASEMANIPULATOR_H
+#define CLEARCASEMANIPULATOR_H
+
+#include "kdevversioncontrol.h"
+
+#include <kprocess.h>
+
+#include <qregexp.h>
+
+#include <string>
+
+/**
+ @author KDevelop Authors
+ */
+class ClearcaseManipulator {
+ public:
+ ClearcaseManipulator();
+
+ ~ClearcaseManipulator();
+
+ static bool isCCRepository(const QString& directory);
+
+ VCSFileInfoMap* retreiveFilesInfos(const QString& directory);
+
+ private:
+ enum FileInfosFields {
+ Type = 0,
+ Name,
+ State,
+ Version,
+ RepositoryVersion
+ };
+
+ static const char CT_DESC_SEPARATOR;
+
+};
+
+#endif
diff --git a/vcs/clearcase/clearcasepart.cpp b/vcs/clearcase/clearcasepart.cpp
new file mode 100644
index 00000000..6c11a4a6
--- /dev/null
+++ b/vcs/clearcase/clearcasepart.cpp
@@ -0,0 +1,363 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Ajay Guleria *
+ * ajay_guleria at yahoo dot 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "clearcasepart.h"
+#include "commentdlg.h"
+
+#include <qfileinfo.h>
+#include <qpopupmenu.h>
+
+#include <kpopupmenu.h>
+#include <kdebug.h>
+#include <kdevgenericfactory.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+
+#include "kdevcore.h"
+#include "kdevmakefrontend.h"
+#include "kdevdifffrontend.h"
+#include "kdevappfrontend.h"
+#include "execcommand.h"
+#include "domutil.h"
+#include "kdevmainwindow.h"
+#include "kdevproject.h"
+#include "kdevplugininfo.h"
+
+#include "clearcasefileinfoprovider.h"
+#include "clearcasemanipulator.h"
+
+
+static const KDevPluginInfo data("kdevclearcase");
+
+typedef KDevGenericFactory<ClearcasePart> ClearcaseFactory;
+K_EXPORT_COMPONENT_FACTORY( libkdevclearcase, ClearcaseFactory( data ) )
+
+ClearcasePart::ClearcasePart( QObject *parent, const char *name, const QStringList & )
+ : KDevVersionControl( &data, parent, name ? name : "ClearcasePart" ),
+ default_checkin(""),
+ default_checkout(""),
+ default_uncheckout("-rm"),
+ default_create("-ci"),
+ default_remove("-f"),
+ default_lshistory(""),
+ default_diff("-pred -diff"),
+ default_lscheckout("-recurse")
+{
+
+ // check if project directory is valid and cache it
+ isValidCCDirectory_ = ClearcaseManipulator::isCCRepository( project()->projectDirectory() );
+
+ fileInfoProvider_ = new ClearcaseFileinfoProvider(this);
+
+ setInstance(ClearcaseFactory::instance());
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+}
+
+ClearcasePart::~ClearcasePart()
+{}
+
+
+
+bool ClearcasePart::isValidDirectory(const QString &dirPath) const {
+ return isValidCCDirectory_;
+}
+
+
+void ClearcasePart::contextMenu(QPopupMenu *popup, const Context *context)
+{
+
+ if (context->hasType( Context::FileContext )) {
+ const FileContext *fcontext = static_cast<const FileContext*>(context);
+ popupfile_ = fcontext->urls().first().path();
+
+ QFileInfo fi(popupfile_);
+ popup->insertSeparator();
+
+ KPopupMenu *sub = new KPopupMenu(popup);
+ QString name = fi.fileName();
+ sub->insertTitle( i18n("Actions for %1").arg(name) );
+ sub->insertItem( i18n("Checkin"),
+ this, SLOT(slotCheckin()) );
+ sub->insertItem( i18n("Checkout"),
+ this, SLOT(slotCheckout()) );
+ sub->insertItem( i18n("Uncheckout"),
+ this, SLOT(slotUncheckout()) );
+ sub->insertSeparator();
+ sub->insertItem( i18n("Create Element"),
+ this, SLOT(slotCreate()) );
+ sub->insertItem( i18n("Remove Element"),
+ this, SLOT(slotRemove()) );
+ sub->insertSeparator();
+ sub->insertItem( i18n("History"),
+ this, SLOT(slotListHistory()) );
+ sub->insertSeparator();
+ sub->insertItem( i18n("Diff"),
+ this, SLOT(slotDiff()) );
+
+ sub->insertSeparator();
+ sub->insertItem( i18n("List Checkouts"),
+ this, SLOT(slotListCheckouts()) );
+
+ popup->insertItem(i18n("Clearcase"), sub);
+
+ if (!project() || !isValidDirectory( project()->projectDirectory() )) {
+ sub->setEnabled( false );
+ }
+ }
+}
+
+
+void ClearcasePart::slotCheckin()
+{
+ QString dir, name;
+ QFileInfo fi(popupfile_);
+ dir = fi.dirPath();
+ name = fi.fileName();
+
+ CcaseCommentDlg dlg(FALSE);
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ QDomDocument &dom = *this->projectDom();
+ QString message = DomUtil::readEntry(dom,"/kdevclearcase/checkin_options",default_checkin);
+ if(dlg.logMessage().isEmpty())
+ message += "-nc ";
+ else
+ message += "-c \"" + dlg.logMessage() + "\"";
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ command += " && ";
+ command += " cleartool checkin ";
+ command += message; // Already quoted, see above
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+}
+
+
+void ClearcasePart::slotCheckout()
+{
+ QString dir, name;
+ QFileInfo fi(popupfile_);
+ dir = fi.dirPath();
+ name = fi.fileName();
+
+ CcaseCommentDlg dlg(TRUE);
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ QDomDocument &dom = *this->projectDom();
+ QString message = DomUtil::readEntry(dom,"/kdevclearcase/checkout_options",default_checkout);
+ if(!dlg.isReserved())
+ message += "-unres ";
+ if(dlg.logMessage().isEmpty())
+ message += "-nc ";
+ else
+ message += "-c \"" + dlg.logMessage() + "\"";
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ command += " && cleartool checkout ";
+ command += message;
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+
+ emit finishedFetching(dir);
+}
+
+
+void ClearcasePart::slotUncheckout()
+{
+ QString dir, name;
+ QFileInfo fi(popupfile_);
+ dir = fi.dirPath();
+ name = fi.fileName();
+
+ QDomDocument &dom = *this->projectDom();
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ command += " && cleartool uncheckout ";
+ command += DomUtil::readEntry(dom,"/kdevclearcase/uncheckout_options",default_uncheckout);
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+
+ emit finishedFetching(dir);
+}
+
+void ClearcasePart::slotCreate()
+{
+ QFileInfo fi(popupfile_);
+ QString dir = fi.dirPath();
+ QString name = fi.fileName();
+
+ QDomDocument &dom = *this->projectDom();
+
+ // Checking whether current directory is checked out or not is cumbersome so skip it for now
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ QFileInfo di(dir);
+ if(!di.isWritable()) { // Work-around to check if directory is checked out
+ command += " && cleartool co -unres -nc ";
+ command += KShellProcess::quote(dir);
+ }
+ command += " && cleartool mkelem ";
+ if(fi.isDir())
+ command += " -elt directory ";
+ command += DomUtil::readEntry(dom,"/kdevclearcase/create_options",default_create);
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+
+ emit finishedFetching(dir);
+}
+
+
+void ClearcasePart::slotRemove()
+{
+ QFileInfo fi(popupfile_);
+ QString dir = fi.dirPath();
+ QString name = fi.fileName();
+
+ QDomDocument &dom = *this->projectDom();
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ QFileInfo di(dir);
+ if(!di.isWritable()) { // Work-around to check if directory is checked out
+ command += " && cleartool co -unres -nc ";
+ command += KShellProcess::quote(dir);
+ }
+ command += " && cleartool rmname "; // Don't use rm command
+ command += DomUtil::readEntry(dom,"/kdevclearcase/remove_options",default_remove);
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+
+ emit finishedFetching(dir);
+}
+
+void ClearcasePart::slotListHistory()
+{
+ QFileInfo fi(popupfile_);
+ QString dir = fi.dirPath();
+ QString name = fi.fileName();
+ QStringList args;
+ QStringList env;
+ QString str;
+
+ QDomDocument &dom = *this->projectDom();
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ command += " && cleartool lshistory ";
+ command += DomUtil::readEntry(dom, "/kdevclearcase/lshistory_options", default_lshistory);
+ command += " ";
+ command += KShellProcess::quote(name);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+}
+
+void ClearcasePart::slotDiff()
+{
+ QFileInfo fi(popupfile_);
+ QString dir = fi.dirPath();
+ QString name = fi.fileName();
+ QStringList args;
+ QStringList env;
+ QString str;
+
+ QDomDocument &dom = *this->projectDom();
+
+ args << "diff";
+ str = DomUtil::readEntry(dom,"/kdevclearcase/diff_options",default_diff);
+ if (str.length()) {
+ QStringList list = QStringList::split(' ',str);
+ for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) args << *it;
+ }
+
+ args << name;
+
+ ExecCommand* cmv = new ExecCommand( "cleartool", args, dir, env, this );
+ connect( cmv, SIGNAL(finished( const QString&, const QString& )),
+ this, SLOT(slotDiffFinished( const QString&, const QString& )) );
+}
+
+
+void ClearcasePart::slotDiffFinished( const QString& diff, const QString& err )
+{
+ if ( diff.isNull() && err.isNull() ) {
+ kdDebug(9000) << "clearcase diff canceled" << endl;
+ return; // user pressed cancel or an error occured
+ }
+
+ if ( diff.isEmpty() && !err.isEmpty() ) {
+ KMessageBox::detailedError( 0, i18n("Clearcase output errors during diff."), err, i18n("Errors During Diff") );
+ return;
+ }
+
+ if ( !err.isEmpty() ) {
+ int s = KMessageBox::warningContinueCancelList( 0, i18n("Clearcase outputted errors during diff. Do you still want to continue?"),
+ QStringList::split( "\n", err, false ), i18n("Errors During Diff") );
+ if ( s != KMessageBox::Continue )
+ return;
+ }
+
+ if ( diff.isEmpty() ) {
+ KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Difference Found") );
+ return;
+ }
+
+ if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("KDevelop/DiffFrontend"))
+ diffFrontend->showDiff( diff );
+}
+
+void ClearcasePart::slotListCheckouts()
+{
+ QString dir;
+ QFileInfo fi(popupfile_);
+ if (fi.isDir()) {
+ dir = fi.absFilePath();
+ } else {
+ dir = fi.dirPath();
+ }
+
+ QDomDocument &dom = *this->projectDom();
+
+ QString command("cd ");
+ command += KShellProcess::quote(dir);
+ command += " && cleartool lsco ";
+ command += DomUtil::readEntry(dom, "/kdevclearcase/lscheckout_options", default_lscheckout);
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+
+}
+
+
+#include "clearcasepart.moc"
diff --git a/vcs/clearcase/clearcasepart.h b/vcs/clearcase/clearcasepart.h
new file mode 100644
index 00000000..2f82b61d
--- /dev/null
+++ b/vcs/clearcase/clearcasepart.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Ajay Guleria *
+ * ajay_guleria at yahoo dot 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _CLEARCASEPART_H_
+#define _CLEARCASEPART_H_
+
+#include <kdevversioncontrol.h>
+
+class Context;
+class QPopupMenu;
+
+class ClearcasePart : public KDevVersionControl {
+ Q_OBJECT
+
+public:
+ ClearcasePart( QObject *parent, const char *name, const QStringList & );
+ ~ClearcasePart();
+
+ const QString default_checkin;
+ const QString default_checkout;
+ const QString default_uncheckout;
+ const QString default_create;
+ const QString default_remove;
+ const QString default_lshistory;
+ const QString default_lscheckout;
+ const QString default_diff;
+
+ virtual void createNewProject(const QString& dir) {}
+ virtual bool fetchFromRepository() { return true; }
+ virtual KDevVCSFileInfoProvider *fileInfoProvider() const { return fileInfoProvider_; }
+ virtual bool isValidDirectory(const QString &dirPath) const;
+
+private slots:
+ void contextMenu(QPopupMenu *popup, const Context *context);
+
+ void slotCheckin();
+ void slotCheckout();
+ void slotUncheckout();
+
+ void slotCreate();
+ void slotRemove();
+ void slotDiff();
+ void slotDiffFinished( const QString& diff, const QString& err );
+ void slotListHistory();
+ void slotListCheckouts();
+
+
+private:
+
+ bool isValidCCDirectory_;
+ QString popupfile_;
+ QString viewname;
+
+ KDevVCSFileInfoProvider *fileInfoProvider_;
+};
+
+#endif
diff --git a/vcs/clearcase/commentdlg.cpp b/vcs/clearcase/commentdlg.cpp
new file mode 100644
index 00000000..36b3bc6f
--- /dev/null
+++ b/vcs/clearcase/commentdlg.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Ajay Guleria *
+ * ajay_guleria at yahoo dot 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "commentdlg.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdguiitem.h>
+
+CcaseCommentDlg::CcaseCommentDlg(bool bCheckin)
+ : QDialog(0, "", true)
+{
+ setCaption( i18n("Clearcase Comment") );
+
+ QBoxLayout *layout = new QVBoxLayout(this, 10);
+
+ QLabel *messagelabel = new QLabel(i18n("Enter log message:"), this);
+ messagelabel->setMinimumSize(messagelabel->sizeHint());
+ layout->addWidget(messagelabel, 0);
+
+ _edit = new QMultiLineEdit(this);
+ QFontMetrics fm(_edit->fontMetrics());
+ _edit->setMinimumSize(fm.width("0")*40, fm.lineSpacing()*3);
+ layout->addWidget(_edit, 10);
+
+ QBoxLayout *layout2 = new QHBoxLayout(layout);
+ if(bCheckin) {
+ _check = new QCheckBox(i18n("Reserve"), this);
+ layout2->addWidget(_check);
+ }
+
+ KButtonBox *buttonbox = new KButtonBox(this);
+ buttonbox->addStretch();
+ QPushButton *ok = buttonbox->addButton(KStdGuiItem::ok());
+ QPushButton *cancel = buttonbox->addButton(KStdGuiItem::cancel());
+ connect(ok, SIGNAL(clicked()), SLOT(accept()) );
+ connect(cancel, SIGNAL(clicked()), SLOT(reject()) );
+ ok->setDefault(true);
+ buttonbox->layout();
+ layout2->addWidget(buttonbox, 0);
+
+ layout->activate();
+ adjustSize();
+}
+
+
+
+#include "commentdlg.moc"
diff --git a/vcs/clearcase/commentdlg.h b/vcs/clearcase/commentdlg.h
new file mode 100644
index 00000000..8ac50a38
--- /dev/null
+++ b/vcs/clearcase/commentdlg.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Ajay Guleria *
+ * ajay_guleria at yahoo dot 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _CLEARCASECOMMENTDLG_H_
+#define _CLEARCASECOMMENTDLG_H_
+
+#include <qcheckbox.h>
+#include <qdialog.h>
+#include <qmultilineedit.h>
+
+class CcaseCommentDlg : public QDialog
+{
+Q_OBJECT
+public:
+ CcaseCommentDlg(bool = FALSE);
+ QString logMessage() { return _edit->text(); };
+ bool isReserved() { return (_check) ? _check->isChecked() : FALSE; };
+
+private:
+ QMultiLineEdit *_edit;
+ QCheckBox* _check;
+};
+
+#endif
diff --git a/vcs/clearcase/integrator/Makefile.am b/vcs/clearcase/integrator/Makefile.am
new file mode 100644
index 00000000..cd998856
--- /dev/null
+++ b/vcs/clearcase/integrator/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \
+ $(all_includes)
+METASOURCES = AUTO
+kde_module_LTLIBRARIES = libclearcaseintegrator.la
+libclearcaseintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
+libclearcaseintegrator_la_LIBADD =\
+ $(top_builddir)/lib/interfaces/extras/libkdevextras.la\
+ $(top_builddir)/lib/libkdevelop.la
+kde_services_DATA = kdevclearcaseintegrator.desktop
+noinst_HEADERS = clearcaseintegrator.h ccintegratordlg.h
+libclearcaseintegrator_la_SOURCES = clearcaseintegrator.cpp \
+ ccintegratordlgbase.ui ccintegratordlg.cpp
diff --git a/vcs/clearcase/integrator/ccintegratordlg.cpp b/vcs/clearcase/integrator/ccintegratordlg.cpp
new file mode 100644
index 00000000..3e58aada
--- /dev/null
+++ b/vcs/clearcase/integrator/ccintegratordlg.cpp
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "ccintegratordlg.h"
+
+CCIntegratorDlg::CCIntegratorDlg(QWidget *parent, const char *name)
+ :CCIntegratorDlgBase(parent, name)
+{
+}
+
+void CCIntegratorDlg::accept()
+{
+}
+
+void CCIntegratorDlg::init(const QString &/*projectName*/, const QString &/*projectLocation*/)
+{
+}
+
+QWidget *CCIntegratorDlg::self()
+{
+ return const_cast<CCIntegratorDlg*>(this);
+}
+
+#include "ccintegratordlg.moc"
diff --git a/vcs/clearcase/integrator/ccintegratordlg.h b/vcs/clearcase/integrator/ccintegratordlg.h
new file mode 100644
index 00000000..0b197437
--- /dev/null
+++ b/vcs/clearcase/integrator/ccintegratordlg.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef CCINTEGRATORDLG_H
+#define CCINTEGRATORDLG_H
+
+#include "ccintegratordlgbase.h"
+#include <kdevvcsintegrator.h>
+
+class CCIntegratorDlg: public CCIntegratorDlgBase, public VCSDialog {
+Q_OBJECT
+public:
+ CCIntegratorDlg(QWidget *parent = 0, const char *name = 0);
+
+ virtual void accept();
+ virtual void init(const QString &projectName, const QString &projectLocation);
+ virtual QWidget *self();
+};
+
+#endif
diff --git a/vcs/clearcase/integrator/ccintegratordlgbase.ui b/vcs/clearcase/integrator/ccintegratordlgbase.ui
new file mode 100644
index 00000000..ae961a9f
--- /dev/null
+++ b/vcs/clearcase/integrator/ccintegratordlgbase.ui
@@ -0,0 +1,47 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>CCIntegratorDlgBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CCIntegratorDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>No options available for this VCS.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>437</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/clearcase/integrator/clearcaseintegrator.cpp b/vcs/clearcase/integrator/clearcaseintegrator.cpp
new file mode 100644
index 00000000..3ea4295f
--- /dev/null
+++ b/vcs/clearcase/integrator/clearcaseintegrator.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "clearcaseintegrator.h"
+
+#include <kdevgenericfactory.h>
+#include <kdevplugininfo.h>
+
+#include "ccintegratordlg.h"
+
+static const KDevPluginInfo data("kdevclearcaseintegrator");
+typedef KDevGenericFactory<ClearcaseIntegrator> ClearcaseIntegratorFactory;
+K_EXPORT_COMPONENT_FACTORY( libclearcaseintegrator, ClearcaseIntegratorFactory(data) )
+
+ClearcaseIntegrator::ClearcaseIntegrator(QObject* parent, const char* name,
+ const QStringList // args
+ )
+ :KDevVCSIntegrator(parent, name)
+{
+}
+
+ClearcaseIntegrator::~ClearcaseIntegrator()
+{
+}
+
+VCSDialog* ClearcaseIntegrator::fetcher(QWidget* // parent
+ )
+{
+ return 0;
+}
+
+VCSDialog* ClearcaseIntegrator::integrator(QWidget* parent)
+{
+ CCIntegratorDlg *dlg = new CCIntegratorDlg(parent);
+ return dlg;
+}
+
+#include "clearcaseintegrator.moc"
diff --git a/vcs/clearcase/integrator/clearcaseintegrator.h b/vcs/clearcase/integrator/clearcaseintegrator.h
new file mode 100644
index 00000000..a6aaf396
--- /dev/null
+++ b/vcs/clearcase/integrator/clearcaseintegrator.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef CLEARCASEINTEGRATOR_H
+#define CLEARCASEINTEGRATOR_H
+
+#include <kdevvcsintegrator.h>
+
+#include <qstringlist.h>
+
+class ClearcaseIntegrator : public KDevVCSIntegrator
+{
+Q_OBJECT
+public:
+ ClearcaseIntegrator(QObject* parent, const char* name, const QStringList args = QStringList());
+ ~ClearcaseIntegrator();
+
+ virtual VCSDialog* fetcher(QWidget* parent);
+ virtual VCSDialog* integrator(QWidget* parent);
+
+};
+
+#endif
diff --git a/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop b/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop
new file mode 100644
index 00000000..b9957370
--- /dev/null
+++ b/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop
@@ -0,0 +1,44 @@
+[Desktop Entry]
+Type=Service
+Name=KDevClearcaseIntegrator
+Name[da]=KDevelop Clearcase-integration
+Name[nds]=KDevelop-Clearcase-Integreren
+Name[sk]=KDev ClearCase integrácia
+Name[sv]=KDevelop Clearcase-integration
+Name[zh_TW]=KDevelop Clearcase æ•´åˆå™¨
+Comment=Clearcase Project Integration Facility
+Comment[ca]=Faciliat per a la integració amb projectes Clearcase
+Comment[da]=Clearcase projektintegration
+Comment[de]=Clearcase-Integration
+Comment[el]=ΛειτουÏγία ενσωμάτωσης Clearcase στο έÏγο
+Comment[es]=Facilidad para integración con proyectos Clearcase
+Comment[et]=Clearcase projekti põimimisvahend
+Comment[eu]=Clearcase proiektu-integraziorako tresna
+Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ Clearcase
+Comment[fr]=Fonction d'intégration pour un projet utilisant Clearcase
+Comment[gl]=Utilidade para a integración de proxectos ClearCase
+Comment[hu]=Integrálás Clearcase-projektekkel
+Comment[it]=Funzione di integrazione del progetto ClearCase
+Comment[ja]=Clearcase プロジェクト統åˆãƒ„ール
+Comment[ms]=Kemudahan Integrasi Projek Clearcase
+Comment[nds]=Projektintegreren för Clearcase
+Comment[ne]=कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾
+Comment[nl]=Clearcase-projectintegratie
+Comment[pl]=Integracja z Clearcase
+Comment[pt]=Integração com Projectos Clearcase
+Comment[pt_BR]=Facilidade de Integração ao Projeto de Clearcase
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Clearcase
+Comment[sk]=Integrácia ClearCase projektu
+Comment[sr]=Интеграција Clearcase-а у пројекат
+Comment[sr@Latn]=Integracija Clearcase-a u projekat
+Comment[sv]=Funktion för integrering av Clearcase i projekt
+Comment[tr]=Clearcase Proje Bütünleştirilmesi Aracı
+Comment[zh_CN]=Clearcase 工程集æˆåŠŸèƒ½
+Comment[zh_TW]=Clearcase 專案整åˆå·¥å…·
+Exec=blubb
+ServiceTypes=KDevelop/VCSIntegrator
+X-KDE-Library=libclearcaseintegrator
+X-KDevelop-Default=false
+X-KDevelop-VCS=ClearCase
+X-KDevelop-VCSPlugin=kdevclearcase
+X-KDevelop-Version=5
diff --git a/vcs/clearcase/kdevclearcase.desktop b/vcs/clearcase/kdevclearcase.desktop
new file mode 100644
index 00000000..5a691980
--- /dev/null
+++ b/vcs/clearcase/kdevclearcase.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+Type=Service
+Exec=blubb
+Comment=A plugin that provides support for Rational ClearCase, a large version control and build management system. http://www.rational.com/products/clearcase/index.jsp
+Comment[ca]=Un connector que proporciona suport per a ClearCase de Rational, un potent sistema de control de versions i gestió de compilacions. http://www.rational.com/products/clearcase/index.jsp
+Comment[da]=Et plugin der sørger for støtte for Rational ClearCase, et stort versionskontrol og byggehåndteringssystem. http://www.rational.com/products/clearcase/index.jsp
+Comment[de]=Eine Komponente, die eine Schnittstelle zu Rational ClearCase zur Verfügung stellt, einem umfangreichen Werkzeug zur Verwaltung von Versionen und Erstellungsvorgängen. http://www.rational.com/products/clearcase/index.jsp
+Comment[el]=Ένα Ï€Ïόσθετο που Ï€ÏοσφέÏει υποστήÏιξη για το Rational ClearCase, ένα μεγάλο σÏστημα διαχείÏισης ελέγχου εκδόσεων και κατασκευής. http://www.rational.com/products/clearcase/index.jsp
+Comment[es]=Un complemento que proporciona soporte para Rational ClearCase, un potente sistema de control de versiones y administración de compilaciones (http://www.rational.com/products/clearcase/index.jsp)
+Comment[et]=See plugin pakub suure versioonikontrolli ja ehitamise haldamise süsteemi Rational ClearCase toetust. http://www.rational.com/products/clearcase/index.jsp
+Comment[eu]=Rational ClearCase euskarri plugin bat. ClearCase bertsio kontrol eta eraikuntza kudeaketa sistema handi bat da. http://www.rational.com/products/clearcase/index.jsp
+Comment[fa]=وصله‌ای Ú©Ù‡ پشتیبانی برای Rational ClearCaseØŒ یک کنترل نسخۀ بزرگ Ùˆ سیستم مدیریت ساختن Ùراهم ‌می‌کند. http://www.rational.com/products/clearcase/index.jsp
+Comment[fr]=Un module externe qui offre une prise en charge pour Rational ClearCase, un puissant système de contrôle de versions et de gestion de compilation. http://www.rational.com/products/clearcase/index.jsp
+Comment[gl]=Extensión que proporciona soporte para Rational ClearCase, un gran sistema de control de versións e xestión da compilación. http://www.rational.com/products/clearcase/index.jsp
+Comment[hu]=Bővítőmodul a Rational ClearCase komplex verziókövető rendszerhez. http://www.rational.com/products/clearcase/index.jsp
+Comment[it]=Un plugin che offre il supporto per Rational ClearCase, un sistema molto vasto per il controllo di versione e la compilazione. http://www.rational.com/products/clearcase/index.jsp
+Comment[ja]=大è¦æ¨¡ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã‚„ビルド管ç†ã‚·ã‚¹ãƒ†ãƒ ã®åˆç†çš„㪠ClearCase ã®æ”¯æ´ã‚’æä¾›ã™ã‚‹ãƒ—ラグイン。http://www.rational.com/products/clearcase/index.jsp
+Comment[ms]=Plugin yang menyediakan sokongan untuk Rational ClearCase, sistem kawalan versi dan pengurus pembinaan yang besar. http://www.rational.com/products/clearcase/index.jsp
+Comment[nds]=En Moduul, dat Ünnerstütten för "Rational ClearCase" praatstellt, en groot Verschoonkuntrull- un Opstellen-Pleegsysteem. http://www.rational.com/products/clearcase/index.jsp
+Comment[ne]=à¤à¤‰à¤Ÿà¤¾ पà¥à¤²à¤—इन जसले रà¥à¤¯à¤¾à¤¸à¤¨à¤² कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸, à¤à¤‰à¤Ÿà¤¾ ठूलो संसà¥à¤•à¤°à¤£ नियनà¥à¤¤à¥à¤°à¤£ र निरà¥à¤®à¤¾à¤£ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ पà¥à¤°à¤£à¤¾à¤²à¥€à¤•à¤¾ लागि समरà¥à¤¥à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ गरà¥à¤¦à¤› । http://www.rational.com/products/clearcase/index.jsp
+Comment[nl]=Een plugin die ondersteuning biedt voor Rational ClearCase, een omvangrijk versiebeheer en buildmanagement-systeem. Zie http://www.rational.com/products/clearcase/index.jsp
+Comment[pl]=Wtyczka udostępniająca obsługę Rational ClearCase, dużego systemu kontroli wersji i zarządzania budowaniem. http://www.rational.com/products/clearcase/index.jsp
+Comment[pt]=Um 'plugin' que oferece o suporte para o ClearCase da Rational, um sistema grande de controlo de versões e de gestão de compilações. http://www.rational.com/products/clearcase/index.jsp
+Comment[pt_BR]=Um plug-in que fornece suporte para o Rational ClearCase, um grande sistema de controle de versão e gerenciamento de compilação. http://www.rational.com/products/clearcase/index.jsp
+Comment[ru]=Модуль поддержки Rational ClearCase, мощной ÑиÑтемы ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð²ÐµÑ€Ñий и ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð¾Ð¼. http://www.rational.com/products/clearcase/index.jsp
+Comment[sk]=Modul poskytuje podporu pre Rational ClearCase, riadenie verzií a projektový manažment.
+Comment[sl]=Vstavek, ki omogoÄa podporo za Rational ClearCase, velik sistem za upravljanje z razliÄicami in grajenjem. http://www.rational.com/products/clearcase/index.jsp
+Comment[sr]=Прикључак који обезбеђује подршку за Rational-ов ClearCase, велики ÑиÑтем за контролу верзија и управљање градњом. http://www.rational.com/products/clearcase/index.jsp
+Comment[sr@Latn]=PrikljuÄak koji obezbeÄ‘uje podrÅ¡ku za Rational-ov ClearCase, veliki sistem za kontrolu verzija i upravljanje gradnjom. http://www.rational.com/products/clearcase/index.jsp
+Comment[sv]=Ett insticksprogram som stöder Rational ClearCase, ett omfattande versions- och bygghanteringssystem. http://www.rational.com/products/clearcase/index.jsp
+Comment[ta]=சொரà¯à®•à®¿ ரெஷியனல௠தெளிவான எழà¯à®¤à¯à®¤à¯ˆ ஆதரிகà¯à®•à¯à®®à¯,கடைசி பதிபà¯à®ªà¯ˆ இயகà¯à®• மறà¯à®±à¯à®®à¯ மேலாளர௠அமைபà¯à®ªà¯ˆ கடà¯à®Ÿ.http://www.rational.com/products/clearcase/index.jsp
+Comment[tg]=Модули тарафдори Rational ClearCase, барномаи назораткунандаи калони тафÑир ва идоракунии лоиҳаҳо мебошад.http://www.rational.com/products/clearcase/index.jsp
+Comment[tr]=Mantıksal ClearCase, büyük bir kontrol ve yapım yönetim sistemi, için destek sağlayan bir eklenti. http://www.rational.com/products/clearcase/index.jsp
+Comment[zh_CN]=æä¾› Rational ClearCase 支æŒï¼Œä¸€ä¸ªå¤§åž‹çš„版本控制和编译管ç†ç³»ç»Ÿã€‚http://www.rational.com/products/clearcase/index.jsp
+Comment[zh_TW]=æä¾›æ”¯æ´ Rational ClearCase,大型的版本控制與建立管ç†ç³»çµ±çš„外掛程å¼ã€‚http://www.rational.com/products/clearcase/index.jsp
+Name=KDevClearCase
+Name[da]=KDevelop ClearCase
+Name[de]=Unterstützung für ClearCase (KDevelop)
+Name[hi]=के-डेव-कà¥à¤²à¥€à¤¯à¤°-केस
+Name[nds]=ClearCase-Ünnerstütten för KDevelop
+Name[sk]=KDev ClearCase
+Name[sv]=KDevelop ClearCase
+Name[ta]=KDevதெளிவானஎழà¯à®¤à¯à®¤à¯
+Name[zh_TW]=KDevelop ClearCase
+GenericName=ClearCase Integration
+GenericName[ca]=Integració amb ClearClase
+GenericName[da]=ClearCase integration
+GenericName[de]=ClearCase-Integration
+GenericName[el]=Ενσωμάτωση ClearCase
+GenericName[es]=Integración con ClearClase
+GenericName[et]=ClearCase'i integratsioon
+GenericName[eu]=ClearCase integrazioa
+GenericName[fa]=مجتمع‌سازی ClearCase
+GenericName[fr]=Intégration de « ClearCase »
+GenericName[ga]=Comhtháthú ClearCase
+GenericName[gl]=Integración de ClearCase
+GenericName[hi]=कà¥à¤²à¥€à¤¯à¤°-केस इंटीगà¥à¤°à¥‡à¤¶à¤¨
+GenericName[hu]=ClearCase-integráció
+GenericName[it]=Integrazione di ClearCase
+GenericName[ja]=ClearCase çµ±åˆ
+GenericName[ms]=Intergrasi ClearCase
+GenericName[nds]=ClearCase-Integreren
+GenericName[ne]=कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸ à¤à¤•à¤¿à¤•à¤°à¤£
+GenericName[nl]=ClearCase-integratie
+GenericName[pl]=Integracja z ClearCase
+GenericName[pt]=Integração com o ClearCase
+GenericName[pt_BR]=Integração com o ClearCase
+GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ ClearCase
+GenericName[sk]=Integrácia ClearCase
+GenericName[sl]=Integracija ClearCase
+GenericName[sr]=Интеграција ClearCase-а
+GenericName[sr@Latn]=Integracija ClearCase-a
+GenericName[sv]=Integrering av ClearCase
+GenericName[ta]=தெளிவான எழà¯à®¤à¯à®¤à¯ à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®ªà¯à®ªà¯
+GenericName[tg]=ИнтегратÑиÑи ClearCase
+GenericName[tr]=ClearCase Bütünleştirmesi
+GenericName[zh_CN]=ClearCase集æˆ
+GenericName[zh_TW]=ClearCase æ•´åˆ
+ServiceTypes=KDevelop/VersionControl
+X-KDE-Library=libkdevclearcase
+X-KDevelop-Version=5
+X-KDevelop-Properties=VCS,ClearcaseVCS
diff --git a/vcs/cvsservice/Makefile.am b/vcs/cvsservice/Makefile.am
new file mode 100644
index 00000000..04802374
--- /dev/null
+++ b/vcs/cvsservice/Makefile.am
@@ -0,0 +1,40 @@
+# Here resides the cvs part
+
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets $(all_includes)
+
+kde_module_LTLIBRARIES = libkdevcvsservice.la
+libkdevcvsservice_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+libkdevcvsservice_la_LIBADD = $(top_builddir)/lib/libkdevelop.la \
+ $(top_builddir)/lib/widgets/libkdevwidgets.la $(LIB_KHTML) -lcvsservice $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la
+
+libkdevcvsservice_la_SOURCES = cvspart.cpp cvspartimpl.cpp cvsformbase.ui \
+ cvsform.cpp commitdialogbase.ui commitdlg.cpp cvsoptionswidgetbase.ui \
+ cvsoptionswidget.cpp cvsprocesswidget.cpp cvsentry.cpp cvsdir.cpp changelog.cpp \
+ cvsoptions.cpp checkoutdialogbase.ui checkoutdialog.cpp tagdialog.cpp tagdialogbase.ui \
+ diffdialogbase.ui diffdialog.cpp releaseinputdialogbase.ui releaseinputdialog.cpp \
+ cvslogdialog.cpp cvslogpage.cpp cvsdiffpage.cpp diffwidget.cpp jobscheduler.cpp \
+ bufferedstringreader.cpp cvsfileinfoprovider.cpp cvsservicedcopIface.skel editorsdialogbase.ui \
+ editorsdialog.cpp annotatedialog.cpp annotatepage.cpp annotateview.cpp
+
+noinst_HEADERS = changelog.h checkoutdialog.h checkoutdialogbase.h commitdlg.h \
+ cvsentry.h cvsform.h cvsformbase.h cvsoptions.h cvsoptionswidget.h \
+ cvsoptionswidgetbase.h cvspart.h cvspartimpl.h cvsprocesswidget.h tagdialog.h tagdialogbase.h \
+ diffdialog.h cvsdir.h cvslogpage.h cvslogdialog.h jobscheduler.h diffwidget.h \
+ cvsfileinfoprovider.h cvsservicedcopIface.h bufferedstringreader.h editorsdialog.h \
+ editorsdialogbase.h annotatedialog.h annotatepage.h annotateview.h
+
+METASOURCES = AUTO
+
+ICONS = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = kdevcvsservice.desktop
+
+servicepicsdir = $(kde_datadir)/kdevcvsservice/pics
+servicepics_DATA = kdev_cvs.png
+
+rcdir = $(kde_datadir)/kdevcvsservice
+rc_DATA = buildcvs.sh
+
+SUBDIRS = integrator
diff --git a/vcs/cvsservice/README b/vcs/cvsservice/README
new file mode 100644
index 00000000..0146b60f
--- /dev/null
+++ b/vcs/cvsservice/README
@@ -0,0 +1 @@
+Please read the README.dox file. \ No newline at end of file
diff --git a/vcs/cvsservice/README.dox b/vcs/cvsservice/README.dox
new file mode 100644
index 00000000..c89e9422
--- /dev/null
+++ b/vcs/cvsservice/README.dox
@@ -0,0 +1,82 @@
+/** \class CvsServicePart
+This plugin integrates Cervisia (version >= 2.1) cvsservice DCOP service into kdevelop (read FAQ at the bottom
+of this document): so, this part _does_ require cvsservice installed on your system: the configure script
+in the main source directory should automagically detect the presence of Cervisia and build this plugin.
+If Cervisia wasn't installed in $KDEDIR than you need to specify paths for lib and include
+files, for example:
+<code>
+ --with-extra-libs=$HOME/kde/lib --with-extra-includes=$HOME/kde/include
+</code>
+(where $HOME/kde is where I install my own kde stuff so I don't mess with working kde installation)
+
+<b>WARNING:</b> So, if you have already compiled kdevelop *without* cvsservice and have now
+installed cervisia to try this nice piece of software, you need to re-run configure so it
+can detect cervisia installation and enable compilation for vcs/cvsservice.
+
+<b>WARNING:</b> This plugin will quite surely change when the upcoming modifications in Cervisia's own
+architecture (separation of core and front-ends and user applications' library) are done (probably
+starting from kde >= 3.3). If you want to partecipate please join discussions on the cervisia@kde.org
+mailing list. Contributions are always welcome :-)
+
+<b>WARNING2:</b> If it doesn't compile try to update your cervisia installation.
+
+Implementation of this component is done by:
+ - class CvsServicePart, which does provide integration within kdevelop, set-up GUI
+ integration, forward cvs commands to the implementation (m_impl). It does also
+ intercepts signals like "new files added to project" and "... removed from ...".
+ - class CvsServicePartImpl implements the actual feature: more general speaking
+ functions (like checking for whether files are in repository, provide checks
+ on file lists, ...).
+ - class CvsProcessWidget provides output wrapping for commands (ok, it is useful
+ for debugging too ;-). It simply starts a DCOP job and awaits notification for
+ its termination.
+ - class CvsOptions* provide info about the user preferences when executing commands:
+ settings are stored in myprj.kdevses file, loaded when project is opened and
+ saved when project is closed.
+ - There is a bunch of dialog classes for collecting useful data about the operations
+ one wants to perform: exception to this are the cvslog* classes which do start
+ cvs jobs independently archiving parallelism with the CvsProcesssWidget.
+ - CVSDir and CVSEntry provide abstraction for accessing to local CVS information
+ - CVSFileInfoProvider is an implementation of KDevVCSFileInfoProvider interface
+ and collects data about files stats: for CVS, both synch (fetch data from local sandbox)
+ and asynch (fetch from repository server) are working with some minor bugs in the parsing
+ of 'cvs status' output for the latter. (Sync means that information are collected
+ from local CVS dirs which do not provide much information; async mean that a
+ "cvs status <dir-name>" request is launched, output parsed and information returned
+ to the client in _different_ times). Obviously this stuff requires the client
+ (actually only the FileTree viewer) to be aware of this feature (see parts/fileview for
+ additional info).
+
+\todo
+ - Fix the "cvs update" function which behave strangely for sub-directories of the main
+ project dir.
+ - (> 3.0) Replace the menu entries text with shorter ones
+ - Fix bugs on bugs.kde.org ;-)
+
+
+\authors <a href="mailto:mario.scalas AT libero.it">Mario Scalas</a>
+
+\maintainer <a href="mailto:mario.scalas AT libero.it">Mario Scalas</a>
+
+\feature All that provided by parts/cvs
+\feature it is possible to 'add as binary' files to repository
+\feature checkout from remote repository ability added to the appwizard/importdlg
+\feature should handle :ext: repositories thanks to cvsservice
+\feature can tag / un-tag files
+\feature can revert and diff between specific releases
+\feature can do multiple diff from a common cvs log output text
+
+\bug bugs in <a href="http://bugs.kde.org/buglist.cgi?product=kdevelop&component=cvs%20part&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=Bug+Number">cvs part component at Bugzilla database</a>
+
+\requirement <a href="http://www.cvshome.org">CVS</a> >= 1.10.6
+\requirement Cervisia >= 2.1 (from kdesdk package included in <a href="http://www.kde.org">KDE</a> >= 3.2)
+
+\todo Test with SSH repositories!
+\todo Share a common outputview between VCS: CvsProcessWidget should be reworked :-/
+\todo Additional slots for more complex stuff as status, revert, patch creation, ...
+
+\faq <b>Does cvsservicepart support login with :pserver: or :ext: ?</b>
+ Well, I dunno ;-) I have no ssh repositories to test so feel free to provide feedback on the subject :-)
+ Update: Ok, it seems at least one user has tried :ext: reporting it to work (with ssh-agent avoiding some
+ typing headache ;-))
+*/
diff --git a/vcs/cvsservice/annotatedialog.cpp b/vcs/cvsservice/annotatedialog.cpp
new file mode 100644
index 00000000..08d0f24f
--- /dev/null
+++ b/vcs/cvsservice/annotatedialog.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qvbox.h>
+#include <qdir.h>
+#include <qstringlist.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "annotatedialog.h"
+#include "annotatepage.h"
+
+AnnotateDialog::AnnotateDialog( CvsService_stub *cvsService, QWidget *parent, const char *name, int )
+ : KDialogBase( Tabbed, i18n("CVS Annotate Dialog"), Close, Close,
+ parent, name? name : "annotateformdialog", false /*modal*/, true /*separator*/ ),
+ m_cvsService( cvsService )
+{
+ setWFlags( getWFlags() | WDestructiveClose );
+
+ QVBox *vbox = addVBoxPage( i18n("Annotate") );
+ m_cvsAnnotatePage = new AnnotatePage( m_cvsService, vbox );
+
+ connect( m_cvsAnnotatePage, SIGNAL(requestAnnotate(const QString)),
+ this, SLOT(slotAnnotate(const QString)) );
+}
+
+AnnotateDialog::~AnnotateDialog()
+{
+ kdDebug(9006) << "AnnotateDialog::~AnnotateDialog()" << endl;
+}
+
+void AnnotateDialog::startFirstAnnotate( const QString pathName, const QString revision )
+{
+ kdDebug(9006) << "AnnotateDialog::startFirstAnnotate() pathName = " << pathName <<
+ "revision = " << revision << endl;
+
+ //save the filename for any later use
+ m_pathName = pathName;
+
+ m_cvsAnnotatePage->startAnnotate( pathName, revision );
+}
+
+void AnnotateDialog::slotAnnotate(const QString rev)
+{
+ kdDebug(9006) << "AnnotateDialog::slotAnnotate(QString) revision = " << rev << endl;
+
+ QVBox *vbox = addVBoxPage( i18n("Annotate")+" "+rev );
+ AnnotatePage * page = new AnnotatePage( m_cvsService, vbox );
+ page->startAnnotate(m_pathName, rev);
+
+ connect( page, SIGNAL(requestAnnotate(const QString)),
+ this, SLOT(slotAnnotate(const QString)) );
+}
+
+#include "annotatedialog.moc"
diff --git a/vcs/cvsservice/annotatedialog.h b/vcs/cvsservice/annotatedialog.h
new file mode 100644
index 00000000..7fea14f1
--- /dev/null
+++ b/vcs/cvsservice/annotatedialog.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef ANNOTATEDIALOG_H
+#define ANNOTATEDIALOG_H
+
+#include <kdialogbase.h>
+
+class CvsJob_stub;
+class CvsService_stub;
+class AnnotatePage;
+
+/**
+ * Implementation for the dialog displaying 'cvs annotate' output.
+ *
+ * This dialog hold a tab for each revision. The user just needs to
+ * click a line in the AnnotateView to get the annotate output for
+ * the selected revision.
+ *
+ * @author Robert Gruber <rgruber@users.sourceforge.net>
+ */
+class AnnotateDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ AnnotateDialog( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 );
+ virtual ~AnnotateDialog();
+
+ /**
+ * Entrypoint from outside.
+ * By calling this method, an annotate job is execuded for the given
+ * file and the specifed a revision.
+ * The output gets showen in the page which has already been created by the constructor.
+ *
+ * You need to call this function in order to set the file which you want to annotate.
+ * Any further operation will be execucted on the file specified by @param pathName
+ *
+ * @param pathName The file for which to run cvs annotate
+ */
+ void startFirstAnnotate( const QString pathName, const QString revision = "" );
+
+private slots:
+ /**
+ * This slot runs cvs annotate for the given revision.
+ * The output gets shown in a new page.
+ * @param rev The revision which will be annotated
+ */
+ void slotAnnotate(const QString rev);
+
+private:
+ QString m_pathName;
+
+ AnnotatePage *m_cvsAnnotatePage;
+ CvsService_stub *m_cvsService;
+};
+
+#endif
diff --git a/vcs/cvsservice/annotatepage.cpp b/vcs/cvsservice/annotatepage.cpp
new file mode 100644
index 00000000..fea16ece
--- /dev/null
+++ b/vcs/cvsservice/annotatepage.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#include <qlabel.h>
+
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <krfcdate.h>
+#include <klineedit.h>
+#include <kpushbutton.h>
+#include <kdialogbase.h>
+#include <kmessagebox.h>
+
+#include <dcopref.h>
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "annotatepage.h"
+#include "annotateview.h"
+
+AnnotatePage::AnnotatePage( CvsService_stub *cvsService, QWidget *parent, const char *name, int )
+ : DCOPObject( "CvsAnnotatePageDCOPIface" ),
+ QWidget( parent, name? name : "annotateformpage" ),
+ m_cvsService( cvsService ), m_cvsAnnotateJob( 0 )
+{
+ kdDebug(9006) << "AnnotatePage::AnnotatePage()" << endl;
+
+ QLayout *dialogLayout = new QVBoxLayout( this );
+
+ //First create the top-line where user can choose a revision
+ QWidget * LayoutWidget = new QWidget( this );
+ QHBoxLayout * AnnotateLayout = new QHBoxLayout( LayoutWidget );
+
+ QLabel * lblRevision = new QLabel( LayoutWidget );
+ AnnotateLayout->addWidget( lblRevision );
+ lblRevision->setText( tr( "Revision:" ) );
+
+ m_leRevision = new KLineEdit( LayoutWidget );
+ AnnotateLayout->addWidget( m_leRevision );
+
+ m_btnAnnotate = new KPushButton( LayoutWidget );
+ AnnotateLayout->addWidget( m_btnAnnotate );
+ m_btnAnnotate->setText( tr( "&Annotate" ) );
+ m_btnAnnotate->setAccel( QKeySequence( tr( "Alt+A" ) ) );
+
+ dialogLayout->add( LayoutWidget );
+
+ connect( m_btnAnnotate, SIGNAL(clicked()),
+ this, SLOT(slotNewAnnotate()) );
+ connect( m_leRevision, SIGNAL( returnPressed() ),
+ m_btnAnnotate, SLOT( setFocus() ) );
+
+ //Nest create the AnnotateView; it will do the actual displaying
+ m_annotateView = new AnnotateView(this, "annotateview");
+ dialogLayout->add( m_annotateView );
+}
+
+AnnotatePage::~AnnotatePage()
+{
+ kdDebug(9006) << "AnnotatePage::~Annotate()" << endl;
+ cancel();
+ delete m_cvsAnnotateJob;
+}
+
+void AnnotatePage::startAnnotate( const QString pathName, const QString revision )
+{
+ kdDebug(9006) << "AnnotatePage::startAnnotate() pathName = " << pathName <<
+ "revision = " << revision << endl;
+
+ m_leRevision->setText(revision);
+
+ m_pathName = pathName;
+
+ DCOPRef job = m_cvsService->annotate( pathName, revision );
+ m_cvsAnnotateJob = new CvsJob_stub( job.app(), job.obj() );
+
+ // establish connections to the signals of the cvs m_job
+ connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+
+ //clear both the outputbuffer and the AnnotateView
+ m_output = "";
+ ((KListView*)m_annotateView)->clear();
+
+ kdDebug(9006) << "Running: " << m_cvsAnnotateJob->cvsCommand() << endl;
+ m_cvsAnnotateJob->execute();
+}
+
+void AnnotatePage::slotJobExited( bool normalExit, int exitStatus )
+{
+ kdDebug(9006) << "AnnotatePage::slotJobExited(bool, int)" << endl;
+
+ if (!normalExit)
+ {
+ KMessageBox::sorry( this, i18n("Annotate failed with exitStatus == %1").arg( exitStatus), i18n("Annotate Failed") );
+ return;
+ }
+
+ //split the collected output and pass the lines to the parser function
+ QStringList lines = QStringList::split("\n", m_output);
+ parseAnnotateOutput(lines);
+}
+
+void AnnotatePage::slotReceivedOutput( QString someOutput )
+{
+ kdDebug(9006) << "AnnotatePage::slotReceivedOutput(QString)" << endl;
+ m_output += someOutput;
+}
+
+void AnnotatePage::slotReceivedErrors( QString )
+{
+ kdDebug(9006) << "AnnotatePage::slotReceivedErrors(QString)" << endl;
+}
+
+void AnnotatePage::cancel()
+{
+ if (m_cvsAnnotateJob && m_cvsAnnotateJob->isRunning())
+ m_cvsAnnotateJob->cancel();
+}
+
+void AnnotatePage::parseAnnotateOutput(QStringList& lines)
+{
+ kdDebug(9006) << "AnnotatePage::parseAnnotateOutput(QStringList)" << endl;
+
+ /**
+ * First we need to parse the output of "cvs log" which the dcop-interface delivers
+ * everytime annotate is requested.
+ * The QMap m_comments stores the revisions together with the matching comments.
+ * The comments will be passed to the AnnotateView in order to display them as QToolTip
+ */
+ QString line, comment, rev;
+
+ enum { Begin, Tags, Admin, Revision,
+ Author, Branches, Comment, Finished } state;
+
+ QStringList::Iterator it = lines.begin();
+ state = Begin;
+ do
+ {
+ line = *it;
+
+ switch( state )
+ {
+ case Begin:
+ if( line == "symbolic names:" )
+ state = Tags;
+ break;
+ case Tags:
+ if( line[0] != '\t' )
+ state = Admin;
+ break;
+ case Admin:
+ if( line == "----------------------------" )
+ state = Revision;
+ break;
+ case Revision:
+ rev = line.section(' ', 1, 1);
+ state = Author;
+ break;
+ case Author:
+ state = Branches;
+ break;
+ case Branches:
+ if( !line.startsWith("branches:") )
+ {
+ state = Comment;
+ comment = line;
+ }
+ break;
+ case Comment:
+ if( line == "----------------------------" )
+ state = Revision;
+ else if( line == "=============================================================================" )
+ state = Finished;
+ if( state == Comment )
+ comment += QString("\n") + line;
+ else
+ m_comments[rev] = comment;
+ break;
+ case Finished:
+ ;
+ }
+
+ if (state == Finished)
+ break;
+ } while( ++it != lines.end());
+
+ // move forward until we get to the actual output of "cvs annotate"
+ bool notEof = true;
+ while( notEof && !(*it).startsWith("*****") ) {
+ notEof = (++it != lines.end());
+ }
+
+ //if the upper loop hit the ent of the list, this can only mean, that
+ //the selected revision is unknown to CVS
+ if (!notEof) {
+ KMessageBox::error(this, i18n("The selected revision does not exist."));
+ ((KListView*)m_annotateView)->clear();
+ return;
+ }
+ ++it;
+
+ QString author, content;
+ QString oldRevision = ""; //we always store the last revision to recognice...
+ bool changeColor = false; //...when the AnnotateView needs to change the coloring
+ QDateTime logDate;
+
+ do
+ {
+ line = *it;
+
+ //the log date should be printed according to the user's global setting
+ //so we pass it as QDateTime to the AnnotateView below
+ QString dateString = line.mid(23, 9);
+ if( !dateString.isEmpty() )
+ logDate.setTime_t(KRFCDate::parseDate(dateString), Qt::UTC);
+
+ rev = line.left(13).stripWhiteSpace();
+ author = line.mid(14, 8).stripWhiteSpace();
+ content = line.mid(35, line.length()-35);
+
+ comment = m_comments[rev];
+ if( comment.isNull() )
+ comment = "";
+
+ if( rev != oldRevision )
+ {
+ oldRevision = rev;
+ changeColor = !changeColor;
+ }
+
+ //finished parsing the annotate line
+ //We pass the needed data to the AnnotateView
+ m_annotateView->addLine(rev, author, logDate, content, m_comments[rev], changeColor);
+ } while (++it != lines.end());
+}
+
+void AnnotatePage::slotNewAnnotate()
+{
+ startAnnotate(m_pathName, m_leRevision->text());
+}
+
+#include "annotatepage.moc"
diff --git a/vcs/cvsservice/annotatepage.h b/vcs/cvsservice/annotatepage.h
new file mode 100644
index 00000000..2a062804
--- /dev/null
+++ b/vcs/cvsservice/annotatepage.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef ANNOTATEPAGE_H
+#define ANNOTATEPAGE_H
+
+#include "cvsservicedcopIface.h"
+#include <qwidget.h>
+#include <qmap.h>
+#include <qlistview.h>
+
+class CvsJob_stub;
+class CvsService_stub;
+class QTextBrowser;
+class AnnotateView;
+class QStringList;
+class KLineEdit;
+class KPushButton;
+
+/**
+ * Implementation for the page displaying 'cvs annotate' output.
+ * To the top of the page the user can enter a revision and request
+ * a annotate run for it.
+ * The main widget of a page is the AnnotateView. It holds the output
+ * of the cvs annotate job. See there for further detail.
+ *
+ * @author Robert Gruber <rgruber@users.sourceforge.net>
+ */
+class AnnotatePage : public QWidget, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+
+ friend class AnnotateDialog;
+ friend class AnnotateView;
+
+public:
+ AnnotatePage( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 );
+ virtual ~AnnotatePage();
+
+ /**
+ * Call cvs annotate for the given file and revistion.
+ * @param pathName The filename to annotate
+ * @param revision The CVS revision number
+ */
+ void startAnnotate( const QString pathName, const QString revision="" );
+
+ /**
+ * Cancels the current operation if any
+ */
+ void cancel();
+
+signals:
+ /**
+ * This signal is ment to be emitted by the nested AnnotateView.
+ * The dialog that holds this page catches it in order to create
+ * a new page with the annotate output for the given revision.
+ * @param rev The revision for which a new annotate run is requested
+ */
+ void requestAnnotate(const QString rev);
+
+private slots:
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+ /**
+ * This slot is connected to the button next to m_leRevision.
+ * It clears the AnnotateView and reruns cvs annotate with the
+ * revision the user entered into m_leRevision
+ */
+ void slotNewAnnotate();
+
+private:
+ /**
+ * This method is executed after the cvs annotate job finished.
+ * It parses the output and passes it to the AnnotateView
+ */
+ void parseAnnotateOutput(QStringList& lines);
+
+
+ /**
+ * This is the output buffer for the cvs annotate job.
+ * Everytime slotReceivedOutput() is called by dcop
+ * we append the gained data to this buffer.
+ */
+ QString m_output;
+ /**
+ * This is the AnnotateView. It gets nested into this page.
+ */
+ AnnotateView *m_annotateView;
+ /**
+ * The file for which this page holds the annotate output.
+ */
+ QString m_pathName;
+ /**
+ * Maps the checkin comments to revision numbers
+ */
+ QMap<QString, QString> m_comments;
+
+ /**
+ * With this KLineEdit and the KPushButton next to it
+ * the user can rerun cvs annotate for any revision he
+ * enters into this KLineEdit.
+ */
+ KLineEdit *m_leRevision;
+ /**
+ * With this KPushButton the user can rerun cvs annotate
+ * for the revision he entered into m_leRevision
+ */
+ KPushButton *m_btnAnnotate;
+
+ CvsService_stub *m_cvsService;
+ CvsJob_stub *m_cvsAnnotateJob;
+};
+
+#endif
diff --git a/vcs/cvsservice/annotateview.cpp b/vcs/cvsservice/annotateview.cpp
new file mode 100644
index 00000000..93a2a46d
--- /dev/null
+++ b/vcs/cvsservice/annotateview.cpp
@@ -0,0 +1,221 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.net *
+ * *
+ * This file has been taken from cervisia an adapted to fit my needs: *
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de> *
+ * Copyright (c) 2003-2005 André Wöbbeking <Woebbeking@web.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "annotateview.h"
+
+#include <qheader.h>
+#include <qdatetime.h>
+#include <qpainter.h>
+#include <kglobalsettings.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "annotatepage.h"
+
+class AnnotateViewItem : public QListViewItem
+{
+ friend class AnnotateView;
+
+public:
+ enum { LineNumberColumn, AuthorColumn, DateColumn,ContentColumn };
+
+ AnnotateViewItem(AnnotateView *parent, QString rev, QString author,
+ QDateTime date, QString content, QString comment,
+ bool odd, int linenumber);
+
+ virtual int compare(QListViewItem *item, int col, bool ascending) const;
+ virtual int width(const QFontMetrics &, const QListView *, int col) const;
+ virtual QString text(int col) const;
+ virtual void paintCell(QPainter *, const QColorGroup &, int, int, int);
+
+private:
+ QString m_revision;
+ QString m_author;
+ QString m_content;
+ QString m_comment;
+ QDateTime m_logDate;
+ bool m_odd;
+ int m_lineNumber;
+
+ static const int BORDER;
+};
+
+
+const int AnnotateViewItem::BORDER = 4;
+
+
+AnnotateViewItem::AnnotateViewItem(AnnotateView *parent, QString rev,
+ QString author, QDateTime date, QString content, QString comment,
+ bool odd, int linenumber)
+ : QListViewItem(parent)
+ , m_revision(rev)
+ , m_author(author)
+ , m_content(content)
+ , m_comment(comment)
+ , m_logDate(date)
+ , m_odd(odd)
+ , m_lineNumber(linenumber)
+{}
+
+
+int AnnotateViewItem::compare(QListViewItem *item, int, bool) const
+{
+ int linenum1 = m_lineNumber;
+ int linenum2 = static_cast<AnnotateViewItem*>(item)->m_lineNumber;
+
+ return (linenum2 > linenum1)? -1 : (linenum2 < linenum1)? 1 : 0;
+}
+
+
+QString AnnotateViewItem::text(int col) const
+{
+ switch (col)
+ {
+ case LineNumberColumn:
+ return QString::number(m_lineNumber);
+ case AuthorColumn:
+ return (m_revision + QChar(' ') + m_author);
+ case DateColumn:
+ return KGlobal::locale()->formatDate(m_logDate.date(), true);
+ case ContentColumn:
+ return m_content;
+ default:
+ ;
+ };
+
+ return QString::null;
+}
+
+
+void AnnotateViewItem::paintCell(QPainter *p, const QColorGroup &, int col, int width, int align)
+{
+ QColor backgroundColor;
+
+ switch (col)
+ {
+ case LineNumberColumn:
+ backgroundColor = KGlobalSettings::highlightColor();
+ p->setPen(KGlobalSettings::highlightedTextColor());
+ break;
+ default:
+ backgroundColor = m_odd ? KGlobalSettings::baseColor()
+ : KGlobalSettings::alternateBackgroundColor();
+ p->setPen(KGlobalSettings::textColor());
+ break;
+ };
+
+ p->fillRect(0, 0, width, height(), backgroundColor);
+
+ QString str = text(col);
+ if (str.isEmpty())
+ return;
+
+ if (align & (AlignTop || AlignBottom) == 0)
+ align |= AlignVCenter;
+
+ p->drawText(BORDER, 0, width - 2*BORDER, height(), align, str);
+}
+
+
+int AnnotateViewItem::width(const QFontMetrics &fm, const QListView *, int col) const
+{
+ return fm.width(text(col)) + 2*BORDER;
+}
+
+
+/******************************************************************************/
+/*****************Definition of class AnnotateView ****************************/
+/******************************************************************************/
+
+AnnotateView::AnnotateView(AnnotatePage *parent, const char *name)
+ : KListView(parent, name), QToolTip( viewport() ),
+ m_page(parent)
+{
+ setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
+ setAllColumnsShowFocus(true);
+ setShowToolTips(false);
+ header()->hide();
+
+ addColumn(QString::null);
+ addColumn(QString::null);
+ addColumn(QString::null);
+ addColumn(QString::null);
+
+ setSorting(AnnotateViewItem::LineNumberColumn);
+ setColumnAlignment(AnnotateViewItem::LineNumberColumn, Qt::AlignRight);
+
+ connect( this, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(itemClicked(QListViewItem*)) );
+}
+
+
+void AnnotateView::addLine(QString rev, QString author, QDateTime date,
+ QString content, QString comment, bool odd)
+{
+ new AnnotateViewItem(this, rev, author, date, content, comment,
+ odd, childCount()+1);
+}
+
+
+QSize AnnotateView::sizeHint() const
+{
+ QFontMetrics fm(fontMetrics());
+ return QSize(100 * fm.width("0"), 20 * fm.lineSpacing());
+}
+
+
+void AnnotateView::maybeTip( const QPoint & p )
+{
+ AnnotateViewItem * item = dynamic_cast<AnnotateViewItem*>( itemAt( p ) );
+ if (!item)
+ return;
+
+ const int column(header()->sectionAt(p.x()));
+ if (column != AnnotateViewItem::AuthorColumn &&
+ column != AnnotateViewItem::DateColumn) {
+ return;
+ }
+
+ QRect r = itemRect( item );
+ //get the dimension of the author + the date column
+ QRect headerRect = header()->sectionRect(AnnotateViewItem::AuthorColumn);
+ headerRect = headerRect.unite(header()->sectionRect(AnnotateViewItem::DateColumn));
+
+ r.setLeft(headerRect.left());
+ r.setWidth(headerRect.width());
+
+ if (r.isValid())
+ {
+ tip( r, "<nobr><b>"+item->text(AnnotateViewItem::AuthorColumn)+"</b></nobr><br>"
+ "<nobr>"+item->text(AnnotateViewItem::DateColumn)+"</nobr>"
+ "<pre>"+item->m_comment+"</pre>");
+ }
+}
+
+void AnnotateView::itemClicked(QListViewItem *item)
+{
+ kdDebug(9006) << "itemClicked()" << endl;
+
+ AnnotateViewItem * line = dynamic_cast<AnnotateViewItem*>(item);
+ if (line) {
+ kdDebug(9006) << "requesting annotate for revision " << line->m_revision << endl;
+ emit m_page->requestAnnotate(line->m_revision);
+ } else {
+ kdDebug(9006) << "This is not an AnnotateViewItem" << endl;
+ }
+}
+
+#include "annotateview.moc"
diff --git a/vcs/cvsservice/annotateview.h b/vcs/cvsservice/annotateview.h
new file mode 100644
index 00000000..6c9cded9
--- /dev/null
+++ b/vcs/cvsservice/annotateview.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Robert Gruber *
+ * rgruber@users.sourceforge.net *
+ * *
+ * This file has been taken from cervisia an adapted to fit my needs: *
+ * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de> *
+ * Copyright (c) 2003-2005 André Wöbbeking <Woebbeking@web.de> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef ANNOTATEVIEW_H
+#define ANNOTATEVIEW_H
+
+
+#include <klistview.h>
+#include <qtooltip.h>
+
+class QDateTime;
+class AnnotatePage;
+
+/**
+ * This is the main widget of each page.
+ * It shows the user the output of cvs annotate.
+ * The user can click any line of this view in order
+ * to get a new page which shows the annotate output
+ * of the clicked revision.
+ */
+class AnnotateView : public KListView, public QToolTip
+{
+ Q_OBJECT
+
+public:
+
+ explicit AnnotateView(AnnotatePage *parent, const char *name=0 );
+
+ void addLine(QString rev, QString author, QDateTime date, QString content,
+ QString comment, bool odd);
+
+ virtual QSize sizeHint() const;
+ void maybeTip( const QPoint & p );
+
+private:
+ AnnotatePage * m_page;
+
+public slots:
+ void itemClicked(QListViewItem *item);
+};
+
+
+#endif
diff --git a/vcs/cvsservice/bufferedstringreader.cpp b/vcs/cvsservice/bufferedstringreader.cpp
new file mode 100644
index 00000000..5c2151fc
--- /dev/null
+++ b/vcs/cvsservice/bufferedstringreader.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "bufferedstringreader.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsOptions
+///////////////////////////////////////////////////////////////////////////////
+
+BufferedStringReader::BufferedStringReader()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+BufferedStringReader::~BufferedStringReader()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList BufferedStringReader::process( const QString &otherChars )
+{
+ // Add to previous buffered chars
+ m_stringBuffer += otherChars;
+ QStringList strings;
+ // Now find all the basic strings in the buffer
+ int pos;
+ while ( (pos = m_stringBuffer.find('\n')) != -1)
+ {
+ QString line = m_stringBuffer.left( pos );
+ if (!line.isEmpty())
+ {
+ strings.append( line );
+ }
+ m_stringBuffer = m_stringBuffer.right( m_stringBuffer.length() - pos - 1 );
+ }
+ return strings;
+}
diff --git a/vcs/cvsservice/bufferedstringreader.h b/vcs/cvsservice/bufferedstringreader.h
new file mode 100644
index 00000000..1f96c0d1
--- /dev/null
+++ b/vcs/cvsservice/bufferedstringreader.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BUFFEREDSTRINGREADER_H
+#define BUFFEREDSTRINGREADER_H
+
+#include <qstringlist.h>
+
+class CvsServicePart;
+class KConfig;
+class KDevProject;
+
+/* This class helps when we have to collect a string list from a text
+ * stream, just as many cvs commands do. The problem is that the these commands
+ * does not provide strings as we need: often a sent string is received
+ * broken in two pieces and so we need a way to rebuild it. This class provide an
+ * abstraction for avoiding this.
+ * @author Mario Scalas <mario.scalas@libero.it>
+*/
+class BufferedStringReader
+{
+public:
+ BufferedStringReader();
+ virtual ~BufferedStringReader();
+
+ /**
+ * Add the specified characters to current buffered ones and grab
+ * as many '\n'-terminated strings as found.
+ * @param otherChars additional chars to be added to the buffer
+ */
+ QStringList process( const QString &otherChars );
+private:
+ QString m_stringBuffer;
+};
+
+#endif // BUFFEREDSTRINGREADER_H
diff --git a/vcs/cvsservice/buildcvs.sh b/vcs/cvsservice/buildcvs.sh
new file mode 100644
index 00000000..9c7c95c4
--- /dev/null
+++ b/vcs/cvsservice/buildcvs.sh
@@ -0,0 +1,25 @@
+#! /bin/sh
+
+# 3 arguments :
+# - relative path to the local directory (e.g. ".")
+# - module name (e.g. "plop")
+# - root repository (e.g. ":ext:me@host:/path/to/cvsroot")
+
+mkcvs() {
+ rm -rf $1/CVS
+ mkdir -p $1/CVS
+
+ echo $2 > $1/CVS/Repository
+ echo $3 > $1/CVS/Root
+
+ for i in $1/*; do
+ if [ -d $i -a $i != $1/CVS ]; then
+ echo "D/"`basename $i`"////" >> $1/CVS/Entries
+ mkcvs "$i" "$2/"`basename $i` $3
+ elif [ -f $i ]; then
+ echo "/"`basename $i`"/1.1.1.1/"`date +"%a %b %d %T %Y//"` >> $1/CVS/Entries
+ fi
+ done
+}
+
+mkcvs $1 $2 $3
diff --git a/vcs/cvsservice/changelog.cpp b/vcs/cvsservice/changelog.cpp
new file mode 100644
index 00000000..a63a2b92
--- /dev/null
+++ b/vcs/cvsservice/changelog.cpp
@@ -0,0 +1,114 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kemailsettings.h>
+
+#include "changelog.h"
+
+ChangeLogEntry::ChangeLogEntry()
+{
+ KEMailSettings emailConfig;
+ emailConfig.setProfile( emailConfig.defaultProfileName() );
+ authorEmail = emailConfig.getSetting( KEMailSettings::EmailAddress );
+ authorName = emailConfig.getSetting( KEMailSettings::RealName );
+
+ QDate currDate = QDate::currentDate();
+ date = currDate.toString( "yyyy-MM-dd" );
+}
+
+ChangeLogEntry::~ChangeLogEntry()
+{
+}
+
+void ChangeLogEntry::addLine( const QString &aLine )
+{
+ lines << aLine;
+}
+
+void ChangeLogEntry::addLines( const QStringList &someLines )
+{
+ lines += someLines;
+}
+
+void streamCopy( QTextStream &is, QTextStream &os )
+{
+ while (!is.eof())
+ os << is.readLine() << "\n"; // readLine() eats '\n' !!
+}
+
+void ChangeLogEntry::addToLog( const QString &logFilePath, const bool prepend, const QString &startLineString )
+{
+ if (prepend) // add on head
+ {
+ QString fakeLogFilePath = logFilePath + ".fake";
+
+ QFile fakeFile( fakeLogFilePath );
+ QFile changeLogFile( logFilePath );
+ {
+ if (!fakeFile.open( IO_WriteOnly | IO_Append))
+ return;
+
+ if (changeLogFile.open( IO_ReadOnly )) // A Changelog already exist
+ {
+ QTextStream is( &changeLogFile );
+ QTextStream os( &fakeFile );
+
+ // Put current entry
+ os << toString( startLineString );
+ // Write the rest of the change log file
+ streamCopy( is, os );
+ }
+ else // ChangeLog doesn't exist: just write our entry
+ {
+ QTextStream t( &fakeFile );
+ t << toString( startLineString );
+ }
+ fakeFile.close();
+ changeLogFile.close();
+ }
+ // Ok, now we have the change log we need in fakeLogFilePath: we should ask for a
+ // 'mv fakeLogFilePath logFilePath'-like command ... :-/
+ if (!fakeFile.open( IO_ReadOnly ))
+ return;
+
+ if (changeLogFile.open( IO_WriteOnly ))
+ {
+ QTextStream os( &changeLogFile );
+ QTextStream is( &fakeFile );
+
+ // Write the rest of the change log file
+ streamCopy( is, os );
+ }
+ fakeFile.close();
+ fakeFile.remove(); // fake changelog is no more needed!
+ changeLogFile.close();
+ }
+ else // add on tail
+ {
+ QFile f( logFilePath );
+ if (!f.open( IO_WriteOnly | IO_Append))
+ return;
+
+ QTextStream t( &f );
+ t << toString( startLineString );
+ }
+}
+
+QString ChangeLogEntry::toString( const QString &startLineString ) const
+{
+ QString header = date + " " + authorName + " <" + authorEmail + ">\n";
+
+ return header + startLineString + lines.join( "\n" + startLineString ) + "\n\n";
+}
diff --git a/vcs/cvsservice/changelog.h b/vcs/cvsservice/changelog.h
new file mode 100644
index 00000000..3d512f95
--- /dev/null
+++ b/vcs/cvsservice/changelog.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CHANGELOG_H
+#define CHANGELOG_H
+
+#include <qstringlist.h>
+
+/**
+A class which abstracts the building of an entry in the ChangeLog file (it formats name, e-mail and text).
+
+@author Mario Scalas
+*/
+struct ChangeLogEntry
+{
+public:
+ ChangeLogEntry();
+ ~ChangeLogEntry();
+
+ //! Add a single line to the lines for this entry
+ void addLine( const QString &aLine );
+ //! Add a bunch of lines for this entry
+ void addLines( const QStringList &someLines );
+ //! Pretty format for this entry: you may insert a line tag (such as tab ("\t") or 4 spaces (" ")
+ //! or whatever you want (such as "\t * ")
+ QString toString( const QString &startLineString = QString::null ) const;
+ //! Once the entry is completed one would like to write on a file! (You may add on start of file
+ //! prepend == true, or append on tail (prepend == false)
+ void addToLog( const QString &logFilePath, const bool prepend = true, const QString &startLineString = "\t" );
+
+ QString authorName,
+ authorEmail,
+ date;
+ QStringList lines;
+};
+
+#endif
diff --git a/vcs/cvsservice/checkoutdialog.cpp b/vcs/cvsservice/checkoutdialog.cpp
new file mode 100644
index 00000000..7fb9455c
--- /dev/null
+++ b/vcs/cvsservice/checkoutdialog.cpp
@@ -0,0 +1,276 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <klistview.h>
+#include <kurlrequester.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <klineedit.h>
+
+#include <dcopref.h>
+#include <cvsjob_stub.h>
+#include <repository_stub.h>
+#include <cvsservice_stub.h>
+
+#include "checkoutdialogbase.h"
+
+#include "checkoutdialog.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Constants
+///////////////////////////////////////////////////////////////////////////////
+
+const QString SSS( ":" ); // Server String Separator :)
+
+///////////////////////////////////////////////////////////////////////////////
+// class ModuleListViewItem
+///////////////////////////////////////////////////////////////////////////////
+
+class ModuleListViewItem : public KListViewItem
+{
+public:
+ ModuleListViewItem( KListView *listview,
+ const QString &moduleAlias, const QString &moduleRealPath )
+ : KListViewItem( listview )
+ {
+ setAlias( moduleAlias );
+ setRealPath( moduleRealPath );
+ }
+
+ void setAlias( const QString &aName ) { setText( 0, aName); }
+ QString alias() const { return text(0); }
+ void setRealPath( const QString &aRealPath ) { setText(1, aRealPath); }
+ QString realPath() const { return text(1); }
+
+// virtual QString text() const { return name(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// class CheckoutDialog
+///////////////////////////////////////////////////////////////////////////////
+
+CheckoutDialog::CheckoutDialog( CvsService_stub *cvsService,
+ QWidget *parent, const char *name, WFlags ) :
+ DCOPObject( "CheckoutDialogDCOPIface" ),
+ KDialogBase( parent, name? name : "checkoutdialog", true, i18n("CVS Checkout"),
+ Ok | Cancel, Ok, true ),
+ m_service( cvsService ), m_job( 0 )
+{
+ m_base = new CheckoutDialogBase( this, "checkoutdialogbase" );
+ setMainWidget( m_base );
+
+ connect( m_base->fetchModulesButton, SIGNAL(clicked()),
+ this, SLOT(slotFetchModulesList()) );
+ connect( m_base->modulesListView, SIGNAL(executed(QListViewItem*)),
+ this, SLOT(slotModuleSelected(QListViewItem*)) );
+
+ // Avoid displaying 'file:/' when displaying the file
+ m_base->workURLRequester->setShowLocalProtocol( false );
+ m_base->workURLRequester->setMode( KFile::Directory );
+
+ // Grab the entries from $HOME/.cvspass
+ fetchUserCvsRepositories();
+ // And suggest to use the default projects dir set in KDevelop's preferences
+ KConfig *config = kapp->config();
+ config->setGroup("General Options");
+ QString defaultProjectsDir = config->readPathEntry("DefaultProjectsDir", QDir::homeDirPath()+"/");
+ setWorkDir( defaultProjectsDir );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CheckoutDialog::~CheckoutDialog()
+{
+ delete m_job;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CheckoutDialog::serverPath() const
+{
+ return m_base->serverPaths->currentText();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::fillServerPaths( const QStringList &serverPaths )
+{
+ m_base->serverPaths->insertStringList( serverPaths );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CheckoutDialog::workDir() const
+{
+ return m_base->workURLRequester->url();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::setWorkDir( const QString &aDir )
+{
+ m_base->workURLRequester->setURL( aDir );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CheckoutDialog::pruneDirs() const
+{
+ return m_base->pruneDirsCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CheckoutDialog::tag() const
+{
+ return m_base->tagEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CheckoutDialog::module() const
+{
+ return m_base->moduleEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::slotFetchModulesList()
+{
+ setCursor( KCursor::waitCursor() );
+
+ if (serverPath().isEmpty() || workDir().isEmpty())
+ return;
+
+ DCOPRef job = m_service->moduleList( serverPath() );
+ if (!m_service->ok())
+ return;
+
+ m_job = new CvsJob_stub( job.app(), job.obj() );
+ // We only need to know when it finishes and then will grab the output
+ // by using m_job->output() :-)
+ connectDCOPSignal( job.app(), job.obj(), "jobFinished(bool,int)", "slotJobExited(bool,int)", true );
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "receivedOutput(QString)", true );
+
+ kdDebug() << "Running: " << m_job->cvsCommand() << endl;
+ m_job->execute();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::slotJobExited( bool /*normalExit*/, int /*exitStatus*/ )
+{
+ kdDebug(9006) << "CheckoutDialog::slotModulesListFetched() here!" << endl;
+
+ kdDebug(9006) << "Received: " << m_job->output().join( "\n" ) << endl;
+
+// m_base->modulesListView->insertStringList( m_job->output() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::slotReceivedOutput( QString someOutput )
+{
+ kdDebug( 9006 ) << " Received output: " << someOutput << endl;
+
+ setCursor( KCursor::arrowCursor() );
+
+ // Fill the modules KListView if the list obtained is not empty
+ // QStringList modules = m_job->output();
+ QStringList modules = QStringList::split( "\n", someOutput );
+ if (modules.count() <= 0)
+ return;
+
+ QStringList::iterator it = modules.begin();
+ for ( ; it != modules.end(); ++it )
+ {
+ QStringList l = QStringList::split( " ", (*it) );
+ // Now, l[0] is the module name, l[1] is ... another string ;-)
+ new ModuleListViewItem( m_base->modulesListView, l[0], l[1] );
+ }
+}
+
+void CheckoutDialog::slotReceivedErrors( QString someErrors )
+{
+ kdDebug( 9006 ) << " Received errors: " << someErrors << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::slotModuleSelected( QListViewItem * )
+{
+ ModuleListViewItem *aModuleItem = static_cast<ModuleListViewItem*>(
+ m_base->modulesListView->selectedItem()
+ );
+ if (!aModuleItem)
+ return;
+
+ m_base->moduleEdit->setText( aModuleItem->alias() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::fetchUserCvsRepositories()
+{
+ QStringList repositories;
+
+ QFile cvspass( QDir::homeDirPath() + QDir::separator() + ".cvspass" );
+ if (!cvspass.open( IO_ReadOnly ))
+ return;
+ QByteArray data = cvspass.readAll();
+ cvspass.close();
+
+ QTextIStream istream( data );
+ // Entries are like:
+ // /1 :pserver:marios@cvs.kde.org:2401/home/kde Ahz:UIK?=d ?
+ // /1 :pserver:mario@xamel:2401/home/cvsroot aJT_d'K?=d ?
+ while (!istream.eof()) {
+ QString line = istream.readLine();
+ QStringList lineElements = QStringList::split( " ", line );
+ if (lineElements.count() > 1) {
+ repositories << lineElements[ 1 ];
+ }
+ }
+
+ fillServerPaths( repositories );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CheckoutDialog::slotOk()
+{
+ QString errorMessage = QString::null;
+
+ if (!(workDir().length() > 0) && QFile::exists( workDir() ))
+ errorMessage = i18n( "Please, choose a valid working directory" );
+ else if (!(serverPath().length() > 0))
+ errorMessage = i18n( "Please, choose a CVS server." );
+ else if (!(module().length() > 0))
+ errorMessage = i18n( "Please, fill the CVS module field." );
+
+ if (errorMessage.isNull())
+ KDialogBase::slotOk();
+ else
+ KMessageBox::error( this, errorMessage );
+}
+
+
+#include "checkoutdialog.moc"
diff --git a/vcs/cvsservice/checkoutdialog.h b/vcs/cvsservice/checkoutdialog.h
new file mode 100644
index 00000000..597a806a
--- /dev/null
+++ b/vcs/cvsservice/checkoutdialog.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CHECKOUTDIALOG_H
+#define CHECKOUTDIALOG_H
+
+#include <kdialogbase.h>
+#include "cvsservicedcopIface.h"
+
+class CvsService_stub;
+class CvsJob_stub;
+class CheckoutDialogBase;
+class QListViewItem;
+//class QStringList;
+
+/**
+* This dialog widget will collect all useful informazion about the module the
+* user want to to check-out from a remote repository.
+*
+* @author Mario Scalas
+*/
+class CheckoutDialog : public KDialogBase, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+public:
+ CheckoutDialog( CvsService_stub *cvsService, QWidget *parent = 0,
+ const char *name = 0, WFlags f = 0 );
+ virtual ~CheckoutDialog();
+
+ virtual void slotOk();
+
+ /**
+ * @return a server path string (i.e. :pserver:marios@cvs.kde.org:/home/kde)
+ */
+ QString serverPath() const;
+ /**
+ * @param serverPaths a list of server location to use when filling the widget
+ */
+ void fillServerPaths( const QStringList &serverPaths );
+ /**
+ * @return the directory which the user has fetched the module in
+ */
+ QString workDir() const;
+ /**
+ * @param aDir directory which fetched modules will be put in (ending with '/')
+ */
+ void setWorkDir( const QString &aDir );
+ /**
+ * @return the module the user has chosen to check-out from repository
+ */
+ QString module() const;
+ /**
+ * @return
+ */
+ bool pruneDirs() const;
+ /**
+ * @return
+ */
+ QString tag() const;
+
+private slots:
+ void slotModuleSelected( QListViewItem *item );
+ void slotFetchModulesList();
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+private:
+ /**
+ * Retrives the known servers from $HOME/.cvspass file
+ * @return a list of server locations (:pserver:user@server.somewhere:/cvsroot)
+ */
+ void fetchUserCvsRepositories();
+
+ CvsService_stub *m_service;
+ CvsJob_stub *m_job;
+
+ CheckoutDialogBase *m_base;
+};
+
+#endif
diff --git a/vcs/cvsservice/checkoutdialogbase.ui b/vcs/cvsservice/checkoutdialogbase.ui
new file mode 100644
index 00000000..f0ebdf8d
--- /dev/null
+++ b/vcs/cvsservice/checkoutdialogbase.ui
@@ -0,0 +1,312 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>CheckoutDialogBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CheckoutDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>671</width>
+ <height>538</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>CVS Server Configuration</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Configuration</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Local destination directory:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>workURLRequester</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>workURLRequester</cstring>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>serverPaths</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Server path (e.g. :pserver:marios@cvs.kde.org:/home/kde):</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>serverPaths</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Select Module</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>156</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Module:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>moduleEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Tag/branch:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>tagEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="2">
+ <property name="name">
+ <cstring>tagEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="0">
+ <property name="name">
+ <cstring>moduleEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>pruneDirsCheck</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Prune directories</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Creates subdirs if needed</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Module</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Real Path</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>modulesListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>421</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>fetchModulesButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Fetch Modules List</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Fetch modules list from server</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click to fetch modules list from server you specified</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<tabstops>
+ <tabstop>workURLRequester</tabstop>
+ <tabstop>serverPaths</tabstop>
+ <tabstop>moduleEdit</tabstop>
+ <tabstop>tagEdit</tabstop>
+ <tabstop>modulesListView</tabstop>
+ <tabstop>pruneDirsCheck</tabstop>
+ <tabstop>fetchModulesButton</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klistview.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/cvsservice/commitdialogbase.ui b/vcs/cvsservice/commitdialogbase.ui
new file mode 100644
index 00000000..90e8f7b4
--- /dev/null
+++ b/vcs/cvsservice/commitdialogbase.ui
@@ -0,0 +1,161 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CommitDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CommitDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>531</width>
+ <height>385</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Commit to Repository</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Message</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextEdit">
+ <property name="name">
+ <cstring>textEdit</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkAddToChangelog</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add to changelog:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>changeLogNameEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Change log filename path (relative to project directory)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;b&gt;Changelog filename path&lt;/b&gt;&lt;br/&gt;Insert here the Changelog filename you wish to use so that the message is appended</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>350</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>CommitDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>checkAddToChangelog</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>changeLogNameEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/commitdlg.cpp b/vcs/cvsservice/commitdlg.cpp
new file mode 100644
index 00000000..4c7eac97
--- /dev/null
+++ b/vcs/cvsservice/commitdlg.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * Copyright (C) 1999, 2000 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qtextedit.h>
+#include <qpushbutton.h>
+
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <klineedit.h>
+
+#include "commitdlg.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CommitDialog
+///////////////////////////////////////////////////////////////////////////////
+
+
+CommitDialog::CommitDialog( const QString &changeLogfileNamePath, QWidget *parent )
+ : CommitDialogBase( parent, "commitdialog", true )
+{
+ connect( buttonOk, SIGNAL(clicked()), SLOT(accept()) );
+ connect( buttonCancel, SIGNAL(clicked()), SLOT(reject()) );
+
+ setChangeLogFileName( changeLogfileNamePath );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList CommitDialog::logMessage() const
+{
+ QStringList textLines;
+ for (int i=0; i<textEdit->paragraphs(); ++i)
+ {
+ textLines << textEdit->text( i );
+ }
+ return textLines;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CommitDialog::mustAddToChangeLog() const
+{
+ return checkAddToChangelog->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CommitDialog::accept()
+{
+ if (textEdit->text().isNull() || textEdit->text().isEmpty()) {
+ int s = KMessageBox::warningContinueCancel( this,
+ i18n("You are committing your changes without any comment. This is not a good practice. Continue anyway?"),
+ i18n("CVS Commit Warning"),
+ KStdGuiItem::cont(),
+ i18n("askWhenCommittingEmptyLogs") );
+ if ( s != KMessageBox::Continue ) {
+ return;
+ }
+ }
+ QDialog::accept();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CommitDialog::setChangeLogFileName( const QString &fileName )
+{
+ changeLogNameEdit->setText( fileName );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CommitDialog::changeLogFileName() const
+{
+ return changeLogNameEdit->text();
+}
+
+#include "commitdlg.moc"
diff --git a/vcs/cvsservice/commitdlg.h b/vcs/cvsservice/commitdlg.h
new file mode 100644
index 00000000..3e98b269
--- /dev/null
+++ b/vcs/cvsservice/commitdlg.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 1999, 2000 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _COMMITDIALOG_H_
+#define _COMMITDIALOG_H_
+
+//#include <qdialog.h>
+#include <qstringlist.h>
+#include "commitdialogbase.h"
+
+class QTextEdit;
+class QCheckBox;
+
+class CommitDialog : public CommitDialogBase
+{
+ Q_OBJECT
+public:
+ CommitDialog( const QString &changeLogfileNamePath, QWidget *parent = 0 );
+
+ //! Returns the text of the log
+ QStringList logMessage() const;
+ //! Returns true if the user requests the log message to be added to the general
+ //! Changelog file
+ bool mustAddToChangeLog() const;
+
+ //! We need to set it when showing the dialog and then when saving the file
+ void setChangeLogFileName( const QString &fileName );
+ QString changeLogFileName() const;
+
+protected slots:
+ //! Override: must check for message not being void.
+ virtual void accept();
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsdiffpage.cpp b/vcs/cvsservice/cvsdiffpage.cpp
new file mode 100644
index 00000000..12947b36
--- /dev/null
+++ b/vcs/cvsservice/cvsdiffpage.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * Copyright (C) 200?-2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qstringlist.h>
+
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "cvsoptions.h"
+#include "cvsdiffpage.h"
+
+#include "diffwidget.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSDiffPage
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDiffPage::CVSDiffPage( CvsService_stub *cvsService,
+ QWidget *parent, const char *name, int )
+ // Leaving it anonymous let us to have multiple objects at the same time!
+ : DCOPObject(), // "CVSDiffPageDCOPIface"
+ QWidget( parent, name? name : "logformdialog" ),
+ m_diffText( 0 ), m_cvsService( cvsService ), m_cvsDiffJob( 0 )
+{
+ QLayout *thisLayout = new QVBoxLayout( this );
+ // This should be replaced by the diff part
+// m_diffText = new QTextEdit( this, "difftextedit" );
+// m_diffText->setReadOnly( true );
+ m_diffText = new DiffWidget( this, "difftextedit" );
+
+ thisLayout->add( m_diffText );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDiffPage::~CVSDiffPage()
+{
+ kdDebug(9006) << "CVSDiffPage::~CVSDiffPage()" << endl;
+ cancel();
+ delete m_cvsDiffJob;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDiffPage::startDiff( const QString &fileName, const QString &v1, const QString &v2 )
+{
+ kdDebug(9006) << "CVSDiffPage::startDiff()" << endl;
+
+ if ( v1.isEmpty() || v2.isEmpty() )
+ {
+ KMessageBox::error( this, i18n("Error: passed revisions are empty!"), i18n( "Error During Diff") );
+ return;
+ }
+
+ CvsOptions *options = CvsOptions::instance();
+ DCOPRef job = m_cvsService->diff( fileName, v1, v2, options->diffOptions(), options->contextLines() );
+ m_cvsDiffJob = new CvsJob_stub( job.app(), job.obj() );
+
+ kdDebug(9006) << "Running command : " << m_cvsDiffJob->cvsCommand() << endl;
+ connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+ bool success = m_cvsDiffJob->execute();
+ if (!success)
+ {
+ kdDebug(9006) << "Argh ... cannot start the diff job!" << endl;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDiffPage::slotJobExited( bool normalExit, int /*exitStatus*/ )
+{
+ kdDebug(9006) << "CVSDiffPage::slotJobExited(bool, int)" << endl;
+
+ if (normalExit)
+ {
+ QString diffText = m_cvsDiffJob->output().join( "\n" );
+ kdDebug(9006) << "*** Received: " << diffText << endl;
+// m_diffText->setText( diffText );
+ m_diffText->setDiff( m_diffString );
+ }
+ else
+ {
+ KMessageBox::error( this, i18n("An error occurred during diffing."), i18n( "Error During Diff"));
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDiffPage::slotReceivedOutput( QString someOutput )
+{
+ kdDebug(9006) << "CVSDiffPage::slotReceivedOutput(QString)" << endl;
+ kdDebug(9006) << "OUTPUT: " << someOutput << endl;
+
+ QStringList strings = m_outputBuffer.process(someOutput);
+ m_diffString += strings.join("\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDiffPage::slotReceivedErrors( QString someErrors )
+{
+ kdDebug(9006) << "CVSDiffPage::slotReceivedErrors(QString)" << endl;
+ kdDebug(9006) << "ERRORS: " << someErrors << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDiffPage::cancel()
+{
+ if (m_cvsDiffJob && m_cvsDiffJob->isRunning())
+ m_cvsDiffJob->cancel();
+}
+
+#include "cvsdiffpage.moc"
+
+
diff --git a/vcs/cvsservice/cvsdiffpage.h b/vcs/cvsservice/cvsdiffpage.h
new file mode 100644
index 00000000..16a6fec6
--- /dev/null
+++ b/vcs/cvsservice/cvsdiffpage.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSDIFFPAGE_H
+#define CVSDIFFPAGE_H
+
+#include "cvsservicedcopIface.h"
+#include <qwidget.h>
+#include "bufferedstringreader.h"
+
+class CvsJob_stub;
+class CvsService_stub;
+class QTextEdit;
+class DiffWidget;
+
+/**
+Implementation for the form displaying 'cvs diff' output.
+
+@author KDevelop Authors
+*/
+class CVSDiffPage : public QWidget, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+public:
+ CVSDiffPage( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 );
+ virtual ~CVSDiffPage();
+
+ void startDiff( const QString &fileName, const QString &v1, const QString &v2 );
+ void cancel();
+
+//private slots:
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+private:
+ //QTextEdit *m_diffText;
+ DiffWidget *m_diffText;
+ BufferedStringReader m_outputBuffer;
+ QString m_diffString;
+
+ CvsService_stub *m_cvsService;
+ CvsJob_stub *m_cvsDiffJob;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsdir.cpp b/vcs/cvsservice/cvsdir.cpp
new file mode 100644
index 00000000..2b7602e6
--- /dev/null
+++ b/vcs/cvsservice/cvsdir.cpp
@@ -0,0 +1,321 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include "cvsdir.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSDir
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDir::CVSDir() : QDir()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDir::CVSDir( const QDir &dir )
+ : QDir( dir )
+{
+ // We deal with absolute paths only
+ convertToAbs();
+
+ m_cvsDir = absPath() + QDir::separator() + "CVS";
+
+ if (isValid())
+ refreshEntriesCache();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDir::CVSDir( const CVSDir &aCvsDir )
+ : QDir( aCvsDir )
+{
+ *this = aCvsDir;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDir &CVSDir::operator=( const CVSDir &aCvsDir )
+{
+ m_cvsDir = aCvsDir.m_cvsDir;
+ m_cachedEntries = aCvsDir.m_cachedEntries;
+ QDir::operator=( aCvsDir );
+
+ return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSDir::~CVSDir()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CVSDir::isValid() const
+{
+ return exists() &&
+ QFile::exists( entriesFileName() ) &&
+ QFile::exists( rootFileName() ) &&
+ QFile::exists( repoFileName() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::entriesFileName() const
+{
+ return m_cvsDir + QDir::separator() + "Entries";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::rootFileName() const
+{
+ return m_cvsDir + QDir::separator() + "Root";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::repoFileName() const
+{
+ return m_cvsDir + QDir::separator() + "Repository";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::cvsIgnoreFileName() const
+{
+ return absPath() + QDir::separator() + ".cvsignore";
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::repository() const
+{
+ // The content of CVS/Repository is a single line with the path into the
+ // repository of the modules checked out in this directory (just like
+ // "kdevelop/parts/cvsservice"): so we can read a single line of the file
+ // and we are done!
+ QString content;
+
+ if (!isValid())
+ return QString::null;
+
+ QByteArray bytes = cacheFile( repoFileName() );
+ QTextStream t( bytes, IO_ReadOnly );
+ content += t.readLine();
+
+ return content;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSDir::root() const
+{
+ // Same as CVSDir::repository() but CVS/Root contains the path of the
+ // CVS server as used in "cvs -d <server-path>" (in example:
+ // ":pserver:marios@cvs.kde.org:/home/kde")
+ QString content;
+
+ if (!isValid())
+ return QString::null;
+
+ QByteArray bytes = cacheFile( repoFileName() );
+ QTextStream t( bytes, IO_ReadOnly );
+ content += t.readLine();
+
+ return content;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QByteArray CVSDir::cacheFile( const QString &fileName )
+{
+ QFile f( fileName );
+ if (!f.open( IO_ReadOnly ))
+ return QByteArray();
+ return f.readAll();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList CVSDir::registeredEntryList() const
+{
+ QStringList l;
+ if (!isValid())
+ return l;
+
+ QByteArray bytes = cacheFile( entriesFileName() );
+ QTextStream t( bytes, IO_ReadOnly );
+ CVSEntry entry;
+ while (!t.eof())
+ {
+ QString line = t.readLine();
+ entry.parse( line, *this );
+ if (entry.isValid())
+ l.append( entry.fileName() );
+ }
+ return l;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CVSDir::isRegistered( const QString fileName ) const
+{
+ CVSEntry entry = fileStatus( fileName );
+ return entry.isValid() && entry.fileName() == fileName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDir::refreshEntriesCache() const
+{
+ m_cachedEntries.clear();
+
+ QByteArray bytes = cacheFile( entriesFileName() );
+ QTextStream t( bytes, IO_ReadOnly );
+ CVSEntry entry;
+ while (!t.eof())
+ {
+ QString line = t.readLine();
+ entry.parse( line, *this );
+ if (entry.isValid())
+ m_cachedEntries[ entry.fileName() ] = entry;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSEntry CVSDir::fileStatus( const QString &fileName, bool refreshCache ) const
+{
+ if (refreshCache)
+ refreshEntriesCache();
+
+ if (m_cachedEntries.contains( fileName ))
+ {
+ return m_cachedEntries[ fileName ];
+ }
+ else
+ return CVSEntry( fileName, *this ); // Just the file name
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDir::ignoreFile( const QString &fileName )
+{
+ if (!isValid())
+ return;
+
+ QFile f( cvsIgnoreFileName() );
+ if (!f.open( IO_ReadOnly))
+ return;
+
+ QByteArray cachedFile = f.readAll();
+ QTextStream t( cachedFile, IO_ReadOnly | IO_WriteOnly );
+
+ QString readFileName;
+ bool found = false;
+
+ while (!t.eof() && !found)
+ {
+ readFileName = t.readLine();
+ found = (fileName == readFileName);
+ }
+
+ f.close();
+ if (!found)
+ {
+ f.open( IO_WriteOnly );
+
+ t << fileName << "\n";
+
+ f.writeBlock( cachedFile );
+ f.close();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSDir::doNotIgnoreFile( const QString &fileName )
+{
+ if (!isValid())
+ return;
+
+ // 1. Read all .ignore file in memory
+ QFile f( cvsIgnoreFileName() );
+ if (!f.open( IO_ReadOnly ))
+ return; // No .cvsignore file? Nothing to do then!
+
+ QByteArray cachedFile = f.readAll();
+ QTextIStream is( cachedFile );
+
+ QByteArray cachedOutputFile;
+ QTextOStream os( cachedOutputFile );
+
+ bool removed = false;
+ while (!is.eof())
+ {
+ QString readLine = is.readLine();
+ if (readLine != fileName)
+ os << readLine << "\n"; // QTextStream::readLine() eats the "\n" ...
+ else
+ removed = true;
+ }
+
+ f.close();
+ if (removed)
+ {
+ f.open( IO_WriteOnly );
+ f.writeBlock( cachedOutputFile );
+ f.close();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+VCSFileInfoMap CVSDir::dirStatus() const
+{
+ VCSFileInfoMap vcsInfo;
+ /// Convert to VCSFileInfoMap: \FIXME : any speed improvement here?
+ QStringList entries = registeredEntryList();
+ QStringList::const_iterator it = entries.begin(), end = entries.end();
+ for ( ; it != end; ++it)
+ {
+ const QString &fileName = (*it);
+ const CVSEntry entry = fileStatus( fileName );
+
+ vcsInfo.insert( fileName, entry.toVCSFileInfo() );
+ }
+
+ return vcsInfo;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+VCSFileInfoMap *CVSDir::cacheableDirStatus() const
+{
+ VCSFileInfoMap *vcsInfo = new VCSFileInfoMap;
+ /// Convert to VCSFileInfoMap: \FIXME : any speed improvement here?
+ QStringList entries = registeredEntryList();
+ QStringList::const_iterator it = entries.begin(), end = entries.end();
+ for ( ; it != end; ++it)
+ {
+ const QString &fileName = (*it);
+ const CVSEntry entry = fileStatus( fileName );
+
+ vcsInfo->insert( fileName, entry.toVCSFileInfo() );
+ }
+
+ return vcsInfo;
+}
diff --git a/vcs/cvsservice/cvsdir.h b/vcs/cvsservice/cvsdir.h
new file mode 100644
index 00000000..606f7507
--- /dev/null
+++ b/vcs/cvsservice/cvsdir.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSDIR_H
+#define CVSDIR_H
+
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qmap.h>
+
+#include "cvsentry.h"
+
+/**
+Helper classes for handling CVS dirs
+
+@author Mario Scalas
+*/
+class CVSDir : public QDir
+{
+public:
+ CVSDir();
+ CVSDir( const QDir &dir );
+ explicit CVSDir( const CVSDir & );
+ CVSDir &operator=( const CVSDir & );
+ virtual ~CVSDir();
+
+ /**
+ * A client can use this method to validate the directory state.
+ * @return true if the directory is a valid CVS dir, false otherwise
+ */
+ bool isValid() const;
+ /**
+ * Returns a list of all the files registered into repository
+ */
+ QStringList registeredEntryList() const;
+ /**
+ * @param fileName is the file name (with no path info, just the file name!)
+ * @param refreshCache update internal cache re-parsing "<dirPath>/CVS/Entries"
+ * @return an empty CVSEntry if the file is not present
+ */
+ CVSEntry fileStatus( const QString &fileName, bool refreshCache = false ) const;
+ /**
+ */
+ VCSFileInfoMap dirStatus() const;
+ VCSFileInfoMap *cacheableDirStatus() const;
+ /**
+ * @return true if the file is registered into repository, false otherwise
+ */
+ bool isRegistered( const QString fileName ) const;
+ /**
+ * Check if the specified @p fileName is in "<CVSDIR>/.cvsignore" and, if not,
+ * append it.
+ */
+ void ignoreFile( const QString &fileName );
+ /**
+ * Check if the specified @p fileName is in "<CVSDIR>/.cvsignore" and, if yes,
+ * remove it.
+ */
+ void doNotIgnoreFile( const QString &fileName );
+ /**
+ * @return the content of "<CVSDIR>/CVS/Repository"
+ */
+ QString repository() const;
+ /**
+ * @return the content of "<CVSDIR>/CVS/Root"
+ */
+ QString root() const;
+ /**
+ * @return full path of "<this-dir>/CVS/Entries"
+ */
+ QString entriesFileName() const;
+ /**
+ * @return full path of "<this-dir>/CVS/Root"
+ */
+ QString rootFileName() const;
+ /**
+ * @return full path of "<this-dir>/CVS/Repository"
+ */
+ QString repoFileName() const;
+ /**
+ * @return full path of "<this-dir>/.cvsignore"
+ */
+ QString cvsIgnoreFileName() const;
+
+private:
+ void refreshEntriesCache() const;
+ static QByteArray cacheFile( const QString &fileName );
+
+ QString m_cvsDir;
+
+ typedef QMap<QString,CVSEntry> CVSEntriesCacheMap;
+ mutable CVSEntriesCacheMap m_cachedEntries;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsentry.cpp b/vcs/cvsservice/cvsentry.cpp
new file mode 100644
index 00000000..ab8b2cc0
--- /dev/null
+++ b/vcs/cvsservice/cvsentry.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include "cvsentry.h"
+#include "cvsdir.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Static
+///////////////////////////////////////////////////////////////////////////////
+
+const QString CVSEntry::invalidMarker = "<Invalid entry>";
+const QString CVSEntry::directoryMarker = "D";
+const QString CVSEntry::fileMarker = "";
+const QString CVSEntry::entrySeparator = "/";
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSEntry
+///////////////////////////////////////////////////////////////////////////////
+
+CVSEntry::CVSEntry()
+{
+ clean();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSEntry::CVSEntry( const QString &aLine, const CVSDir& dir )
+{
+ parse( aLine, dir );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSEntry::clean()
+{
+ m_type = invalidEntry;
+ m_state = Unknown;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSEntry::EntryType CVSEntry::type() const
+{
+ return m_type;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSEntry::parse( const QString &aLine, const CVSDir& dir )
+{
+ clean();
+
+ m_fields = QStringList::split( "/", aLine );
+
+ if (aLine.startsWith( entrySeparator )) // Is a file?
+ {
+ m_type = fileEntry; // Is a file
+ }
+ else if (aLine.startsWith( directoryMarker )) // Must be a directory then
+ {
+ m_type = directoryEntry; // Is a directory
+ m_fields.pop_front(); // QStringList::split() fills and empty item in head
+ return;
+ }
+ else // What the hell is this? >:-)
+ {
+ m_type = invalidEntry;
+ return;
+ }
+
+ //if we're a file, keep going
+ QDateTime entryFileDate(QDateTime::fromString(timeStamp()));
+ QDateTime realFileDate;
+ QFileInfo info(dir, m_fields[0]);
+ realFileDate = info.lastModified();
+
+ m_state = UpToDate;
+
+ if ( revision() == "0" )
+ m_state = Added;
+ else if ( revision().length() > 3 && revision()[0] == '-' )
+ m_state = Removed;
+ else if ( timeStamp().find('+') >= 0 )
+ m_state = Conflict;
+ else
+ {
+ QDateTime date( QDateTime::fromString( timeStamp() ) );
+ QDateTime fileDateUTC;
+ fileDateUTC.setTime_t( QFileInfo(dir, fileName()).lastModified().toTime_t(), Qt::UTC );
+ if ( date != fileDateUTC )
+ m_state = Modified;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSEntry::fileName() const
+{
+ if (type() != invalidEntry && m_fields.count() >= 1)
+ return m_fields[0];
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSEntry::revision() const
+{
+ if (type() != invalidEntry && m_fields.count() >= 2)
+ return m_fields[1];
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSEntry::timeStamp() const
+{
+ if (type() != invalidEntry && m_fields.count() >= 3)
+ return m_fields[2];
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSEntry::options() const
+{
+ if (type() != invalidEntry && m_fields.count() >= 4)
+ return m_fields[3];
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSEntry::tag() const
+{
+ if (type() != invalidEntry && m_fields.count() >= 5)
+ return m_fields[4];
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+VCSFileInfo CVSEntry::toVCSFileInfo() const
+{
+ VCSFileInfo::FileState fileState = VCSFileInfo::Unknown;
+ if (isDirectory())
+ fileState = VCSFileInfo::Directory;
+
+ switch (m_state)
+ {
+ case Added:
+ fileState = VCSFileInfo::Added;
+ break;
+ case Conflict:
+ fileState = VCSFileInfo::Conflict;
+ break;
+ case Modified:
+ case Removed:
+ fileState = VCSFileInfo::Modified;
+ break;
+ case UpToDate:
+ fileState = VCSFileInfo::Uptodate;
+ break;
+ default:
+ fileState = VCSFileInfo::Unknown;
+ break;
+ }
+
+ return VCSFileInfo( fileName(), revision(), revision(), fileState );
+}
+
+//kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/vcs/cvsservice/cvsentry.h b/vcs/cvsservice/cvsentry.h
new file mode 100644
index 00000000..1c3db926
--- /dev/null
+++ b/vcs/cvsservice/cvsentry.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * Copyright (C) 2005 by Matt Rogers <mattr@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSENTRY_H
+#define CVSENTRY_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kdevversioncontrol.h>
+
+class CVSDir;
+
+class CVSEntry
+{
+public:
+ enum EntryType { invalidEntry, fileEntry, directoryEntry };
+ enum FileState { UpToDate, Modified, Added, Conflict, Removed, Unknown };
+
+ static const QString invalidMarker;
+ static const QString directoryMarker;
+ static const QString fileMarker;
+ static const QString entrySeparator;
+
+ CVSEntry();
+ CVSEntry( const QString &aLine, const CVSDir& dir );
+
+ void clean();
+ void parse( const QString &aLine, const CVSDir& dir );
+ VCSFileInfo toVCSFileInfo() const;
+ bool isValid() const { return type() != invalidEntry; }
+ bool isDirectory() const { return type() == directoryEntry; }
+
+ EntryType type() const;
+ FileState state() const;
+ QString fileName() const;
+ QString revision() const;
+ QString timeStamp() const;
+ QString options() const;
+ QString tag() const;
+
+private:
+ EntryType m_type;
+ FileState m_state;
+ QStringList m_fields;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsfileinfoprovider.cpp b/vcs/cvsservice/cvsfileinfoprovider.cpp
new file mode 100644
index 00000000..1ac5bd76
--- /dev/null
+++ b/vcs/cvsservice/cvsfileinfoprovider.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qregexp.h>
+#include <qtimer.h>
+#include <kurl.h>
+#include <kdebug.h>
+
+#include <urlutil.h>
+#include <kdevproject.h>
+
+#include <dcopref.h>
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "cvspart.h"
+#include "cvsdir.h"
+#include "cvsentry.h"
+#include "cvsfileinfoprovider.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSFileInfoProvider
+///////////////////////////////////////////////////////////////////////////////
+
+CVSFileInfoProvider::CVSFileInfoProvider( CvsServicePart *parent, CvsService_stub *cvsService )
+ : KDevVCSFileInfoProvider( parent, "cvsfileinfoprovider" ),
+ m_requestStatusJob( 0 ), m_cvsService( cvsService ), m_cachedDirEntries( 0 )
+{
+ connect( this, SIGNAL(needStatusUpdate(const CVSDir&)), this, SLOT(updateStatusFor(const CVSDir&)));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSFileInfoProvider::~CVSFileInfoProvider()
+{
+ if (m_requestStatusJob && m_requestStatusJob->isRunning())
+ m_requestStatusJob->cancel();
+ delete m_requestStatusJob;
+ delete m_cachedDirEntries;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const VCSFileInfoMap *CVSFileInfoProvider::status( const QString &dirPath )
+{
+ // Same dir: we can do with cache ...
+ if (dirPath != m_previousDirPath)
+ {
+ // ... different dir: flush old cache and cache new dir
+ delete m_cachedDirEntries;
+ CVSDir cvsdir( projectDirectory() + QDir::separator() + dirPath );
+ m_previousDirPath = dirPath;
+ m_cachedDirEntries = cvsdir.cacheableDirStatus();
+ }
+ return m_cachedDirEntries;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CVSFileInfoProvider::requestStatus( const QString &dirPath, void *callerData, bool recursive, bool checkRepos )
+{
+ m_savedCallerData = callerData;
+ if (m_requestStatusJob)
+ {
+ delete m_requestStatusJob;
+ m_requestStatusJob = 0;
+ }
+ // Flush old cache
+ if (m_cachedDirEntries)
+ {
+ delete m_cachedDirEntries;
+ m_cachedDirEntries = 0;
+ m_previousDirPath = dirPath;
+ }
+
+
+ if (!checkRepos) {
+ kdDebug(9006) << "No repo check reqested; Just read CVS/Entries from: " << dirPath << endl;
+ QDir qd(projectDirectory()+QDir::separator()+dirPath);
+ CVSDir cdir(qd);
+ if (cdir.isValid())
+ {
+ emit needStatusUpdate(cdir);
+ return true;
+ }
+ kdDebug(9006) << dirPath << " is not a valid cvs directory" << endl;
+ return false;
+ }
+
+ // Fix a possible bug in cvs client:
+ // When "cvs status" get's called nonrecursiv for a directory, it will
+ // not print anything if the path ends with a slash. So we need to ensure
+ // this here.
+ QString newPath = dirPath;
+ if (newPath.endsWith("/"))
+ newPath.truncate( newPath.length()-1 );
+
+
+ // path, recursive, tagInfo: hmmm ... we may use tagInfo for collecting file tags ...
+ DCOPRef job = m_cvsService->status( newPath, recursive, false );
+ m_requestStatusJob = new CvsJob_stub( job.app(), job.obj() );
+
+ kdDebug(9006) << "Running command : " << m_requestStatusJob->cvsCommand() << endl;
+ connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+ return m_requestStatusJob->execute();
+ /*
+ kdDebug(9006) << k_funcinfo << "Attempting to parse " << dirPath << " using CVS/Entries" << endl;
+ QDir qd(dirPath);
+ CVSDir cdir(qd);
+ if (cdir.isValid())
+ {
+ emit needStatusUpdate(cdir);
+ return true;
+ }*/
+}
+
+void CVSFileInfoProvider::propagateUpdate()
+{
+ emit statusReady( *m_cachedDirEntries, m_savedCallerData );
+}
+
+void CVSFileInfoProvider::updateStatusFor(const CVSDir& dir)
+{
+ m_cachedDirEntries = dir.cacheableDirStatus();
+ printOutFileInfoMap( *m_cachedDirEntries );
+
+ /* FileTree will call requestStatus() everytime the user expands a directory
+ * Unfortunatly requestStatus() will be called before the
+ * VCSFileTreeViewItem of the directory will be filled with the files
+ * it contains. Meaning, m_savedCallerData contains no childs at that
+ * time. When a dcop call is made to run "cvs status" this is no problem.
+ * The dcop call takes quit long, and so FileTree has enough time the fill
+ * in the childs before we report the status back.
+ * As far as the reading of the CVS/Entries file is very fast,
+ * it will happen that we emit statusReady() here before the directory
+ * item conains any childs. Therefor we need to give FileTree some time
+ * to update the directory item before we give the status infos.
+ */
+ QTimer::singleShot( 1000, this, SLOT(propagateUpdate()) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSFileInfoProvider::slotJobExited( bool normalExit, int /*exitStatus*/ )
+{
+ kdDebug(9006) << "CVSFileInfoProvider::slotJobExited(bool,int)" << endl;
+ if (!normalExit)
+ return;
+
+// m_cachedDirEntries = parse( m_requestStatusJob->output() );
+ m_cachedDirEntries = parse( m_statusLines );
+ // Remove me when not debugging
+ printOutFileInfoMap( *m_cachedDirEntries );
+
+ emit statusReady( *m_cachedDirEntries, m_savedCallerData );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSFileInfoProvider::slotReceivedOutput( QString someOutput )
+{
+ QStringList strings = m_bufferedReader.process( someOutput );
+ if (strings.count() > 0)
+ {
+ m_statusLines += strings;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSFileInfoProvider::slotReceivedErrors( QString /*someErrors*/ )
+{
+ /* Nothing to do */
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CVSFileInfoProvider::projectDirectory() const
+{
+ return owner()->project()->projectDirectory();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+VCSFileInfoMap *CVSFileInfoProvider::parse( QStringList stringStream )
+{
+ QRegExp rx_recordStart( "^=+$" );
+ QRegExp rx_fileName( "^File: (\\.|\\-|\\w)+" );
+ QRegExp rx_fileStatus( "Status: (\\.|-|\\s|\\w)+" );
+ QRegExp rx_fileWorkRev( "\\bWorking revision:" );
+ QRegExp rx_fileRepoRev( "\\bRepository revision:" );
+ //QRegExp rx_stickyTag( "\\s+(Sticky Tag:\\W+(w+|\\(none\\)))" );
+ //QRegExp rx_stickyDate( "" ); // @todo but are they useful?? :-/
+ //QRegExp rx_stickyOptions( "" ); //@todo
+
+ QString fileName,
+ fileStatus,
+ workingRevision,
+ repositoryRevision,
+ stickyTag,
+ stickyDate,
+ stickyOptions;
+
+ VCSFileInfoMap *vcsStates = new VCSFileInfoMap;
+
+ int state = 0;
+ const int lastAcceptableState = 4;
+ // This is where the dirty parsing is done: from a string stream representing the
+ // 'cvs log' output we build a map with more useful strunctured data ;-)
+ for (QStringList::const_iterator it=stringStream.begin(); it != stringStream.end(); ++it)
+ {
+ QString s = (*it).stripWhiteSpace();
+ kdDebug(9006) << ">> Parsing: " << s << endl;
+
+ if (rx_recordStart.exactMatch( s ))
+ state = 1;
+ else if (state == 1 && rx_fileName.search( s ) >= 0 && rx_fileStatus.search( s ) >= 0) // FileName
+ {
+ fileName = rx_fileName.cap().replace( "File:", "" ).stripWhiteSpace();
+ fileStatus = rx_fileStatus.cap().replace( "Status:", "" ).stripWhiteSpace();
+ ++state; // Next state
+ kdDebug(9006) << ">> " << fileName << ", " << fileStatus << endl;
+ }
+ else if (state == 2 && rx_fileWorkRev.search( s ) >= 0)
+ {
+ workingRevision = s.replace( "Working revision:", "" ).stripWhiteSpace();
+
+ QRegExp rx_revision( "\\b(((\\d)+\\.?)*|New file!)" );
+ if (rx_revision.search( workingRevision ) >= 0)
+ {
+ workingRevision = rx_revision.cap();
+ kdDebug(9006) << ">> WorkRev: " << workingRevision << endl;
+ ++state;
+ }
+ }
+ else if (state == 3 && rx_fileRepoRev.search( s ) >= 0)
+ {
+ repositoryRevision = s.replace( "Repository revision:", "" ).stripWhiteSpace();
+
+ QRegExp rx_revision( "\\b(((\\d)+\\.?)*|No revision control file)" );
+ if (rx_revision.search( s ) >= 0)
+ {
+ repositoryRevision = rx_revision.cap();
+ kdDebug(9006) << ">> RepoRev: " << repositoryRevision << endl;
+ ++state;
+ }
+ }
+/*
+ else if (state == 4 && rx_stickyTag.search( s ) >= 0)
+ {
+ stickyTag = rx_stickyTag.cap();
+ ++state;
+ }
+*/
+ else if (state >= lastAcceptableState) // OK, parsed all useful info?
+ {
+ // Package stuff, put into map and get ready for a new record
+ VCSFileInfo vcsInfo( fileName, workingRevision, repositoryRevision,
+ String2EnumState( fileStatus ) );
+ kdDebug(9006) << "== Inserting: " << vcsInfo.toString() << endl;
+ vcsStates->insert( fileName, vcsInfo );
+ }
+ }
+ return vcsStates;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+VCSFileInfo::FileState CVSFileInfoProvider::String2EnumState( QString stateAsString )
+{
+ // @todo add more status as "Conflict" and "Sticky" (but I dunno how CVS writes it so I'm going
+ // to await until I have a conflict or somebody else fix it ;-)
+ // @todo use QRegExp for better matching since it seems strings have changed between CVS releases :-(
+ // @todo a new state for 'Needs patch'
+ if (stateAsString == "Up-to-date")
+ return VCSFileInfo::Uptodate;
+ else if (stateAsString == "Locally Modified")
+ return VCSFileInfo::Modified;
+ else if (stateAsString == "Locally Added")
+ return VCSFileInfo::Added;
+ else if (stateAsString == "Unresolved Conflict")
+ return VCSFileInfo::Conflict;
+ else if (stateAsString == "Needs Patch")
+ return VCSFileInfo::NeedsPatch;
+ else if (stateAsString == "Needs Checkout")
+ return VCSFileInfo::NeedsCheckout;
+ else
+ return VCSFileInfo::Unknown; /// \FIXME exhaust all the previous cases first ;-)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSFileInfoProvider::printOutFileInfoMap( const VCSFileInfoMap &map )
+{
+ kdDebug(9006) << "Files parsed:" << endl;
+ for (VCSFileInfoMap::const_iterator it = map.begin(); it != map.end(); ++it)
+ {
+ const VCSFileInfo &vcsInfo = *it;
+ kdDebug(9006) << vcsInfo.toString() << endl;
+ }
+}
+
+#include "cvsfileinfoprovider.moc"
+// kate: space-indent on; indent-width 4; replace-tabs on;
diff --git a/vcs/cvsservice/cvsfileinfoprovider.h b/vcs/cvsservice/cvsfileinfoprovider.h
new file mode 100644
index 00000000..2c0b5cf1
--- /dev/null
+++ b/vcs/cvsservice/cvsfileinfoprovider.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSFILEINFOPROVIDER_H
+#define CVSFILEINFOPROVIDER_H
+
+#include <qmap.h>
+
+#include <kdevversioncontrol.h>
+#include "cvsservicedcopIface.h"
+#include "cvsdir.h"
+#include "bufferedstringreader.h"
+
+class CvsServicePart;
+class CvsService_stub;
+class CvsJob_stub;
+
+/**
+Provider for CVS file information
+
+@author Mario Scalas
+*/
+class CVSFileInfoProvider : public KDevVCSFileInfoProvider, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+public:
+ CVSFileInfoProvider( CvsServicePart *parent, CvsService_stub *cvsService );
+ virtual ~CVSFileInfoProvider();
+
+// -- Sync interface
+ virtual const VCSFileInfoMap *status( const QString &dirPath ) ;
+
+// -- Async interface for requesting data
+ virtual bool requestStatus( const QString &dirPath, void *callerData, bool recursive = true, bool checkRepos = true );
+
+public slots:
+ void updateStatusFor( const CVSDir& );
+private slots:
+ void propagateUpdate();
+
+signals:
+ void needStatusUpdate(const CVSDir&);
+
+private:
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+ QString projectDirectory() const;
+
+ static VCSFileInfoMap *parse( QStringList stringStream );
+
+ static VCSFileInfo::FileState String2EnumState( QString stateAsString );
+
+ static void printOutFileInfoMap( const VCSFileInfoMap &map );
+
+ BufferedStringReader m_bufferedReader;
+ QStringList m_statusLines;
+
+ mutable void *m_savedCallerData;
+ mutable CvsJob_stub *m_requestStatusJob;
+ CvsService_stub *m_cvsService;
+
+ //! Caching
+ mutable QString m_previousDirPath;
+ mutable VCSFileInfoMap *m_cachedDirEntries;
+};
+
+#endif
+//kate: space-indent on; indent-width 4;
diff --git a/vcs/cvsservice/cvsform.cpp b/vcs/cvsservice/cvsform.cpp
new file mode 100644
index 00000000..a23a1df2
--- /dev/null
+++ b/vcs/cvsservice/cvsform.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <klineedit.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include "cvsform.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsForm
+///////////////////////////////////////////////////////////////////////////////
+
+CvsForm::CvsForm( QWidget *parent, const char *name, WFlags f )
+ : CvsFormBase( parent, name, f )
+{
+ setWFlags( getWFlags() | WDestructiveClose );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsForm::~CvsForm()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::module() const
+{
+ return module_edit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::vendor() const
+{
+ return vendor_edit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::message() const
+{
+ return message_edit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::release() const
+{
+ return release_edit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::location() const
+{
+ return serverPathEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsForm::cvsRsh() const
+{
+ return cvsRshComboBox->currentText();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsForm::mustInitRoot() const
+{
+ return init_check->isChecked();
+}
+
+#include "cvsform.moc"
diff --git a/vcs/cvsservice/cvsform.h b/vcs/cvsservice/cvsform.h
new file mode 100644
index 00000000..471e10d6
--- /dev/null
+++ b/vcs/cvsservice/cvsform.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSFORM_H
+#define CVSFORM_H
+
+#include "cvsformbase.h"
+
+/**
+An instance of this class is used by the AppWizard to collect
+information about setting up the cvs repository.
+*/
+class CvsForm : public CvsFormBase
+{
+ Q_OBJECT
+public:
+ CvsForm( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ virtual ~CvsForm();
+
+ QString module() const;
+ QString vendor() const;
+ QString message() const;
+ QString release() const;
+ QString location() const;
+ QString cvsRsh() const;
+ bool mustInitRoot() const;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsformbase.ui b/vcs/cvsservice/cvsformbase.ui
new file mode 100644
index 00000000..2a7b5c42
--- /dev/null
+++ b/vcs/cvsservice/cvsformbase.ui
@@ -0,0 +1,223 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CvsFormBase</class>
+<author>Yann Hodique</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>CvsFormBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>603</width>
+ <height>625</height>
+ </rect>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This form allows you to create a CVS repository for your new project</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>TextLabel5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>Release &amp;tag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>release_edit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>module_edit</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the name of the repository</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>CVS Repository name goes here.
+Most of the thime you'll just reuse the project name</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>vendor_edit</cstring>
+ </property>
+ <property name="text">
+ <string>vendor</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter the vendor name</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Message:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>message_edit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Module:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>module_edit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Vendor tag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>vendor_edit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>message_edit</cstring>
+ </property>
+ <property name="text">
+ <string>new project</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Repository creation message</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="5" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>release_edit</cstring>
+ </property>
+ <property name="text">
+ <string>start</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Tag that will be associated with initial state</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>&amp;Server path:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>serverPathEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>serverPathEdit</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Enter your CVS Root location</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>CVS Root location goes here, for example:&lt;ul&gt;
+&lt;li&gt;/home/cvsroot or&lt;/li&gt;&lt;li&gt;:pserver:me@localhost:/home/cvs&lt;/li&gt;&lt;/ul&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel1_2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Plain</enum>
+ </property>
+ <property name="text">
+ <string>CVS_&amp;RSH:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cvsRshComboBox</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string></string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>ssh</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cvsRshComboBox</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="3">
+ <property name="name">
+ <cstring>init_check</cstring>
+ </property>
+ <property name="text">
+ <string>Init &amp;root</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Check if you defined a new CVS Root</string>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Preferred</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>51</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>serverPathEdit</tabstop>
+ <tabstop>cvsRshComboBox</tabstop>
+ <tabstop>init_check</tabstop>
+ <tabstop>module_edit</tabstop>
+ <tabstop>vendor_edit</tabstop>
+ <tabstop>message_edit</tabstop>
+ <tabstop>release_edit</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/vcs/cvsservice/cvslogdialog.cpp b/vcs/cvsservice/cvslogdialog.cpp
new file mode 100644
index 00000000..ac6fd97c
--- /dev/null
+++ b/vcs/cvsservice/cvslogdialog.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ * Copyright (C) 200?-2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qvbox.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qstringlist.h>
+
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "cvsoptions.h"
+#include "cvslogpage.h"
+#include "cvsdiffpage.h"
+
+#include "cvslogdialog.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSLogDialog
+///////////////////////////////////////////////////////////////////////////////
+
+CVSLogDialog::CVSLogDialog( CvsService_stub *cvsService, QWidget *parent, const char *name, int )
+ : KDialogBase( Tabbed, i18n("CVS Log & Diff Dialog"), Close, Close,
+ parent, name? name : "logformdialog", false /*modal*/, true /*separator*/ ),
+ m_cvsLogPage( 0 ), m_cvsService( cvsService )
+{
+ setWFlags( getWFlags() | WDestructiveClose );
+
+ QVBox *vbox = addVBoxPage( i18n("Log From CVS") );
+ m_cvsLogPage = new CVSLogPage( m_cvsService, vbox );
+
+ connect( m_cvsLogPage, SIGNAL(diffRequested(const QString&, const QString&, const QString&)),
+ this, SLOT(slotDiffRequested(const QString&, const QString&, const QString&)) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSLogDialog::~CVSLogDialog()
+{
+ kdDebug(9006) << "CVSLogDialog::~CVSLogDialog()" << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogDialog::startLog( const QString &workDir, const QString &pathName )
+{
+ kdDebug(9006) << "CVSLogDialog::start() here! workDir = " << workDir <<
+ ", pathName = " << pathName << endl;
+
+// displayActionFeedback( true );
+/*
+ QVBox *vbox = addVBoxPage( i18n("Log From CVS: ") + pathName );
+ m_cvsLogPage = new CVSLogPage( m_cvsService, vbox );
+ this->resize( m_cvsLogPage->size() );
+
+ connect( m_cvsLogPage, SIGNAL(linkClicked(const QString&, const QString&)),
+ this, SLOT(slotDiffRequested(const QString&, const QString&)) );
+*/
+ m_cvsLogPage->startLog( workDir, pathName );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogDialog::slotDiffRequested( const QString &pathName, const QString &revA, const QString &revB )
+{
+ kdDebug(9006) << "CVSLogDialog::slotDiffRequested()" << endl;
+
+ // Create a new CVSDiffPage and start diffing process
+ QString diffTitle = i18n("Diff between %1 and %2").arg( revA ).arg( revB );
+ QVBox *vbox = addVBoxPage( diffTitle );
+ CVSDiffPage *diffPage = new CVSDiffPage( m_cvsService, vbox );
+ diffPage->startDiff( pathName, revA, revB );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogDialog::slotCancel()
+{
+ // Hmmm ...
+
+ KDialogBase::slotCancel();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogDialog::displayActionFeedback( bool working )
+{
+ if (working)
+ {
+ setCursor( KCursor::waitCursor() );
+ }
+ else
+ {
+ setCursor( KCursor::arrowCursor() );
+ }
+}
+
+#include "cvslogdialog.moc"
+
+
diff --git a/vcs/cvsservice/cvslogdialog.h b/vcs/cvsservice/cvslogdialog.h
new file mode 100644
index 00000000..12a7a2eb
--- /dev/null
+++ b/vcs/cvsservice/cvslogdialog.h
@@ -0,0 +1,50 @@
+//
+// C++ Interface: cvslogdialog
+//
+// Description:
+//
+//
+// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2003
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+//
+#ifndef CVSLOGDIALOG_H
+#define CVSLOGDIALOG_H
+
+#include <kdialogbase.h>
+
+class CvsJob_stub;
+class CvsService_stub;
+class CVSLogPage;
+
+/**
+Implementation for the form displaying 'cvs log' output.
+
+@author KDevelop Authors
+*/
+class CVSLogDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ CVSLogDialog( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 );
+ virtual ~CVSLogDialog();
+
+ void startLog( const QString &workDir, const QString &pathName );
+
+private slots:
+ void slotDiffRequested( const QString &pathName, const QString &revA, const QString &revB );
+ virtual void slotCancel();
+
+private:
+// void parseLogContent( const QString& text );
+ void displayActionFeedback( bool working );
+
+private:
+ QString m_pathName;
+
+ CVSLogPage *m_cvsLogPage;
+ CvsService_stub *m_cvsService;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvslogpage.cpp b/vcs/cvsservice/cvslogpage.cpp
new file mode 100644
index 00000000..cf8645e9
--- /dev/null
+++ b/vcs/cvsservice/cvslogpage.cpp
@@ -0,0 +1,212 @@
+/***************************************************************************
+ * Copyright (C) 200?-2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qtextbrowser.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qdir.h>
+#include <qstringlist.h>
+
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <dcopref.h>
+
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+#include "cvsoptions.h"
+#include "cvslogpage.h"
+#include "cvsdiffpage.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class CVSLogPage
+///////////////////////////////////////////////////////////////////////////////
+
+CVSLogPage::CVSLogPage( CvsService_stub *cvsService, QWidget *parent, const char *name, int )
+ : DCOPObject( "CvsLogPageDCOPIface" ),
+ QWidget( parent, name? name : "logformpage" ),
+ m_cvsService( cvsService ), m_cvsLogJob( 0 )
+{
+ QLayout *thisLayout = new QVBoxLayout( this );
+
+ m_textBrowser = new QTextBrowser( this, "logbrowser" );
+ thisLayout->add( m_textBrowser );
+
+ /// \FIXME a better way?
+ m_textBrowser->setMinimumWidth(fontMetrics().width('X')*50);
+ m_textBrowser->setMinimumHeight(fontMetrics().width('X')*43);
+
+ connect( m_textBrowser, SIGNAL(linkClicked( const QString& )), this, SLOT(slotLinkClicked( const QString& )) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CVSLogPage::~CVSLogPage()
+{
+ kdDebug(9006) << "CVSLogPage::~CVSLogPage()" << endl;
+ cancel();
+ delete m_cvsLogJob;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::startLog( const QString &workDir, const QString &pathName )
+{
+ kdDebug(9006) << "CVSLogPage::start() here! workDir = " << workDir <<
+ ", pathName = " << pathName << endl;
+
+// CvsOptions *options = CvsOptions::instance();
+ // "cvs log" needs to be done on relative-path basis
+ m_pathName = pathName;
+ m_diffStrings.clear();
+
+ DCOPRef job = m_cvsService->log( pathName );
+ m_cvsLogJob = new CvsJob_stub( job.app(), job.obj() );
+
+ // establish connections to the signals of the cvs m_job
+ connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ // We'll read the ouput directly from the job ...
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+// connectDCOPSignal( job.app(), job.obj(), "receivedStderr(QString)", "slotReceivedErrors(QString)", true );
+
+ kdDebug(9006) << "Running: " << m_cvsLogJob->cvsCommand() << endl;
+ m_cvsLogJob->execute();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+void CVSLogPage::parseLogContent( const QString& text )
+{
+ kdDebug(9006) << "CVSLogPage::parseLogContent()" << endl;
+
+ m_base->contents->clear();
+
+ QStringList l = QStringList::split( "----------------------------", text );
+ QString header = l.front();
+ l.pop_front();
+
+ for( QStringList::Iterator it=l.begin(); it!=l.end(); ++it )
+ {
+ const QString &s = *it;
+ if (s)
+ {
+ m_base->contents->append( s );
+ m_base->contents->append( "<hr>" );
+ }
+ }
+}
+*/
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::slotJobExited( bool normalExit, int exitStatus )
+{
+// m_part->core()->running( m_part, false );
+ if (!normalExit)
+ {
+ KMessageBox::sorry( this, i18n("Log failed with exitStatus == %1").arg( exitStatus), i18n("Log Failed") );
+ return;
+ }
+
+ static QRegExp rx_sep( "\\-+" );
+ static QRegExp rx_sep2( "=+" );
+ static QRegExp rx_date( "date: .* author: .* state: .* lines: .*" );
+ // "revision" followed by one or more decimals followed by a optional dot
+ static QRegExp rx_rev( "revision ((\\d+\\.?)+)" );
+ m_textBrowser->setTextFormat( QTextBrowser::PlainText );
+
+ for (size_t i=0; i<m_diffStrings.count(); ++i) {
+ QString s = m_diffStrings[i];
+ kdDebug(9006) << "Examining line: " << s << endl;
+ if ( rx_rev.exactMatch(s) )
+ {
+ QString ver = rx_rev.cap( 1 );
+ QString dstr = "<b>" + s + "</b> ";
+ int lastVer = ver.section( '.', -1 ).toInt() - 1;
+ if ( lastVer > 0 ) {
+ QString lv = ver.left( ver.findRev( "." ) + 1 ) + QString::number( lastVer );
+ dstr += " [<a href=\"diff:/" + m_pathName + "/" + lv + "_" + ver + "\">diff to " + lv + "</a>]";
+ }
+ m_textBrowser->setTextFormat( QTextBrowser::RichText );
+ m_textBrowser->append( dstr );
+ m_textBrowser->setTextFormat( QTextBrowser::PlainText );
+ }
+ else if ( rx_date.exactMatch(s) )
+ {
+ m_textBrowser->setTextFormat( QTextBrowser::RichText );
+ m_textBrowser->append( "<i>" + s + "</i>" );
+ m_textBrowser->setTextFormat( QTextBrowser::PlainText );
+ }
+ else if ( rx_sep.exactMatch(s) || rx_sep2.exactMatch(s) )
+ {
+ m_textBrowser->append( "\n" );
+ m_textBrowser->setTextFormat( QTextBrowser::RichText );
+ m_textBrowser->append( "<hr>" );
+ m_textBrowser->setTextFormat( QTextBrowser::PlainText );
+ } else
+ {
+ m_textBrowser->append( s );
+ }
+ }
+ m_logTextBackup = m_textBrowser->source();
+
+// emit jobFinished( normalExit, exitStatus );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::slotLinkClicked( const QString &link )
+{
+ kdDebug(9006) << "CVSLogPage::slotLinkClicked()" << endl;
+
+ // The text browser clears the page so we go back to our old one
+ /// \FIXME in this way I lose the source
+ m_textBrowser->setSource( m_logTextBackup );
+
+ QString ver = link.mid( link.findRev( "/" ) + 1 );
+ QString v1 = ver.section( '_', 0, 0 );
+ QString v2 = ver.section( '_', 1, 1 );
+ if ( v1.isEmpty() || v2.isEmpty() )
+ {
+ m_textBrowser->append( i18n( "invalid link clicked" ) );
+ return;
+ }
+
+ emit diffRequested( m_pathName, v1, v2 );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::slotReceivedOutput( QString someOutput )
+{
+ kdDebug(9006) << "CVSLogPage::slotReceivedOutput(QString)" << endl;
+
+ kdDebug(9006) << "OUTPUT: " << someOutput << endl;
+ m_diffStrings += m_outputBuffer.process(someOutput);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::slotReceivedErrors( QString someErrors )
+{
+ kdDebug(9006) << "ERRORS: " << someErrors << endl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CVSLogPage::cancel()
+{
+ if (m_cvsLogJob && m_cvsLogJob->isRunning())
+ m_cvsLogJob->cancel();
+}
+
+#include "cvslogpage.moc"
diff --git a/vcs/cvsservice/cvslogpage.h b/vcs/cvsservice/cvslogpage.h
new file mode 100644
index 00000000..a3480e91
--- /dev/null
+++ b/vcs/cvsservice/cvslogpage.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * Copyright (C) 200?-2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSLOGPAGE_H
+#define CVSLOGPAGE_H
+
+#include "cvsservicedcopIface.h"
+#include <qwidget.h>
+#include "bufferedstringreader.h"
+
+class CvsJob_stub;
+class CvsService_stub;
+class QTextBrowser;
+
+/**
+Implementation for the form displaying 'cvs log' output.
+
+@author KDevelop Authors
+*/
+class CVSLogPage : public QWidget, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+public:
+ CVSLogPage( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 );
+ virtual ~CVSLogPage();
+
+ void startLog( const QString &workDir, const QString &pathName );
+ void cancel();
+
+signals:
+ // Emitted when the user click upon a link
+ void diffRequested( const QString &pathName, const QString &revA, const QString &revB );
+
+private slots:
+ void slotLinkClicked( const QString &link );
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+//private:
+// void parseLogContent( const QString& text );
+
+private:
+ QString m_pathName;
+ QTextBrowser *m_textBrowser;
+ QString m_logTextBackup;
+ BufferedStringReader m_outputBuffer;
+ QStringList m_diffStrings;
+
+ CvsService_stub *m_cvsService;
+ CvsJob_stub *m_cvsLogJob;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsoptions.cpp b/vcs/cvsservice/cvsoptions.cpp
new file mode 100644
index 00000000..448f4761
--- /dev/null
+++ b/vcs/cvsservice/cvsoptions.cpp
@@ -0,0 +1,288 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include "domutil.h"
+#include "kdevproject.h"
+#include "cvsoptions.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Macros
+///////////////////////////////////////////////////////////////////////////////
+
+#define default_revert QString::fromLatin1("-C")
+#define default_diff QString::fromLatin1("-p")
+#define default_rsh QString::fromLatin1("")
+#define default_contextLines 3
+#define default_compression 0
+
+///////////////////////////////////////////////////////////////////////////////
+// static members
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptions *CvsOptions::m_instance = 0;
+QString CvsOptions::invalidLocation( "ERROR-LOCATION-IS-NOT-SET-IN-PROJECT" );
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsOptions
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptions::CvsOptions()
+ : m_recursiveWhenCommitRemove( true ),
+ m_pruneEmptyDirsWhenUpdate( true ),
+ m_recursiveWhenUpdate( true ),
+ m_createDirsWhenUpdate( true ),
+ m_revertOptions( default_revert ),
+ m_diffOptions( default_diff ),
+ m_cvsRshEnvVar( default_rsh ),
+ m_compressionLevel( default_compression ),
+ m_contextLines( default_contextLines )
+{
+ kdDebug( 9006 ) << " **** CvsOptions instance CREATED!" << endl;
+ // We share some configuration data with cvsservice
+ m_serviceConfig = new KConfig( "cvsservicerc" );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptions::~CvsOptions()
+{
+ kdDebug( 9006 ) << " **** CvsOptions instance DESTROYED!" << endl;
+ delete m_serviceConfig;
+
+ m_instance = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptions* CvsOptions::instance()
+{
+ if (!m_instance)
+ {
+ m_instance = new CvsOptions();
+ }
+ return m_instance;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::save( KDevProject *project )
+{
+ kdDebug( 9006 ) << " **** CvsOptions::save( KDevProject* ) here" << endl;
+ Q_ASSERT( project );
+
+ QDomDocument &dom = *project->projectDom();
+
+ DomUtil::writeBoolEntry( dom, "/kdevcvsservice/recursivewhenupdate", recursiveWhenUpdate() );
+ DomUtil::writeBoolEntry( dom, "/kdevcvsservice/prunedirswhenupdate", pruneEmptyDirsWhenUpdate() );
+ DomUtil::writeBoolEntry( dom, "/kdevcvsservice/createdirswhenupdate", createDirsWhenUpdate() );
+ DomUtil::writeBoolEntry( dom, "/kdevcvsservice/recursivewhencommitremove", recursiveWhenCommitRemove() );
+ DomUtil::writeEntry( dom, "/kdevcvsservice/revertoptions", revertOptions() );
+// DomUtil::writeEntry( dom, "/kdevcvsservice/location", location() );
+
+ // [Repository-:ext:anonymous@cvs.ogre.sourceforge.net:/cvsroot/ogrenew]
+ QString groupName = "Repository-" + guessLocation( project->projectDirectory() );
+ m_serviceConfig->setGroup( groupName );
+
+ m_serviceConfig->writeEntry( "ContextLines", contextLines() );
+ m_serviceConfig->writeEntry( "DiffOptions", diffOptions() );
+ m_serviceConfig->writeEntry( "rsh", cvsRshEnvVar() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::load( KDevProject *project )
+{
+ kdDebug( 9006 ) << " **** CvsOptions::load( KDevProject* ) here" << endl;
+ Q_ASSERT( project );
+ QDomDocument &dom = *project->projectDom();
+
+ m_recursiveWhenUpdate = DomUtil::readBoolEntry( dom, "/kdevcvsservice/recursivewhenupdate", true );
+ m_pruneEmptyDirsWhenUpdate = DomUtil::readBoolEntry( dom, "/kdevcvsservice/prunedirswhenupdate", true );
+ m_createDirsWhenUpdate = DomUtil::readBoolEntry( dom, "/kdevcvsservice/createdirswhenupdate", true );
+ m_recursiveWhenCommitRemove = DomUtil::readBoolEntry( dom, "/kdevcvsservice/recursivewhencommitremove", true );
+ m_revertOptions = DomUtil::readEntry( dom, "/kdevcvsservice/revertoptions", default_revert );
+// m_location = DomUtil::readEntry( dom, "/kdevcvsservice/location", guessLocation( project->projectDirectory() ) );
+
+ QString groupName = "Repository-" + guessLocation( project->projectDirectory() );
+ m_serviceConfig->setGroup( groupName );
+
+ m_contextLines = m_serviceConfig->readUnsignedNumEntry( "ContextLines", default_contextLines );
+ m_diffOptions = m_serviceConfig->readEntry( "DiffOptions", default_diff );
+ m_cvsRshEnvVar = m_serviceConfig->readEntry( "rsh", default_rsh );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setRecursiveWhenCommitRemove( bool b )
+{
+ this->m_recursiveWhenCommitRemove = b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptions::recursiveWhenCommitRemove() const
+{
+ return this->m_recursiveWhenCommitRemove;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setPruneEmptyDirsWhenUpdate( bool b )
+{
+ this->m_pruneEmptyDirsWhenUpdate = b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptions::pruneEmptyDirsWhenUpdate() const
+{
+ return this->m_pruneEmptyDirsWhenUpdate;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setRecursiveWhenUpdate( bool b )
+{
+ this->m_recursiveWhenUpdate = b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptions::recursiveWhenUpdate() const
+{
+ return this->m_recursiveWhenUpdate;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setCreateDirsWhenUpdate( bool b )
+{
+ this->m_createDirsWhenUpdate = b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptions::createDirsWhenUpdate() const
+{
+ return this->m_createDirsWhenUpdate;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setRevertOptions( const QString &p )
+{
+ this->m_revertOptions = p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptions::revertOptions()
+{
+ return this->m_revertOptions;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setDiffOptions( const QString &p )
+{
+ this->m_diffOptions = p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptions::diffOptions()
+{
+ return this->m_diffOptions;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setCvsRshEnvVar( const QString &p )
+{
+ this->m_cvsRshEnvVar = p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptions::cvsRshEnvVar()
+{
+ return this->m_cvsRshEnvVar;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptions::location()
+{
+ return m_location;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setLocation( const QString &p )
+{
+ m_location = p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setContextLines( unsigned int contextLines )
+{
+ m_contextLines = contextLines;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned int CvsOptions::contextLines() const
+{
+ return m_contextLines;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptions::setCompressionLevel( unsigned int compressionLevel )
+{
+ m_compressionLevel = compressionLevel;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned int CvsOptions::compressionLevel() const
+{
+ return m_compressionLevel;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptions::guessLocation( const QString &projectDir ) const
+{
+ QString rootFileName( projectDir + "/CVS/Root" );
+
+ QFile f( rootFileName );
+ if (f.open( IO_ReadOnly ))
+ {
+ QTextStream t( &f );
+ QString serverLocation = t.readLine();
+ kdDebug(9000) << "===> Server location guessed: " << serverLocation << endl;
+ return serverLocation;
+ }
+ else
+ {
+ kdDebug(9000) << "===> Error: could not open CVS/Entries!! " << endl;
+ return i18n( "Error while guessing repository location." );
+ }
+}
diff --git a/vcs/cvsservice/cvsoptions.h b/vcs/cvsservice/cvsoptions.h
new file mode 100644
index 00000000..222a34c7
--- /dev/null
+++ b/vcs/cvsservice/cvsoptions.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSOPTIONS_H
+#define CVSOPTIONS_H
+
+#include <qstring.h>
+#include <qdom.h>
+
+class CvsServicePart;
+class KConfig;
+class KDevProject;
+
+/* This class represents the command line options for the used cvs commands.
+ * It uses the singleton pattern.
+ * @author Mario Scalas <mario.scalas@libero.it>
+*/
+class CvsOptions
+{
+public:
+ static CvsOptions *instance();
+
+ static QString invalidLocation;
+
+ virtual ~CvsOptions();
+
+ void save( KDevProject *project );
+ /// \FIXME parameter should be const!!
+ void load( KDevProject *project );
+
+ void setRecursiveWhenCommitRemove( bool b );
+ bool recursiveWhenCommitRemove() const;
+
+ void setPruneEmptyDirsWhenUpdate( bool b );
+ bool pruneEmptyDirsWhenUpdate() const;
+
+ void setRecursiveWhenUpdate( bool b );
+ bool recursiveWhenUpdate() const;
+
+ void setCreateDirsWhenUpdate( bool b );
+ bool createDirsWhenUpdate() const;
+
+ void setDiffOptions( const QString &p );
+ QString diffOptions();
+
+ void setRevertOptions( const QString &p );
+ QString revertOptions();
+
+ void setCvsRshEnvVar( const QString &p );
+ QString cvsRshEnvVar();
+
+ /**
+ * Will try to determine location by using CVS/Root file
+ */
+ QString guessLocation( const QString &projectDir ) const;
+
+ /**
+ * Set server path string (this should be called by the part when a new project
+ * is created or imported)
+ * @param p (i.e. :pserver:marios@cvs.kde.org:/home/kde)
+ */
+ void setLocation( const QString &p );
+ /**
+ * @result remote path (i.e. :pserver:marios@cvs.kde.org:/home/kde)
+ */
+ QString location();
+
+ void setContextLines( unsigned int contextLines );
+ unsigned int contextLines() const;
+
+ void setCompressionLevel( unsigned int compressionLevel = 0 );
+ unsigned int compressionLevel() const;
+
+private:
+ // Cache
+ bool m_recursiveWhenCommitRemove;
+ bool m_pruneEmptyDirsWhenUpdate;
+ bool m_recursiveWhenUpdate;
+ bool m_createDirsWhenUpdate;
+ QString m_revertOptions;
+ QString m_diffOptions;
+ QString m_cvsRshEnvVar;
+ QString m_location;
+ unsigned int m_compressionLevel;
+ unsigned int m_contextLines;
+ //! So we can access cvssservice configuration (repositories first of all)
+ KConfig *m_serviceConfig;
+
+ static CvsOptions *m_instance;
+ CvsOptions();
+};
+
+#endif // CVSOPTIONS_H
+
diff --git a/vcs/cvsservice/cvsoptionswidget.cpp b/vcs/cvsservice/cvsoptionswidget.cpp
new file mode 100644
index 00000000..aa7a98c1
--- /dev/null
+++ b/vcs/cvsservice/cvsoptionswidget.cpp
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * kdevelop-devel@kde.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qcheckbox.h>
+#include <klineedit.h>
+#include <knuminput.h>
+#include <kdialog.h>
+
+#include "domutil.h"
+#include "cvsoptions.h"
+#include "cvsoptionswidget.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class DiffDialog
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptionsWidget::CvsOptionsWidget( QWidget *parent, const char *name )
+ : CvsOptionsWidgetBase( parent, name )
+{
+ readConfig();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsOptionsWidget::~CvsOptionsWidget()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::readConfig()
+{
+ CvsOptions *options = CvsOptions::instance();
+
+ this->setCvsRshEnvVar( options->cvsRshEnvVar() );
+ this->setServerLocation( options->location() );
+ this->setPruneEmptyDirWhenUpdating( options->pruneEmptyDirsWhenUpdate() );
+ this->setCreateNewDirWhenUpdating( options->createDirsWhenUpdate() );
+ this->setRecursiveWhenUpdating( options->recursiveWhenUpdate() );
+ this->setRecursiveWhenCommittingRemoving( options->recursiveWhenCommitRemove() );
+ this->setDiffOptions( options->diffOptions() );
+ this->setContextLines( options->contextLines() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::storeConfig()
+{
+ CvsOptions *options = CvsOptions::instance();
+
+ options->setCvsRshEnvVar( this->cvsRshEnvVar().stripWhiteSpace() );
+ options->setLocation( this->serverLocation().stripWhiteSpace() );
+ options->setPruneEmptyDirsWhenUpdate( this->pruneEmptyDirWhenUpdating() );
+ options->setCreateDirsWhenUpdate( this->createNewDirWhenUpdating() );
+ options->setRecursiveWhenUpdate( this->recursiveWhenUpdating() );
+ options->setRecursiveWhenCommitRemove( this->recursiveWhenCommittingRemoving() );
+ options->setDiffOptions( this->diffOptions().stripWhiteSpace() );
+ options->setContextLines( this->contextLines() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::accept() {
+ storeConfig();
+// emit configChange();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setPruneEmptyDirWhenUpdating( bool b )
+{
+ this->pruneEmptyDirWhenUpdateCheck->setChecked( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setCreateNewDirWhenUpdating( bool b )
+{
+ this->createNewDirWhenUpdateCheck->setChecked( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setRecursiveWhenUpdating( bool b )
+{
+ this->recursiveWhenUpdateCheck->setChecked( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setRecursiveWhenCommittingRemoving( bool b )
+{
+ this->recursiveWhenCommitRemoveCheck->setChecked( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setContextLines( unsigned int p )
+{
+ this->contextLinesInput->setValue( p );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setDiffOptions( const QString &p )
+{
+ this->diffOptionsEdit->setText( p );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptionsWidget::diffOptions() const
+{
+ return this->diffOptionsEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setCvsRshEnvVar( const QString &p )
+{
+ this->cvsRshEnvVarEdit->setText( p );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsOptionsWidget::setServerLocation( const QString &p )
+{
+ this->serverLocationEdit->setText( p );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptionsWidget::pruneEmptyDirWhenUpdating() const
+{
+ return pruneEmptyDirWhenUpdateCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptionsWidget::createNewDirWhenUpdating() const
+{
+ return createNewDirWhenUpdateCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptionsWidget::recursiveWhenUpdating() const
+{
+ return recursiveWhenUpdateCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsOptionsWidget::recursiveWhenCommittingRemoving() const
+{
+ return recursiveWhenCommitRemoveCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+unsigned int CvsOptionsWidget::contextLines() const
+{
+ return contextLinesInput->value();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptionsWidget::cvsRshEnvVar() const
+{
+ return cvsRshEnvVarEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsOptionsWidget::serverLocation() const
+{
+ return serverLocationEdit->text();
+}
+
+#include "cvsoptionswidget.moc"
diff --git a/vcs/cvsservice/cvsoptionswidget.h b/vcs/cvsservice/cvsoptionswidget.h
new file mode 100644
index 00000000..5df98d76
--- /dev/null
+++ b/vcs/cvsservice/cvsoptionswidget.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * kdevelop-devel@kde.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _CVSOPTIONSWIDGET_H_
+#define _CVSOPTIONSWIDGET_H_
+
+#include <qwidget.h>
+#include "cvsoptionswidgetbase.h"
+
+class QLabel;
+class QVBoxLayout;
+
+class CvsOptionsWidget : public CvsOptionsWidgetBase
+{
+ Q_OBJECT
+public:
+ CvsOptionsWidget( QWidget *parent, const char *name=0 );
+ virtual ~CvsOptionsWidget();
+
+ bool pruneEmptyDirWhenUpdating() const;
+ void setPruneEmptyDirWhenUpdating( bool b );
+
+ bool createNewDirWhenUpdating() const;
+ void setCreateNewDirWhenUpdating( bool b );
+
+ bool recursiveWhenUpdating() const;
+ void setRecursiveWhenUpdating( bool b );
+
+ bool recursiveWhenCommittingRemoving() const;
+ void setRecursiveWhenCommittingRemoving( bool b );
+
+ unsigned int contextLines() const;
+ void setContextLines( unsigned int p );
+
+ QString diffOptions() const;
+ void setDiffOptions( const QString &p );
+
+ QString cvsRshEnvVar() const;
+ void setCvsRshEnvVar( const QString &p );
+
+ QString serverLocation() const;
+ void setServerLocation( const QString &p );
+
+public slots:
+ void accept();
+
+private:
+ void readConfig();
+ void storeConfig();
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsoptionswidgetbase.ui b/vcs/cvsservice/cvsoptionswidgetbase.ui
new file mode 100644
index 00000000..4938ea4a
--- /dev/null
+++ b/vcs/cvsservice/cvsoptionswidgetbase.ui
@@ -0,0 +1,230 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>CvsOptionsWidgetBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>cvsOptionsWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>500</width>
+ <height>507</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>CVS Options</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox4</cstring>
+ </property>
+ <property name="title">
+ <string>Common Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>m_rshLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Remote shell (CVS_RSH environment variable):</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>cvsRshEnvVarEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>cvsRshEnvVarEdit</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>sets the CVS_RSH variable</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Set this option to "ssh" to use ssh as remote shell for CVS. Note that you need password-less login (see the ssh documentation for how to generate a public/private key pair) otherwise CVS will just hang forever.</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>CVS server &amp;location:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>serverLocationEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>serverLocationEdit</cstring>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>When Updating</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>createNewDirWhenUpdateCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Create &amp;new directories (if any)</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>pruneEmptyDirWhenUpdateCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Prune empty directories</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>recursiveWhenUpdateCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Update subdirectories too</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>When Committing/Removing</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>recursiveWhenCommitRemoveCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Be recursive</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>When Creating Diffs</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="1" column="0">
+ <property name="name">
+ <cstring>diffOptionsEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_diffLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Use these e&amp;xtra options:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>diffOptionsEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="1">
+ <property name="name">
+ <cstring>contextLinesInput</cstring>
+ </property>
+ <property name="value">
+ <number>3</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Con&amp;text lines:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>contextLinesInput</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/cvsservice/cvspart.cpp b/vcs/cvsservice/cvspart.cpp
new file mode 100644
index 00000000..9d885056
--- /dev/null
+++ b/vcs/cvsservice/cvspart.cpp
@@ -0,0 +1,780 @@
+/**************************************************************************
+ * Copyright (C) 1999-2001 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include "cvspart.h"
+
+#include <qdir.h>
+#include <qpopupmenu.h>
+#include <qwhatsthis.h>
+#include <qtimer.h>
+
+#include <kpopupmenu.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialogbase.h>
+#include <kstandarddirs.h>
+#include <kaction.h>
+#include <kurl.h>
+#include <kapplication.h>
+#include <kmainwindow.h>
+// Because of KShellProcess::quote()
+#include <kprocess.h>
+#include <kiconloader.h>
+
+#include <dcopref.h>
+#include <repository_stub.h>
+#include <cvsservice_stub.h>
+#include <cvsjob_stub.h>
+
+#include <kparts/part.h>
+#include <kdevpartcontroller.h>
+#include <kdevgenericfactory.h>
+
+#include "kdevcore.h"
+#include "kdevmakefrontend.h"
+#include "kdevdifffrontend.h"
+#include "kdevappfrontend.h"
+#include "kdevplugininfo.h"
+#include "domutil.h"
+#include "kdevmainwindow.h"
+#include "kdevproject.h"
+#include "urlutil.h"
+
+#include "cvsform.h"
+#include "commitdlg.h"
+#include "checkoutdialog.h"
+#include "tagdialog.h"
+#include "cvsprocesswidget.h"
+#include "cvsoptions.h"
+#include "cvsoptionswidget.h"
+#include "cvspartimpl.h"
+#include "cvsdir.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Global vars
+///////////////////////////////////////////////////////////////////////////////
+
+// See createNewProject( const QString &) and slotProjectOpened()
+bool g_projectWasJustCreated = false;
+
+///////////////////////////////////////////////////////////////////////////////
+// Plugin factory
+///////////////////////////////////////////////////////////////////////////////
+
+static const KDevPluginInfo data("kdevcvsservice");
+typedef KDevGenericFactory<CvsServicePart> CvsFactory;
+K_EXPORT_COMPONENT_FACTORY( libkdevcvsservice, CvsFactory( data ) )
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsServicePart
+///////////////////////////////////////////////////////////////////////////////
+
+CvsServicePart::CvsServicePart( QObject *parent, const char *name, const QStringList & )
+ : KDevVersionControl( &data, parent,
+ name ? name : "CvsService" ),
+ actionCommit( 0 ), actionDiff( 0 ), actionLog( 0 ), actionAnnotate(0), actionAdd( 0 ),
+ actionAddBinary( 0 ), actionRemove( 0 ), actionUpdate( 0 ),
+ actionRemoveSticky( 0 ), actionEdit( 0 ), actionEditors(0), actionUnEdit(0),
+ actionAddToIgnoreList( 0 ), actionRemoveFromIgnoreList( 0 ),
+ actionTag( 0 ), actionUnTag( 0 ),
+ actionLogin( 0), actionLogout( 0 ),
+ m_impl( 0 )
+{
+ setInstance( CvsFactory::instance() );
+
+ m_impl = new CvsServicePartImpl( this );
+
+ // Load / store project configuration every time project is opened/closed
+ connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) );
+ connect( core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) );
+
+ QTimer::singleShot(0, this, SLOT(init()));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsServicePart::~CvsServicePart()
+{
+ delete m_cvsConfigurationForm;
+ delete m_impl;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::init()
+{
+ if ( !m_impl->m_widget ) return;
+
+ setupActions();
+
+ // Re-route our implementation signal for when check-out finishes to the standard signal
+ connect( m_impl, SIGNAL(checkoutFinished(QString)), SIGNAL(finishedFetching(QString)) );
+
+ // Context menu
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+ connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
+ this, SLOT(projectConfigWidget(KDialogBase*)) );
+ connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)),
+ this, SLOT(slotStopButtonClicked(KDevPlugin*)) );
+
+ m_impl->m_widget->setIcon( UserIcon( "kdev_cvs", KIcon::DefaultState, CvsFactory::instance()) );
+ QWhatsThis::add( m_impl->processWidget(), i18n("<b>CVS</b><p>Concurrent Versions System operations window. Shows output of Cervisia CVS Service.") );
+ m_impl->processWidget()->setCaption(i18n("CvsService Output"));
+ mainWindow()->embedOutputView( m_impl->processWidget(), i18n("CvsService"), i18n("cvs output") );
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::setupActions()
+{
+ // This actions are used in the menubar: for context menu we build the
+ // context at runtime. See CvsServicePart::contextMenu().
+
+ actionCommit = new KAction( i18n("&Commit to Repository"), 0, this,
+ SLOT(slotActionCommit()), actionCollection(), "cvsservice_commit" );
+ actionCommit->setToolTip( i18n("Commit file(s)") );
+ actionCommit->setWhatsThis( i18n("<b>Commit file(s)</b><p>Commits file to repository if modified.") );
+
+ actionDiff = new KAction( i18n("&Difference Between Revisions"), 0, this, SLOT(slotActionDiff()),
+ actionCollection(), "cvsservice_diff" );
+ actionDiff->setToolTip( i18n("Build difference") );
+ actionDiff->setWhatsThis( i18n("<b>Build difference</b><p>Builds difference between releases.") );
+
+ actionLog = new KAction( i18n("Generate &Log"), 0, this, SLOT(slotActionLog()),
+ actionCollection(), "cvsservice_log" );
+ actionLog->setToolTip( i18n("Generate log") );
+ actionLog->setWhatsThis( i18n("<b>Generate log</b><p>Produces log for this file.") );
+
+ actionAnnotate = new KAction( i18n("&Annotate"), 0, this, SLOT(slotActionAnnotate()),
+ actionCollection(), "cvsservice_annotate" );
+ actionAnnotate->setToolTip( i18n("Generate annotations") );
+ actionAnnotate->setWhatsThis( i18n("<b>Annotate</b><p>Produces annotations for this file.") );
+
+ actionAdd = new KAction( i18n("&Add to Repository"), 0, this, SLOT(slotActionAdd()),
+ actionCollection(), "cvsservice_add" );
+ actionAdd->setToolTip( i18n("Add file to repository") );
+ actionAdd->setWhatsThis( i18n("<b>Add to repository</b><p>Adds file to repository.") );
+
+ actionEdit = new KAction( i18n("&Edit Files"), 0, this, SLOT(slotActionEdit()),
+ actionCollection(), "cvsservice_edit" );
+ actionEdit->setToolTip( i18n("Mark as being edited") );
+ actionEdit->setWhatsThis( i18n("<b>Mark as being edited</b><p>Mark the files as being edited.") );
+
+ actionUnEdit = new KAction( i18n("&Unedit Files"), 0, this, SLOT(slotActionUnEdit()),
+ actionCollection(), "cvsservice_unedit" );
+ actionUnEdit->setToolTip( i18n("Remove editing mark from files") );
+ actionUnEdit->setWhatsThis( i18n("<b>Remove editing mark</b><p>Remove the editing mark from the files.") );
+
+ actionEditors = new KAction( i18n("&Show Editors"), 0, this, SLOT(slotActionEditors()),
+ actionCollection(), "cvsservice_editors" );
+ actionEditors->setToolTip( i18n("Show editors") );
+ actionEditors->setWhatsThis( i18n("<b>Show editors</b><p>Shows the list of users who are editing files.") );
+
+ actionAddBinary = new KAction( i18n("Add to Repository as &Binary"), 0, this,
+ SLOT(slotActionAddBinary()), actionCollection(), "cvsservice_add_bin" );
+ actionAddBinary->setToolTip( i18n("Add file to repository as binary") );
+ actionAddBinary->setWhatsThis( i18n("<b>Add to repository as binary</b><p>Adds file to repository as binary (-kb option).") );
+
+ actionRemove = new KAction( i18n("&Remove From Repository"), 0, this,
+ SLOT(slotActionRemove()), actionCollection(), "cvsservice_remove" );
+ actionRemove->setToolTip( i18n("Remove from repository") );
+ actionRemove->setWhatsThis( i18n("<b>Remove from repository</b><p>Removes file(s) from repository.") );
+
+ actionUpdate = new KAction( i18n("&Update/Revert to Another Release"), 0, this,
+ SLOT(slotActionUpdate()), actionCollection(), "cvsservice_update" );
+ actionUpdate->setToolTip( i18n("Update/revert") );
+ actionUpdate->setWhatsThis( i18n("<b>Update/revert to another release</b><p>Updates/reverts file(s) to another release.") );
+
+ actionRemoveSticky = new KAction( i18n("R&emove Sticky Flag"), 0,
+ this, SLOT(slotActionRemoveSticky()), actionCollection(), "cvsservice_removesticky" );
+ actionRemoveSticky->setToolTip( i18n("Remove sticky flag") );
+ actionRemoveSticky->setWhatsThis( i18n("<b>Remove sticky flag</b><p>Removes sticky flag from file(s).") );
+
+ actionTag = new KAction( i18n("Make &Tag/Branch"), 0,
+ this, SLOT(slotActionTag()), actionCollection(), "cvsservice_tag" );
+ actionTag->setToolTip( i18n("Make tag/branch") );
+ actionTag->setWhatsThis( i18n("<b>Make tag/branch</b><p>Tags/branches selected file(s).") );
+
+ actionUnTag = new KAction( i18n("&Delete Tag"), 0,
+ this, SLOT(slotActionUnTag()), actionCollection(), "cvsservice_untag" );
+ actionUnTag->setToolTip( i18n("Delete tag") );
+ actionUnTag->setWhatsThis( i18n("<b>Delete tag</b><p>Delete tag from selected file(s).") );
+
+ actionAddToIgnoreList = new KAction( i18n("&Ignore in CVS Operations"), 0,
+ this, SLOT(slotActionAddToIgnoreList()), actionCollection(), "cvsservice_ignore" );
+ actionAddToIgnoreList->setToolTip( i18n("Ignore in CVS operations") );
+ actionAddToIgnoreList->setWhatsThis( i18n("<b>Ignore in CVS operations</b><p>Ignore file(s) by adding it to .cvsignore file.") );
+
+ actionRemoveFromIgnoreList = new KAction( i18n("Do &Not Ignore in CVS Operations"), 0,
+ this, SLOT(slotActionRemoveFromIgnoreList()), actionCollection(), "cvsservice_donot_ignore" );
+ actionRemoveFromIgnoreList->setToolTip( i18n("Do not ignore in CVS operations") );
+ actionRemoveFromIgnoreList->setWhatsThis( i18n("<b>Do not ignore in CVS operations</b><p>Do not ignore file(s) by removing\nit from .cvsignore file.") );
+
+ actionLogin = new KAction( i18n("&Log to Server"), 0, this,
+ SLOT(slotActionLogin()), actionCollection(), "cvsservice_login" );
+ actionLogin->setToolTip( i18n("Login to server") );
+ actionLogin->setWhatsThis( i18n("<b>Login to server</b><p>Logs in to the CVS server.") );
+
+ actionLogout = new KAction( i18n("L&ogout From Server"), 0, this,
+ SLOT(slotActionLogout()), actionCollection(), "cvsservice_logout" );
+ actionLogout->setToolTip( i18n("Logout from server") );
+ actionLogout->setWhatsThis( i18n("<b>Logout from server</b><p>Logs out from the CVS server.") );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePart::fetchFromRepository()
+{
+ return m_impl->checkout();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KDevVCSFileInfoProvider *CvsServicePart::fileInfoProvider() const
+{
+ return m_impl->fileInfoProvider();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::createNewProject( const QString &dirName )
+{
+ kdDebug( 9006 ) << "====> CvsServicePart::createNewProject( const QString& )" << endl;
+
+ if (!m_cvsConfigurationForm)
+ return;
+
+ /// \FIXME actually there is no way to inform that a _new_ ("just created")
+ // project has been opened because projectOpened() is emitted after the project
+ // has been created :-/ So the only way to inform that slotProjectOpened() to not
+ // load default settings (overriding the CvsOptions instance is to set this flag
+ // here ...
+ g_projectWasJustCreated = true;
+
+ m_impl->createNewProject( dirName,
+ m_cvsConfigurationForm->cvsRsh(), m_cvsConfigurationForm->location(),
+ m_cvsConfigurationForm->message(), m_cvsConfigurationForm->module(),
+ m_cvsConfigurationForm->vendor(), m_cvsConfigurationForm->release(),
+ m_cvsConfigurationForm->mustInitRoot()
+ );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::projectConfigWidget( KDialogBase *dlg )
+{
+ QVBox *vbox = dlg->addVBoxPage( i18n("CvsService"), i18n("CvsService"), BarIcon( info()->icon(), KIcon::SizeMedium) );
+ CvsOptionsWidget *w = new CvsOptionsWidget( (QWidget *)vbox, "cvs config widget" );
+ connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QWidget* CvsServicePart::newProjectWidget( QWidget *parent )
+{
+ m_cvsConfigurationForm = new CvsForm( parent, "cvsform" );
+ return m_cvsConfigurationForm;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::contextMenu( QPopupMenu *popup, const Context *context )
+{
+ kdDebug(9006) << "contextMenu()" << endl;
+ if (context->hasType( Context::FileContext ) ||
+ context->hasType( Context::EditorContext ))
+ {
+
+ if (context->hasType( Context::FileContext ))
+ {
+ kdDebug(9006) << "Requested for a FileContext" << endl;
+ const FileContext *fcontext = static_cast<const FileContext*>( context );
+ m_urls = fcontext->urls();
+ }
+ else
+ {
+ kdDebug(9006) << "Requested for an EditorContext" << endl;
+ const EditorContext *editorContext = static_cast<const EditorContext*>( context );
+// m_urls << editorContext->url(); // this can't be right?
+ m_urls = editorContext->url();
+ }
+ // THis stuff should end up into prepareOperation()
+ URLUtil::dump( m_urls );
+ if (m_urls.count() <= 0)
+ return;
+
+ KPopupMenu *subMenu = new KPopupMenu( popup );
+ if (context->hasType( Context::FileContext ))
+ popup->insertSeparator();
+
+ int id = subMenu->insertItem( actionCommit->text(), this, SLOT(slotCommit()) );
+ subMenu->setWhatsThis(id, i18n("<b>Commit file(s)</b><p>Commits file to repository if modified."));
+ // CvsService let to do log and diff operations only on one file (or directory) at time
+ if (m_urls.count() == 1)
+ {
+ id = subMenu->insertItem( actionDiff->text(), this, SLOT(slotDiff()) );
+ subMenu->setWhatsThis(id, i18n("<b>Build difference</b><p>Builds difference between releases."));
+ id = subMenu->insertItem( actionLog->text(), this, SLOT(slotLog()) );
+ subMenu->setWhatsThis(id, i18n("<b>Generate log</b><p>Produces log for this file."));
+ id = subMenu->insertItem( actionAnnotate->text(), this, SLOT(slotAnnotate()) );
+ subMenu->setWhatsThis(id, i18n("<b>Generate Annotate</b><p>Produces annotation output for this file."));
+ }
+ id = subMenu->insertItem( actionEditors->text(), this, SLOT(slotEditors()) );
+ subMenu->setWhatsThis(id, i18n("<b>Show editors</b><p>Shows the list of users who are editing files."));
+ id = subMenu->insertItem( actionEdit->text(), this, SLOT(slotEdit()) );
+ subMenu->setWhatsThis(id, i18n("<b>Mark as beeing edited</b><p>Mark the files as beeing edited."));
+ id = subMenu->insertItem( actionUnEdit->text(), this, SLOT(slotUnEdit()) );
+ subMenu->setWhatsThis(id, i18n("<b>Remove editing mark</b><p>Remove the editing mark from the files."));
+ id = subMenu->insertItem( actionAdd->text(), this, SLOT(slotAdd()) );
+ subMenu->setWhatsThis(id, i18n("<b>Add to repository</b><p>Adds file to repository."));
+ id = subMenu->insertItem( actionAddBinary->text(), this, SLOT(slotAddBinary()) );
+ subMenu->setWhatsThis(id, i18n("<b>Add to repository as binary</b><p>Adds file to repository as binary (-kb option)."));
+ id = subMenu->insertItem( actionRemove->text(), this, SLOT(slotRemove()) );
+ subMenu->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Removes file(s) from repository."));
+
+ subMenu->insertSeparator();
+ id = subMenu->insertItem( actionTag->text(), this, SLOT(slotTag()) );
+ subMenu->setWhatsThis(id, i18n("<b>Make tag/branch</b><p>Tags/branches selected file(s)."));
+ id = subMenu->insertItem( actionUnTag->text(), this, SLOT(slotUnTag()) );
+ subMenu->setWhatsThis(id, i18n("<b>Delete tag</b><p>Delete tag from selected file(s)."));
+ id = subMenu->insertItem( actionUpdate->text(), this, SLOT(slotUpdate()) );
+ subMenu->setWhatsThis(id, i18n("<b>Update/revert to another release</b><p>Updates/reverts file(s) to another release."));
+ id = subMenu->insertItem( actionRemoveSticky->text(), this, SLOT(slotRemoveSticky()) );
+ subMenu->setWhatsThis(id, i18n("<b>Remove sticky flag</b><p>Removes sticky flag from file(s)."));
+
+ subMenu->insertSeparator();
+ id = subMenu->insertItem( actionAddToIgnoreList->text(), this, SLOT(slotAddToIgnoreList()) );
+ subMenu->setWhatsThis(id, i18n("<b>Ignore in CVS operations</b><p>Ignore file(s) by adding it to .cvsignore file."));
+ id = subMenu->insertItem( actionRemoveFromIgnoreList->text(), this, SLOT(slotRemoveFromIgnoreList()) );
+ subMenu->setWhatsThis(id, i18n("<b>Do not ignore in CVS operations</b><p>Do not ignore file(s) by removing\nit from .cvsignore file."));
+
+ // Now insert in parent menu
+ popup->insertItem( i18n("CvsService"), subMenu );
+
+ // If the current project doesn't support CVS, we don't
+ // want to confuse the user with a CVS popup menu.
+ if( !project() || !isValidDirectory( project()->projectDirectory() ) )
+ {
+ subMenu->setEnabled( false );
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePart::urlFocusedDocument( KURL &url )
+{
+ kdDebug(9006) << "CvsServicePartImpl::retrieveUrlFocusedDocument() here!" << endl;
+ KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
+ if ( part )
+ {
+ if (part->url().isLocalFile() )
+ {
+ url = part->url();
+ return true;
+ }
+ else
+ {
+ kdDebug(9006) << "Cannot handle non-local files!" << endl;
+ }
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePart::isValidDirectory( const QString &dirPath ) const
+{
+ return m_impl->isValidDirectory( dirPath );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionLogin()
+{
+ m_impl->login();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionLogout()
+{
+ m_impl->logout();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionCommit()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->commit( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionUpdate()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->update( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionAdd()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->add( currDocument, false );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionAnnotate()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->annotate( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionEdit()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->edit( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionEditors()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->editors( currDocument );
+ }
+}
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionUnEdit()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->unedit( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionAddBinary()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->add( currDocument, true );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionRemove()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->remove( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionRemoveSticky()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->removeStickyFlag( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionLog()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->log( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionDiff()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->diff( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionTag()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->tag( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionUnTag()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->unTag( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionAddToIgnoreList()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->addToIgnoreList( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotActionRemoveFromIgnoreList()
+{
+ KURL currDocument;
+ if (urlFocusedDocument( currDocument ))
+ {
+ m_impl->removeFromIgnoreList( currDocument );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotCommit()
+{
+ m_impl->commit( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotUpdate()
+{
+ m_impl->update( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotAdd()
+{
+ m_impl->add( m_urls, false );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotAnnotate()
+{
+ m_impl->annotate( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotEdit()
+{
+ m_impl->edit( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotUnEdit()
+{
+ m_impl->unedit( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotEditors()
+{
+ m_impl->editors( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotAddBinary()
+{
+ m_impl->add( m_urls, true );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotRemove()
+{
+ m_impl->remove( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotRemoveSticky()
+{
+ m_impl->removeStickyFlag( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotLog()
+{
+ m_impl->log( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotDiff()
+{
+ m_impl->diff( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotTag()
+{
+ m_impl->tag( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotUnTag()
+{
+ m_impl->unTag( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotAddToIgnoreList()
+{
+ m_impl->addToIgnoreList( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotRemoveFromIgnoreList()
+{
+ m_impl->removeFromIgnoreList( m_urls );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotStopButtonClicked( KDevPlugin* which )
+{
+ if ( which != 0 && which != this )
+ return;
+
+ m_impl->flushJobs();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotAddFilesToProject( const QStringList &filesToAdd )
+{
+ m_impl->addFilesToProject( filesToAdd );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotRemovedFilesFromProject(const QStringList &fileToRemove)
+{
+ m_impl->removedFilesFromProject( fileToRemove );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotProjectOpened()
+{
+ kdDebug(9006) << "CvsServicePart::slotProjectOpened() here!" << endl;
+
+ // Avoid bothering the user if this project has no support for CVS
+ if (!isValidDirectory( project()->projectDirectory() ))
+ {
+ kdDebug(9006) << "Project has no CVS Support: too bad!! :-(" << endl;
+ return;
+ }
+
+ CvsOptions *options = CvsOptions::instance();
+
+ // If createNewProject() has set this var then we have to get it.
+ if (g_projectWasJustCreated)
+ {
+ options->save( project() );
+ g_projectWasJustCreated = false;
+ }
+ options->load( project() );
+
+ // When files are added to project they may be added to/removed from repository too
+ connect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) );
+ connect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePart::slotProjectClosed()
+{
+ kdDebug(9006) << "CvsServicePart::slotProjectClosed() here!" << endl;
+
+ // Avoid bothering the user if this project has no support for CVS
+ if (!isValidDirectory( project()->projectDirectory() ))
+ {
+ kdDebug(9006) << "Project had no CVS Support: too bad!! :-(" << endl;
+ return;
+ }
+
+ CvsOptions *options = CvsOptions::instance();
+ options->save( project() );
+ delete options;
+
+ // We don't have a project anymore ...
+ disconnect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) );
+ disconnect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) );
+}
+
+#include "cvspart.moc"
+
diff --git a/vcs/cvsservice/cvspart.h b/vcs/cvsservice/cvspart.h
new file mode 100644
index 00000000..e3513a98
--- /dev/null
+++ b/vcs/cvsservice/cvspart.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+ * Copyright (C) 1999-2001 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _CVSPART_H_
+#define _CVSPART_H_
+
+#include <qguardedptr.h>
+#include <qcstring.h>
+#include <kurl.h>
+#include "kdevversioncontrol.h"
+
+class Context;
+class QPopupMenu;
+class QDir;
+class KDialogBase;
+class KURL;
+class KURL::List;
+class KAction;
+
+class CvsProcessWidget;
+class CvsForm;
+class CheckoutDialog;
+
+class CvsService_stub;
+class Repository_stub;
+class CvsServicePartImpl;
+
+class CvsServicePart : public KDevVersionControl
+{
+ Q_OBJECT
+
+ friend class CvsServicePartImpl;
+
+public:
+ //! Standard constructor.
+ CvsServicePart( QObject *parent, const char *name, const QStringList & );
+ //! Destructor.
+ virtual ~CvsServicePart();
+
+ /**
+ * Returns the configuration widget (for properly configuring the project to
+ * use CVS), child of @p parent.
+ */
+ virtual QWidget *newProjectWidget( QWidget *parent );
+ /**
+ * Setup a directory tree for use with CVS.
+ */
+ virtual void createNewProject( const QString& dir );
+ /**
+ * Fetch a module from remote repository, so it can be used for importing
+ */
+ virtual bool fetchFromRepository();
+ /**
+ * @return the info provider for VCS sandboxes
+ */
+ virtual KDevVCSFileInfoProvider *fileInfoProvider() const;
+ /**
+ * @param dirPath absolute path of the directory
+ * @return true if the the directory is a valid CVS sandbox
+ */
+ virtual bool isValidDirectory( const QString &dirPath ) const;
+
+private slots:
+ /** Add menu items binded to cvs operations' slots to @p popup, using
+ * data in @p context.
+ * Not that @p context _must_ be FileContext-type, otherwise will do
+ * nothing.
+ */
+ void contextMenu( QPopupMenu *popup, const Context *context );
+
+ // Cvs operations (menubar)
+ void slotActionLogin();
+ void slotActionLogout();
+
+ void slotActionCommit();
+ void slotActionUpdate();
+ void slotActionEditors();
+ void slotActionEdit();
+ void slotActionUnEdit();
+ void slotActionAdd();
+ void slotActionAnnotate();
+ void slotActionAddBinary();
+ void slotActionRemove();
+ void slotActionRemoveSticky();
+ void slotActionLog();
+ void slotActionDiff();
+ void slotActionTag();
+ void slotActionUnTag();
+ void slotActionAddToIgnoreList();
+ void slotActionRemoveFromIgnoreList();
+
+ // Cvs operations (context menu)
+ void slotCommit();
+ void slotUpdate();
+ void slotEditors();
+ void slotEdit();
+ void slotUnEdit();
+ void slotAdd();
+ void slotAnnotate();
+ void slotAddBinary();
+ void slotRemove();
+ void slotRemoveSticky();
+ void slotLog();
+ void slotDiff();
+ void slotTag();
+ void slotUnTag();
+ void slotAddToIgnoreList();
+ void slotRemoveFromIgnoreList();
+
+ void slotProjectOpened();
+ void slotProjectClosed();
+
+ void slotAddFilesToProject(const QStringList &);
+ void slotRemovedFilesFromProject(const QStringList &);
+
+ /** Adds a configuration widget (for properly configuring CVS command-line options)
+ * and adds it to @p dlg.
+ */
+ void projectConfigWidget( KDialogBase *dlg );
+
+ //! Called when the user wishes to stop an operation.
+ void slotStopButtonClicked( KDevPlugin* );
+
+private slots:
+ void init();
+
+private:
+ void setupActions();
+ //! Returns the KURL for the currently focused document, if there is any
+ bool urlFocusedDocument( KURL &url );
+
+ //! A list of KURLs of the files to be "operated" on (to be committed, added, removed, ...)
+ KURL::List m_urls;
+
+ /** This is a pointer to the d->form used for collecting data about CVS project creation (used
+ * by the ApplicationWizard in example)
+ */
+ QGuardedPtr<CvsForm> m_cvsConfigurationForm;
+
+ // Actions
+ KAction *actionCommit,
+ *actionDiff,
+ *actionLog,
+ *actionAnnotate,
+ *actionAdd,
+ *actionAddBinary,
+ *actionRemove,
+ *actionUpdate,
+ *actionRemoveSticky,
+ *actionEdit,
+ *actionEditors,
+ *actionUnEdit,
+ *actionAddToIgnoreList,
+ *actionRemoveFromIgnoreList,
+ *actionTag,
+ *actionUnTag,
+ *actionLogin,
+ *actionLogout;
+
+ CvsServicePartImpl *m_impl;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvspartimpl.cpp b/vcs/cvsservice/cvspartimpl.cpp
new file mode 100644
index 00000000..e6177739
--- /dev/null
+++ b/vcs/cvsservice/cvspartimpl.cpp
@@ -0,0 +1,1012 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include<qcheckbox.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kmainwindow.h>
+#include <dcopref.h>
+// CvsService stuff
+#include <repository_stub.h>
+#include <cvsservice_stub.h>
+#include <cvsjob_stub.h>
+// KDevelop SDK stuff
+#include <urlutil.h>
+#include <kdevproject.h>
+#include <kdevmainwindow.h>
+#include <kdevcore.h>
+#include <kdevdifffrontend.h>
+#include <kdevmakefrontend.h>
+#include <kdevpartcontroller.h>
+// Part's widgets
+#include "cvsprocesswidget.h"
+#include "checkoutdialog.h"
+#include "commitdlg.h"
+#include "tagdialog.h"
+#include "diffdialog.h"
+#include "releaseinputdialog.h"
+#include "cvslogdialog.h"
+#include "editorsdialog.h"
+#include "annotatedialog.h"
+
+#include "changelog.h"
+#include "cvsoptions.h"
+#include "cvsdir.h"
+#include "cvsentry.h"
+#include "jobscheduler.h"
+#include "cvsfileinfoprovider.h"
+
+#include "cvspart.h"
+#include "cvspartimpl.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class Constants
+///////////////////////////////////////////////////////////////////////////////
+
+// Nice name (relative to projectDirectory()) ;-)
+const QString CvsServicePartImpl::changeLogFileName( "ChangeLog" );
+// Four spaces for every log line (except the first, which includes the
+// developers name)
+const QString CvsServicePartImpl::changeLogPrependString( " " );
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsServicePartImpl
+///////////////////////////////////////////////////////////////////////////////
+
+CvsServicePartImpl::CvsServicePartImpl( CvsServicePart *part, const char *name )
+ : QObject( this, name? name : "cvspartimpl" ),
+ m_scheduler( 0 ), m_part( part ), m_widget( 0 )
+{
+ if (requestCvsService())
+ {
+ m_widget = new CvsProcessWidget( m_cvsService, part, 0, "cvsprocesswidget" );
+ m_scheduler = new DirectScheduler( m_widget );
+ m_fileInfoProvider = new CVSFileInfoProvider( part, m_cvsService );
+
+ connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) );
+ }
+ else
+ {
+ kdDebug(9006) << "CvsServicePartImpl::CvsServicePartImpl(): somebody kills me because"
+ "I could not request a valid CvsService!!!! :-((( " << endl;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsServicePartImpl::~CvsServicePartImpl()
+{
+ if (processWidget())
+ {
+ // Inform toplevel, that the output view is gone
+ mainWindow()->removeView( m_widget );
+ delete m_widget;
+ }
+ delete m_scheduler;
+ //delete m_fileInfoProvider;
+ releaseCvsService();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePartImpl::prepareOperation( const KURL::List &someUrls, CvsOperation op )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ bool correctlySetup = (m_cvsService != 0) && (m_repository != 0);
+ if (!correctlySetup)
+ {
+ kdDebug(9006) << "DCOP CvsService is not available!!!" << endl;
+ return false;
+ }
+
+ KURL::List urls = someUrls;
+ URLUtil::dump( urls, "Requested CVS operation for: " );
+
+ if (!m_part->project())
+ {
+ kdDebug(9006) << k_funcinfo << "No project???" << endl;
+ KMessageBox::sorry( 0, i18n("Open a project first.\nOperation will be aborted.") );
+ return false;
+ }
+
+ if (m_widget->isAlreadyWorking())
+ {
+ if (KMessageBox::warningYesNo( 0,
+ i18n("Another CVS operation is executing: do you want to cancel it \n"
+ "and start this new one?"),
+ i18n("CVS: Operation Already Pending ")) == KMessageBox::Yes)
+ {
+ m_widget->cancelJob();
+ }
+ else // Operation canceled
+ {
+ kdDebug(9006) << k_funcinfo << "Operation canceled by user request" << endl;
+ return false;
+ }
+ }
+
+ validateURLs( projectDirectory(), urls, op );
+ if (urls.count() <= 0) // who knows? ;)
+ {
+ kdDebug(9006) << "CvsServicePartImpl::prepareOperation(): No valid document URL selected!!!" << endl;
+ KMessageBox::sorry( 0, i18n("None of the file(s) you selected seem to be valid for repository.") );
+ return false;
+ }
+
+ URLUtil::dump( urls );
+ // Save for later use
+ m_urlList = urls;
+ m_lastOperation = op;
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::doneOperation( const KURL::List &/*someUrls*/, CvsOperation /*op*/ )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ // @ todo notify clients (filetree) about changed status?)
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+const KURL::List &CvsServicePartImpl::urlList() const
+{
+ return m_urlList;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList CvsServicePartImpl::fileList( bool relativeToProjectDir ) const
+{
+ if (relativeToProjectDir)
+ return URLUtil::toRelativePaths( projectDirectory(), urlList() );
+ else
+ return urlList().toStringList();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePartImpl::isRegisteredInRepository( const QString &projectDirectory, const KURL &url )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ // KURL::directory() is a bit tricky when used on file or _dir_ paths ;-)
+ KURL projectURL = KURL::fromPathOrURL( projectDirectory );
+ kdDebug(9006) << k_funcinfo << "projectURL = " << projectURL.url() << endl;
+ kdDebug(9006) << k_funcinfo << "url = " << url.url() << endl;
+
+ if ( projectURL == url)
+ {
+ CVSDir cvsdir = CVSDir( projectDirectory );
+ return cvsdir.isValid();
+ }
+ else
+ {
+ CVSDir cvsdir = CVSDir( url.directory() );
+
+ if (!cvsdir.isValid())
+ {
+ kdDebug(9006) << k_funcinfo << " Error: " << cvsdir.path() << " is not a valid CVS directory " << endl;
+ return false;
+ }
+ CVSEntry entry = cvsdir.fileStatus( url.fileName() );
+ return entry.isValid();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::validateURLs( const QString &projectDirectory, KURL::List &urls, CvsOperation op )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ // If files are to be added, we can avoid to check them to see if they are registered in the
+ // repository ;)
+ if (op == opAdd)
+ {
+ kdDebug(9006) << "This is a Cvs Add operation and will not be checked against repository ;-)" << endl;
+ return;
+ }
+ QValueList<KURL>::iterator it = urls.begin();
+ while (it != urls.end())
+ {
+ if (!CvsServicePartImpl::isRegisteredInRepository( projectDirectory, (*it) ))
+ {
+ kdDebug(9006) << "Warning: file " << (*it).path() << " does NOT belong to repository and will not be used" << endl;
+
+ it = urls.erase( it );
+ }
+ else
+ {
+ kdDebug(9006) << "Warning: file " << (*it).path() << " is in repository and will be accepted" << endl;
+
+ ++it;
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::addToIgnoreList( const QString &projectDirectory, const KURL &url )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if ( url.path() == projectDirectory )
+ {
+ kdDebug(9006) << "Can't add to ignore list current project directory " << endl;
+ return;
+ }
+
+ CVSDir cvsdir( url.directory() );
+ cvsdir.ignoreFile( url.fileName() );
+}
+
+void CvsServicePartImpl::addToIgnoreList( const QString &projectDirectory, const KURL::List &urls )
+{
+ for (size_t i=0; i<urls.count(); ++i)
+ {
+ addToIgnoreList( projectDirectory, urls[i] );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::removeFromIgnoreList( const QString &/*projectDirectory*/, const KURL &url )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ QStringList ignoreLines;
+
+ CVSDir cvsdir( url.directory() );
+ cvsdir.doNotIgnoreFile( url.fileName() );
+}
+
+void CvsServicePartImpl::removeFromIgnoreList( const QString &projectDirectory, const KURL::List &urls )
+{
+ for (size_t i=0; i<urls.count(); ++i)
+ {
+ removeFromIgnoreList( projectDirectory, urls[i] );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePartImpl::isValidDirectory( const QDir &dir ) const
+{
+ CVSDir cvsdir( dir );
+
+ return cvsdir.isValid();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsProcessWidget *CvsServicePartImpl::processWidget() const
+{
+ return m_widget;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KDevMainWindow *CvsServicePartImpl::mainWindow() const
+{
+ return m_part->mainWindow();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString CvsServicePartImpl::projectDirectory() const
+{
+ return m_part->project() ? m_part->project()->projectDirectory() : QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KDevCore *CvsServicePartImpl::core() const
+{
+ return m_part->core();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KDevDiffFrontend *CvsServicePartImpl::diffFrontend() const
+{
+ return m_part->extension<KDevDiffFrontend>("KDevelop/DiffFrontend");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::login()
+{
+ DCOPRef job = m_cvsService->login( this->projectDirectory() );
+
+ m_scheduler->schedule( job );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::logout()
+{
+ DCOPRef job = m_cvsService->logout( this->projectDirectory() );
+
+ m_scheduler->schedule( job );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePartImpl::checkout()
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ CheckoutDialog dlg( m_cvsService, mainWindow()->main()->centralWidget() );
+
+ if ( dlg.exec() == QDialog::Accepted )
+ {
+ DCOPRef job = m_cvsService->checkout( dlg.workDir(), dlg.serverPath(),
+ dlg.module(), dlg.tag(), dlg.pruneDirs(), "", false
+ );
+ if (!m_cvsService->ok()) {
+ KMessageBox::sorry( mainWindow()->main(), i18n( "Unable to checkout" ) );
+ } else {
+ // Save the path for later retrieval since slotCheckoutFinished(bool,int)
+ // will use it for return the info to the caller.
+ modulePath = dlg.workDir() + dlg.module();
+
+ m_scheduler->schedule( job );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotCheckoutFinished(bool,int)) );
+ return true;
+ }
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::commit( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+ kdDebug(9006) << "Commit requested for " << urlList.count() << " file(s)." << endl;
+
+ if (!prepareOperation( urlList, opCommit ))
+ return;
+
+ CommitDialog dlg( projectDirectory() + "/ChangeLog" );
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ CvsOptions *options = CvsOptions::instance();
+ QString logString = dlg.logMessage().join( "\n" );
+
+ DCOPRef cvsJob = m_cvsService->commit( fileList(), logString, options->recursiveWhenCommitRemove() );
+ if (!m_cvsService->ok())
+ {
+ kdDebug( 9006 ) << "Commit of " << fileList().join( ", " ) << " failed!!!" << endl;
+ return;
+ }
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotJobFinished(bool,int)) );
+
+ // 2. if requested to do so, add an entry to the Changelog too
+ if (dlg.mustAddToChangeLog())
+ {
+ // 2.1 Modify the Changelog
+ ChangeLogEntry entry;
+ entry.addLines( dlg.logMessage() );
+ entry.addToLog( dlg.changeLogFileName() );
+
+ kdDebug( 9006 ) << " *** ChangeLog entry : " <<
+ entry.toString( changeLogPrependString ) << endl;
+ }
+
+ doneOperation( KURL::List( fileList() ), opCommit );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::update( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opCommit ))
+ return;
+
+ CvsOptions *options = CvsOptions::instance();
+ ReleaseInputDialog dlg( mainWindow()->main()->centralWidget() );
+ if (dlg.exec() == QDialog::Rejected)
+ return;
+
+ QString additionalOptions = dlg.release();
+ if (dlg.isRevert())
+ additionalOptions = additionalOptions + " " + options->revertOptions();
+
+ DCOPRef cvsJob = m_cvsService->update( fileList(),
+ options->recursiveWhenUpdate(),
+ options->createDirsWhenUpdate(),
+ options->pruneEmptyDirsWhenUpdate(),
+ additionalOptions );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::add( const KURL::List& urlList, bool binary )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opAdd ))
+ return;
+
+ DCOPRef cvsJob = m_cvsService->add( fileList(), binary );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::annotate( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opAnnotate ))
+ return;
+
+ //get the directory of the file we want to annotate
+ QString tagFilename = URLUtil::directory(projectDirectory()+"/"+fileList()[0]);
+ //CVS stores tag information in the ./CVS/Tag file
+ tagFilename += "/CVS/Tag";
+
+
+ //Check if such a Tag file exists, and try to read the tag/branch from it
+ QFile fileTag(tagFilename);
+ QString strRev = ""; //default revision is empty ...
+ if (fileTag.exists()) { //... but if there is a Tag file, we get the revision from there
+ if ( fileTag.open( IO_ReadOnly ) ) {
+ QTextStream stream( &fileTag );
+ QString line;
+ line = stream.readLine();
+ if (line.startsWith("T")) { //the line always starts with a "T"...
+ strRev = line.right(line.length()-1); //...and after this there is the tag name
+ kdDebug(9006) << "The found revision is: >>" << strRev << "<<" <<endl;
+ }
+ fileTag.close();
+ }
+ }
+
+ AnnotateDialog * f = new AnnotateDialog( m_cvsService );
+ f->show();
+ //the dialog will do all the work, just give him the file and the revision to start with
+ f->startFirstAnnotate( fileList()[0], strRev );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::unedit( const KURL::List& urlList)
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ int s = KMessageBox::questionYesNo( 0,
+ i18n("Do you really want to unedit the selected files?"),
+ i18n("CVS - Unedit Files"),
+ i18n("Unedit"),
+ i18n("Do Not Unedit"),
+ "askUneditingFiles" );
+ if (s == KMessageBox::No) {
+ return;
+ }
+
+ if (!prepareOperation( urlList, opUnEdit ))
+ return;
+
+ DCOPRef cvsJob = m_cvsService->unedit( fileList() );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::edit( const KURL::List& urlList)
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opEdit ))
+ return;
+
+ DCOPRef cvsJob = m_cvsService->edit( fileList() );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::editors( const KURL::List& urlList)
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opEditors ))
+ return;
+
+ EditorsDialog * f = new EditorsDialog( m_cvsService );
+ f->show();
+ //the dialog will do all the work
+ f->startjob( fileList()[0] );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::remove( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opRemove ))
+ return;
+
+ DCOPRef cvsJob = m_cvsService->remove( fileList(), true );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)),
+ this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::removeStickyFlag( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opUpdate ))
+ return;
+
+ CvsOptions *options = CvsOptions::instance();
+
+ DCOPRef cvsJob = m_cvsService->update( fileList(),
+ options->recursiveWhenUpdate(),
+ options->createDirsWhenUpdate(),
+ options->pruneEmptyDirsWhenUpdate(),
+ "-A" );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)),
+ this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::log( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opLog ))
+ return;
+
+ CVSLogDialog* f = new CVSLogDialog( m_cvsService );
+ f->show();
+ // Form will do all the work
+ f->startLog( projectDirectory(), fileList()[0] );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::diff( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opDiff ))
+ return;
+
+ CVSDir cvsdir = CVSDir( urlList[0].directory() );
+ CVSEntry entry = cvsdir.fileStatus( urlList[0].fileName() );
+
+ DiffDialog dlg(entry);
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ CvsOptions *options = CvsOptions::instance();
+ DCOPRef cvsJob = m_cvsService->diff( fileList()[0], dlg.revA(),
+ dlg.revB(), options->diffOptions(), options->contextLines() );
+ if (!m_cvsService->ok())
+ {
+ KMessageBox::sorry( 0, i18n("Sorry, cannot diff."),
+ i18n("Error During Diff") );
+ return;
+ }
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)),
+ this, SLOT(slotDiffFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::tag( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opTag ))
+ return;
+
+ TagDialog dlg( i18n("Creating Tag/Branch for files ..."),
+ mainWindow()->main()->centralWidget() );
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ DCOPRef cvsJob = m_cvsService->createTag( fileList(), dlg.tagName(),
+ dlg.isBranch(), dlg.force() );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)),
+ this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::unTag( const KURL::List& urlList )
+{
+ kdDebug(9006) << k_funcinfo << endl;
+
+ if (!prepareOperation( urlList, opUnTag ))
+ return;
+
+ TagDialog dlg( i18n("Removing Tag from files ..."),
+ mainWindow()->main()->centralWidget() );
+ dlg.tagAsBranchCheck->hide();
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ DCOPRef cvsJob = m_cvsService->deleteTag( fileList(), dlg.tagName(),
+ dlg.isBranch(), dlg.force() );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)),
+ this, SLOT(slotJobFinished(bool,int)) );
+
+ doneOperation();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::addToIgnoreList( const KURL::List& urlList )
+{
+ addToIgnoreList( projectDirectory(), urlList );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::removeFromIgnoreList( const KURL::List& urlList )
+{
+ removeFromIgnoreList( projectDirectory(), urlList );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+* \FIXME Current implementation doesn't use CvsService :-( I just ported the
+* old code which relies on buildcvs.sh script. [marios]
+*/
+void CvsServicePartImpl::createNewProject( const QString &dirName,
+ const QString &cvsRsh, const QString &location,
+ const QString &message, const QString &module, const QString &vendor,
+ const QString &release, bool mustInitRoot )
+{
+ kdDebug( 9006 ) << "====> CvsServicePartImpl::createNewProject( const QString& )" << endl;
+
+ CvsOptions *options = CvsOptions::instance();
+ options->setCvsRshEnvVar( cvsRsh );
+ options->setLocation( location );
+/*
+ //virtual DCOPRef import( const QString& workingDir, const QString& repository, const QString& module, const QString& ignoreList, const QString& comment, const
+ QString filesToIgnore;
+ DCOPRef cvsJob = m_cvsService->import( dirName, location, module, filesToIgnore, message, vendor, release, false );
+
+ m_scheduler->schedule( cvsJob );
+ connect( processWidget(), SIGNAL(jobFinished(bool,int)), this, SLOT(slotCheckoutFinished(bool,int)) );
+*/
+ QString rsh_preamble;
+ if ( !options->cvsRshEnvVar().isEmpty() )
+ rsh_preamble = "CVS_RSH=" + KShellProcess::quote( options->cvsRshEnvVar() );
+
+ QString init;
+ if (mustInitRoot)
+ {
+ init = rsh_preamble + " cvs -d " + KShellProcess::quote( options->location() ) + " init && ";
+ }
+ QString cmdLine = init + "cd " + KShellProcess::quote(dirName) +
+ " && " + rsh_preamble +
+ " cvs -d " + KShellProcess::quote(options->location()) +
+ " import -m " + KShellProcess::quote(message) + " " +
+ KShellProcess::quote(module) + " " +
+ KShellProcess::quote(vendor) + " " +
+ KShellProcess::quote(release) +
+ // CVS build-up magic here ...
+ " && sh " +
+ locate("data","kdevcvsservice/buildcvs.sh") + " . " +
+ KShellProcess::quote(module) + " " +
+ KShellProcess::quote(location);
+
+ kdDebug( 9006 ) << " ** Will run the following command: " << endl << cmdLine << endl;
+ kdDebug( 9006 ) << " ** on directory: " << dirName << endl;
+
+ if (KDevMakeFrontend *makeFrontend = m_part->extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand( dirName, cmdLine );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsServicePartImpl::requestCvsService()
+{
+ QCString appId;
+ QString error;
+
+ if (KApplication::startServiceByDesktopName( "cvsservice",
+ QStringList(), &error, &appId ))
+ {
+ QString msg = i18n( "Unable to find the Cervisia KPart. \n"
+ "Cervisia Integration will not be available. Please check your\n"
+ "Cervisia installation and re-try. Reason was:\n" ) + error;
+ KMessageBox::error( processWidget(), msg, "DCOP Error" );
+
+ return false;
+ }
+ else
+ {
+ m_cvsService = new CvsService_stub( appId, "CvsService" );
+ m_repository = new Repository_stub( appId, "CvsRepository" );
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::releaseCvsService()
+{
+ if (m_cvsService)
+ m_cvsService->quit();
+ delete m_cvsService;
+ m_cvsService = 0;
+ delete m_repository;
+ m_repository = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::flushJobs()
+{
+ processWidget()->cancelJob();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::addFilesToProject( const QStringList &filesToAdd )
+{
+ kdDebug( 9006 ) << k_funcinfo << " " << filesToAdd << endl;
+
+ QStringList filesInCVS = checkFileListAgainstCVS( filesToAdd );
+ if (filesInCVS.isEmpty())
+ return;
+
+ kdDebug( 9006 ) << k_funcinfo << " " << filesInCVS << endl;
+
+ int s = KMessageBox::questionYesNo( 0,
+ i18n("Do you want the files to be added to CVS repository too?"),
+ i18n("CVS - New Files Added to Project"),
+ KStdGuiItem::add(),
+ i18n("Do Not Add"),
+ i18n("askWhenAddingNewFiles") );
+ if (s == KMessageBox::Yes)
+ {
+ kdDebug( 9006 ) << "Adding these files: " << filesInCVS.join( ", " ) << endl;
+
+ const KURL::List urls = KURL::List( filesInCVS );
+ URLUtil::dump( urls );
+ add( urls );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::removedFilesFromProject(const QStringList &filesToRemove)
+{
+ kdDebug( 9006 ) << k_funcinfo << endl;
+
+ QStringList filesInCVS = checkFileListAgainstCVS( filesToRemove );
+ if (filesInCVS.isEmpty())
+ return;
+
+ int s = KMessageBox::warningContinueCancel( 0,
+ i18n("Do you want them to be removed from CVS repository too?\nWarning: They will be removed from disk too."),
+ i18n("CVS - Files Removed From Project"),
+ KStdGuiItem::del(),
+ i18n("askWhenRemovingFiles") );
+
+ if (s == KMessageBox::Continue)
+ {
+ kdDebug( 9006 ) << "Removing these files: " << filesInCVS.join( ", " ) << endl;
+ const KURL::List urls = KURL::List( filesInCVS );
+ URLUtil::dump( urls );
+ remove( urls );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QStringList CvsServicePartImpl::checkFileListAgainstCVS( const QStringList &filesToCheck ) const
+{
+ QStringList filesInCVS;
+ for (QStringList::const_iterator it = filesToCheck.begin(); it != filesToCheck.end(); ++it )
+ {
+ const QString &fn = (*it);
+ QFileInfo fi( fn );
+ if (fi.isRelative())
+ fi = projectDirectory() + QDir::separator() + fn;
+ if (isValidDirectory( fi.dirPath( true ) ))
+ filesInCVS += ( fi.filePath() );
+ }
+
+ return filesInCVS;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::emitFileStateModified( const KURL::List &/*urls*/, VCSFileInfo::FileState &/*commonState*/ )
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+KDevVCSFileInfoProvider *CvsServicePartImpl::fileInfoProvider() const
+{
+ return m_fileInfoProvider;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SLOTS here!
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::slotDiffFinished( bool normalExit, int exitStatus )
+{
+ core()->running( m_part, false );
+
+ QString diff = processWidget()->output().join("\n"),
+ err = processWidget()->errors().join("\n");
+
+ kdDebug( 9006 ) << "diff = " << diff << endl;
+ kdDebug( 9006 ) << "err = " << err << endl;
+
+ if (normalExit)
+ kdDebug( 9006 ) << " *** Process died nicely with exit status = " <<
+ exitStatus << endl;
+ else
+ kdDebug( 9999 ) << " *** Process was killed with exit status = " <<
+ exitStatus << endl;
+
+ // Now show a message about operation ending status
+ if (diff.isEmpty() && (exitStatus != 0))
+ {
+ KMessageBox::information( 0, i18n("Operation aborted (process killed)."),
+ i18n("CVS Diff") );
+ return;
+ }
+ if ( diff.isEmpty() && !err.isEmpty() )
+ {
+ KMessageBox::detailedError( 0, i18n("CVS outputted errors during diff."),
+ err, i18n("Errors During Diff") );
+ return;
+ }
+
+ if ( !err.isEmpty() )
+ {
+ int s = KMessageBox::warningContinueCancelList( 0,
+ i18n("CVS output errors during diff. Do you still want to continue?"),
+ QStringList::split( "\n", err, false ), i18n("Errors During Diff")
+ );
+ if ( s != KMessageBox::Continue )
+ return;
+ }
+
+ if ( diff.isEmpty() )
+ {
+ KMessageBox::information( 0, i18n("There is no difference to the repository."),
+ i18n("No Difference Found") );
+ return;
+ }
+
+ Q_ASSERT( diffFrontend() );
+ diffFrontend()->showDiff( diff );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::slotCheckoutFinished( bool exitStatus, int )
+{
+ kdDebug(9006) << "CvsServicePartImpl::slotCheckoutFinished(): job ended with status == "
+ << exitStatus << endl;
+ // Return a null string if the operation was not succesfull
+ if (!exitStatus)
+ modulePath = QString::null;
+
+ kdDebug(9006) << " I'll emit modulePath == " << modulePath << endl;
+
+ emit checkoutFinished( modulePath );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::slotJobFinished( bool /*exitStatus*/, int exitCode )
+{
+ // Return a null string if the operation was not succesfull
+ kdDebug(9006) << "CvsServicePartImpl::slotJobFinished(): job ended with code == "
+ << exitCode << endl;
+/*
+ // Operation has been successfull
+ if (!exitStatus)
+ return;
+
+ // 1. Assemble the CVSFileInfoList
+ // 2. notify all clients
+*/
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsServicePartImpl::slotProjectOpened()
+{
+ kdDebug(9006) << "CvsServicePartImpl::slotProjectOpened(): setting work directory to "
+ << projectDirectory() << endl;
+
+ if ( m_repository )
+ {
+ m_repository->setWorkingCopy( projectDirectory() );
+ }
+}
+
+
+#include "cvspartimpl.moc"
diff --git a/vcs/cvsservice/cvspartimpl.h b/vcs/cvsservice/cvspartimpl.h
new file mode 100644
index 00000000..e5087f68
--- /dev/null
+++ b/vcs/cvsservice/cvspartimpl.h
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef CVSPARTIMPL_H
+#define CVSPARTIMPL_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+#include <qguardedptr.h>
+#include <kurl.h>
+
+#include <kdevversioncontrol.h>
+
+class CvsServicePart;
+class KDialogBase;
+class KURL;
+class KURL::List;
+class CvsProcessWidget;
+class KDevMainWindow;
+class KDevCore;
+class KDevDiffFrontend;
+class QDir;
+class JobScheduler;
+class KDevVCSFileInfoProvider;
+class CVSFileInfoProvider;
+
+/**
+* @short This is the base class for implementation of the core service.
+*
+* This is an attempt to separate the container part (CvsServicePart) and its implementation
+* for reducing code complexity for module (cvspart.{h,cpp} was becoming too
+* cumbersome). So a CvsServicePart can have several implementations, one directly wrapping
+* 'cvs' command and another using cervisia's cvsservice.
+*
+* @author Mario Scalas
+*/
+class CvsServicePartImpl : public QObject
+{
+ friend class CvsServicePart;
+
+ Q_OBJECT
+public:
+ //! Available Cvs operations
+ enum CvsOperation
+ {
+ opFakeStub, opAdd, opCommit, opUpdate, opRevert, opRemove, opLog, opDiff, opTag, opUnTag, opEdit, opUnEdit, opEditors, opAnnotate
+ };
+
+ /**
+ * Costructor
+ * @param part the CvsServicePart component
+ * @param name
+ */
+ CvsServicePartImpl( CvsServicePart *part, const char *name=0 );
+ /**
+ * Destructor
+ */
+ virtual ~CvsServicePartImpl();
+
+ /**
+ * Do login into repository. The component will show a dialog requesting the
+ * needed data to the user.
+ */
+ virtual void login();
+ /**
+ * Do logout. Of course one must be logged into repository first ;-)
+ */
+ virtual void logout();
+ /**
+ * Do checkout of module from some remote directory. Requested data will be
+ * collected here.
+ * @return true if the operation was successful
+ */
+ virtual bool checkout();
+ /**
+ * Commit the specified files (as KURL) to repository.
+ * @param urlList
+ */
+ virtual void commit( const KURL::List& urlList );
+ /**
+ * Update the specified files (as KURL): files will be
+ * updated if not locally modified.
+ * @param urlList
+ */
+ virtual void update( const KURL::List& urlList );
+ /**
+ * Add the specified files (as KURL) to repository.
+ * @param urlList
+ * @param binary is the file binary or plain text
+ */
+ virtual void add( const KURL::List& urlList, bool binary = false );
+ /**
+ * Annotate the specified file (as KURL).
+ * @param urlList
+ */
+ virtual void annotate( const KURL::List& urlList);
+ /**
+ * Mark the specified files (as KURL) for beeing edited
+ * @param urlList
+ */
+ virtual void edit( const KURL::List& urlList );
+ /**
+ * Remove editing mark from the specified files (as KURL)
+ * @param urlList
+ */
+ virtual void unedit( const KURL::List& urlList );
+ /**
+ * Show list of editors for the specified files (as KURL)
+ * @param urlList
+ */
+ virtual void editors( const KURL::List& urlList );
+ /**
+ * Remove the specified files (as KURL) from repository.
+ * @param urlList
+ */
+ virtual void remove( const KURL::List& urlList );
+ /**
+ * Produce a log of changes about the specified files.
+ * @param urlList
+ */
+ virtual void log( const KURL::List& urlList );
+ /**
+ * Produce a diff of the the specified files (as KURL). The diff could
+ * be displayed in the diff frontend or in an ad-hoc container.
+ * @param urlList
+ */
+ virtual void diff( const KURL::List& urlList );
+ /**
+ * Tag the specified files (as KURL) with a release or branch tag.
+ * @param urlList
+ */
+ virtual void tag( const KURL::List& urlList );
+ /**
+ * Remove tag from the specified files (as KURL) in repository.
+ * @param urlList
+ */
+ virtual void unTag( const KURL::List& urlList );
+ /**
+ * Remove tag from the specified files (as KURL) in repository.
+ * @param urlList
+ */
+ virtual void removeStickyFlag( const KURL::List& urlList );
+ /**
+ * Add the specified files (as KURL) to the .cvsignore file.
+ * @param urlList
+ */
+ virtual void addToIgnoreList( const KURL::List& urlList );
+ /**
+ * Commit the specified files (as KURL) to repository.
+ * @param urlList
+ */
+ virtual void removeFromIgnoreList( const KURL::List& urlList );
+ /**
+ * Creates a new project with cvs support, that is will import the
+ * generated sources in the repository.
+ * @param dirName path to project directory on local system
+ * @param cvsRsh value for the CVS_RSH env var (for accessing :ext:
+ * repositories)
+ * @param location cvs server path (i.e. :pserver:marios@cvs.kde.org:/home/kde)
+ * @param message an initial creation message for the project
+ * @param module the module into repository where to put this source tree
+ * @param vendor vendor string
+ * @param release release tag
+ * @param mustInitRoot if true will attempt to initialize $CVSROOT if not already prepared
+ */
+ virtual void createNewProject( const QString &dirName,
+ const QString &cvsRsh, const QString &location,
+ const QString &message, const QString &module, const QString &vendor,
+ const QString &release, bool mustInitRoot );
+
+ /**
+ * @return true if the directory is valid as CVS directory (has the /CVS/ dir inside) (FORWARDER)
+ */
+ virtual bool isValidDirectory( const QDir &dir ) const;
+ /**
+ * @return a reference to the custom FileInforProvider object (FORWARDER)
+ */
+ KDevVCSFileInfoProvider *fileInfoProvider() const;
+
+
+// Helpers
+public:
+ /**
+ * Stops the CVS job, both currently executing and queued.
+ * @todo queuing is not yet implemented
+ */
+ void flushJobs();
+ /**
+ * @return a reference to the process widget: many worker methods
+ * display their output in it and the CvsServicePart will embed it in the
+ * bottom embedded view.
+ */
+ CvsProcessWidget *processWidget() const;
+
+signals:
+ void warning( const QString &msg );
+ /**
+ * Emitted when the component has terminated checkout operation
+ * @param checkedDir directory where the module has been checked out
+ * (will be empty if the operation failed)
+ */
+ void checkoutFinished( QString checkedDir );
+
+private slots:
+ void slotJobFinished( bool normalExit, int exitStatus );
+ void slotDiffFinished( bool normalExit, int exitStatus );
+ void slotCheckoutFinished( bool normalExit, int exitStatus );
+ void slotProjectOpened();
+
+private:
+ /**
+ * Call this every time a slot for cvs operations starts!! (It will setup the
+ * state (file/dir URL, ...).
+ * It will also display proper error messages so the caller must only exit if
+ * it fails (return false); if return true than basic requisites for cvs operation
+ * are satisfied.
+ * @return true and the valid URLs paths in m_fileList if the operation can be performed,
+ * false otherwise.
+ */
+ bool prepareOperation( const KURL::List &someUrls, CvsOperation op );
+ /**
+ * Call this every time a slot for cvs operations ends!! (It will restore the state for a new
+ * operation) and notify clients about changes.
+ */
+ void doneOperation( const KURL::List &someUrls = KURL::List(), CvsOperation op = opFakeStub );
+
+ void emitFileStateModified( const KURL::List &urls, VCSFileInfo::FileState &commonState );
+
+ /**
+ * @return true if the @p url is present in CVS/Entry file
+ */
+ static bool isRegisteredInRepository( const QString &projectDirectory, const KURL &url );
+ /**
+ * Ideally this function will take a bunch of URLs and validate them (they are valid files,
+ * are files registered in CVS, are on a supported filesystem, ...). Currently checks
+ * only for files belonging to the repository ;)
+ * @param projectDirectory
+ * @param urls list of KURL to check (the list can be modified during the operation)
+ * @param op type of cvs operation, as pecified in @see CvsOperation enum
+ */
+ static void validateURLs( const QString &projectDirectory, KURL::List &urls, CvsOperation op );
+
+ /**
+ * Add file to it's respective ignore list. This means that, for example, if you
+ * add '/home/mario/src/myprj/mylib/module1/bad.cpp' then the string 'bad.cpp' will be
+ * appended to file '/home/mario/src/myprj/mylib/module1/.cvsignore'.
+ * @param projectDirectory
+ * @param url url to be added to the check list.
+ */
+ static void addToIgnoreList( const QString &projectDirectory, const KURL &url );
+
+ /**
+ * Add files to their respective ignore list. This means that, for example, if you
+ * add '/home/mario/src/myprj/mylib/module1/bad.cpp' then the string 'bad.cpp' will be
+ * appended to file '/home/mario/src/myprj/mylib/module1/.cvsignore'.
+ * @param projectDirectory
+ * @param urls list of urls to be added to the check list.
+ */
+ static void addToIgnoreList( const QString &projectDirectory, const KURL::List &urls );
+
+ /**
+ * Remove file from it's respective .ignore files. As specified for @see addToIgnoreList
+ * function, this means that, for example, if you remove '/home/mario/src/myprj/mylib/module1/bad.cpp'
+ * then a search for the string 'bad.cpp' will be performed on file
+ * '/home/mario/src/myprj/mylib/module1/.cvsignore': if found, it will be removed, otherwise
+ * nothing will be removed.
+ * @param projectDirectory
+ * @param url url to be removed from the check list.
+ */
+ static void removeFromIgnoreList( const QString &projectDirectory, const KURL &url );
+
+ /**
+ * Remove files from their respective .ignore files. As specified for @see addToIgnoreList
+ * function, this means that, for example, if you remove '/home/mario/src/myprj/mylib/module1/bad.cpp'
+ * then a search for the string 'bad.cpp' will be performed on file
+ * '/home/mario/src/myprj/mylib/module1/.cvsignore': if found, it will be removed, otherwise
+ * nothing will be removed.
+ * @param projectDirectory
+ * @param urls list of urls to be removed from the check list.
+ */
+ static void removeFromIgnoreList( const QString &projectDirectory, const KURL::List &urls );
+ /**
+ * Implementation for requesting user input when files are added to project
+ */
+ void addFilesToProject( const QStringList &filesToAdd );
+ /**
+ * Implementation for requesting user input when files are removed from project
+ */
+ void removedFilesFromProject(const QStringList &filesToRemove);
+ /**
+ * Check each file in the list against CVS and returns a new list with the files
+ * currently registered in the repository: if none is registered the returned list
+ * is (quite rightly) empty.
+ */
+ QStringList checkFileListAgainstCVS( const QStringList &filesToCheck ) const;
+
+ //! Changelog filename (currently "CHANGELOG" )
+ static const QString changeLogFileName;
+ //! Four spaces for every log line (except the first which includes the
+ //! developers name)
+ static const QString changeLogPrependString;
+
+ // Internal short-cuts
+ KDevMainWindow *mainWindow() const;
+ KDevCore *core() const;
+ QString projectDirectory() const;
+ KDevDiffFrontend *diffFrontend() const;
+
+ /** Locate and setup DCOP CvsService */
+ bool requestCvsService();
+ /** De-initialize and release CvsService */
+ void releaseCvsService();
+
+ CvsService_stub *m_cvsService;
+ Repository_stub *m_repository;
+
+ /** Used for storing module path between start and ending of check-out */
+ QString modulePath;
+
+ CVSFileInfoProvider *m_fileInfoProvider;
+ JobScheduler *m_scheduler;
+ /** Reference to owner part */
+ CvsServicePart *m_part;
+
+ //! Reference to widget integrated in the "bottom tabbar" (IDEAL)
+ //! (_Must_ be initialized by derived class)
+ QGuardedPtr<CvsProcessWidget> m_widget;
+
+ //! Urls which to work upon
+ const KURL::List &urlList() const;
+ /**
+ * @param relativeToProjectDir if true paths will be provided as relative to project directory,
+ * as absolute paths otherwise
+ * @return These are the file path contained in the urls provided for convenience
+ * has been requested for.
+ */
+ QStringList fileList( bool relativeToProjectDir = true ) const;
+ /** Last operation type: we save it so we can retrieve and use in slot*Exited() */
+ CvsOperation lastOperation() const;
+
+ // Both this data members are set by prepareOperation() method
+ KURL::List m_urlList;
+ CvsOperation m_lastOperation;
+};
+
+#endif
diff --git a/vcs/cvsservice/cvsprocesswidget.cpp b/vcs/cvsservice/cvsprocesswidget.cpp
new file mode 100644
index 00000000..2d41a356
--- /dev/null
+++ b/vcs/cvsservice/cvsprocesswidget.cpp
@@ -0,0 +1,288 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <dcopref.h>
+#include <kstatusbar.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "kdevpartcontroller.h"
+#include "kdevmainwindow.h"
+#include "kdevcore.h"
+
+#include "cvspart.h"
+#include "cvsprocesswidget.h"
+#include "processwidget.h"
+
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+// Undef
+//#define MYDCOPDEBUG
+
+///////////////////////////////////////////////////////////////////////////////
+// class CvsProcessWidget
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef MYDCOPDEBUG
+int g_dcopExitCounter = 0;
+int g_dcopOutCounter = 0;
+int g_dcopErrCounter = 0;
+#endif
+
+
+CvsProcessWidget::CvsProcessWidget( CvsService_stub *service, CvsServicePart *part, QWidget *parent, const char *name )
+ : DCOPObject( "CvsProcessWidgetDCOPIface" ),
+ QTextEdit( parent, name ),
+ m_part( part ), m_service( service ), m_job( 0 )
+{
+ setReadOnly( true );
+ setTextFormat( Qt::LogText );
+
+ QStyleSheetItem *style = 0;
+ style = new QStyleSheetItem( styleSheet(), "goodtag" );
+ style->setColor( "black" );
+
+ style = new QStyleSheetItem( styleSheet(), "errortag" );
+ style->setColor( "red" );
+ style->setFontWeight( QFont::Bold );
+
+ style = new QStyleSheetItem( styleSheet(), "infotag" );
+ style->setColor( "blue" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_conflict" );
+ style->setColor( "red" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_added" );
+ style->setColor( "green" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_removed" );
+ style->setColor( "yellow" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_updated" );
+ style->setColor( "lightblue" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_modified" );
+ style->setColor( "darkgreen" );
+
+ style = new QStyleSheetItem( styleSheet(), "cvs_unknown" );
+ style->setColor( "gray" );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+CvsProcessWidget::~CvsProcessWidget()
+{
+ if (m_job)
+ {
+ delete m_job;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsProcessWidget::isAlreadyWorking() const
+{
+ if (m_job)
+ return m_job->isRunning();
+ else
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::clear()
+{
+ QTextEdit::clear();
+ this->m_errors = QString::null;
+ this->m_output = QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool CvsProcessWidget::startJob( const DCOPRef &aJob )
+{
+ kdDebug(9006) << "CvsProcessWidget::startJob(const DCOPRef &) here!" << endl;
+
+ clear();
+ m_part->mainWindow()->raiseView( this );
+ m_part->core()->running( m_part, true );
+
+ // create a DCOP stub for the non-concurrent cvs job
+ if (m_job)
+ {
+ delete m_job;
+ m_job = 0;
+ }
+ m_job = new CvsJob_stub( aJob.app(), aJob.obj() );
+
+ // establish connections to the signals of the cvs m_job
+ connectDCOPSignal( m_job->app(), m_job->obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ connectDCOPSignal( m_job->app(), m_job->obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+ connectDCOPSignal( m_job->app(), m_job->obj(), "receivedStderr(QString)", "slotReceivedErrors(QString)", true );
+
+ // get command line and add it to output buffer
+ QString cmdLine = m_job->cvsCommand();
+ m_part->mainWindow()->statusBar()->message( cmdLine );
+
+ kdDebug(9006) << "Running: " << cmdLine << endl;
+
+ // disconnect 3rd party slots from our signals
+ disconnect( SIGNAL(jobFinished(bool, int)) );
+
+ showInfo( i18n("Started job: %1").arg( cmdLine ) );
+
+#ifdef MYDCOPDEBUG
+ g_dcopExitCounter = 0;
+ g_dcopOutCounter = 0;
+ g_dcopErrCounter = 0;
+#endif
+
+ return m_job->execute();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::cancelJob()
+{
+ kdDebug(9006) << "CvsProcessWidget::cancelJob() here!" << endl;
+
+ if (!m_job || !m_job->isRunning())
+ return;
+ m_job->cancel();
+ delete m_job; m_job = 0;
+
+ showInfo( i18n("*** Job canceled by user request ***") );
+
+ m_part->core()->running( m_part, false );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::slotJobExited( bool normalExit, int exitStatus )
+{
+ kdDebug(9006) << "CvsProcessWidget::slotJobExited(bool, int) here!" << endl;
+#ifdef MYDCOPDEBUG
+ g_dcopExitCounter++;
+ kdDebug(9006) << "MYDCOPDEBUG: dcopExitCounter == " << g_dcopExitCounter << endl;
+#endif
+ if (m_job)
+ {
+ disconnectDCOPSignal( m_job->app(), m_job->obj(), "jobExited(bool, int)", "slotJobExited(bool, int)" );
+ disconnectDCOPSignal( m_job->app(), m_job->obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)" );
+ disconnectDCOPSignal( m_job->app(), m_job->obj(), "receivedStderr(QString)", "slotReceivedErrors(QString)" );
+ delete m_job;
+ m_job = 0;
+ }
+ QString exitMsg = i18n("Job finished with exitCode == %1");
+ showInfo( exitMsg.arg( exitStatus) );
+
+ m_part->core()->running( m_part, false );
+ m_part->mainWindow()->statusBar()->message( i18n("Done CVS command ..."), 2000 );
+
+ emit jobFinished( normalExit, exitStatus );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::slotReceivedOutput( QString someOutput )
+{
+ kdDebug(9006) << "CvsProcessWidget::slotReceivedOutput(QString) here!" << endl;
+#ifdef MYDCOPDEBUG
+ g_dcopOutCounter++;
+ kdDebug(9006) << "MYDCOPDEBUG: dcopOutCounter == " << g_dcopOutCounter << endl;
+#endif
+
+ QStringList strings = m_outputBuffer.process( someOutput );
+ if (strings.count() > 0)
+ {
+ m_output += strings;
+ showOutput( strings );
+ scrollToBottom();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::slotReceivedErrors( QString someErrors )
+{
+ kdDebug(9006) << "CvsProcessWidget::slotReceivedErrors(QString) here!" << endl;
+#ifdef MYDCOPDEBUG
+ g_dcopErrCounter++;
+ kdDebug(9006) << "MYDCOPDEBUG: dcopErrCounter == " << g_dcopErrCounter << endl;
+#endif
+
+ QStringList strings = m_errorBuffer.process( someErrors );
+ if (strings.count() > 0)
+ {
+ m_errors += strings;
+ showError( strings );
+ scrollToBottom();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::showInfo( const QStringList &msg )
+{
+ for (QStringList::const_iterator it = msg.begin(); it != msg.end(); ++it)
+ append( "<infotag>" + (*it) + "</infotag>" );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::showError( const QStringList &msg )
+{
+ for (QStringList::const_iterator it = msg.begin(); it != msg.end(); ++it)
+ append( "<errortag>" + (*it) + "</errortag>" );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CvsProcessWidget::showOutput( const QStringList &msg )
+{
+ for (QStringList::const_iterator it = msg.begin(); it != msg.end(); ++it)
+ {
+ // @todo here we can interpret lines as [C], [M], ...
+ const QString &line = (*it);
+
+ //If the line already contains tags we need to replace the
+ //delimiters with the corresponding HTML code so that they are no longer
+ //recognized as tags.
+ //This will prevent QTextEdit from crashing on trying to parse the tags.
+ //This should fix BUG:99590
+ QString lineNew(line);
+ lineNew.replace("<", "&lt;");
+ lineNew.replace(">", "&gt;");
+ lineNew.replace("&", "&amp;");
+
+ if (line.startsWith( "C " ))
+ append( "<cvs_conflict>" + lineNew + "</cvs_conflict>" );
+ else if (line.startsWith( "M " ))
+ append( "<cvs_modified>" + lineNew + "</cvs_modified>" );
+ else if (line.startsWith( "A " ))
+ append( "<cvs_added>" + lineNew + "</cvs_added>" );
+ else if (line.startsWith( "R " ))
+ append( "<cvs_removed>" + lineNew + "</cvs_removed>" );
+ else if (line.startsWith( "U " ))
+ append( "<cvs_updated>" + lineNew + "</cvs_updated>" );
+ else if (line.startsWith( "? " ))
+ append( "<cvs_unknown>" + lineNew + "</cvs_unknown>" );
+ else // default
+ append( "<goodtag>" + lineNew + "</goodtag>" );
+ }
+}
+
+#include "cvsprocesswidget.moc"
diff --git a/vcs/cvsservice/cvsprocesswidget.h b/vcs/cvsservice/cvsprocesswidget.h
new file mode 100644
index 00000000..cb55205c
--- /dev/null
+++ b/vcs/cvsservice/cvsprocesswidget.h
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _CVSPROCESSWIDGET_H_
+#define _CVSPROCESSWIDGET_H_
+
+#include <qtextedit.h>
+#include <qstringlist.h>
+
+#include "cvsservicedcopIface.h"
+#include "bufferedstringreader.h"
+
+class CvsServicePart;
+class DCOPRef;
+class CvsJob_stub;
+class CvsService_stub;
+class QStyleSheetItem;
+
+class CvsProcessWidget : public QTextEdit, virtual public CVSServiceDCOPIface
+{
+ Q_OBJECT
+public:
+ CvsProcessWidget( CvsService_stub *service, CvsServicePart *part,
+ QWidget *parent, const char *name );
+ virtual ~CvsProcessWidget();
+
+ bool startJob( const DCOPRef &aJob );
+
+ /**
+ * @return true if there is already a job pending, false otherwise
+ * (another job can be requested)
+ */
+ bool isAlreadyWorking() const;
+ void cancelJob();
+
+ virtual void clear();
+
+ QStringList output() const { return m_output; }
+ QStringList errors() const { return m_errors; }
+
+//private slots:
+ //! DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+signals:
+ void jobFinished( bool normalExit, int exitStatus );
+
+private:
+ void showInfo( const QStringList &msg );
+ void showError( const QStringList &msg );
+ void showOutput( const QStringList &msg );
+
+ CvsServicePart *m_part;
+ CvsService_stub *m_service;
+ CvsJob_stub *m_job;
+
+ //! Buffered reader for safely reading stdout and stderr from cvs
+ //! commands' output
+ BufferedStringReader m_outputBuffer,
+ m_errorBuffer;
+
+ QStringList m_output,
+ m_errors;
+};
+
+#endif
+
diff --git a/vcs/cvsservice/cvsservicedcopIface.h b/vcs/cvsservice/cvsservicedcopIface.h
new file mode 100644
index 00000000..14cd8629
--- /dev/null
+++ b/vcs/cvsservice/cvsservicedcopIface.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * Copyright (C) 2003 by KDevelop Authors *
+ * www.kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <dcopobject.h>
+
+#ifndef __CVSSERVICEDCOPIFACE_H_
+#define __CVSSERVICEDCOPIFACE_H_
+/**
+* DCOP Iface for classes which use CvsService services.
+*/
+class CVSServiceDCOPIface : virtual public DCOPObject
+{
+ K_DCOP
+k_dcop:
+ virtual void slotJobExited( bool normalExit, int exitStatus ) = 0;
+ virtual void slotReceivedOutput( QString someOutput ) = 0;
+ virtual void slotReceivedErrors( QString someErrors ) = 0;
+};
+
+#endif
diff --git a/vcs/cvsservice/diffdialog.cpp b/vcs/cvsservice/diffdialog.cpp
new file mode 100644
index 00000000..37ba79fc
--- /dev/null
+++ b/vcs/cvsservice/diffdialog.cpp
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <klineedit.h>
+#include <qradiobutton.h>
+
+#include "diffdialog.h"
+#include <klocale.h>
+#include <qbuttongroup.h>
+
+///////////////////////////////////////////////////////////////////////////////
+// class DiffDialog
+///////////////////////////////////////////////////////////////////////////////
+
+DiffDialog::DiffDialog( const CVSEntry &entry, QWidget *parent, const char *name, WFlags f )
+ : DiffDialogBase( parent, name, true, f)
+{
+ m_entry = entry;
+ QString currentRevision = entry.revision();
+ revaEdit->setText(currentRevision);
+ revbEdit->setText(currentRevision);
+ revOtherEdit->setText(currentRevision);
+ languageChange();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DiffDialog::~DiffDialog()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+DiffDialog::DiffType DiffDialog::requestedDiff() const
+{
+ if (diffArbitraryRevRadio->isChecked())
+ return diffArbitrary;
+ else if (diffLocalOtherRadio->isChecked())
+ return diffLocalOther;
+ else if (diffLocalBaseRadio->isChecked())
+ return diffLocalBASE;
+ else
+ return diffLocalHEAD;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString DiffDialog::revA() const
+{
+ if (requestedDiff() == diffArbitrary)
+ return revaEdit->text();
+ else if (requestedDiff() == diffLocalOther)
+ return revOtherEdit->text();
+ else if (requestedDiff() == diffLocalHEAD)
+ return "HEAD";
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString DiffDialog::revB() const
+{
+ if (requestedDiff())
+ return this->revbEdit->text();
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void DiffDialog::languageChange() {
+ DiffDialogBase::languageChange();
+ //buttonGroup1->setTitle( tr2i18n( "Build Difference Between" ) );
+
+ //FIXME: We need a function in CVSEntry to return the latest revision there is in cvs
+// if(!m_entry.revision().isNull())
+// diffLocalHeadRadio->setText( tr2i18n( "Local copy and &HEAD (%1)" ).arg( m_entry.revision()) );
+}
+
+#include "diffdialog.moc"
diff --git a/vcs/cvsservice/diffdialog.h b/vcs/cvsservice/diffdialog.h
new file mode 100644
index 00000000..12bfc88a
--- /dev/null
+++ b/vcs/cvsservice/diffdialog.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DIFFDIALOG_H
+#define __DIFFDIALOG_H
+
+#include "diffdialogbase.h"
+#include "cvsentry.h"
+
+/**
+* Implementation for a dialog which collects data for diff operation
+*
+* @author Mario Scalas
+*/
+class DiffDialog : public DiffDialogBase
+{
+ Q_OBJECT
+public:
+ DiffDialog(const CVSEntry &entry, QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ virtual ~DiffDialog();
+
+ QString revA() const;
+ QString revB() const;
+
+private:
+ enum DiffType { diffLocalBASE, diffLocalHEAD, diffLocalOther, diffArbitrary };
+
+ DiffType requestedDiff() const;
+ CVSEntry m_entry;
+protected slots:
+ virtual void languageChange();
+};
+
+#endif // __DIFFDIALOG_H
diff --git a/vcs/cvsservice/diffdialogbase.ui b/vcs/cvsservice/diffdialogbase.ui
new file mode 100644
index 00000000..0290c530
--- /dev/null
+++ b/vcs/cvsservice/diffdialogbase.ui
@@ -0,0 +1,275 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DiffDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>DiffDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>246</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Choose Revisions to Diff</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Build Difference Between</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>diffLocalOtherRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Local copy and an arbitrary &amp;revision:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>revOtherEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>diffArbitraryRevRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Two arbitrary revisions/tags:</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="4" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Revision A:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>revbEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Second revision to compare (leave empty to diff against HEAD)</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="0">
+ <property name="name">
+ <cstring>revaEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>First revision to compare</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Revision B:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>diffLocalHeadRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Local cop&amp;y and HEAD</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>diffLocalBaseRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Local copy a&amp;nd BASE</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>DiffDialog</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>DiffDialog</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>diffArbitraryRevRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>revaEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>diffArbitraryRevRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>revbEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>diffLocalOtherRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>revOtherEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>diffLocalBaseRadio</tabstop>
+ <tabstop>diffLocalHeadRadio</tabstop>
+ <tabstop>diffLocalOtherRadio</tabstop>
+ <tabstop>revOtherEdit</tabstop>
+ <tabstop>revaEdit</tabstop>
+ <tabstop>revbEdit</tabstop>
+ <tabstop>buttonOk</tabstop>
+ <tabstop>buttonCancel</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/diffwidget.cpp b/vcs/cvsservice/diffwidget.cpp
new file mode 100644
index 00000000..c51c16b0
--- /dev/null
+++ b/vcs/cvsservice/diffwidget.cpp
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qtextedit.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qfile.h>
+
+#include <kconfig.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kservice.h>
+#include <ktempfile.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+
+#include <kparts/componentfactory.h>
+#include <kparts/part.h>
+
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+
+#include "diffwidget.h"
+
+// yup, magic value for the popupmenu-id
+static const int POPUP_BASE = 130977;
+
+QStringList KDiffTextEdit::extParts;
+QStringList KDiffTextEdit::extPartsTranslated;
+
+KDiffTextEdit::KDiffTextEdit( QWidget* parent, const char* name ): QTextEdit( parent, name )
+{
+ KConfig* config = kapp->config();
+ config->setGroup( "Diff" );
+ _highlight = config->readBoolEntry( "Highlight", true );
+
+ searchExtParts();
+}
+
+KDiffTextEdit::~KDiffTextEdit()
+{
+ KConfig* config = kapp->config();
+
+ config->setGroup( "Diff" );
+ config->writeEntry( "Highlight", _highlight );
+}
+
+QPopupMenu* KDiffTextEdit::createPopupMenu()
+{
+ return createPopupMenu( QPoint() );
+}
+
+QPopupMenu* KDiffTextEdit::createPopupMenu( const QPoint& p )
+{
+ QPopupMenu* popup = QTextEdit::createPopupMenu( p );
+ if ( !popup )
+ popup = new QPopupMenu( this );
+
+ int i = 0;
+
+ for ( QStringList::Iterator it = extPartsTranslated.begin(); it != extPartsTranslated.end(); ++it ) {
+ popup->insertItem( i18n( "Show in %1" ).arg( *it ), i + POPUP_BASE, i );
+ i++;
+ }
+ if ( !extPartsTranslated.isEmpty() )
+ popup->insertSeparator( i );
+ connect( popup, SIGNAL(activated(int)), this, SLOT(popupActivated(int)) );
+
+ popup->insertItem( SmallIconSet( "filesaveas" ), i18n( "&Save As..." ), this, SLOT(saveAs()), CTRL + Key_S, POPUP_BASE - 2, 0 );
+ popup->setItemEnabled( POPUP_BASE - 2, length() > 0 );
+
+ popup->insertSeparator( 1 );
+
+ popup->insertItem( i18n( "Highlight Syntax" ), this, SLOT(toggleSyntaxHighlight()), 0, POPUP_BASE - 1, 2 );
+ popup->setItemChecked( POPUP_BASE - 1, _highlight );
+ popup->insertSeparator( 3 );
+
+ return popup;
+}
+
+void KDiffTextEdit::saveAs()
+{
+ QString fName = KFileDialog::getSaveFileName();
+ if ( fName.isEmpty() )
+ return;
+
+ QFile f( fName );
+ if ( f.open( IO_WriteOnly ) ) {
+ QTextStream stream( &f );
+ int pCount = paragraphs();
+ for ( int i = 0; i < pCount; ++i )
+ stream << text( i ) << "\n";
+ f.close();
+ } else {
+ KMessageBox::sorry( this, i18n("Unable to open file."), i18n("Diff Frontend") );
+ }
+}
+
+void KDiffTextEdit::toggleSyntaxHighlight()
+{
+ _highlight = !_highlight;
+ if ( _highlight )
+ applySyntaxHighlight();
+ else
+ clearSyntaxHighlight();
+}
+
+void KDiffTextEdit::applySyntaxHighlight()
+{
+ // the diff has been loaded so we apply a simple highlighting
+ static QColor cAdded( 190, 190, 237);
+ static QColor cRemoved( 190, 237, 190 );
+
+ if ( !_highlight )
+ return;
+
+ int paragCount = paragraphs();
+ for ( int i = 0; i < paragCount; ++i ) {
+ QString txt = text( i );
+ if ( txt.length() > 0 ) {
+ if ( txt.startsWith( "+" ) || txt.startsWith( ">" ) ) {
+ setParagraphBackgroundColor( i, cAdded );
+ } else if ( txt.startsWith( "-" ) || txt.startsWith( "<" ) ) {
+ setParagraphBackgroundColor( i, cRemoved );
+ }
+ }
+ }
+}
+
+void KDiffTextEdit::clearSyntaxHighlight()
+{
+ int paragCount = paragraphs();
+ for ( int i = 0; i < paragCount; ++i ) {
+ clearParagraphBackground( i );
+ }
+}
+
+void KDiffTextEdit::searchExtParts()
+{
+ // only execute once
+ static bool init = false;
+ if ( init )
+ return;
+ init = true;
+
+ // search all parts that can handle text/x-diff
+ KTrader::OfferList offers = KTrader::self()->query("text/x-diff", "('KParts/ReadOnlyPart' in ServiceTypes) and ('text/x-diff' in ServiceTypes)");
+ KTrader::OfferList::const_iterator it;
+ for ( it = offers.begin(); it != offers.end(); ++it ) {
+ KService::Ptr ptr = (*it);
+ extPartsTranslated << ptr->name();
+ extParts << ptr->desktopEntryName();
+ }
+ return;
+}
+
+void KDiffTextEdit::popupActivated( int id )
+{
+ id -= POPUP_BASE;
+ if ( id < 0 || id > (int)extParts.count() )
+ return;
+
+ emit externalPartRequested( extParts[ id ] );
+}
+
+DiffWidget::DiffWidget( QWidget *parent, const char *name, WFlags f ):
+ QWidget( parent, name, f ), tempFile( 0 )
+{
+ job = 0;
+ extPart = 0;
+
+ te = new KDiffTextEdit( this, "Main Diff Viewer" );
+ te->setReadOnly( true );
+ te->setTextFormat( QTextEdit::PlainText );
+// te->setMinimumSize( 300, 200 );
+ connect( te, SIGNAL(externalPartRequested(const QString&)), this, SLOT(loadExtPart(const QString&)) );
+
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->addWidget( te );
+}
+
+DiffWidget::~DiffWidget()
+{
+ delete tempFile;
+}
+
+void DiffWidget::setExtPartVisible( bool visible )
+{
+ if ( !extPart || !extPart->widget() ) {
+ te->show();
+ return;
+ }
+ if ( visible ) {
+ te->hide();
+ extPart->widget()->show();
+ } else {
+ te->show();
+ extPart->widget()->hide();
+ }
+}
+
+void DiffWidget::loadExtPart( const QString& partName )
+{
+ if ( extPart ) {
+ setExtPartVisible( false );
+ delete extPart;
+ extPart = 0;
+ }
+
+ KService::Ptr extService = KService::serviceByDesktopName( partName );
+ if ( !extService )
+ return;
+
+ extPart = KParts::ComponentFactory::createPartInstanceFromService<KParts::ReadOnlyPart>( extService, this, 0, this, 0 );
+ if ( !extPart || !extPart->widget() )
+ return;
+
+ layout()->add( extPart->widget() );
+
+ setExtPartVisible( true );
+
+ if ( te->paragraphs() > 0 )
+ populateExtPart();
+}
+
+void DiffWidget::slotClear()
+{
+ te->clear();
+ if ( extPart )
+ extPart->closeURL();
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotAppend( const QString& str )
+{
+ te->append( str );
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotAppend( KIO::Job*, const QByteArray& ba )
+{
+ slotAppend( QString( ba ) );
+}
+
+void DiffWidget::populateExtPart()
+{
+ if ( !extPart )
+ return;
+
+ bool ok = false;
+ int paragCount = te->paragraphs();
+ if ( extPart->openStream( "text/plain", KURL() ) ) {
+ for ( int i = 0; i < paragCount; ++i )
+ extPart->writeStream( te->text( i ).local8Bit() );
+ ok = extPart->closeStream();
+ } else {
+ // workaround for parts that cannot handle streams
+ delete tempFile;
+ tempFile = new KTempFile();
+ tempFile->setAutoDelete( true );
+ for ( int i = 0; i < paragCount; ++i )
+ *(tempFile->textStream()) << te->text( i ) << endl;
+ tempFile->close();
+ ok = extPart->openURL( KURL( tempFile->name() ) );
+ }
+ if ( !ok )
+ setExtPartVisible( false );
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotFinished()
+{
+ te->applySyntaxHighlight();
+ populateExtPart();
+}
+
+void DiffWidget::setDiff( const QString& diff )
+{
+ slotClear();
+ slotAppend( diff );
+ slotFinished();
+}
+
+void DiffWidget::openURL( const KURL& url )
+{
+ if ( job )
+ job->kill();
+
+ KIO::TransferJob* job = KIO::get( url );
+ if ( !job )
+ return;
+
+ connect( job, SIGNAL(data( KIO::Job *, const QByteArray & )),
+ this, SLOT(slotAppend( KIO::Job*, const QByteArray& )) );
+ connect( job, SIGNAL(result( KIO::Job * )),
+ this, SLOT(slotFinished()) );
+}
+
+void DiffWidget::contextMenuEvent( QContextMenuEvent* /* e */ )
+{
+ QPopupMenu* popup = new QPopupMenu( this );
+
+ if ( !te->isVisible() )
+ popup->insertItem( i18n("Display &Raw Output"), this, SLOT(showTextEdit()) );
+
+ popup->exec( QCursor::pos() );
+ delete popup;
+}
+
+void DiffWidget::showExtPart()
+{
+ setExtPartVisible( true );
+}
+
+void DiffWidget::showTextEdit()
+{
+ setExtPartVisible( false );
+}
+
+#include "diffwidget.moc"
diff --git a/vcs/cvsservice/diffwidget.h b/vcs/cvsservice/diffwidget.h
new file mode 100644
index 00000000..d7aaf48c
--- /dev/null
+++ b/vcs/cvsservice/diffwidget.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _DIFFWIDGET_H_
+#define _DIFFWIDGET_H_
+
+#include <qwidget.h>
+#include <qtextedit.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+
+class KTempFile;
+
+namespace KIO {
+ class Job;
+}
+
+namespace KParts {
+ class ReadOnlyPart;
+}
+
+// Helper class that displays a modified RMB popup menu
+class KDiffTextEdit: public QTextEdit
+{
+ Q_OBJECT
+public:
+ KDiffTextEdit( QWidget* parent = 0, const char* name = 0 );
+ virtual ~KDiffTextEdit();
+ void applySyntaxHighlight();
+ void clearSyntaxHighlight();
+
+signals:
+ void externalPartRequested( const QString& partName );
+
+protected:
+ virtual QPopupMenu* createPopupMenu( const QPoint& );
+ virtual QPopupMenu* createPopupMenu();
+
+private slots:
+ void popupActivated( int );
+ void toggleSyntaxHighlight();
+ void saveAs();
+
+private:
+ static void searchExtParts();
+ static QStringList extParts;
+ static QStringList extPartsTranslated;
+ bool _highlight;
+};
+
+class DiffWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DiffWidget( QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ virtual ~DiffWidget();
+
+public slots:
+ /** The URL has to point to a diff file */
+ void openURL( const KURL& url );
+ /** Pass a diff file in here */
+ void setDiff( const QString& diff );
+ /** clears the difference viewer */
+ void slotClear();
+
+private slots:
+ /** appends a piece of "diff" */
+ void slotAppend( const QString& str );
+ /** overloaded for convenience */
+ void slotAppend( KIO::Job*, const QByteArray& ba );
+ /** call this when the whole "diff" has been sent.
+ * Don't call slotAppend afterwards!
+ */
+ void slotFinished();
+ void showExtPart();
+ void showTextEdit();
+ void loadExtPart( const QString& partName );
+
+protected:
+ void contextMenuEvent( QContextMenuEvent* e );
+
+private:
+ void setExtPartVisible( bool visible );
+ void populateExtPart();
+
+private:
+ KDiffTextEdit* te;
+ KIO::Job* job;
+ KParts::ReadOnlyPart* extPart;
+ KTempFile* tempFile;
+};
+
+#endif
diff --git a/vcs/cvsservice/editorsdialog.cpp b/vcs/cvsservice/editorsdialog.cpp
new file mode 100644
index 00000000..12319102
--- /dev/null
+++ b/vcs/cvsservice/editorsdialog.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kmessagebox.h>
+#include <kcursor.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <dcopref.h>
+
+#include <qtextbrowser.h>
+#include <qregexp.h>
+
+#include "editorsdialog.h"
+
+//dcop connection to cervisia
+#include <cvsjob_stub.h>
+#include <cvsservice_stub.h>
+
+EditorsDialog::EditorsDialog(CvsService_stub *cvsService, QWidget *parent, const char *name)
+ : DCOPObject( "CvsEditorsDCOPIface"), EditorsDialogBase(parent, name, TRUE, Qt::WDestructiveClose),
+ m_cvsService(cvsService), m_cvsJob(0)
+{
+}
+
+EditorsDialog::~EditorsDialog()
+{
+ kdDebug(9006) << "EditorsDialog::~EditorsDialog"<< endl;
+
+ if (m_cvsJob && m_cvsJob->isRunning()) {
+ m_cvsJob->cancel();
+ }
+ if (m_cvsJob)
+ delete m_cvsJob;
+}
+
+void EditorsDialog::startjob(QString strDir)
+{
+ kdDebug(9006) << "EditorsDialog::start() workDir = " << strDir << endl;
+
+ DCOPRef job = m_cvsService->editors( strDir );
+ m_cvsJob = new CvsJob_stub( job.app(), job.obj() );
+
+ // establish connections to the signals of the cvs m_job
+ connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true );
+ // We'll read the ouput directly from the job ...
+ connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true );
+
+ kdDebug(9006) << "Running: " << m_cvsJob->cvsCommand() << endl;
+ m_cvsJob->execute();
+}
+
+void EditorsDialog::slotJobExited( bool normalExit, int exitStatus )
+{
+ if (!normalExit)
+ {
+ KMessageBox::sorry( this, i18n("Log failed with exitStatus == %1").arg( exitStatus), i18n("Log Failed") );
+ return;
+ }
+
+ static QRegExp re("([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s"
+ "([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s(.*)");
+ static QRegExp subre("([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s"
+ "([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s([^\\s]+)\\s(.*)");
+ QString lastfilename;
+
+ QStringList lines = QStringList::split( "\n", m_output );
+ int found = 0;
+ for (size_t i=0; i<lines.count(); ++i) {
+ QString s = lines[i].simplifyWhiteSpace();
+ kdDebug(9006) << "editors:---" << s << "---" << endl;
+ kdDebug(9006) << " : lastfile was " << lastfilename << endl;
+
+ if (re.exactMatch(s)) {
+ QString file = re.cap( 1 );
+ QString locker = re.cap( 2 );
+ QString date = re.cap(5)+" "+re.cap(4)+" "+re.cap(7)+" "+re.cap(6);
+
+ m_textBrowser->append( "<b>"+i18n("File")+": <code>"+file+"</code></b>" );
+ m_textBrowser->append( "<b>"+i18n("User")+":</b> "+locker );
+ m_textBrowser->append( "<b>"+i18n("Date")+":</b> "+date );
+ m_textBrowser->append( "<hr>" );
+ found++;
+
+ lastfilename = file;
+ } else {
+ if (subre.exactMatch(s)) {
+ QString file = lastfilename;
+ QString locker = subre.cap( 1 );
+ QString date = subre.cap(4)+" "+subre.cap(3)+" "+subre.cap(6)+" "+subre.cap(5);
+
+ m_textBrowser->append( "<b>"+i18n("File")+": <code>"+file+"</code></b>" );
+ m_textBrowser->append( "<b>"+i18n("User")+":</b> "+locker );
+ m_textBrowser->append( "<b>"+i18n("Date")+":</b> "+date );
+ m_textBrowser->append( "<hr>" );
+ found++;
+ }
+ }
+ }
+
+ if (!found)
+ m_textBrowser->append(i18n("No files from your query are marked as being edited."));
+
+ m_textBrowser->source();
+
+ if (m_cvsJob) {
+ disconnectDCOPSignal( m_cvsJob->app(), m_cvsJob->obj(), "jobExited(bool, int)", "slotJobExited(bool, int)" );
+ delete m_cvsJob;
+ m_cvsJob=NULL;
+ }
+}
+
+void EditorsDialog::slotReceivedOutput( QString someOutput )
+{
+ kdDebug(9006) << "OUTPUT: " << someOutput << endl;
+
+ m_output += someOutput; //append the whole output into one large QStrin
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void EditorsDialog::slotReceivedErrors( QString someErrors )
+{
+ kdDebug(9006) << "ERRORS: " << someErrors << endl;
+}
+
+#include "editorsdialog.moc"
diff --git a/vcs/cvsservice/editorsdialog.h b/vcs/cvsservice/editorsdialog.h
new file mode 100644
index 00000000..1aedbc64
--- /dev/null
+++ b/vcs/cvsservice/editorsdialog.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Robert Gruber *
+ * rgruber@users.sourceforge.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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef EDITORSDIALOG_H
+#define EDITORSDIALOG_H
+
+#include "editorsdialogbase.h"
+#include "cvsservicedcopIface.h"
+
+class CvsJob_stub;
+class CvsService_stub;
+class QStringList;
+
+class EditorsDialog: public EditorsDialogBase, virtual public CVSServiceDCOPIface
+{
+Q_OBJECT
+public:
+ EditorsDialog(CvsService_stub *cvsService, QWidget *parent = 0, const char *name = 0);
+ virtual ~EditorsDialog();
+
+ void startjob(QString strDir);
+
+private slots:
+ // DCOP Iface
+ virtual void slotJobExited( bool normalExit, int exitStatus );
+ virtual void slotReceivedOutput( QString someOutput );
+ virtual void slotReceivedErrors( QString someErrors );
+
+private:
+ CvsService_stub *m_cvsService;
+ CvsJob_stub *m_cvsJob;
+ QString m_output;
+};
+
+#endif
diff --git a/vcs/cvsservice/editorsdialogbase.ui b/vcs/cvsservice/editorsdialogbase.ui
new file mode 100644
index 00000000..b0cb925a
--- /dev/null
+++ b/vcs/cvsservice/editorsdialogbase.ui
@@ -0,0 +1,88 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EditorsDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>EditorsDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>282</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Editors</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="0">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QTextBrowser" row="0" column="0">
+ <property name="name">
+ <cstring>m_textBrowser</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>EditorsDialogBase</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/integrator/Makefile.am b/vcs/cvsservice/integrator/Makefile.am
new file mode 100644
index 00000000..7768aad5
--- /dev/null
+++ b/vcs/cvsservice/integrator/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \
+ $(all_includes)
+METASOURCES = AUTO
+kde_module_LTLIBRARIES = libcvsserviceintegrator.la
+libcvsserviceintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
+libcvsserviceintegrator_la_LIBADD = \
+ $(top_builddir)/lib/interfaces/extras/libkdevextras.la $(top_builddir)/lib/libkdevelop.la -lcvsservice
+noinst_HEADERS = cvsserviceintegrator.h integratordlg.h
+libcvsserviceintegrator_la_SOURCES = cvsserviceintegrator.cpp \
+ integratordlgbase.ui fetcherdlgbase.ui integratordlg.cpp initdlg.ui
+kde_services_DATA = kdevcvsserviceintegrator.desktop
diff --git a/vcs/cvsservice/integrator/cvsserviceintegrator.cpp b/vcs/cvsservice/integrator/cvsserviceintegrator.cpp
new file mode 100644
index 00000000..f23e3831
--- /dev/null
+++ b/vcs/cvsservice/integrator/cvsserviceintegrator.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "cvsserviceintegrator.h"
+
+#include <kdevgenericfactory.h>
+#include <kdevplugininfo.h>
+
+#include "integratordlg.h"
+
+static const KDevPluginInfo data("kdevcvsserviceintegrator");
+typedef KDevGenericFactory<CVSServiceIntegrator> CVSIntegratorFactory;
+K_EXPORT_COMPONENT_FACTORY( libcvsserviceintegrator, CVSIntegratorFactory(data) )
+
+CVSServiceIntegrator::CVSServiceIntegrator(QObject* parent, const char* name,
+ const QStringList args)
+ :KDevVCSIntegrator(parent, name)
+{
+}
+
+CVSServiceIntegrator::~CVSServiceIntegrator( )
+{
+}
+
+VCSDialog* CVSServiceIntegrator::fetcher(QWidget* parent)
+{
+ return 0;
+}
+
+VCSDialog* CVSServiceIntegrator::integrator(QWidget* parent)
+{
+ IntegratorDlg *dlg = new IntegratorDlg(this, parent);
+ return dlg;
+}
+
+#include "cvsserviceintegrator.moc"
diff --git a/vcs/cvsservice/integrator/cvsserviceintegrator.h b/vcs/cvsservice/integrator/cvsserviceintegrator.h
new file mode 100644
index 00000000..46d3bdeb
--- /dev/null
+++ b/vcs/cvsservice/integrator/cvsserviceintegrator.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef CVSSERVICEINTEGRATOR_H
+#define CVSSERVICEINTEGRATOR_H
+
+#include <kdevvcsintegrator.h>
+
+#include <qstringlist.h>
+
+class CVSServiceIntegrator: public KDevVCSIntegrator {
+Q_OBJECT
+public:
+ CVSServiceIntegrator(QObject* parent, const char* name, const QStringList args = QStringList());
+ virtual ~CVSServiceIntegrator();
+
+ virtual VCSDialog* fetcher(QWidget* parent);
+ virtual VCSDialog* integrator(QWidget* parent);
+
+};
+
+#endif
diff --git a/vcs/cvsservice/integrator/fetcherdlgbase.ui b/vcs/cvsservice/integrator/fetcherdlgbase.ui
new file mode 100644
index 00000000..be0556c2
--- /dev/null
+++ b/vcs/cvsservice/integrator/fetcherdlgbase.ui
@@ -0,0 +1,153 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>FetcherDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>FetcherDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>458</width>
+ <height>110</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>module</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Branch tag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboBox5</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Repository:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>repository</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>repository</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Fetch &amp;List</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Module:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>module</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>comboBox5</cstring>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer row="3" column="1">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>repository</tabstop>
+ <tabstop>module</tabstop>
+ <tabstop>pushButton2</tabstop>
+ <tabstop>comboBox5</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/integrator/initdlg.ui b/vcs/cvsservice/integrator/initdlg.ui
new file mode 100644
index 00000000..1b36ecfb
--- /dev/null
+++ b/vcs/cvsservice/integrator/initdlg.ui
@@ -0,0 +1,71 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>InitDlg</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>InitDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>346</width>
+ <height>63</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Choose Repository Location</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1_2_2_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Repository location:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>location</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="0" column="1">
+ <property name="name">
+ <cstring>location</cstring>
+ </property>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/cvsservice/integrator/integratordlg.cpp b/vcs/cvsservice/integrator/integratordlg.cpp
new file mode 100644
index 00000000..8f3fc2b5
--- /dev/null
+++ b/vcs/cvsservice/integrator/integratordlg.cpp
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "integratordlg.h"
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <qcheckbox.h>
+
+#include <kapplication.h>
+#include <kdialogbase.h>
+#include <kurlrequester.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klineedit.h>
+
+#include <cvsservice_stub.h>
+
+#include "initdlg.h"
+
+IntegratorDlg::IntegratorDlg(CVSServiceIntegrator *integrator, QWidget *parent, const char *name)
+ :IntegratorDlgBase(parent, name), m_integrator(integrator)
+{
+ QFile cvspass(QDir::homeDirPath() + "/.cvspass");
+ if (cvspass.open(IO_ReadOnly))
+ {
+ QTextStream stream(&cvspass);
+ while (!stream.atEnd())
+ {
+ QString line = stream.readLine();
+ QStringList recs = QStringList::split(" ", line, false);
+ repository->insertItem(recs[1]);
+ }
+ cvspass.close();
+ }
+}
+
+void IntegratorDlg::init_clicked()
+{
+ KDialogBase dlg(KDialogBase::Plain, i18n("Init CVS Repository"), KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok);
+ dlg.plainPage()->setMargin(0);
+ (new QVBoxLayout(dlg.plainPage(), 0, 0))->setAutoAdd(true);
+ InitDlg *initDlg = new InitDlg(dlg.plainPage());
+ initDlg->show();
+
+ initDlg->location->setFocus();
+ initDlg->location->setMode(KFile::Directory);
+ QRegExp localrep(":local:(.*)");
+ if (localrep.search(repository->currentText()) != -1)
+ initDlg->location->setURL(localrep.cap(1));
+
+ if (dlg.exec() == QDialog::Accepted)
+ {
+ QString url = initDlg->location->url();
+ KProcess *proc = new KProcess();
+ *proc << "cvs";
+ *proc << "-d" << url << "init";
+ proc->start(KProcess::Block);
+ if (!proc->normalExit())
+ KMessageBox::error(this, i18n("cvs init did not exit normally. Please check if cvs is installed and works correctly."), i18n("Init CVS Repository"));
+ else if (proc->exitStatus() != 0)
+ KMessageBox::error(this, i18n("cvs init exited with status %1. Please check if the cvs location is correct.").arg(proc->exitStatus()), i18n("Init CVS Repository"));
+ else
+ {
+ repository->insertItem(QString(":local:%1").arg(url));
+ repository->setCurrentText(QString(":local:%1").arg(url));
+ }
+ }
+}
+
+void IntegratorDlg::login_clicked()
+{
+ QCString appId;
+ QString error;
+
+ if (KApplication::startServiceByDesktopName("cvsservice",
+ QStringList(), &error, &appId))
+ {
+ QString msg = i18n("Unable to find the Cervisia KPart. \n"
+ "Cervisia Integration will not be available. Please check your\n"
+ "Cervisia installation and re-try. Reason was:\n") + error;
+ KMessageBox::error(this, msg, "DCOP Error");
+ }
+ else
+ {
+ CvsService_stub *cvsService = new CvsService_stub(appId, "CvsService");
+ cvsService->login(repository->currentText());
+ }
+}
+
+void IntegratorDlg::accept()
+{
+ if (m_projectLocation.isEmpty())
+ return;
+
+ if (!createModule->isChecked())
+ return;
+
+ KProcess *proc = new KProcess();
+ proc->setWorkingDirectory(m_projectLocation);
+ *proc << "cvs";
+ *proc << "-d" << repository->currentText() << "import"
+ << "-m" << QString("\"%1\"").arg(comment->text()) << module->text()
+ << vendorTag->text() << releaseTag->text();
+ proc->start(KProcess::Block);
+ if (!proc->normalExit())
+ KMessageBox::error(this, i18n("cvs import did not exit normally. Please check if cvs is installed and works correctly."), i18n("Init CVS Repository"));
+ else if (proc->exitStatus() != 0)
+ KMessageBox::error(this, i18n("cvs import exited with status %1. Please check if the cvs location is correct.").arg(proc->exitStatus()), i18n("Init CVS Repository"));
+ else
+ {
+ kdDebug() << "Project is in: " << m_projectLocation << endl;
+
+ KURL url = KURL::fromPathOrURL(m_projectLocation);
+ QString up = url.upURL().path();
+ kdDebug() << "Up is: " << up << endl;
+
+ //delete sources in project dir
+ KProcess *rmproc = new KProcess();
+ *rmproc << "rm";
+ *rmproc << "-f" << "-r" << m_projectLocation;
+ rmproc->start(KProcess::Block);
+
+ //checkout sources from cvs
+ KProcess *coproc = new KProcess();
+ coproc->setWorkingDirectory(up);
+ *coproc << "cvs";
+ *coproc << "-d" << repository->currentText() << "checkout" << "-d" << m_projectName << module->text();
+ coproc->start(KProcess::Block);
+ }
+
+/* QCString appId;
+ QString error;
+
+ if (KApplication::startServiceByDesktopName("cvsservice",
+ QStringList(), &error, &appId))
+ {
+ QString msg = i18n("Unable to find the Cervisia KPart. \n"
+ "Cervisia Integration will not be available. Please check your\n"
+ "Cervisia installation and re-try. Reason was:\n") + error;
+ KMessageBox::error(this, msg, "DCOP Error");
+ }
+ else
+ {
+ kdDebug() << "!!!!! IMPORT" << endl;
+ CvsService_stub *cvsService = new CvsService_stub(appId, "CvsService");
+ cvsService->import(m_projectLocation, repository->currentText(), module->text(),
+ "", comment->text(), vendorTag->text(), releaseTag->text(), false);
+ }*/
+}
+
+void IntegratorDlg::createModule_clicked()
+{
+}
+
+QWidget *IntegratorDlg::self()
+{
+ return const_cast<IntegratorDlg*>(this);
+}
+
+void IntegratorDlg::init(const QString &projectName, const QString &projectLocation)
+{
+ if( m_projectName != projectName )
+ module->setText(projectName);
+ m_projectName = projectName;
+ m_projectLocation = projectLocation;
+}
+
+#include "integratordlg.moc"
diff --git a/vcs/cvsservice/integrator/integratordlg.h b/vcs/cvsservice/integrator/integratordlg.h
new file mode 100644
index 00000000..5d0ad950
--- /dev/null
+++ b/vcs/cvsservice/integrator/integratordlg.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef INTEGRATORDLG_H
+#define INTEGRATORDLG_H
+
+#include "integratordlgbase.h"
+#include "cvsserviceintegrator.h"
+
+class QDomDocument;
+
+class IntegratorDlg: public IntegratorDlgBase, public VCSDialog {
+Q_OBJECT
+public:
+ IntegratorDlg(CVSServiceIntegrator *integrator, QWidget *parent = 0, const char *name = 0);
+
+ virtual QWidget *self();
+ virtual void init(const QString &projectName, const QString &projectLocation);
+
+public slots:
+ virtual void login_clicked();
+ virtual void init_clicked();
+ virtual void accept();
+ virtual void createModule_clicked();
+
+private:
+ CVSServiceIntegrator *m_integrator;
+ QString m_projectLocation;
+ QString m_projectName;
+};
+
+#endif
diff --git a/vcs/cvsservice/integrator/integratordlgbase.ui b/vcs/cvsservice/integrator/integratordlgbase.ui
new file mode 100644
index 00000000..e17f44e1
--- /dev/null
+++ b/vcs/cvsservice/integrator/integratordlgbase.ui
@@ -0,0 +1,398 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>IntegratorDlgBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>IntegratorDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>540</width>
+ <height>212</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>createModule</cstring>
+ </property>
+ <property name="text">
+ <string>Create module in the repository</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>vendorTag</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>vendor</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="4">
+ <property name="name">
+ <cstring>init</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Init Local Repository...</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>repository</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="3">
+ <property name="name">
+ <cstring>login</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Login to &amp;Repository...</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="6" column="2">
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KLineEdit" row="2" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>module</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>moduleLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Mo&amp;dule:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>module</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>vendorLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Vendor tag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>vendorTag</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>releaseLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Re&amp;lease tag:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>releaseTag</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>commentLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Co&amp;mment:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comment</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>repositoryLabel</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Repository:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>repository</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="5" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>comment</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>First Import</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="4" column="1" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>releaseTag</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>start</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>init</sender>
+ <signal>clicked()</signal>
+ <receiver>IntegratorDlgBase</receiver>
+ <slot>init_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>login</sender>
+ <signal>clicked()</signal>
+ <receiver>IntegratorDlgBase</receiver>
+ <slot>login_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>clicked()</signal>
+ <receiver>IntegratorDlgBase</receiver>
+ <slot>createModule_clicked()</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>repositoryLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>repository</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>login</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>init</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>moduleLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>module</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>vendorLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>vendorTag</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>releaseLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>releaseTag</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>commentLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createModule</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>comment</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>repository</tabstop>
+ <tabstop>module</tabstop>
+ <tabstop>vendorTag</tabstop>
+ <tabstop>releaseTag</tabstop>
+ <tabstop>comment</tabstop>
+ <tabstop>login</tabstop>
+ <tabstop>init</tabstop>
+</tabstops>
+<slots>
+ <slot>init_clicked()</slot>
+ <slot>login_clicked()</slot>
+ <slot>createModule_clicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/integrator/kdevcvsserviceintegrator.desktop b/vcs/cvsservice/integrator/kdevcvsserviceintegrator.desktop
new file mode 100644
index 00000000..f8c8a5f3
--- /dev/null
+++ b/vcs/cvsservice/integrator/kdevcvsserviceintegrator.desktop
@@ -0,0 +1,45 @@
+[Desktop Entry]
+Type=Service
+Name=KDevCVSIntegrator
+Name[da]=KDevelop CVS-integration
+Name[nds]=KDevelop-CVS-Integreren
+Name[sk]=KDev CVS integrácia
+Name[sv]=KDevelop CVS-integration
+Name[zh_TW]=KDevelop CVS æ•´åˆå™¨
+Comment=CVS Service Project Integration Facility
+Comment[ca]=Facilitat d'integració amb projectes que usin CVS
+Comment[da]=CVS service projektintegration
+Comment[de]=CVS-Dienst-Projektintegration
+Comment[el]=ΛειτουÏγία ενσωμάτωσης υπηÏεσίας CVS στο έÏγο
+Comment[es]=Facilidad de integración con proyectos que utilicen CVS
+Comment[et]=CVS-teenuse projekti põimimisvahend
+Comment[eu]=CVS zerbitzuen proiektuen integrazio-tresna
+Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ خدمت CVS
+Comment[fr]=Fonction d'intégration pour un projet utilisant le service CVS
+Comment[gl]=Utilidade para a integración de proxectos do servizo CVS
+Comment[hu]=Integrálás a Cvsservice-szel
+Comment[it]=Funzione di integrazione del progetto CVS Service
+Comment[ja]=CVS サービス プロジェクト統åˆãƒ„ール
+Comment[ms]=Kemudahan Integrasi Projek Servis CVS
+Comment[nds]=Projektintegreren för den CVS-Deenst
+Comment[ne]=CVS सेवा परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾
+Comment[nl]=CVS project-integratie
+Comment[pl]=Integracja z usługą CVS
+Comment[pt]=Integração com Projectos de Serviço CVS
+Comment[pt_BR]=Facilidade de Integração ao Projeto do Serviço CVS
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ CVS
+Comment[sk]=Integrácia CVS projektu
+Comment[sr]=Интеграција Cervisia-је у пројекат
+Comment[sr@Latn]=Integracija Cervisia-je u projekat
+Comment[sv]=Funktion för integrering av CVS-tjänst i projekt
+Comment[tr]=CVS Servis Projesi Bütünleştirme Aracı
+Comment[zh_CN]=CVS æœåŠ¡å·¥ç¨‹é›†æˆåŠŸèƒ½
+Comment[zh_TW]=CVS æœå‹™å°ˆæ¡ˆæ•´åˆå·¥å…·
+Icon=cervisia
+Exec=blubb
+ServiceTypes=KDevelop/VCSIntegrator
+X-KDE-Library=libcvsserviceintegrator
+X-KDevelop-Default=true
+X-KDevelop-VCS=CVS
+X-KDevelop-VCSPlugin=kdevcvsservice
+X-KDevelop-Version=5
diff --git a/vcs/cvsservice/jobscheduler.cpp b/vcs/cvsservice/jobscheduler.cpp
new file mode 100644
index 00000000..0c9a55ea
--- /dev/null
+++ b/vcs/cvsservice/jobscheduler.cpp
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "jobscheduler.h"
+
+#include "cvsprocesswidget.h"
+
+#include "kdebug.h"
+#include "dcopref.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class JobScheduler
+///////////////////////////////////////////////////////////////////////////////
+
+JobScheduler::JobScheduler( CvsProcessWidget *aProcessWidget )
+ : m_processWidget( aProcessWidget )
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+JobScheduler::~JobScheduler()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// class DirectScheduler
+///////////////////////////////////////////////////////////////////////////////
+
+DirectScheduler::DirectScheduler( CvsProcessWidget *aProcessWidget )
+ : JobScheduler( aProcessWidget )
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool DirectScheduler::schedule( DCOPRef &job )
+{
+ if (job.isNull())
+ {
+ kdDebug(9006) << "DirectScheduler::schedule(DCOPRef &): Job is null and will be rejected!" << endl;
+ return false;
+ }
+ processWidget()->startJob( job );
+
+ return true;
+}
diff --git a/vcs/cvsservice/jobscheduler.h b/vcs/cvsservice/jobscheduler.h
new file mode 100644
index 00000000..3bf7397a
--- /dev/null
+++ b/vcs/cvsservice/jobscheduler.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef JOBSCHEDULER_H
+#define JOBSCHEDULER_H
+
+class CvsProcessWidget;
+class CvsJob_stub;
+class DCOPRef;
+
+/**
+ * A simple interface for CVS jobs scheduling
+ *
+ * @author Mario Scalas
+*/
+class JobScheduler
+{
+public:
+ JobScheduler( CvsProcessWidget *aProcessWidget );
+ virtual ~JobScheduler();
+
+ virtual bool schedule( DCOPRef &job ) = 0;
+
+ CvsProcessWidget *processWidget() const { return m_processWidget; }
+
+private:
+ CvsProcessWidget *m_processWidget;
+};
+
+
+/**
+ * An implementation which simply run the job, without any buffering
+ *
+*/
+class DirectScheduler : public JobScheduler
+{
+public:
+ DirectScheduler( CvsProcessWidget *aProcessWidget );
+
+ virtual bool schedule( DCOPRef &job );
+};
+
+#endif
diff --git a/vcs/cvsservice/kdev_cvs.png b/vcs/cvsservice/kdev_cvs.png
new file mode 100644
index 00000000..921b0674
--- /dev/null
+++ b/vcs/cvsservice/kdev_cvs.png
Binary files differ
diff --git a/vcs/cvsservice/kdev_cvs.xcf b/vcs/cvsservice/kdev_cvs.xcf
new file mode 100644
index 00000000..aafee609
--- /dev/null
+++ b/vcs/cvsservice/kdev_cvs.xcf
Binary files differ
diff --git a/vcs/cvsservice/kdevcvsservice.desktop b/vcs/cvsservice/kdevcvsservice.desktop
new file mode 100644
index 00000000..4aa7226c
--- /dev/null
+++ b/vcs/cvsservice/kdevcvsservice.desktop
@@ -0,0 +1,77 @@
+[Desktop Entry]
+Type=Service
+Exec=blubb
+Comment=CVS Integration using Cervisia's cvsservice. http://www.kde.org/apps/cervisia/
+Comment[ca]=Integració amb el CVS emprant el cvsservice de Cervisia. http://www.kde.org/apps/cervisia/
+Comment[da]=CVS Integration ved brug af Cervisias cvsservice. http://www.kde.org/apps/cervisia/
+Comment[de]=CVS-Integration mit Hilfe von Cervisias cvsservice. http://www.kde.org/apps/cervisia/
+Comment[el]=Ενσωμάτωση CVS χÏησιμοποιώντας τη cvsservice του Cervisia. http://www.kde.org/apps/cervisia/
+Comment[es]=Integración con CVS utilizando el cvsservice. http://www.kde.org/apps/cervisia/
+Comment[et]=CVS põimimine Cervisia cvsservice'i abil. http://www.kde.org/apps/cervisia/
+Comment[eu]=CVS integrazioa Cervisia-ren cvsservice erabiliz. http://www.kde.org/apps/cervisia/
+Comment[fa]=مجتمع‌سازی CVSØŒ با استÙاده از خدمت cvs متعلق به Cervisia. http://www.kde.org/apps/cervisia/
+Comment[fr]=Intégration de CVS à l'aide du processus « cvsservice » de Cervisia. http://www.kde.org/apps/cervisia/
+Comment[ga]=Comhtháthú CVS le cvsservice Cervisia. http://www.kde.org/apps/cervisia/
+Comment[gl]=Integración CVS usando o servizo cvsservice de Cervisia. http://www.kde.org/apps/cervisia/
+Comment[hu]=CVS-integráció a Cervisia cvsservice segítségével. http://www.kde.org/apps/cervisia/
+Comment[it]=Integrazione del CVS utilizzando il cvsservice di Cervisia. http://www.kde.org/apps/cervisia/
+Comment[ja]=CVS çµ±åˆã¯ã€Cervisia ã® CVS サービスを利用ã—ã¾ã™ã€‚http://www.kde.org/apps/cervisia/
+Comment[ms]=Integrasi CVS menggunakan cvsservice Cervisia. http://www.kde.org/apps/cervisia/
+Comment[nds]=CVS-Integreren över den CVS-Service vun Cervisia. http://www.kde.org/apps/cervisia/
+Comment[ne]= Cervisia's cvsservice पà¥à¤°à¤¯à¥‹à¤— गरेर CVS à¤à¤•à¤¿à¤•à¤°à¤£ । http://www.kde.org/apps/cervisia/
+Comment[nl]=CVS-integratie via Cervisia's cvsservice. Zie http://www.kde.org/apps/cervisia/
+Comment[pl]=Integracja z CVS-em za pomocą usługi CVS Cervisii http://www.kde.org/apps/cervisia/
+Comment[pt]=Integração do CVS usando o cvsservice do Cervisia. http://www.kde.org/apps/cervisia/
+Comment[pt_BR]=Integração com o CVS usando o cvsservice do Cervisia. http://www.kde.org/apps/cervisia/
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ CVS Ñ Ð¸Ñпользованием Cervisia cvsservice. http://www.kde.org/apps/cervisia/
+Comment[sk]=Integrácia CVS pomocou Cervisia Cvs služby. http://www.kde.org/apps/cervisia/
+Comment[sl]=Integracija CVS z uporabo Cervisijeve cvsservice. http://www.kde.org/apps/cervisia/
+Comment[sr]=Интеграција CVS-а помоћу Cervisia-jиног cvsservice. http://www.kde.org/apps/cervisia/
+Comment[sr@Latn]=Integracija CVS-a pomoću Cervisia-jinog cvsservice. http://www.kde.org/apps/cervisia/
+Comment[sv]=Integrering av CVS med användning av Cervisias CVS-tjänst. http://www.kde.org/apps/cervisia/
+Comment[tr]=Cervisia'nın cvsservice'i kullanılarak CVS bütünleştirilmesi http://www.kde.org/apps/cervisia/
+Comment[zh_CN]=使用 Cervisia çš„ cvsservice çš„ CVS 集æˆã€‚http://www.kde.org/apps/cervisia/
+Comment[zh_TW]=使用 Cervisia æœå‹™åš CVS æ•´åˆã€‚http://www.kde.org/apps/cervisia/
+Name=KDevCvsService
+Name[da]=KDevelop CVS-service
+Name[nds]=KDevelop-CVS-Deenst
+Name[sk]=KDev Cvs služba
+Name[sv]=KDevelop CVS-tjänst
+Name[zh_TW]=KDevelop CVS æœå‹™
+GenericName=CVS Integration (Cervisia)
+GenericName[ca]=Integració amb CVS (Cervisia)
+GenericName[de]=Unterstützung für CVS (Cervisia)
+GenericName[el]=Ενσωμάτωση CVS (Cervisia)
+GenericName[es]=Integración con CVS (Cervisia)
+GenericName[et]=CVS põimimine (Cervisia)
+GenericName[eu]=CVS integrazioa (Cervisia)
+GenericName[fa]=مجتمع‌سازی CVS (Cervisia)
+GenericName[fr]=Intégration de CVS (Cervisia)
+GenericName[ga]=Comhtháthú CVS (Cervisia)
+GenericName[gl]=Integración CVS (Cervisia)
+GenericName[hu]=CVS-integráció (Cervisia)
+GenericName[it]=Integrazione CVS (Cervisia)
+GenericName[ja]=CVS çµ±åˆ (Cervisia)
+GenericName[ms]=Integrasi CVS (Cervisia)
+GenericName[nds]=Ünnerstütten för CVS (Cervisia)
+GenericName[ne]=CVS à¤à¤•à¤¿à¤•à¤°à¤£ (Cervisia)
+GenericName[nl]=CVS-integratie (Cervisia)
+GenericName[pl]=Integracja z CVS-em (Cervisia)
+GenericName[pt]=Integração com CVS (Cervisia)
+GenericName[pt_BR]=Integração com o CVS (Cervisia)
+GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ CVS (Cervisia)
+GenericName[sk]=CVS integrácia (Cervisia)
+GenericName[sl]=Integracija CVS (Cervisia)
+GenericName[sr]=Интеграција CVS-а (Cervisia)
+GenericName[sr@Latn]=Integracija CVS-a (Cervisia)
+GenericName[sv]=Integrering av CVS (Cervisia)
+GenericName[ta]=CVS à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆ (செரà¯à®µà®¿à®šà®¿à®¯à®¾)
+GenericName[tg]=ИнтегратÑиÑи CVS (Cervisia)
+GenericName[tr]=CVS Bütünleştirmesi (Cervisia)
+GenericName[zh_CN]=CVS 集æˆ(Cervisia)
+GenericName[zh_TW]=CVS æ•´åˆï¼ˆCervisia)
+Icon=cervisia
+ServiceTypes=KDevelop/VersionControl
+X-KDE-Library=libkdevcvsservice
+X-KDevelop-Version=5
+X-KDevelop-Properties=VCS,CVSService
diff --git a/vcs/cvsservice/kdevcvsservicepart.rc b/vcs/cvsservice/kdevcvsservicepart.rc
new file mode 100644
index 00000000..a1bce434
--- /dev/null
+++ b/vcs/cvsservice/kdevcvsservicepart.rc
@@ -0,0 +1,36 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KDevCvsServicePart" version="2">
+<MenuBar>
+ <Menu name="tools">
+ <Menu name="version_control">
+ <Text>&amp;Version Control</Text>
+ <Merge />
+ <Menu name="version_control_tools_cvsservice" group="tools_project_operations">
+ <Text>&amp;CVS Service</Text>
+ <Action name="cvsservice_commit" />
+ <Action name="cvsservice_diff" />
+ <Action name="cvsservice_log" />
+ <Action name="cvsservice_annotate" />
+ <Action name="cvsservice_editors" />
+ <Action name="cvsservice_edit" />
+ <Action name="cvsservice_unedit" />
+ <Action name="cvsservice_add" />
+ <Action name="cvsservice_add_bin" />
+ <Action name="cvsservice_remove" />
+ <Separator />
+ <Action name="cvsservice_tag" />
+ <Action name="cvsservice_untag" />
+ <Action name="cvsservice_update" />
+ <Action name="cvsservice_removesticky" />
+ <Separator />
+ <Action name="cvsservice_ignore" />
+ <Action name="cvsservice_donot_ignore" />
+ <Separator />
+ <Action name="cvsservice_login" />
+ <Action name="cvsservice_logout" />
+ </Menu>
+ </Menu>
+ </Menu>
+</MenuBar>
+</kpartgui>
+
diff --git a/vcs/cvsservice/releaseinputdialog.cpp b/vcs/cvsservice/releaseinputdialog.cpp
new file mode 100644
index 00000000..31907769
--- /dev/null
+++ b/vcs/cvsservice/releaseinputdialog.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <klineedit.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+
+#include "releaseinputdialog.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class ReleaseInputDialog
+///////////////////////////////////////////////////////////////////////////////
+
+ReleaseInputDialog::ReleaseInputDialog( QWidget* parent)
+ : ReleaseInputDialogBase( parent, "releaseinputdialog", true, 0 )
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ReleaseInputDialog::~ReleaseInputDialog()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool ReleaseInputDialog::isRevert() const
+{
+ return revertCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString ReleaseInputDialog::release() const
+{
+ if (type() == byRevision)
+ return " -r " + revisionEdit->text();
+ else if (type() == byDate)
+ return " -D " + dateEdit->text();
+ else
+ return QString::null;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ReleaseInputDialog::ReleaseType ReleaseInputDialog::type() const
+{
+ if (revisionRadio->isChecked())
+ return byRevision;
+ else if (dateRadio->isChecked())
+ return byDate;
+ else
+ return byHead;
+}
+
+#include "releaseinputdialog.moc"
+
diff --git a/vcs/cvsservice/releaseinputdialog.h b/vcs/cvsservice/releaseinputdialog.h
new file mode 100644
index 00000000..5de2c3e6
--- /dev/null
+++ b/vcs/cvsservice/releaseinputdialog.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef RELEASEINPUTDIALOG_H
+#define RELEASEINPUTDIALOG_H
+
+#include "releaseinputdialogbase.h"
+
+/**
+* Every time an operation needs to prompt the user about a release name,
+* it can use this class: just customize the message to display
+*/
+class ReleaseInputDialog : public ReleaseInputDialogBase
+{
+ Q_OBJECT
+
+public:
+ /**
+ * C-tor
+ * @param parent
+ */
+ ReleaseInputDialog( QWidget* parent = 0 );
+ /**
+ * Destructor
+ */
+ virtual ~ReleaseInputDialog();
+
+ /**
+ * @return a QString formatted as "-r <RELEASE-TAG> " or "-D <RELEASE-DATE> "
+ * so it can be embedded in the command line.
+ */
+ QString release() const;
+
+ /**
+ * @return true if the user has checked "rever": enforce operation then even
+ * if the files have been locally modified.
+ */
+ bool isRevert() const;
+
+private:
+ enum ReleaseType { byHead, byDate, byRevision };
+
+ ReleaseType type() const;
+};
+
+#endif
+
diff --git a/vcs/cvsservice/releaseinputdialogbase.ui b/vcs/cvsservice/releaseinputdialogbase.ui
new file mode 100644
index 00000000..be5bf136
--- /dev/null
+++ b/vcs/cvsservice/releaseinputdialogbase.ui
@@ -0,0 +1,246 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>ReleaseInputDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ReleaseInputDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>626</width>
+ <height>239</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Update/Revert to Release/Branch/Date</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Revision</string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignLeft</set>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>headRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Most recent from current branch</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>revisionRadio</cstring>
+ </property>
+ <property name="text">
+ <string>An arbitrary &amp;revision/tag/branch:</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>revisionEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Type your release name here (leave empty for HEAD)</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Fill the field with the release or branch name (e.g. &lt;i&gt;make_it_cool, kdevelop_alpha5, ...&lt;/i&gt;)</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>dateRadio</cstring>
+ </property>
+ <property name="text">
+ <string>An arbitrary &amp;date:</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>dateEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>FIll the field with a date (e.g. &lt;i&gt;20030204&lt;/i&gt;)</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Additional Options</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>revertCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Enforce even if the file has been locally modified (revert)</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>140</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>ReleaseInputDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>ReleaseInputDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>dateRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>dateEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>revisionRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>revisionEdit</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/cvsservice/tagdialog.cpp b/vcs/cvsservice/tagdialog.cpp
new file mode 100644
index 00000000..846cfce9
--- /dev/null
+++ b/vcs/cvsservice/tagdialog.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <klineedit.h>
+#include <qcheckbox.h>
+
+#include "tagdialog.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// class TagDialog
+///////////////////////////////////////////////////////////////////////////////
+
+TagDialog::TagDialog( const QString &caption, QWidget *parent, const char *name )
+ : TagDialogBase( parent, name ? name : "tagdialog", true )
+{
+ if (!caption.isEmpty())
+ {
+ setCaption( caption );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+TagDialog::~TagDialog()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void TagDialog::accept()
+{
+ if (tagBranchEdit->text().isEmpty())
+ return;
+
+ TagDialogBase::accept();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString TagDialog::tagName() const
+{
+ return tagBranchEdit->text();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+QString TagDialog::branchName() const
+{
+ return tagName();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool TagDialog::isBranch() const
+{
+ return tagAsBranchCheck->isChecked();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool TagDialog::force() const
+{
+ return forceCheck->isChecked();
+}
+
+#include "tagdialog.moc"
diff --git a/vcs/cvsservice/tagdialog.h b/vcs/cvsservice/tagdialog.h
new file mode 100644
index 00000000..86b63010
--- /dev/null
+++ b/vcs/cvsservice/tagdialog.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2003 by Mario Scalas *
+ * mario.scalas@libero.it *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TAGDIALOG_H
+#define TAGDIALOG_H
+
+#include "tagdialogbase.h"
+
+/**
+* Implementation for a dialog collecting data for tagging / branching
+* CVS repositories.
+*
+* @author Mario Scalas
+*/
+class TagDialog : public TagDialogBase
+{
+ Q_OBJECT
+public:
+ TagDialog( const QString &caption, QWidget *parent = 0, const char *name = 0 );
+ virtual ~TagDialog();
+
+ /**
+ * @return the tag name selected by the user
+ */
+ QString tagName() const;
+ /**
+ * @return the branch name selected by the user
+ */
+ QString branchName() const;
+ /**
+ * @return true if the user want to branch the selected files
+ */
+ bool isBranch() const;
+ /**
+ * @return true if operation must be enforced
+ */
+ bool force() const;
+
+protected slots:
+ virtual void accept();
+};
+
+#endif
diff --git a/vcs/cvsservice/tagdialogbase.ui b/vcs/cvsservice/tagdialogbase.ui
new file mode 100644
index 00000000..ce816c2d
--- /dev/null
+++ b/vcs/cvsservice/tagdialogbase.ui
@@ -0,0 +1,159 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>TagDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>TagDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>410</width>
+ <height>175</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Tag Files on CVS Repository</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Tag/Branch &amp;name:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>tagBranchEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>tagBranchEdit</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>tagAsBranchCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Tag as &amp;branch</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>forceCheck</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Force</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>200</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>TagDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>TagDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/perforce/Makefile.am b/vcs/perforce/Makefile.am
new file mode 100644
index 00000000..e684e2f0
--- /dev/null
+++ b/vcs/perforce/Makefile.am
@@ -0,0 +1,19 @@
+# Here resides the cvs part
+
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util $(all_includes)
+
+kde_module_LTLIBRARIES = libkdevperforce.la
+libkdevperforce_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+libkdevperforce_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la
+
+libkdevperforce_la_SOURCES = perforcepart.cpp commitdlg.cpp
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = kdevperforce.desktop
+
+rcdir = $(kde_datadir)/kdevperforce
+
+SUBDIRS = integrator
diff --git a/vcs/perforce/README b/vcs/perforce/README
new file mode 100644
index 00000000..731741e1
--- /dev/null
+++ b/vcs/perforce/README
@@ -0,0 +1,3 @@
+Please read the on-line, automaticaly updated KDevelop API documentation at:
+http://www.kdevelop.org
+or read the README.dox file.
diff --git a/vcs/perforce/README.dox b/vcs/perforce/README.dox
new file mode 100644
index 00000000..6a0ae647
--- /dev/null
+++ b/vcs/perforce/README.dox
@@ -0,0 +1,15 @@
+/** \class PerforcePart
+Integrates the perforce version managment system into KDevelop.
+
+\authors <a href="mailto:bernd AT kdevelop.org">Bernd Gehrmann</a> Copyright (C) 1999-2001
+\authors <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a> Copyright (C) 2002-2003
+
+\maintainer <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a>
+
+\feature edit, revert and submit
+\feature use the diff frontend (also removes the crappy perforce diff headers)
+\feature Uses KAction, so you can assign your favourite shortcuts to the commands.
+
+\requirement Perforce 2003.1 http://www.perforce.com/perforce/products.html
+
+*/
diff --git a/vcs/perforce/commitdlg.cpp b/vcs/perforce/commitdlg.cpp
new file mode 100644
index 00000000..8a9be561
--- /dev/null
+++ b/vcs/perforce/commitdlg.cpp
@@ -0,0 +1,161 @@
+/***************************************************************************
+ * Copyright (C) 1999, 2000 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Modified for perforce 2002 by Harald Fernengel <harry@kdevelop.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "commitdlg.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <qpushbutton.h>
+#include <qregexp.h>
+#include <kprocess.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include <stdlib.h>
+
+#include "execcommand.h"
+
+CommitDialog::CommitDialog( QWidget *parent, const char *name )
+ : KDialogBase( parent, name, true, i18n("Perforce Submit"), Ok|Cancel|Details )
+{
+ QWidget *w = new QWidget( this, "main widget" );
+ setMainWidget( w );
+
+ edit = new QTextEdit( w );
+ QFontMetrics fm(edit->fontMetrics());
+ edit->setMinimumSize(fm.width("0")*40, fm.lineSpacing()*3);
+
+ QVBoxLayout *layout = new QVBoxLayout( w, 0, spacingHint() );
+ QLabel *editLabel = new QLabel(i18n("&Enter description:"), w);
+ editLabel->setBuddy(edit);
+ layout->addWidget(editLabel);
+ layout->addWidget(edit);
+
+ w = new QWidget( this, "details widget" );
+
+ clientEdit = new KLineEdit( w );
+ userEdit = new KLineEdit( w );
+ filesBox = new KListBox( w );
+
+ layout = new QVBoxLayout( w, 0, spacingHint() );
+ QLabel *clientLabel = new QLabel(i18n("C&lient:"), w);
+ clientLabel->setBuddy(clientEdit);
+ layout->addWidget(clientLabel);
+ layout->addWidget( clientEdit );
+ QLabel *userLabel = new QLabel(i18n("&User:"), w);
+ userLabel->setBuddy(userEdit);
+ layout->addWidget( userLabel );
+ layout->addWidget( userEdit );
+ QLabel *filesLabel = new QLabel(i18n("&File(s):"), w);
+ filesLabel->setBuddy(filesBox);
+ layout->addWidget( filesLabel );
+ layout->addWidget( filesBox );
+
+ setDetailsWidget( w );
+ autoGuess();
+ edit->setFocus();
+}
+
+CommitDialog::~CommitDialog()
+{
+}
+
+void CommitDialog::autoGuess()
+{
+ char *cenv;
+
+ cenv = getenv( "P4USER" );
+ if ( cenv ) {
+ setUser( QString::fromLocal8Bit( cenv ) );
+ }
+
+ cenv = getenv( "P4CLIENT" );
+ if ( cenv ) {
+ setClient( QString::fromLocal8Bit( cenv ) );
+ }
+}
+
+void CommitDialog::setFiles( const QStringList& lst )
+{
+ filesBox->clear();
+ setDepotFiles( lst );
+}
+
+void CommitDialog::setDepotFiles( const QStringList& lst )
+{
+ QStringList args;
+
+ args << "files";
+ for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
+ args << (*it);
+ }
+
+ ExecCommand* cmd = new ExecCommand( "p4", args, QString::null, QStringList(), this );
+ connect( cmd, SIGNAL(finished( const QString&, const QString& )),
+ this, SLOT(getFilesFinished( const QString&, const QString& )) );
+}
+
+void CommitDialog::getFilesFinished( const QString& out, const QString& /* err */ )
+{
+ QStringList lst = QStringList::split( QChar('\n'), out );
+ for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) {
+ int pos = (*it).find( QChar('#') );
+ if ( pos > 1 && (*it).startsWith( "//" ) ) {
+ filesBox->insertItem( (*it).left( pos ) );
+ }
+ }
+}
+
+QString CommitDialog::changeList() const
+{
+ QString lst;
+
+ lst += "Change: new\n"
+ "Client: " + client() + "\n"
+ "User: " + user() + "\n"
+ "Status: new\n"
+ "Description:\n ";
+
+ lst += logMessage().replace(QRegExp("\n"), "\n ") + "\n\n";
+
+ lst += "Files:\n";
+
+ for ( uint i = 0; i < filesBox->count(); ++i ) {
+ lst += " " + filesBox->text( i ) + "\n";
+ }
+
+ return lst;
+}
+
+void CommitDialog::accept()
+{
+ if ( client().isEmpty() ) {
+ setDetails( true );
+ KMessageBox::error( this, i18n("Please enter the P4 client name.") );
+ clientEdit->setFocus();
+ } else if ( user().isEmpty() ) {
+ setDetails( true );
+ KMessageBox::error( this, i18n("Please enter the P4 user.") );
+ userEdit->setFocus();
+ } else if ( filesBox->count() == 0 ) {
+ setDetails( true );
+ KMessageBox::error( this, i18n("The changelist does not contain any files.") );
+ } else {
+ KDialogBase::accept();
+ }
+}
+
+#include "commitdlg.moc"
diff --git a/vcs/perforce/commitdlg.h b/vcs/perforce/commitdlg.h
new file mode 100644
index 00000000..390681fd
--- /dev/null
+++ b/vcs/perforce/commitdlg.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 1999, 2000 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Modified for perforce 2002 by Harald Fernengel <harry@kdevelop.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _COMMITDIALOG_H_
+#define _COMMITDIALOG_H_
+
+#include <qstringlist.h>
+#include <qtextedit.h>
+#include <klineedit.h>
+#include <klistbox.h>
+#include <kdialogbase.h>
+
+class KProcess;
+
+class CommitDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ CommitDialog( QWidget *parent = 0, const char *name = 0 );
+ ~CommitDialog();
+
+ QString logMessage() const { return edit->text(); }
+ QString user() const { return userEdit->text(); }
+ QString client() const { return clientEdit->text(); }
+ QString changeList() const;
+
+ void setUser( const QString& usr ) { userEdit->setText( usr ); }
+ void setClient( const QString& clnt ) { clientEdit->setText( clnt ); }
+ void setFiles( const QStringList& lst );
+
+ /** tries to fill out user and client */
+ void autoGuess();
+
+protected slots:
+ void accept();
+
+private slots:
+ void getFilesFinished( const QString& out, const QString& err );
+
+private:
+ void setDepotFiles( const QStringList& lst );
+ QTextEdit *edit;
+ KLineEdit *clientEdit, *userEdit;
+ KListBox *filesBox;
+};
+
+#endif
+
diff --git a/vcs/perforce/integrator/Makefile.am b/vcs/perforce/integrator/Makefile.am
new file mode 100644
index 00000000..0df84d8e
--- /dev/null
+++ b/vcs/perforce/integrator/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \
+ $(all_includes)
+METASOURCES = AUTO
+kde_module_LTLIBRARIES = libperforceintegrator.la
+libperforceintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
+libperforceintegrator_la_LIBADD =\
+ $(top_builddir)/lib/interfaces/extras/libkdevextras.la\
+ $(top_builddir)/lib/libkdevelop.la
+kde_services_DATA = kdevperforceintegrator.desktop
+noinst_HEADERS = perforceintegrator.h pfintegratordlg.h
+libperforceintegrator_la_SOURCES = perforceintegrator.cpp \
+ pfintegratordlgbase.ui pfintegratordlg.cpp
diff --git a/vcs/perforce/integrator/kdevperforceintegrator.desktop b/vcs/perforce/integrator/kdevperforceintegrator.desktop
new file mode 100644
index 00000000..d70c7f67
--- /dev/null
+++ b/vcs/perforce/integrator/kdevperforceintegrator.desktop
@@ -0,0 +1,44 @@
+[Desktop Entry]
+Type=Service
+Name=KDevPerforceIntegrator
+Name[da]=KDevelop Perforce-integration
+Name[nds]=KDevelop-Perforce-Integreren
+Name[sk]=KDev Perforce integrácia
+Name[sv]=KDevelop Perforce-integration
+Name[zh_TW]=KDevelop Perforce æ•´åˆå™¨
+Comment=Perforce Project Integration Facility
+Comment[ca]=Facilitat per a la integració amb projectes Perforce
+Comment[da]=Perforce projektintegration
+Comment[de]=Perforce-Projektintegration
+Comment[el]=ΛειτουÏγία ενσωμάτωσης Perforce στο έÏγο
+Comment[es]=Entorno para integración con proyectos Perforce
+Comment[et]=Perforce projekti põimimisvahend
+Comment[eu]=Perforce proiektuen integrazio-tresna
+Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ Perforce
+Comment[fr]=Fonction d'intégration pour un projet utilisant Perforce
+Comment[gl]=Utilidade para a integración de proxectos Perforce
+Comment[hu]=Integrálás a Perforce-szal
+Comment[it]=Funzione di integrazione del progetto Perforce
+Comment[ja]=Perforce プロジェクト統åˆãƒ„ール
+Comment[ms]=Kemudahan Integrasi Projek Perforce
+Comment[nds]=Perforce-Projektintegreren
+Comment[ne]=परफोरà¥à¤¸ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾
+Comment[nl]=Perforce project-integratie
+Comment[pl]=Integracja z Perforce
+Comment[pt]=Integração com Projectos Perforce
+Comment[pt_BR]=Facilidade de Integração ao Projeto de Perforce
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Perforce
+Comment[sk]=Perforce projektová integrácia
+Comment[sr]=Интеграција Perforce-а у пројекат
+Comment[sr@Latn]=Integracija Perforce-a u projekat
+Comment[sv]=Funktion för integrering av Perforce i projekt
+Comment[tr]=Perforce Proje Bütünleştirme Aracı
+Comment[zh_CN]=Perforce 工程集æˆåŠŸèƒ½
+Comment[zh_TW]=Perforce 專案整åˆå·¥å…·
+Exec=blubb
+ServiceTypes=KDevelop/VCSIntegrator
+X-KDE-Library=libperforceintegrator
+X-KDevelop-Default=false
+X-KDevelop-VCS=Perforce
+X-KDevelop-VCSPlugin=kdevperforce
+X-KDevelop-Version=5
diff --git a/vcs/perforce/integrator/perforceintegrator.cpp b/vcs/perforce/integrator/perforceintegrator.cpp
new file mode 100644
index 00000000..a5e40a36
--- /dev/null
+++ b/vcs/perforce/integrator/perforceintegrator.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "perforceintegrator.h"
+
+#include <kdevgenericfactory.h>
+#include <kdevplugininfo.h>
+
+#include "pfintegratordlg.h"
+
+static const KDevPluginInfo data("kdevperforceintegrator");
+typedef KDevGenericFactory<PerforceIntegrator> PerforceIntegratorFactory;
+K_EXPORT_COMPONENT_FACTORY( libperforceintegrator, PerforceIntegratorFactory(data) )
+
+PerforceIntegrator::PerforceIntegrator(QObject* parent, const char* name,
+ const QStringList // args
+ )
+ :KDevVCSIntegrator(parent, name)
+{
+}
+
+PerforceIntegrator::~PerforceIntegrator()
+{
+}
+
+VCSDialog* PerforceIntegrator::fetcher(QWidget* // parent
+ )
+{
+ return 0;
+}
+
+VCSDialog* PerforceIntegrator::integrator(QWidget* parent)
+{
+ PFIntegratorDlg *dlg = new PFIntegratorDlg(parent);
+ return dlg;
+}
+
+#include "perforceintegrator.moc"
diff --git a/vcs/perforce/integrator/perforceintegrator.h b/vcs/perforce/integrator/perforceintegrator.h
new file mode 100644
index 00000000..3bb82a2d
--- /dev/null
+++ b/vcs/perforce/integrator/perforceintegrator.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PERFORCEINTEGRATOR_H
+#define PERFORCEINTEGRATOR_H
+
+#include <kdevvcsintegrator.h>
+
+#include <qstringlist.h>
+
+class PerforceIntegrator : public KDevVCSIntegrator
+{
+Q_OBJECT
+public:
+ PerforceIntegrator(QObject* parent, const char* name, const QStringList args = QStringList());
+ ~PerforceIntegrator();
+
+ virtual VCSDialog* fetcher(QWidget* parent);
+ virtual VCSDialog* integrator(QWidget* parent);
+
+};
+
+#endif
diff --git a/vcs/perforce/integrator/pfintegratordlg.cpp b/vcs/perforce/integrator/pfintegratordlg.cpp
new file mode 100644
index 00000000..917f2a20
--- /dev/null
+++ b/vcs/perforce/integrator/pfintegratordlg.cpp
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "pfintegratordlg.h"
+
+PFIntegratorDlg::PFIntegratorDlg(QWidget *parent, const char *name)
+ :PFIntegratorDlgBase(parent, name)
+{
+}
+
+void PFIntegratorDlg::accept()
+{
+}
+
+void PFIntegratorDlg::init(const QString &/*projectName*/, const QString &/*projectLocation*/)
+{
+}
+
+QWidget *PFIntegratorDlg::self()
+{
+ return const_cast<PFIntegratorDlg*>(this);
+}
+
+#include "pfintegratordlg.moc"
diff --git a/vcs/perforce/integrator/pfintegratordlg.h b/vcs/perforce/integrator/pfintegratordlg.h
new file mode 100644
index 00000000..a74b6749
--- /dev/null
+++ b/vcs/perforce/integrator/pfintegratordlg.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef PFINTEGRATORDLG_H
+#define PFINTEGRATORDLG_H
+
+#include "pfintegratordlgbase.h"
+#include <kdevvcsintegrator.h>
+
+class PFIntegratorDlg: public PFIntegratorDlgBase, public VCSDialog {
+Q_OBJECT
+public:
+ PFIntegratorDlg(QWidget *parent = 0, const char *name = 0);
+
+ virtual void accept();
+ virtual void init(const QString &projectName, const QString &projectLocation);
+ virtual QWidget *self();
+};
+
+#endif
diff --git a/vcs/perforce/integrator/pfintegratordlgbase.ui b/vcs/perforce/integrator/pfintegratordlgbase.ui
new file mode 100644
index 00000000..5b12a70f
--- /dev/null
+++ b/vcs/perforce/integrator/pfintegratordlgbase.ui
@@ -0,0 +1,47 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>PFIntegratorDlgBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PFIntegratorDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>600</width>
+ <height>480</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>No options available for this VCS.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>435</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/perforce/kdevperforce.desktop b/vcs/perforce/kdevperforce.desktop
new file mode 100644
index 00000000..678eab7e
--- /dev/null
+++ b/vcs/perforce/kdevperforce.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+Type=Service
+Exec=blubb
+Comment=Integrates Perforce, a software configuration management system. http://www.perforce.com/
+Comment[ca]=Integra Perforce, un sistema de gestió de la configuració del programari. http://www.perforce.com/
+Comment[da]=Integrerer Perforce, et software-indstilling håndteringssystem. http://www.perforce.com/
+Comment[de]=Integration von Perforce, einem System zur Verwaltung von Software-Konfigurationen. http://www.perforce.com/
+Comment[el]=Ενσωματώνει το Perforce, ένα σÏστημα διαχείÏισης και ÏÏθμισης λογισμικοÏ.http://www.perforce.com/
+Comment[es]=Integra Perforce, un sistema de adminsitración de la configuración del software. http://www.perforce.com/
+Comment[et]=Integreerib tarkvaraseadistuste haldamise süsteemi Perforce. http://www.perforce.com/
+Comment[eu]=Perforce integratzen du, software konfiguazio kudeaketa sistema bat. http://www.perforce.com/
+Comment[fa]=Perforce را مجتمع‌سازی می‌کند. یک سیستم مدیریت پیکربندی نرم‌اÙزار. http://www.perforce.com/
+Comment[fr]=Intègre « PerForce », un système de gestion de configuration de logiciels. http:/www.perforce.com/
+Comment[gl]=Integra Perforce, un sistema de xestións de configuracións. http://www.perforce.com/
+Comment[hi]=परफ़ोरà¥à¤¸ को इंटीगà¥à¤°à¥‡à¤Ÿ करता है, जो कि सॉफà¥à¤Ÿà¤µà¥‡à¤¯à¤° कॉनà¥à¤«à¤¼à¤¿à¤—रेशन पà¥à¤°à¤¬à¤‚धन तंतà¥à¤° है. http://www.perforce.com/
+Comment[hu]=Integrációt biztosít a Perforce szoftverkonfigurációs rendszerrel - http://www.perforce.com/
+Comment[it]=Integra Perforce, un sistema per la configurazione software. http://www.perforce.com/
+Comment[ja]=ソフトウェア設定管ç†ã‚·ã‚¹ãƒ†ãƒ  Perforce ã‚’çµ±åˆã—ã¾ã™ã€‚
+Comment[ms]=Menggabungkan Perforce, sebuah sistem pengurusan tetapan perisian. http://www.perforce.com/
+Comment[nds]=Integreren vun Perforce, en Systeem för't Plegen vun Programminstellen. http://www.perforce.com/
+Comment[ne]=परफोरà¥à¤¸ à¤à¤•à¤¿à¤•à¤°à¤£ गरà¥à¤¦à¤›, सफà¥à¤Ÿà¤µà¥‡à¤¯à¤° कनà¥à¤«à¤¿à¤—रेसन वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ पà¥à¤°à¤£à¤¾à¤²à¥€ http://www.perforce.com/
+Comment[nl]=Integreert Perforce, een systeem voor softwareconfiguratie. Zie http://www.perforce.com/
+Comment[pl]=Integracja z Perforce, systemem zarzÄ…dzania konfiguracjÄ… oprogramowania. http://www.perforce.com/
+Comment[pt]=Integra o Perforce, um sistema de gestão de configurações de 'software'. http://www.perforce.com/
+Comment[pt_BR]=Integra o Perforce, um software de configuração e gerenciamento do sistema. http://www.perforce.com/
+Comment[ru]=Интегрирует Perforce, ÑиÑтему ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñми программного обеÑпечениÑ. http://www.perforce.com/
+Comment[sk]=Integrácia Perforce, konfiguraÄný projektový manažment. http://www.perforce.com/
+Comment[sl]=Integrira Perforce, upravljalni sistem programja. http://www.perforce.com/
+Comment[sr]=Интегрише Perforce, ÑиÑтем за управљање подешавањем Ñофтвера. http://www.perforce.com/
+Comment[sr@Latn]=Integriše Perforce, sistem za upravljanje podešavanjem softvera. http://www.perforce.com/
+Comment[sv]=Integrerar Perforce, ett konfigurationshanteringsverktyg för programvara. http://www.perforce.com/
+Comment[ta]=à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®•à¯à®•à¯à®®à¯ Perforce, ஒர௠மெனà¯à®ªà¯Šà®°à¯à®³à¯ மேலாளர௠அமைபà¯à®ªà¯. http://www.perforce.com/
+Comment[tg]=Интеграл намудани Perforce, барномаи идоракунандаро шарҳи барномаҳои таъмин нигоҳ медорад.http://www.perforce.com/
+Comment[tr]=Bir yazılım ayar yönetimi sistemi olan Perforce'u bütünleştirir. http://www.perforce.com/
+Comment[zh_CN]=é›†æˆ Perforce,系统é…置管ç†è½¯ä»¶ http://www.perforce.com/
+Comment[zh_TW]=æ•´åˆ Perforce,一套軟體設定管ç†ç³»çµ±ã€‚http://www.perforce.com/
+Name=KDevPerforce
+Name[da]=KDevelop Perforce
+Name[de]=Unterstützung für Perforce (KDevelop)
+Name[hi]=के-डेव-परफ़ोरà¥à¤¸
+Name[nds]=Perforce-Ünnerstütten för KDevelop
+Name[sk]=KDev Perforce
+Name[sv]=KDevelop Perforce
+Name[ta]=Kdev Perforce
+Name[zh_TW]=KDevelop Perforce
+GenericName=Perforce Integration
+GenericName[ca]=Integració amb Perforce
+GenericName[da]=Perforce integration
+GenericName[de]=Perforce-Integration
+GenericName[el]=Ενσωμάτωση Perforce
+GenericName[es]=Integración de Perforce
+GenericName[et]=Perforce'i põimimine
+GenericName[eu]=Perforce integrazioa
+GenericName[fa]=مجتمع‌سازی Perforce
+GenericName[fr]=Intégration de « Perforce »
+GenericName[ga]=Comhtháthú Perforce
+GenericName[gl]=Integración de Perforce
+GenericName[hi]=परफ़ोरà¥à¤¸ इंटीगà¥à¤°à¥‡à¤¶à¤¨
+GenericName[hu]=Perforce-integráció
+GenericName[it]=Integrazione di Perforce
+GenericName[ms]=Intergrasi Perforce
+GenericName[nds]=Perforce-Integreren
+GenericName[ne]=परफोरà¥à¤¸ इनà¥à¤Ÿà¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨
+GenericName[nl]=Perforce-integratie
+GenericName[pl]=Integracja z Perforce
+GenericName[pt]=Integração com o Perforce
+GenericName[pt_BR]=Integração com o Perforce
+GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Perforce
+GenericName[sk]=Perforce integrácia
+GenericName[sl]=Integracija Perforce
+GenericName[sr]=Интеграција perforce-а
+GenericName[sr@Latn]=Integracija perforce-a
+GenericName[sv]=Integrering av Perforce
+GenericName[ta]=Perforce à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®ªà¯à®ªà¯
+GenericName[tg]=ИнтегратÑÐ¸Ñ Perforce
+GenericName[tr]=Perforce Bütünleştirmesi
+GenericName[zh_CN]=Perforce 集æˆ
+GenericName[zh_TW]=Perforce æ•´åˆ
+ServiceTypes=KDevelop/VersionControl
+X-KDE-Library=libkdevperforce
+X-KDevelop-Version=5
+X-KDevelop-Properties=VCS,PerforceVCS
diff --git a/vcs/perforce/kdevperforcepart.rc b/vcs/perforce/kdevperforcepart.rc
new file mode 100644
index 00000000..27b5fe08
--- /dev/null
+++ b/vcs/perforce/kdevperforcepart.rc
@@ -0,0 +1,23 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KDevPerforcePart" version="1">
+<MenuBar>
+ <Menu name="tools">
+ <Menu name="version_control" group="tools_project_operations">
+ <Text>&amp;Version Control</Text>
+ <Merge />
+ <Menu name="version_control_tools_perforce">
+ <Text>&amp;Perforce</Text>
+ <Action name="perforce_submit" />
+ <Action name="perforce_diff" />
+ <Action name="perforce_edit" />
+ <Action name="perforce_revert" />
+ <Action name="perforce_sync" />
+ <Action name="perforce_add" />
+ <Action name="perforce_remove" />
+ </Menu>
+ </Menu>
+ </Menu>
+</MenuBar>
+
+</kpartgui>
+
diff --git a/vcs/perforce/perforcepart.cpp b/vcs/perforce/perforcepart.cpp
new file mode 100644
index 00000000..9aeadc6f
--- /dev/null
+++ b/vcs/perforce/perforcepart.cpp
@@ -0,0 +1,364 @@
+/***************************************************************************
+ * Copyright (C) 1999-2001 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Extended 2002 by Harald Fernengel <harry@kdevelop.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "perforcepart.h"
+
+#include <qfileinfo.h>
+#include <qpopupmenu.h>
+#include <qregexp.h>
+#include <kpopupmenu.h>
+#include <kdebug.h>
+#include <kdevgenericfactory.h>
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kurl.h>
+#include <kparts/part.h>
+
+#include "kdevpartcontroller.h"
+#include "kdevcore.h"
+#include "kdevmakefrontend.h"
+#include "kdevdifffrontend.h"
+#include "kdevplugininfo.h"
+#include "commitdlg.h"
+#include "execcommand.h"
+
+static const KDevPluginInfo data("kdevperforce");
+
+typedef KDevGenericFactory<PerforcePart> PerforceFactory;
+K_EXPORT_COMPONENT_FACTORY( libkdevperforce, PerforceFactory( data ) )
+
+PerforcePart::PerforcePart( QObject *parent, const char *name, const QStringList & )
+ : KDevVersionControl( &data, parent, name ? name : "PerforcePart" )
+{
+ setInstance(PerforceFactory::instance());
+ setupActions();
+
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+}
+
+
+PerforcePart::~PerforcePart()
+{}
+
+void PerforcePart::setupActions()
+{
+ actionEdit = new KAction( i18n("Edit"), 0, this, SLOT(slotActionEdit()),
+ actionCollection(), "perforce_edit" );
+ actionEdit->setToolTip(i18n("Edit"));
+ actionEdit->setWhatsThis(i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
+ actionRevert = new KAction( i18n("Revert"), 0, this, SLOT(slotActionRevert()),
+ actionCollection(), "perforce_revert" );
+ actionRevert->setToolTip(i18n("Revert"));
+ actionRevert->setWhatsThis(i18n("<b>Revert</b><p>Discards changes made to open files."));
+ actionSubmit = new KAction( i18n("Submit"), 0, this, SLOT(slotActionCommit()),
+ actionCollection(), "perforce_submit" );
+ actionSubmit->setToolTip(i18n("Submit"));
+ actionSubmit->setWhatsThis(i18n("<b>Submit</b><p>Sends changes made to open files to the depot."));
+ actionSync = new KAction( i18n("Sync"), 0, this, SLOT(slotActionUpdate()),
+ actionCollection(), "perforce_sync" );
+ actionSync->setToolTip(i18n("Sync"));
+ actionSync->setWhatsThis(i18n("<b>Sync</b><p>Copies files from the depot into the workspace."));
+ actionDiff = new KAction( i18n("Diff Against Repository"), 0, this, SLOT(slotActionDiff()),
+ actionCollection(), "perforce_diff" );
+ actionDiff->setToolTip(i18n("Diff against repository"));
+ actionDiff->setWhatsThis(i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
+ actionAdd = new KAction( i18n("Add to Repository"), 0, this, SLOT(slotActionAdd()),
+ actionCollection(), "perforce_add" );
+ actionAdd->setToolTip(i18n("Add to repository"));
+ actionAdd->setWhatsThis(i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
+ actionRemove = new KAction( i18n("Remove From Repository"), 0, this, SLOT(slotActionRemove()),
+ actionCollection(), "perforce_remove" );
+ actionRemove->setToolTip(i18n("Remove from repository"));
+ actionRemove->setWhatsThis(i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
+}
+
+void PerforcePart::contextMenu(QPopupMenu *popup, const Context *context)
+{
+ if (context->hasType( Context::FileContext )) {
+ const FileContext *fcontext = static_cast<const FileContext*>(context);
+ popupfile = fcontext->urls().first().path();
+ QFileInfo fi( popupfile );
+ popup->insertSeparator();
+
+ KPopupMenu *sub = new KPopupMenu(popup);
+ QString name = fi.fileName();
+ sub->insertTitle( i18n("Actions for %1").arg(name) );
+
+ int id = sub->insertItem( i18n("Edit"),
+ this, SLOT(slotEdit()) );
+ sub->setWhatsThis(id, i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit."));
+ id = sub->insertItem( i18n("Revert"),
+ this, SLOT(slotRevert()) );
+ sub->setWhatsThis(id, i18n("<b>Revert</b><p>Discards changes made to open files."));
+ id = sub->insertItem( i18n("Submit"),
+ this, SLOT(slotCommit()) );
+ sub->setWhatsThis(id, i18n("<b>Submit</b><p>Sends changes made to open files to the depot."));
+ id = sub->insertItem( i18n("Sync"),
+ this, SLOT(slotUpdate()) );
+ sub->setWhatsThis(id, i18n("<b>Sync</b><p>Copies files from the depot into the workspace."));
+ sub->insertSeparator();
+ id = sub->insertItem( i18n("Diff Against Repository"),
+ this, SLOT(slotDiff()) );
+ sub->setWhatsThis(id, i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot."));
+ id = sub->insertItem( i18n("Add to Repository"),
+ this, SLOT(slotAdd()) );
+ sub->setWhatsThis(id, i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot."));
+ id = sub->insertItem( i18n("Remove From Repository"),
+ this, SLOT(slotRemove()) );
+ sub->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot."));
+ id = popup->insertItem(i18n("Perforce"), sub);
+ }
+}
+
+void PerforcePart::execCommand( const QString& cmd, const QString& filename )
+{
+ if ( filename.isEmpty() )
+ return;
+
+ QFileInfo fi( filename );
+ if (fi.isDir()) {
+ KMessageBox::error( 0, i18n("Cannot handle directories, please select single files") );
+ return;
+ }
+ QString dir = fi.dirPath();
+ QString name = fi.fileName();
+
+ QString command("cd ");
+ command += KProcess::quote(dir);
+ command += " && p4 " + cmd + " ";
+ command += name;
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+}
+
+void PerforcePart::edit( const QString& filename )
+{
+ execCommand( "edit", filename );
+}
+
+void PerforcePart::revert( const QString& filename )
+{
+ if ( KMessageBox::questionYesNo( 0,
+ i18n("Do you really want to revert "
+ "the file %1 and lose all your changes?").arg( filename ), QString::null, i18n("Revert"), i18n("Do Not Revert") ) == KMessageBox::Yes ) {
+ execCommand( "revert", filename );
+ }
+}
+
+void PerforcePart::commit( const QString& filename )
+{
+ if ( filename.isEmpty() )
+ return;
+
+ QFileInfo fi( filename );
+ if ( fi.isDir() ) {
+ KMessageBox::error( 0, i18n("Submitting of subdirectories is not supported") );
+ return;
+ }
+
+ CommitDialog d;
+ QStringList lst;
+ lst << filename;
+ d.setFiles( lst );
+ if (d.exec() == QDialog::Rejected)
+ return;
+
+ QString message = d.changeList();
+ if (!message.isEmpty())
+ message = KShellProcess::quote(message);
+
+ QString command("echo " + message);
+ command += " | p4 submit -i";
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand("", command);
+}
+
+
+void PerforcePart::update( const QString& filename )
+{
+ if ( filename.isEmpty() )
+ return;
+
+ QString dir, name;
+ QFileInfo fi( filename );
+ if (fi.isDir()) {
+ dir = fi.absFilePath();
+ name = "..."; // three dots means "recoursive"
+ } else {
+ dir = fi.dirPath();
+ name = fi.fileName();
+ }
+
+ QString command("cd ");
+ command += KProcess::quote(dir);
+ command += " && p4 sync ";
+ command += name;
+
+ if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend"))
+ makeFrontend->queueCommand(dir, command);
+}
+
+
+void PerforcePart::add( const QString& filename )
+{
+ execCommand( "add", filename );
+}
+
+
+void PerforcePart::remove( const QString& filename )
+{
+ execCommand( "delete", filename );
+}
+
+void PerforcePart::diff( const QString& filename )
+{
+ if ( filename.isEmpty() )
+ return;
+
+ QString name;
+ QFileInfo fi( filename );
+
+ if ( fi.isDir() ) {
+ name = fi.absFilePath() + "...";
+ } else {
+ name = filename;
+ }
+ QStringList args;
+
+ args << "diff";
+ args << "-du";
+ args << name;
+ ExecCommand* cmv = new ExecCommand( "p4", args, QString::null, QStringList(), this );
+ connect( cmv, SIGNAL(finished( const QString&, const QString& )),
+ this, SLOT(slotDiffFinished( const QString&, const QString& )) );
+}
+
+void PerforcePart::slotDiffFinished( const QString& diff, const QString& err )
+{
+ if ( diff.isNull() && err.isNull() ) {
+ kdDebug(9000) << "p4 diff cancelled" << endl;
+ return; // user pressed cancel or an error occured
+ }
+
+ if ( diff.isEmpty() && !err.isEmpty() ) {
+ KMessageBox::detailedError( 0, i18n("P4 output errors during diff."), err, i18n("Errors During Diff") );
+ return;
+ }
+
+ if ( !err.isEmpty() ) {
+ int s = KMessageBox::warningContinueCancelList( 0, i18n("P4 output errors during diff. Do you still want to continue?"),
+ QStringList::split( "\n", err, false ), i18n("Errors During Diff") );
+ if ( s != KMessageBox::Continue )
+ return;
+ }
+
+ if ( diff.isEmpty() ) {
+ KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Differences Found") );
+ return;
+ }
+
+ // strip the ==== headers
+ static QRegExp rx( "(^|\\n)==== ([^ ]+) -.*====\\n" );
+ rx.setMinimal( true );
+ QString strippedDiff = diff;
+ strippedDiff.replace( rx, "--- \\2\n+++ \\2\n" );
+
+ if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("KDevelop/DiffFrontend"))
+ diffFrontend->showDiff( strippedDiff );
+}
+
+QString PerforcePart::currentFile()
+{
+ KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
+ if ( part ) {
+ KURL url = part->url();
+ if ( url.isLocalFile() )
+ return url.path();
+ }
+ return QString::null;
+}
+
+void PerforcePart::slotActionCommit()
+{
+ commit( currentFile() );
+}
+
+void PerforcePart::slotActionUpdate()
+{
+ update( currentFile() );
+}
+void PerforcePart::slotActionAdd()
+{
+ add( currentFile() );
+}
+
+void PerforcePart::slotActionRemove()
+{
+ remove( currentFile() );
+}
+
+void PerforcePart::slotActionEdit()
+{
+ edit( currentFile() );
+}
+
+void PerforcePart::slotActionRevert()
+{
+ revert( currentFile() );
+}
+
+void PerforcePart::slotActionDiff()
+{
+ diff( currentFile() );
+}
+
+void PerforcePart::slotCommit()
+{
+ commit( popupfile );
+}
+
+void PerforcePart::slotUpdate()
+{
+ update( popupfile );
+}
+
+void PerforcePart::slotAdd()
+{
+ add( popupfile );
+}
+
+void PerforcePart::slotRemove()
+{
+ remove( popupfile );
+}
+
+void PerforcePart::slotEdit()
+{
+ edit( popupfile );
+}
+
+void PerforcePart::slotRevert()
+{
+ revert( popupfile );
+}
+
+void PerforcePart::slotDiff()
+{
+ diff( popupfile );
+}
+
+#include "perforcepart.moc"
diff --git a/vcs/perforce/perforcepart.h b/vcs/perforce/perforcepart.h
new file mode 100644
index 00000000..5a50871c
--- /dev/null
+++ b/vcs/perforce/perforcepart.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * Copyright (C) 1999-2001 by Bernd Gehrmann *
+ * bernd@kdevelop.org *
+ * Extended to use perforce 2002 by Harald Fernengel <harry@kdevelop.org>*
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _PERFORCEPART_H_
+#define _PERFORCEPART_H_
+
+#include <kdevversioncontrol.h>
+#include <klocale.h>
+
+class Context;
+class QPopupMenu;
+class KAction;
+
+class PerforcePart : public KDevVersionControl
+{
+ Q_OBJECT
+
+public:
+ PerforcePart( QObject *parent, const char *name, const QStringList & );
+ ~PerforcePart();
+
+ virtual QString shortDescription() const
+ { return i18n( "Perforce is a version control system" ); }
+
+ virtual void createNewProject(const QString& /* dir */) {}
+ virtual bool fetchFromRepository() { return true; }
+ virtual KDevVCSFileInfoProvider *fileInfoProvider() const { return 0; }
+ virtual bool isValidDirectory(const QString& /* dirPath*/) const
+ { return true; }
+
+private slots:
+ void contextMenu(QPopupMenu *popup, const Context *context);
+ void slotCommit();
+ void slotUpdate();
+ void slotAdd();
+ void slotRemove();
+ void slotEdit();
+ void slotRevert();
+ void slotDiff();
+
+ void slotActionCommit();
+ void slotActionUpdate();
+ void slotActionAdd();
+ void slotActionRemove();
+ void slotActionEdit();
+ void slotActionRevert();
+ void slotActionDiff();
+
+ void slotDiffFinished( const QString&, const QString& );
+
+private:
+ void commit( const QString& filename );
+ void update( const QString& filename );
+ void add( const QString& filename );
+ void remove( const QString& filename );
+ void edit( const QString& filename );
+ void revert( const QString& filename );
+ void diff( const QString& filename );
+ QString currentFile();
+
+ /** calls p4 with the command cmd and appends the filename */
+ void execCommand( const QString& cmd, const QString& filename );
+ void setupActions();
+ QString popupfile;
+ KAction *actionEdit, *actionRevert,
+ *actionSubmit, *actionSync,
+ *actionDiff, *actionAdd, *actionRemove;
+};
+
+#endif
diff --git a/vcs/subversion/Makefile.am b/vcs/subversion/Makefile.am
new file mode 100644
index 00000000..449d3889
--- /dev/null
+++ b/vcs/subversion/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/interfaces/extensions $(SVN_INCLUDE) $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libkdevsubversion.la kio_kdevsvn.la kded_kdevsvnd.la
+
+libkdevsubversion_la_SOURCES = subversion_core.cpp subversion_fileinfo.cpp \
+ subversion_fileinfo.skel subversion_part.cpp subversion_widget.cpp subversiondiff.ui \
+ subversionprojectwidget.ui svn_blamewidget.cpp svn_co.ui svn_commitdlgbase.ui svn_copydlgwidget.ui \
+ svn_copywidget.cpp svn_fileselectdlg_commit.cpp svn_logviewoptiondlgbase.ui \
+ svn_logviewwidget.cpp svn_mergeoptiondlgbase.ui svn_mergewidget.cpp svn_switchdlgbase.ui \
+ svn_switchwidget.cpp
+libkdevsubversion_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la
+libkdevsubversion_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+
+
+kio_kdevsvn_la_SOURCES = svn_kio.cpp
+kio_kdevsvn_la_LIBADD = $(LIB_KIO)
+kio_kdevsvn_la_LDFLAGS = -module $(all_libraries) $(KDE_PLUGIN) $(SVN_LIB)
+
+kded_kdevsvnd_la_SOURCES = commitdlg.cpp commitdlgbase.ui kdevsvnd.cpp \
+ kdevsvnd.skel kdevsvnd_widgets.cpp svnssltrustpromptbase.ui
+kded_kdevsvnd_la_LIBADD = $(LIB_KIO) -lkdeinit_kded
+kded_kdevsvnd_la_LDFLAGS = -module $(all_libraries) $(KDE_PLUGIN)
+
+kdeddir = $(kde_servicesdir)/kded
+kded_DATA = kdevsvnd.desktop
+
+servicedir = $(kde_servicesdir)
+service_DATA = kdevsubversion.desktop
+
+protocoldir = $(kde_servicesdir)
+protocol_DATA = kdevsvn+file.protocol kdevsvn+http.protocol kdevsvn+https.protocol kdevsvn+ssh.protocol kdevsvn+svn.protocol
+
+
+SUBDIRS = integrator
+noinst_HEADERS = commitdlg.h kdevsvnd.h svn_blamewidget.h svn_copywidget.h \
+ svn_fileselectdlg_commit.h svn_logviewwidget.h svn_mergewidget.h svn_switchwidget.h
diff --git a/vcs/subversion/README.dox b/vcs/subversion/README.dox
new file mode 100644
index 00000000..df3badcc
--- /dev/null
+++ b/vcs/subversion/README.dox
@@ -0,0 +1,13 @@
+/** \class subversionPart
+Integrates the SVN (Subversion) version management system into KDevelop.
+
+\authors <a href="mailto:marchand AT kde.org">Mickael Marchand</a>
+
+\maintainer <a href="mailto:marchand AT kde.org">Mickael Marchand</a>
+
+\feature Integrates the SVN (Subversion) version management system into KDevelop.
+
+\requirement You need to compile and install kdesdk/kioslave/svn
+
+*/
+
diff --git a/vcs/subversion/commitdlg.cpp b/vcs/subversion/commitdlg.cpp
new file mode 100644
index 00000000..e227dd67
--- /dev/null
+++ b/vcs/subversion/commitdlg.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * This file is part of KDevelop *
+ * Copyright (C) 2007 The KDevelop Authors <kdevelop-devel@kdevelop.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include "commitdlg.h"
+#include <qevent.h>
+#include <ktextedit.h>
+
+CommitDlg::CommitDlg( QWidget* parent )
+ : CommitDlgBase( parent )
+{
+ textMessage->installEventFilter(this);
+}
+
+bool CommitDlg::eventFilter( QObject* obj, QEvent* ev )
+{
+ if( ev->type() == QEvent::KeyPress )
+ {
+ QKeyEvent* k = static_cast<QKeyEvent*>(ev);
+ if( ( k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter ) && k->state() == Qt::ControlButton )
+ {
+ accept();
+ return true;
+ }
+ }
+ return false;
+}
+
+#include "commitdlg.moc"
+
+//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle;
diff --git a/vcs/subversion/commitdlg.h b/vcs/subversion/commitdlg.h
new file mode 100644
index 00000000..4ac54054
--- /dev/null
+++ b/vcs/subversion/commitdlg.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * This file is part of KDevelop *
+ * Copyright (C) 2007 The KDevelop Authors <kdevelop-devel@kdevelop.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Library General Public License as *
+ * published by the Free Software Foundation; either version 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef COMMITDLG_H
+#define COMMITDLG_H
+
+#include "commitdlgbase.h"
+
+class CommitDlg : public CommitDlgBase
+{
+ Q_OBJECT
+public:
+ CommitDlg( QWidget* = 0 );
+protected:
+ bool eventFilter( QObject* o, QEvent* e );
+};
+
+#endif
+
+//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle;
diff --git a/vcs/subversion/commitdlgbase.ui b/vcs/subversion/commitdlgbase.ui
new file mode 100644
index 00000000..76499a60
--- /dev/null
+++ b/vcs/subversion/commitdlgbase.ui
@@ -0,0 +1,111 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>CommitDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CommitDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>451</width>
+ <height>337</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Log Message</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>textMessage</cstring>
+ </property>
+ </widget>
+ <widget class="KTextEdit">
+ <property name="name">
+ <cstring>listMessage</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>220</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="text">
+ <string>Ca&amp;ncel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>pushButton1</sender>
+ <signal>clicked()</signal>
+ <receiver>CommitDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>pushButton2</sender>
+ <signal>clicked()</signal>
+ <receiver>CommitDlgBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>ktextedit.h</includehint>
+ <includehint>ktextedit.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/configure.in.bot b/vcs/subversion/configure.in.bot
new file mode 100644
index 00000000..ccab94db
--- /dev/null
+++ b/vcs/subversion/configure.in.bot
@@ -0,0 +1,9 @@
+if test "x$with_subversion" = xcheck && test -z "$SVN_SUBDIR"; then
+ echo ""
+ echo "You're missing Subversion libraries (1.x)"
+ echo "KDE will not be able to browse Subversion repositories without it,"
+ echo "consider installing it."
+ echo "Look at kioslave/svn/README for more information"
+ echo ""
+ all_tests=bad
+fi
diff --git a/vcs/subversion/configure.in.in b/vcs/subversion/configure.in.in
new file mode 100644
index 00000000..9bccba66
--- /dev/null
+++ b/vcs/subversion/configure.in.in
@@ -0,0 +1,134 @@
+SVN_SUBDIR=""
+
+AC_ARG_ENABLE(subversion, AC_HELP_STRING([--disable-subversion], [disable vcs support for subversion]), [with_subversion=${enableval}], [with_subversion=check])
+
+
+
+if test "x$with_subversion" != xno; then
+
+ APR_CONFIGS="/usr/bin/apr-config /usr/bin/apr-1-config /usr/local/bin/apr-config /usr/local/apr/bin/apr-config"
+ SVN_SUBDIR="svn"
+ 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 test -x "$VALUE"; then
+ if $VALUE --cflags > /dev/null; then
+ APR_CONFIG="$VALUE"
+ break
+ fi
+ fi
+ done
+ if test -n "$APR_CONFIG" ; then
+ AC_MSG_RESULT([$APR_CONFIG])
+ APR_CPPFLAGS="`$APR_CONFIG --cppflags`"
+ APR_INCLUDE="`$APR_CONFIG --includes`"
+ APR_LIBS="`$APR_CONFIG --link-ld --libs`"
+ else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+ fi
+
+ dnl
+ dnl APR util
+ dnl
+
+ APU_CONFIGS="/usr/bin/apu-config /usr/bin/apu-1-config /usr/local/bin/apu-config /usr/local/apu/bin/apu-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 test -x $VALUE
+ then
+ if $VALUE --includes > /dev/null; then
+ APU_CONFIG=$VALUE
+ break
+ fi
+ fi
+ done
+ if test -n "$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])
+ SVN_SUBDIR=
+ fi
+
+ dnl Search for subversion libraries
+ dnl svn-config was removed at current subversion release.
+
+
+ SVN_INCLUDES="/usr/local/include /usr/include /usr/include/subversion-1 /usr/local/include/subversion-1"
+ 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
+ ])
+ AC_MSG_CHECKING([for Subversion headers])
+ SVN_INCLUDE=""
+ for VALUE in $SVN_INCLUDES ; do
+ if test -f $VALUE/svn_types.h ; then
+ SVN_INCLUDE="-I$VALUE"
+ break
+ fi
+ done
+ if test $SVN_INCLUDE ; then
+ AC_MSG_RESULT([found])
+ else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+ fi
+ SVN_LIBS="/usr/local/lib /usr/lib /usr/lib64"
+ 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="-L$VALUE"
+ break
+ fi
+ done
+ if test $SVN_LIB ; then
+ AC_MSG_RESULT([found])
+ else
+ AC_MSG_RESULT([not found])
+ SVN_SUBDIR=
+ fi
+ SVN_LIB="$SVN_LIB $APR_LIBS -lsvn_client-1 -lsvn_subr-1 -lsvn_ra-1"
+ SVN_INCLUDE="$SVN_INCLUDE $APR_INCLUDE"
+ SVN_CPPFLAGS="$APR_CPPFLAGS $SVN_CPPFLAGS"
+
+ if test "x$with_subversion" != xcheck && test -z "$SVN_SUBDIR"; then
+ AC_MSG_ERROR([--enable-subversion was given, but test for subversion failed. Please install subversion headers and libraries and its dependencies (APR and APU utils)])
+ fi
+fi
+
+AM_CONDITIONAL(include_subversion, test -n "$SVN_SUBDIR")
+
+AC_SUBST(SVN_INCLUDE)
+AC_SUBST(SVN_LIB)
+AC_SUBST(SVN_CPPFLAGS)
+AM_CONDITIONAL(include_kioslave_svn, test -n "$SVN_SUBDIR")
diff --git a/vcs/subversion/integrator/Makefile.am b/vcs/subversion/integrator/Makefile.am
new file mode 100644
index 00000000..a0fe82cd
--- /dev/null
+++ b/vcs/subversion/integrator/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \
+ $(all_includes)
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = libsubversionintegrator.la
+libsubversionintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries)
+libsubversionintegrator_la_LIBADD =\
+ $(top_builddir)/lib/interfaces/extras/libkdevextras.la\
+ $(top_builddir)/lib/libkdevelop.la
+kde_services_DATA = kdevsubversionintegrator.desktop
+noinst_HEADERS = subversionintegrator.h svnintegratordlg.h
+libsubversionintegrator_la_SOURCES = subversionintegrator.cpp \
+ svnintegratordlgbase.ui svnintegratordlg.cpp
diff --git a/vcs/subversion/integrator/kdevsubversionintegrator.desktop b/vcs/subversion/integrator/kdevsubversionintegrator.desktop
new file mode 100644
index 00000000..4b3a1c1c
--- /dev/null
+++ b/vcs/subversion/integrator/kdevsubversionintegrator.desktop
@@ -0,0 +1,45 @@
+[Desktop Entry]
+Type=Service
+Name=KDevSubversionIntegrator
+Name[da]=KDevelop Subversion-integration
+Name[nds]=KDevelop-Subversion-Integreren
+Name[sk]=KDev Subversion integrácia
+Name[sv]=KDevelop Subversion-integration
+Name[zh_TW]=KDevelop Subversion æ•´åˆå™¨
+Comment=Subversion Project Integration Facility
+Comment[ca]=Facilitat per a la integració amb Subversion
+Comment[da]=Subversion projektintegration
+Comment[de]=Subversion-Projektintegration
+Comment[el]=ΛειτουÏγία ενσωμάτωσης Subversion στο έÏγο
+Comment[es]=Facilidad para integración con proyectos que utilicen Subversion
+Comment[et]=Subversion projekti põimimisvahend
+Comment[eu]=Subversion proiektuen integrazio-tesna
+Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ زیرنسخه
+Comment[fr]=Fonction d'intégration pour un projet utilisant Subversion
+Comment[gl]=Utilidade para a integración de proxectos Subversión
+Comment[hu]=Projektintegrálást tesz lehetővé a Subversion-nel
+Comment[it]=Funzione di integrazione del progetto Subversion
+Comment[ja]=Subversion プロジェクト統åˆãƒ„ール
+Comment[ms]=Kemudahan Integrasi Projek Subversion
+Comment[nds]=Subversion-Projektintegreren
+Comment[ne]=सबभरà¥à¤¸à¤¨ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾
+Comment[nl]=Subversion project-integratie
+Comment[pl]=Integracja z Subversion
+Comment[pt]=Integração com Projectos Subversion
+Comment[pt_BR]=Facilidade de Integração ao Projeto de Subversão
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion
+Comment[sk]=Subversion projektová integrácia
+Comment[sr]=Интеграција Subversion-а у пројекат
+Comment[sr@Latn]=Integracija Subversion-a u projekat
+Comment[sv]=Funktion för integrering av Subversion i projekt
+Comment[tr]=Subversion Proje Bütünleştirme Aracı
+Comment[zh_CN]=Subversion 工程集æˆåŠŸèƒ½
+Comment[zh_TW]=Subversion 專案整åˆå·¥å…·
+Icon=misc
+Exec=blubb
+ServiceTypes=KDevelop/VCSIntegrator
+X-KDE-Library=libsubversionintegrator
+X-KDevelop-Default=false
+X-KDevelop-VCS=Subversion
+X-KDevelop-VCSPlugin=kdevsubversion
+X-KDevelop-Version=5
diff --git a/vcs/subversion/integrator/subversionintegrator.cpp b/vcs/subversion/integrator/subversionintegrator.cpp
new file mode 100644
index 00000000..65bf1a78
--- /dev/null
+++ b/vcs/subversion/integrator/subversionintegrator.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "subversionintegrator.h"
+
+#include <kdevgenericfactory.h>
+#include <kdevplugininfo.h>
+
+#include "svnintegratordlg.h"
+
+static const KDevPluginInfo data("kdevsubversionintegrator");
+typedef KDevGenericFactory<SubversionIntegrator> SubversionIntegratorFactory;
+K_EXPORT_COMPONENT_FACTORY( libsubversionintegrator, SubversionIntegratorFactory(data) )
+
+SubversionIntegrator::SubversionIntegrator(QObject* parent, const char* name,
+ const QStringList // args
+ )
+ :KDevVCSIntegrator(parent, name)
+{
+}
+
+SubversionIntegrator::~SubversionIntegrator()
+{
+}
+
+VCSDialog* SubversionIntegrator::fetcher(QWidget* // parent
+ )
+{
+ return 0;
+}
+
+VCSDialog* SubversionIntegrator::integrator(QWidget* parent)
+{
+ SvnIntegratorDlg *dlg = new SvnIntegratorDlg(parent);
+ return dlg;
+}
+
+#include "subversionintegrator.moc"
diff --git a/vcs/subversion/integrator/subversionintegrator.h b/vcs/subversion/integrator/subversionintegrator.h
new file mode 100644
index 00000000..e58c7786
--- /dev/null
+++ b/vcs/subversion/integrator/subversionintegrator.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SUBVERSIONINTEGRATOR_H
+#define SUBVERSIONINTEGRATOR_H
+
+#include <kdevvcsintegrator.h>
+
+#include <qstringlist.h>
+
+class SubversionIntegrator : public KDevVCSIntegrator
+{
+Q_OBJECT
+public:
+ SubversionIntegrator(QObject* parent, const char* name, const QStringList args = QStringList());
+ ~SubversionIntegrator();
+
+ virtual VCSDialog* fetcher(QWidget* parent);
+ virtual VCSDialog* integrator(QWidget* parent);
+
+};
+
+#endif
diff --git a/vcs/subversion/integrator/svnintegratordlg.cpp b/vcs/subversion/integrator/svnintegratordlg.cpp
new file mode 100644
index 00000000..9d271a90
--- /dev/null
+++ b/vcs/subversion/integrator/svnintegratordlg.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * Copyright (C) 2004 *
+ * Mickael Marchand <marchand@kde.org> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "svnintegratordlg.h"
+#include "blockingkprocess.h"
+#include <kurl.h>
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+#include <kurlrequester.h>
+#include <kdebug.h>
+#include <qradiobutton.h>
+#include <kio/scheduler.h>
+#include <kprocess.h>
+#include <kdeversion.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <kio/netaccess.h>
+
+using namespace KIO;
+
+SvnIntegratorDlg::SvnIntegratorDlg( QWidget *parent, const char *name )
+ : SvnIntegratorDlgBase( parent, name )
+{
+ repos1->setMode( KFile::Directory );
+}
+
+void SvnIntegratorDlg::accept()
+{
+ // to let ioslave know which protocol it should start.
+ KURL protocolUrl = KURL("kdevsvn+svn://blah/");
+ KURL servURL( repos1->url() );
+ if ( servURL.isEmpty() ) return;
+
+ kdDebug( 9036 ) << "servURL : " << servURL.prettyURL() << endl;
+ if ( createProject->isChecked() )
+ {
+ KURL::List list;
+ list << servURL; // project root directory
+ KURL miscURL = servURL.url();
+ miscURL.setPath( servURL.path() + "/tags/" );
+ list << miscURL;
+ miscURL.setPath( servURL.path() + "/branches/" );
+ list << miscURL;
+ miscURL.setPath( servURL.path() + "/trunk/" );
+ list << miscURL;
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 10; // MKDIR(list)
+ s << cmd << list;
+ KIO::SimpleJob* job = KIO::special( protocolUrl, parms, true );
+ if( !NetAccess::synchronousRun( job, 0 ) ){
+ KMessageBox::error( this, i18n("Unable to create project directories on repository") );
+ return;
+ }
+
+ QByteArray parms2;
+ QDataStream s2( parms2, IO_WriteOnly );
+ cmd = 5; //IMPORT
+ servURL.setPath( servURL.path() + "/trunk/" );
+ s2 << cmd << servURL << KURL::fromPathOrURL( m_projectLocation );
+ KIO::SimpleJob* importJob = KIO::special( protocolUrl, parms2, true );
+ if( !NetAccess::synchronousRun( importJob, 0 ) ){
+ KMessageBox::error( this, i18n("Unable to import into repository.") );
+ return;
+ }
+ }
+ //delete the template directory and checkout a fresh one from the server
+ BlockingKProcess *rmproc = new BlockingKProcess();
+ *rmproc << "rm";
+ *rmproc << "-f" << "-r" << m_projectLocation;
+ rmproc->start();
+
+ delete rmproc;
+ rmproc = NULL;
+
+ QByteArray parms3;
+ QDataStream s3( parms3, IO_WriteOnly );
+ int cmd2 = 1; //CHECKOUT
+ int rev = -1;
+
+ s3 << cmd2 << servURL << KURL::fromPathOrURL( m_projectLocation ) << rev << QString( "HEAD" );
+ SimpleJob *job2 = KIO::special( protocolUrl, parms3, true );
+ if( ! NetAccess::synchronousRun( job2, 0 ) ){
+ // Checkout failed
+ KMessageBox::error(this, i18n("Unable to checkout from repository.") );
+ return;
+ }
+}
+
+void SvnIntegratorDlg::init( const QString &projectName, const QString &projectLocation )
+{
+ m_name = projectName;
+ m_projectLocation = projectLocation;
+}
+
+QWidget *SvnIntegratorDlg::self()
+{
+ return const_cast<SvnIntegratorDlg*>( this );
+}
+
+#include "svnintegratordlg.moc"
diff --git a/vcs/subversion/integrator/svnintegratordlg.h b/vcs/subversion/integrator/svnintegratordlg.h
new file mode 100644
index 00000000..c68ee256
--- /dev/null
+++ b/vcs/subversion/integrator/svnintegratordlg.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Alexander Dymo *
+ * adymo@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SVNINTEGRATORDLG_H
+#define SVNINTEGRATORDLG_H
+
+#include "svnintegratordlgbase.h"
+#include <kdevvcsintegrator.h>
+
+class SvnIntegratorDlg: public SvnIntegratorDlgBase, public VCSDialog {
+Q_OBJECT
+public:
+ SvnIntegratorDlg(QWidget *parent = 0, const char *name = 0);
+
+ virtual void accept();
+ virtual void init(const QString &projectName, const QString &projectLocation);
+ virtual QWidget *self();
+private:
+ QString m_name;
+ QString m_projectLocation;
+};
+
+#endif
diff --git a/vcs/subversion/integrator/svnintegratordlgbase.ui b/vcs/subversion/integrator/svnintegratordlgbase.ui
new file mode 100644
index 00000000..a2ec9982
--- /dev/null
+++ b/vcs/subversion/integrator/svnintegratordlgbase.ui
@@ -0,0 +1,190 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnIntegratorDlgBase</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SvnIntegratorDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>648</width>
+ <height>429</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup" row="0" column="0">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>doNothing</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Do not do anything</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Adds subversion menus to project.
+
+NOTE: Unless you import the project
+out of kdevelop, you will not be able
+to perform any subversion operations.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Adds subversion menus to project.
+
+NOTE: Unless you import the project
+out of kdevelop, you will not be able
+to perform any subversion operations.</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>createProject</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Create a project tree and import new project into trunk, then checkout from the repository</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Creates project, imports it into the subversion
+repository and checks it out as a working copy.
+
+NOTE: The repository has to exist.
+e.g. has been created with 'svnadmin'</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Creates project, imports it into the subversion
+repository and checks it out as a working copy.
+
+NOTE: The repository has to exist.
+e.g. has been created with 'svnadmin'</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Example for the url (if /home/user/subversion is the subversion repository):
+file:///home/user/subversion/mynewproject</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>repositoryLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Repository:</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>repos1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Subversion repository location.
+The repository has to exist -
+e.g. has been created with 'svnadmin'</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Subversion repository location. This should include the subdirectory for the project in the repository. The project subdirectory and further subdirectories will be created.
+
+So for example if you give http://localhost/svn/projectname the following directories will be created and the project imported into the trunk subdirectory:
+http://localhost/svn/projectname
+http://localhost/svn/projectname/tags
+http://localhost/svn/projectname/branches
+http://localhost/svn/projectname/trunk</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>131</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>createProject</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>repositoryLabel1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>createProject</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>repos1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/kdevpart_subversion.rc b/vcs/subversion/kdevpart_subversion.rc
new file mode 100644
index 00000000..ad957e99
--- /dev/null
+++ b/vcs/subversion/kdevpart_subversion.rc
@@ -0,0 +1,31 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="subversion" library="libsubversionplugin" version="2">
+<MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Menu name="version_control"><Text>&amp;Version Control</Text>
+ <Merge/>
+ <Menu name="version_control_tools_subversion" group="tools_project_operations">
+ <Text>&amp;Subversion</Text>
+ <Action name="subversion_commit" />
+ <Action name="subversion_diff" />
+ <Action name="subversion_log" />
+ <Action name="subversion_add" />
+ <Action name="subversion_add_bin" />
+ <Action name="subversion_remove" />
+ <Separator />
+ <Action name="subversion_tag" />
+ <Action name="subversion_untag" />
+ <Action name="subversion_update" />
+ <Action name="subversion_removesticky" />
+ <Action name="subversion_revert" />
+ <Separator />
+ <Action name="subversion_ignore" />
+ <Action name="subversion_donot_ignore" />
+<!-- <Separator />
+ <Action name="subversion_login" />
+ <Action name="subversion_logout" /> -->
+ </Menu>
+ </Menu>
+ </Menu>
+</MenuBar>
+</kpartplugin>
diff --git a/vcs/subversion/kdevsubversion.desktop b/vcs/subversion/kdevsubversion.desktop
new file mode 100644
index 00000000..500b5fb0
--- /dev/null
+++ b/vcs/subversion/kdevsubversion.desktop
@@ -0,0 +1,34 @@
+[Desktop Entry]
+Type=Service
+Exec=blubb
+Comment=Subversion
+Comment[fa]=زیرنسخه
+Comment[hi]=सबवरà¥à¤¸à¤¨
+Comment[ne]=सबभरà¥à¤¸à¤¨
+Comment[pt_BR]=Subversão
+Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion
+Comment[ta]=உப பதிபà¯à®ªà¯
+Comment[tg]=ИнтегратÑÐ¸Ñ Subversion
+Name=KDevsubversion
+Name[da]=KDevelop Subversion
+Name[de]=Unterstützung für Subversion (KDevelop)
+Name[hi]=के-डेव-सबवरà¥à¤¸à¤¨
+Name[nds]=Subversion-Ünnerstütten för KDevelop
+Name[sk]=KDev Subversion
+Name[sv]=KDevelop Subversion
+Name[ta]=kdev உப பதிபà¯à®ªà¯
+Name[tg]=KDevзер-ривоÑÑ‚
+Name[zh_TW]=KDevelop Subversion
+GenericName=Subversion
+GenericName[fa]=زیرنسخه
+GenericName[hi]=सबवरà¥à¤¸à¤¨
+GenericName[ne]=सबभरà¥à¤¸à¤¨
+GenericName[pt_BR]=Subversão
+GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion
+GenericName[ta]=தà¯à®£à¯ˆ பதிபà¯à®ªà¯
+GenericName[tg]=Зер-ривоÑÑ‚
+Icon=misc
+ServiceTypes=KDevelop/VersionControl
+X-KDE-Library=libkdevsubversion
+X-KDevelop-Version=5
+X-KDevelop-Properties=VCS,SubversionVCS
diff --git a/vcs/subversion/kdevsvn+file.protocol b/vcs/subversion/kdevsvn+file.protocol
new file mode 100644
index 00000000..decc1cc4
--- /dev/null
+++ b/vcs/subversion/kdevsvn+file.protocol
@@ -0,0 +1,39 @@
+[Protocol]
+exec=kio_kdevsvn
+protocol=kdevsvn+file
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+deleteRecursive=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave for KDevelop
+Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop
+Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop)
+Description[el]=Subversion ioslave για το KDevelop
+Description[es]=El ioslave de Subversion para KDevelop
+Description[et]=KDevelopi Subversioni IO-moodul
+Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop
+Description[hu]=Subversion KDE-protokoll a KDevelophoz
+Description[it]=ioslave di subversion per KDevelop
+Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave
+Description[ms]=IOslave Subversion untuk KDevelop
+Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion
+Description[nl]=Subversion-ioslave voor KDevelop
+Description[pl]=Wtyczka protokołu Subversion dla KDevelopa
+Description[pt]='Ioslave' do Subversion para o KDevelop
+Description[pt_BR]='Ioslave' do Subversion para o KDevelop
+Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop
+Description[sk]=Subversion ioslave pre KDevelop
+Description[sr]=KIOSlave Subversion-а за KDevelop
+Description[sr@Latn]=KIOSlave Subversion-a za KDevelop
+Description[sv]=Subversion I/O-slav för KDevelop
+Description[zh_TW]=KDevelop çš„ Subversion ioslave
+maxInstances=5
+class=:internet
diff --git a/vcs/subversion/kdevsvn+http.protocol b/vcs/subversion/kdevsvn+http.protocol
new file mode 100644
index 00000000..5e836c02
--- /dev/null
+++ b/vcs/subversion/kdevsvn+http.protocol
@@ -0,0 +1,39 @@
+[Protocol]
+exec=kio_kdevsvn
+protocol=kdevsvn+http
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+deleteRecursive=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave for KDevelop
+Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop
+Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop)
+Description[el]=Subversion ioslave για το KDevelop
+Description[es]=El ioslave de Subversion para KDevelop
+Description[et]=KDevelopi Subversioni IO-moodul
+Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop
+Description[hu]=Subversion KDE-protokoll a KDevelophoz
+Description[it]=ioslave di subversion per KDevelop
+Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave
+Description[ms]=IOslave Subversion untuk KDevelop
+Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion
+Description[nl]=Subversion-ioslave voor KDevelop
+Description[pl]=Wtyczka protokołu Subversion dla KDevelopa
+Description[pt]='Ioslave' do Subversion para o KDevelop
+Description[pt_BR]='Ioslave' do Subversion para o KDevelop
+Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop
+Description[sk]=Subversion ioslave pre KDevelop
+Description[sr]=KIOSlave Subversion-а за KDevelop
+Description[sr@Latn]=KIOSlave Subversion-a za KDevelop
+Description[sv]=Subversion I/O-slav för KDevelop
+Description[zh_TW]=KDevelop çš„ Subversion ioslave
+maxInstances=5
+class=:internet
diff --git a/vcs/subversion/kdevsvn+https.protocol b/vcs/subversion/kdevsvn+https.protocol
new file mode 100644
index 00000000..af9301af
--- /dev/null
+++ b/vcs/subversion/kdevsvn+https.protocol
@@ -0,0 +1,39 @@
+[Protocol]
+exec=kio_kdevsvn
+protocol=kdevsvn+https
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+deleteRecursive=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave for KDevelop
+Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop
+Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop)
+Description[el]=Subversion ioslave για το KDevelop
+Description[es]=El ioslave de Subversion para KDevelop
+Description[et]=KDevelopi Subversioni IO-moodul
+Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop
+Description[hu]=Subversion KDE-protokoll a KDevelophoz
+Description[it]=ioslave di subversion per KDevelop
+Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave
+Description[ms]=IOslave Subversion untuk KDevelop
+Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion
+Description[nl]=Subversion-ioslave voor KDevelop
+Description[pl]=Wtyczka protokołu Subversion dla KDevelopa
+Description[pt]='Ioslave' do Subversion para o KDevelop
+Description[pt_BR]='Ioslave' do Subversion para o KDevelop
+Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop
+Description[sk]=Subversion ioslave pre KDevelop
+Description[sr]=KIOSlave Subversion-а за KDevelop
+Description[sr@Latn]=KIOSlave Subversion-a za KDevelop
+Description[sv]=Subversion I/O-slav för KDevelop
+Description[zh_TW]=KDevelop çš„ Subversion ioslave
+maxInstances=5
+class=:internet
diff --git a/vcs/subversion/kdevsvn+ssh.protocol b/vcs/subversion/kdevsvn+ssh.protocol
new file mode 100644
index 00000000..33a644f0
--- /dev/null
+++ b/vcs/subversion/kdevsvn+ssh.protocol
@@ -0,0 +1,39 @@
+[Protocol]
+exec=kio_kdevsvn
+protocol=kdevsvn+ssh
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+deleteRecursive=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave for KDevelop
+Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop
+Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop)
+Description[el]=Subversion ioslave για το KDevelop
+Description[es]=El ioslave de Subversion para KDevelop
+Description[et]=KDevelopi Subversioni IO-moodul
+Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop
+Description[hu]=Subversion KDE-protokoll a KDevelophoz
+Description[it]=ioslave di subversion per KDevelop
+Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave
+Description[ms]=IOslave Subversion untuk KDevelop
+Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion
+Description[nl]=Subversion-ioslave voor KDevelop
+Description[pl]=Wtyczka protokołu Subversion dla KDevelopa
+Description[pt]='Ioslave' do Subversion para o KDevelop
+Description[pt_BR]='Ioslave' do Subversion para o KDevelop
+Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop
+Description[sk]=Subversion ioslave pre KDevelop
+Description[sr]=KIOSlave Subversion-а за KDevelop
+Description[sr@Latn]=KIOSlave Subversion-a za KDevelop
+Description[sv]=Subversion I/O-slav för KDevelop
+Description[zh_TW]=KDevelop çš„ Subversion ioslave
+maxInstances=5
+class=:internet
diff --git a/vcs/subversion/kdevsvn+svn.protocol b/vcs/subversion/kdevsvn+svn.protocol
new file mode 100644
index 00000000..0f9ab069
--- /dev/null
+++ b/vcs/subversion/kdevsvn+svn.protocol
@@ -0,0 +1,39 @@
+[Protocol]
+exec=kio_kdevsvn
+protocol=kdevsvn+svn
+input=none
+output=filesystem
+reading=true
+writing=true
+deleting=true
+makedir=true
+linking=false
+moving=true
+deleteRecursive=true
+listing=Name,Size,Date,Owner
+defaultMimetype=application/octet-stream
+Icon=remote
+Description=Subversion ioslave for KDevelop
+Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop
+Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop)
+Description[el]=Subversion ioslave για το KDevelop
+Description[es]=El ioslave de Subversion para KDevelop
+Description[et]=KDevelopi Subversioni IO-moodul
+Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop
+Description[hu]=Subversion KDE-protokoll a KDevelophoz
+Description[it]=ioslave di subversion per KDevelop
+Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave
+Description[ms]=IOslave Subversion untuk KDevelop
+Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion
+Description[nl]=Subversion-ioslave voor KDevelop
+Description[pl]=Wtyczka protokołu Subversion dla KDevelopa
+Description[pt]='Ioslave' do Subversion para o KDevelop
+Description[pt_BR]='Ioslave' do Subversion para o KDevelop
+Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop
+Description[sk]=Subversion ioslave pre KDevelop
+Description[sr]=KIOSlave Subversion-а за KDevelop
+Description[sr@Latn]=KIOSlave Subversion-a za KDevelop
+Description[sv]=Subversion I/O-slav för KDevelop
+Description[zh_TW]=KDevelop çš„ Subversion ioslave
+maxInstances=5
+class=:internet
diff --git a/vcs/subversion/kdevsvnd.cpp b/vcs/subversion/kdevsvnd.cpp
new file mode 100644
index 00000000..9963cddd
--- /dev/null
+++ b/vcs/subversion/kdevsvnd.cpp
@@ -0,0 +1,394 @@
+/*
+ This file is part of the KDE Project
+
+ Copyright (C) 2003, 2004 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software 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 library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <ktextedit.h>
+#include <kpassdlg.h>
+#include <qdir.h>
+#include <qfile.h>
+
+#include "config.h"
+
+#include "kdevsvnd.h"
+
+#include "kdevsvnd_widgets.h"
+#include "commitdlg.h"
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_kdevsvnd(const QCString &name) {
+ return new KDevSvnd(name);
+ }
+}
+
+KDevSvnd::KDevSvnd(const QCString &name)
+ : KDEDModule(name) {
+}
+KDevSvnd::~KDevSvnd()
+{}
+
+QString KDevSvnd::commitDialog(QString modifiedFiles) {
+ CommitDlg commitDlg;
+ commitDlg.setCaption(i18n("Enter Commit Log Message:"));
+ commitDlg.listMessage->setText( modifiedFiles );
+ int result = commitDlg.exec();
+ if ( result == QDialog::Accepted ) {
+ return commitDlg.textMessage->text();
+ } else
+ return QString::null;
+}
+int KDevSvnd::sslServerTrustPrompt( QString errmsg, QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert )
+{
+ SvnSSLTrustPrompt dlg;
+ dlg.setupCertInfo( hostname, fingerPrint, validfrom, validuntil, issuerName, ascii_cert );
+ dlg.setupFailedReasonMsg( errmsg );
+ int result = dlg.exec();
+ if ( result == QDialog::Accepted ){
+ return dlg.code();
+ } else{
+ return -1;
+ }
+}
+QString KDevSvnd::sslCertFile()
+{
+ QString fileName = KFileDialog::getOpenFileName(QString::null,QString::null,0, i18n("Open SSL certificate file"));
+ return fileName;
+}
+QCString KDevSvnd::sslPasswdDlg(QString promptMsg)
+{
+ QCString passwd;
+ int ret = KPasswordDialog::getPassword( passwd,promptMsg );
+ if( ret == KPasswordDialog::Accepted ){
+ QCString retstr;
+ retstr.setNum(1);
+ return retstr + passwd;
+ } else{
+ QCString nullstr;
+ nullstr.setNum(-1);
+ return nullstr;
+ }
+}
+
+
+// void KDevSvnd::registerMe(const QCString &app)
+// {
+// insert(app, "test", new TestObject(app));
+// // When 'app' unregisters with DCOP, the TestObject will get deleted.
+// }
+
+// bool KSvnd::AreAnyFilesInSvn( const KURL::List& wclist ) {
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl;
+// QDir bdir ( ( *it ).path() );
+// if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+// return true;
+// } else if ( !bdir.exists() ) {
+// if ( isFileInSvnEntries( ( *it ).fileName(), ( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+// return true;
+// }
+// }
+// return false;
+// }
+//
+// bool KSvnd::AreAnyFilesNotInSvn( const KURL::List& wclist ) {
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl;
+// QDir bdir ( ( *it ).path() );
+// if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+// return true;
+// } else if ( !bdir.exists() ) {
+// if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+// return true;
+// }
+// }
+// return false;
+// }
+//
+// bool KSvnd::AreAllFilesInSvn( const KURL::List& wclist ) {
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl;
+// QDir bdir ( ( *it ).path() );
+// if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+// return false;
+// } else if ( !bdir.exists() ) {
+// if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+// return false;
+// }
+// }
+// return true;
+// }
+//
+// bool KSvnd::AreAllFilesNotInSvn( const KURL::List& wclist ) {
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl;
+// QDir bdir ( ( *it ).path() );
+// if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) {
+// return false;
+// } else if ( !bdir.exists() ) {
+// if ( isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) )
+// return false;
+// }
+// }
+// return true;
+// }
+//
+// bool KSvnd::isFileInSvnEntries ( const QString filename, const QString entfile ) {
+// QFile file( entfile );
+// if ( file.open( IO_ReadOnly ) ) {
+// QTextStream stream( &file );
+// QString line;
+// while ( !stream.atEnd() ) {
+// line = stream.readLine().simplifyWhiteSpace();
+// if ( line == "name=\""+ filename + "\"" ) {
+// file.close();
+// return true;
+// }
+// }
+// file.close();
+// }
+// return false;
+// }
+//
+// bool KSvnd::isFileInExternals ( const QString filename, const QString propfile ) {
+// QFile file( propfile );
+// if ( file.open( IO_ReadOnly ) ) {
+// QTextStream stream( &file );
+// QStringList line;
+// while ( !stream.atEnd() )
+// line << stream.readLine().simplifyWhiteSpace();
+// for ( uint i = 0 ; i < line.count(); i++ ) {
+// if ( line[ i ] == "K 13" && line[ i+1 ] == "svn:externals" ) { //Key 13 : svn:externals
+// //next line should be "V xx"
+// if ( line [ i+2 ].startsWith( "V " ) ) {
+// //ok browse the values now
+// i+=2;
+// while ( i < line.count() ) {
+// if ( line[ i ].startsWith( filename+" " ) ) { //found it !
+// file.close( );
+// return true;
+// } else if ( line[ i ].isEmpty() ) {
+// file.close( );
+// return false; //we are out of svn:externals now...
+// }
+// i++;
+// }
+// }
+// }
+// }
+// file.close();
+// }
+// return false;
+// }
+//
+// bool KSvnd::anyNotValidWorkingCopy( const KURL::List& wclist ) {
+// bool result = true; //one negative match is enough
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// //exception for .svn dirs
+// if ( ( *it ).path(-1).endsWith( "/.svn" ) )
+// return true;
+// //if is a directory check whether it contains a .svn/entries file
+// QDir dir( ( *it ).path() );
+// if ( dir.exists() ) { //it's a dir
+// if ( !QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+// result = false;
+// }
+//
+// //else check if ./.svn/entries exists
+// if ( !QFile::exists( ( *it ).directory() + "/.svn/entries" ) )
+// result = false;
+// }
+// return result;
+// }
+//
+// bool KSvnd::anyValidWorkingCopy( const KURL::List& wclist ) {
+// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) {
+// //skip .svn dirs
+// if ( ( *it ).path(-1).endsWith( "/.svn" ) )
+// continue;
+// //if is a directory check whether it contains a .svn/entries file
+// QDir dir( ( *it ).path() );
+// if ( dir.exists() ) { //it's a dir
+// if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+// return true;
+// }
+//
+// //else check if ./.svn/entries exists
+// if ( QFile::exists( ( *it ).directory() + "/.svn/entries" ) )
+// return true;
+// }
+// return false;
+// }
+//
+// int KSvnd::getStatus( const KURL::List& list ) {
+// int result = 0;
+// uint files = 0, folders = 0, parentsentries = 0, parentshavesvn = 0, subdirhavesvn = 0, external = 0;
+// for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+// if ( isFolder ( ( *it ) ) ) {
+// folders++;
+// } else {
+// files++;
+// }
+// if ( isFileInSvnEntries ( (*it).filename(),( *it ).directory() + "/.svn/entries" ) ) { // normal subdir known in the working copy
+// parentsentries++;
+// } else if ( isFolder( *it ) ) { // other subfolders (either another module checkouted or an external, or something not known at all)
+// if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) )
+// subdirhavesvn++;
+// if ( isFileInExternals( (*it).filename(), ( *it ).directory() + "/.svn/dir-props" ) ) {
+// external++;
+// }
+// }
+// if ( ( isFolder( ( *it ) ) && QFile::exists( ( *it ).directory() + "../.svn/entries" ) ) || QFile::exists( ( *it ).directory() + "/.svn/entries" ) ) //parent has a .svn ?
+// parentshavesvn++;
+// }
+// if ( files > 0 )
+// result |= SomeAreFiles;
+// if ( folders == list.count() ) {
+// result |= AllAreFolders;
+// result |= SomeAreFolders;
+// }
+// if ( folders > 0 )
+// result |= SomeAreFolders;
+// if ( parentsentries == list.count() ) {
+// result |= AllAreInParentsEntries;
+// result |= SomeAreInParentsEntries;
+// } else if ( parentsentries != 0 )
+// result |= SomeAreInParentsEntries;
+// if ( parentshavesvn == list.count() ) {
+// result |= AllParentsHaveSvn;
+// result |= SomeParentsHaveSvn;
+// } else if ( parentshavesvn > 0 )
+// result |= SomeParentsHaveSvn;
+// if ( subdirhavesvn == list.count() ) {
+// result |= AllHaveSvn;
+// result |= SomeHaveSvn;
+// } else if ( subdirhavesvn > 0 )
+// result |= SomeHaveSvn;
+// if ( external == list.count() ) {
+// result |= AllAreExternalToParent;
+// result |= SomeAreExternalToParent;
+// } else if ( external > 0 )
+// result |= SomeAreExternalToParent;
+//
+// return result;
+// }
+//
+// bool KSvnd::isFolder( const KURL& url ) {
+// QDir d( url.path() );
+// return d.exists();
+// }
+//
+// QStringList KSvnd::getActionMenu ( const KURL::List &list ) {
+// QStringList result;
+// int listStatus = getStatus( list );
+//
+// if ( !(listStatus & SomeAreInParentsEntries) &&
+// !(listStatus & SomeAreExternalToParent) &&
+// !(listStatus & SomeHaveSvn)) {
+// if( list.size() == 1 && listStatus & SomeAreFolders) {
+// result << "Checkout";
+// result << "Export";
+// // result << "CreateRepository";
+// result << "Import";
+// }
+// } else if ( (listStatus & AllAreInParentsEntries) ) {
+// result << "Diff";
+// //In SVN
+// // result << "ShowLog";
+// // result << "CheckForModifications";
+// // result << "RevisionGraph";
+// // result << "_SEPARATOR_";
+// // result << "Update to revision..."
+// result << "Rename";
+// result << "Delete";
+// if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) {
+// result << "Revert";
+// // result << "Cleanup";
+// }
+// result << "_SEPARATOR_";
+// // result << "BranchTag";
+// result << "Switch";
+// result << "Merge";
+// if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) {
+// // result << "Export";
+// // result << "Relocate";
+// result << "_SEPARATOR_";
+// result << "Add";
+// }
+// result << "_SEPARATOR_";
+// if( listStatus & SomeAreFiles && !(listStatus & SomeAreFolders)) {
+// result << "Blame";
+// }
+// result << "CreatePatch";
+//
+// if( list.size() == 1 && listStatus & SomeAreFolders) {
+// // result << "ApplyPatchToFolder";
+// }
+// }
+// return result;
+// }
+//
+// QStringList KSvnd::getTopLevelActionMenu ( const KURL::List &list ) {
+// QStringList result;
+// int listStatus = getStatus( list );
+//
+//
+// if ( ( listStatus & AllParentsHaveSvn &&
+// ( ( listStatus & SomeAreExternalToParent ) || ( listStatus & SomeAreInParentsEntries ) )
+// || ( listStatus & SomeHaveSvn ) )
+// ) {
+// result << "Update";
+// result << "Commit";
+// }
+//
+// return result;
+// }
+//
+// #if 0
+// void KSvnd::notify(const QString& path, int action, int kind, const QString& mime_type, int content_state, int prop_state, long int revision, const QString& userstring) {
+// kdDebug(9036) << "KDED/Subversion : notify " << path << " action : " << action << " mime_type : " << mime_type << " content_state : " << content_state << " prop_state : " << prop_state << " revision : " << revision << " userstring : " << userstring << endl;
+// QByteArray params;
+//
+// QDataStream stream(params, IO_WriteOnly);
+// stream << path << action << kind << mime_type << content_state << prop_state << revision << userstring;
+//
+// emitDCOPSignal( "subversionNotify(QString,int,int,QString,int,int,long int,QString)", params );
+// }
+//
+// void KSvnd::status(const QString& path, int text_status, int prop_status, int repos_text_status, int repos_prop_status, long int rev ) {
+// kdDebug(9036) << "KDED/Subversion : status " << path << " " << text_status << " " << prop_status << " "
+// << repos_text_status << " " << repos_prop_status << " " << rev << endl;
+// QByteArray params;
+//
+// QDataStream stream(params, IO_WriteOnly);
+// stream << path << text_status << prop_status << repos_text_status << repos_prop_status << rev;
+//
+// emitDCOPSignal( "subversionStatus(QString,int,int,int,int,long int)", params );
+// }
+//
+// void KSvnd::popupMessage( const QString& message ) {
+// kdDebug(9036) << "KDED/Subversion : popupMessage" << message << endl;
+// KMessageBox::information(0, message, i18n( "Subversion" ) );
+// }
+// #endif
+
+#include "kdevsvnd.moc"
diff --git a/vcs/subversion/kdevsvnd.desktop b/vcs/subversion/kdevsvnd.desktop
new file mode 100644
index 00000000..139350f5
--- /dev/null
+++ b/vcs/subversion/kdevsvnd.desktop
@@ -0,0 +1,31 @@
+[Desktop Entry]
+Type=Service
+Name=KDevelop subversion module
+Name[ca]=Mòdul de Subversion per a KDevelop
+Name[da]=KDevelop Subversion-modul
+Name[de]=Subversion-Komponente (KDevelop)
+Name[el]=ΆÏθÏωμα subversion του KDevelop
+Name[es]=Módulo de Subversion de KDevelop
+Name[et]=KDevelopi Subversioni moodul
+Name[fr]=Module Subversion pour KDevelop
+Name[hu]=KDevelop-modul a Subversion kezeléséhez
+Name[it]=Modulo subversion di KDevelop
+Name[ja]=KDevelop Subversion モジュール
+Name[ms]=Modul Subversion KDevelop
+Name[nds]=KDevelop-Moduul för Subversion
+Name[nl]=KDevelop subversion-module
+Name[pl]=Modul Subversion dla KDevelopa
+Name[pt]=Módulo de Subversion do KDevelop
+Name[pt_BR]=Módulo de Subversion do KDevelop
+Name[ru]=Модуль Subversion Ð´Ð»Ñ KDevelop
+Name[sk]=KDevelop subversion modul
+Name[sr]=KDevelop-ов модул за Subversion
+Name[sr@Latn]=KDevelop-ov modul za Subversion
+Name[sv]=KDevelop Subversion-modul
+Name[zh_TW]=KDevelop Subversion 模組
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=kdevsvnd
+X-KDE-FactoryName=kdevsvnd
+X-KDE-Kded-autoload=true
+X-KDE-Kded-load-on-demand=true
diff --git a/vcs/subversion/kdevsvnd.h b/vcs/subversion/kdevsvnd.h
new file mode 100644
index 00000000..ad718f0c
--- /dev/null
+++ b/vcs/subversion/kdevsvnd.h
@@ -0,0 +1,50 @@
+/*
+ This file is part of the KDE Project
+
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as published by the Free Software Foundation.
+
+ This software 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 library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef KSVND_H
+#define KSVND_H
+
+#include <dcopclient.h>
+#include <kdedmodule.h>
+#include <kurl.h>
+#include <qstringlist.h>
+
+class KDevSvnd : public KDEDModule
+{
+Q_OBJECT
+
+K_DCOP
+
+ //note: InSVN means parent is added. InRepos means itself is added
+ enum { SomeAreFiles = 1, SomeAreFolders = 2, SomeAreInParentsEntries = 4, SomeParentsHaveSvn = 8, SomeHaveSvn = 16, SomeAreExternalToParent = 32, AllAreInParentsEntries = 64, AllParentsHaveSvn = 128, AllHaveSvn = 256, AllAreExternalToParent = 512, AllAreFolders = 1024 };
+public:
+ KDevSvnd(const QCString &);
+ ~KDevSvnd();
+
+k_dcop:
+// void addAuthInfo(KIO::AuthInfo, long);
+ QString commitDialog(QString);
+ int sslServerTrustPrompt(QString certFailMsg, QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert );
+ QString sslCertFile();
+ QCString sslPasswdDlg(QString promptMsg);
+
+};
+
+#endif
diff --git a/vcs/subversion/kdevsvnd_widgets.cpp b/vcs/subversion/kdevsvnd_widgets.cpp
new file mode 100644
index 00000000..16e35ce3
--- /dev/null
+++ b/vcs/subversion/kdevsvnd_widgets.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+#include "kdevsvnd_widgets.h"
+#include <qpushbutton.h>
+#include <qlistview.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+SvnSSLTrustPrompt::SvnSSLTrustPrompt( QWidget* parent, const char* name, bool modal, WFlags f )
+ :SvnSSLTrustPromptBase( parent, name, modal, f )
+ , m_code(-1)
+{
+ listView1->setColumnText( 0, "Items" );
+ listView1->setColumnText( 1, "Values" );
+ btnPermanent->setText(i18n("Accept Permanently"));
+ btnTemporary->setText(i18n("Accept Temporarily"));
+ btnReject->setText(i18n("Reject"));
+ connect( btnPermanent, SIGNAL(clicked()), this, SLOT(setPermanent()) );
+ connect( btnTemporary, SIGNAL(clicked()), this, SLOT(setTemporary()) );
+ connect( btnReject, SIGNAL(clicked()), this, SLOT(setRejected ()) );
+}
+SvnSSLTrustPrompt::~SvnSSLTrustPrompt()
+{}
+
+void SvnSSLTrustPrompt::setupCertInfo( QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert )
+{
+ // setup texts
+ QListViewItem *host= new QListViewItem(listView1, i18n("Hostname"), hostname );
+ QListViewItem *finger = new QListViewItem(listView1, i18n("FingerPrint"), fingerPrint );
+ QListViewItem *validFrom = new QListViewItem(listView1, i18n("Valid From"), validfrom );
+ QListViewItem *validUntil = new QListViewItem(listView1, i18n("Valid Until"), validuntil );
+ QListViewItem *issName = new QListViewItem(listView1, i18n("Issuer"), issuerName );
+ QListViewItem *cert = new QListViewItem(listView1, i18n("Cert"), ascii_cert );
+}
+void SvnSSLTrustPrompt::setupFailedReasonMsg( QString msg )
+{
+ errMsgLabel->setText( msg );
+}
+int SvnSSLTrustPrompt::code()
+{
+ return m_code;
+}
+
+void SvnSSLTrustPrompt::setPermanent()
+{
+ m_code = 1;
+}
+
+void SvnSSLTrustPrompt::setTemporary()
+{
+ m_code = 0;
+}
+
+void SvnSSLTrustPrompt::setRejected()
+{
+ m_code = -1;
+}
+#include "kdevsvnd_widgets.moc"
diff --git a/vcs/subversion/kdevsvnd_widgets.h b/vcs/subversion/kdevsvnd_widgets.h
new file mode 100644
index 00000000..c69fdb14
--- /dev/null
+++ b/vcs/subversion/kdevsvnd_widgets.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+#ifndef KDEVSVND_WIDGETS_H
+#define KDEVSVND_WIDGETS_H
+
+#include "svnssltrustpromptbase.h"
+
+class SvnSSLTrustPrompt : public SvnSSLTrustPromptBase{
+Q_OBJECT
+public:
+ SvnSSLTrustPrompt( QWidget* parent=0, const char* name=0, bool modal=true, WFlags f=0 );
+ ~SvnSSLTrustPrompt();
+ void setupCertInfo( QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert );
+ void setupFailedReasonMsg( QString msg );
+ int code();
+
+public slots:
+ void setPermanent();
+ void setTemporary();
+ void setRejected();
+
+protected:
+ // -1 for reject
+ // 0 for accept temporarily
+ // 1 for accept permanently
+ int m_code;
+};
+
+#endif
diff --git a/vcs/subversion/subversion_core.cpp b/vcs/subversion/subversion_core.cpp
new file mode 100644
index 00000000..0a91d349
--- /dev/null
+++ b/vcs/subversion/subversion_core.cpp
@@ -0,0 +1,738 @@
+/**
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#include <kparts/part.h>
+#include <kdevcore.h>
+#include <kdevproject.h>
+#include "subversion_part.h"
+#include "subversion_core.h"
+#include "subversion_widget.h"
+#include "svn_blamewidget.h"
+#include "svn_logviewwidget.h"
+#include "subversiondiff.h"
+#include <kdevmainwindow.h>
+#include "svn_co.h"
+#include <kurlrequester.h>
+#include <klineedit.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kio/netaccess.h>
+#include <kdebug.h>
+#include <kmainwindow.h>
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <ktempfile.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+#include <qtextbrowser.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+using namespace KIO;
+using namespace SvnGlobal;
+
+subversionCore::subversionCore(subversionPart *part)
+// : QObject(NULL, "subversion core"), DCOPObject("subversion") {
+ : QObject(NULL, "subversion core") {
+ m_part = part;
+ m_widget = new subversionWidget(part, 0 , "subversionprocesswidget");
+// m_logViewWidget = new SvnLogViewWidget( part, 0 );
+// m_part->mainWindow()->embedOutputView( m_logViewWidget, i18n( "Subversion Log" ), i18n( "Subversion Log" ) );
+// if ( ! connectDCOPSignal("kded", "ksvnd", "subversionNotify(QString,int,int,QString,int,int,long int,QString)", "notification(QString,int,int,QString,int,int,long int,QString)", false ) )
+// kdWarning() << "Failed to connect to kded dcop signal ! Notifications won't work..." << endl;
+
+ m_fileInfoProvider = new SVNFileInfoProvider( part );
+ diffTmpDir = new KTempDir();
+ diffTmpDir->setAutoDelete(true);
+}
+
+subversionCore::~subversionCore() {
+ if ( processWidget() ) {
+ m_part->mainWindow()->removeView( processWidget() );
+ delete processWidget();
+ }
+// if( m_logViewWidget ){
+// m_part->mainWindow()->removeView( m_logViewWidget );
+// delete m_logViewWidget;
+// }
+ delete diffTmpDir;
+ //FIXME delete m_fileInfoProvider here?
+}
+
+KDevVCSFileInfoProvider *subversionCore::fileInfoProvider() const {
+ return m_fileInfoProvider;
+}
+
+//not used anymore
+// void subversionCore::notification( const QString& path, int action, int kind, const QString& mime_type, int content_state ,int prop_state ,long int revision, const QString& userstring ) {
+// kdDebug(9036) << "Subversion Notification : "
+// << "path : " << path
+// << "action: " << action
+// << "kind : " << kind
+// << "mime_type : " << mime_type
+// << "content_state : " << content_state
+// << "prop_state : " << prop_state
+// << "revision : " << revision
+// << "userstring : " << userstring
+// << endl;
+// if ( !userstring.isEmpty() ) {
+// m_part->mainWindow()->raiseView(processWidget());
+// processWidget()->append( userstring );
+// }
+// }
+
+subversionWidget *subversionCore::processWidget() const {
+// SvnLogViewWidget* subversionCore::processWidget() const {
+// return processWidget();
+// return m_logViewWidget;
+ return m_widget;
+}
+
+void subversionCore::resolve( const KURL::List& list ) {
+ KURL servURL = m_part->baseURL();
+ if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/";
+ if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) {
+ servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn"
+ }
+ kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(9036) << "resolving: " << (*it).prettyURL() << endl;
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 11;
+ bool recurse = true;
+ s << cmd << *it << recurse;
+ SimpleJob * job = KIO::special(servURL, parms, true);
+ job->setWindow( m_part->mainWindow()->main() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ }
+}
+
+void subversionCore::update( const KURL::List& list ) {
+ KURL servURL = "kdevsvn+svn://blah/";
+ kdDebug(9036) << "Updating. servURL : " << servURL.prettyURL() << endl;
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 2;
+ int rev = -1;
+ s << cmd << list << rev << QString( "HEAD" );
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, i18n("Subversion Update") , i18n("Subversion Update") );
+}
+
+void subversionCore::diff( const KURL::List& list, const QString& where){
+ kdDebug(9036) << "diff " << list << endl;
+ KURL servURL = "kdevsvn+svn://this_is_a_fake_URL_and_this_is_normal/";
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 13;
+ kdDebug(9036) << "diffing : " << (*it).prettyURL() << endl;
+ int rev1=-1;
+ int rev2=-1;
+ QString revkind1 = where;
+ QString revkind2 = "WORKING";
+ s << cmd << *it << *it << rev1 << revkind1 << rev2 << revkind2 << true ;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, true);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ KIO::NetAccess::synchronousRun( job, 0 );
+ if ( diffresult.count() > 0 ) {
+ //check kompare is available
+ if ( !KStandardDirs::findExe( "kompare" ).isNull() ) {
+ if (!KStandardDirs::findExe("patch").isNull()){
+ // we have patch - so can merge
+ KTempDir tmpDir = KTempDir(diffTmpDir->name());
+ KTempFile tmpPatch = KTempFile(tmpDir.name());
+
+ // write the patch
+ QTextStream *stream = tmpPatch.textStream();
+ stream->setCodec( QTextCodec::codecForName( "utf8" ) );
+ for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) {
+ ( *stream ) << ( *it2 ) << "\n";
+ }
+ tmpPatch.close();
+
+ QString ourCopy = tmpDir.name()+(*it).fileName();
+
+ KProcess copy;
+ copy << "cp" << (*it).prettyURL(0,KURL::StripFileProtocol) << tmpDir.name();
+ copy.start(KProcess::Block);
+
+ KProcess patch;
+ patch.setWorkingDirectory(tmpDir.name());
+ patch << "patch" << "-R" << ourCopy << tmpPatch.name();
+ patch.start(KProcess::Block, KProcess::All);
+
+ KProcess *p = new KProcess;
+ *p << "kompare" << ourCopy << (*it).prettyURL();
+ p->start();
+ }
+ else{
+ // only diff
+ KTempFile *tmp = new KTempFile;
+ tmp->setAutoDelete(true);
+ QTextStream *stream = tmp->textStream();
+ stream->setCodec( QTextCodec::codecForName( "utf8" ) );
+ for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) {
+ ( *stream ) << ( *it2 ) << "\n";
+ }
+ tmp->close();
+ KProcess *p = new KProcess;
+ *p << "kompare" << "-n" << "-o" << tmp->name();
+ p->start();
+ }
+ } else { //else do it with message box
+ Subversion_Diff df;
+ for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) {
+ df.text->append( *it2 );
+ }
+ QFont f = df.font();
+ f.setFixedPitch( true );
+ df.text->setFont( f );
+ df.exec();
+ }
+ }
+ else{
+ QString diffTo = i18n("the local disk checked out copy.");
+ if ( where=="HEAD"){
+ diffTo=i18n("the current svn HEAD version.");
+ }
+ KMessageBox::information( 0, i18n("No differences between the file and %1").arg(diffTo), i18n("No difference") );
+ }
+ diffresult.clear();
+ }
+}
+
+void subversionCore::diffAsync( const KURL &pathOrUrl1, const KURL &pathOrUrl2,
+ int rev1, QString revKind1, int rev2, QString revKind2,
+ bool recurse, bool pegdiff )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 13;
+ kdDebug(9036) << "diffing async : " << pathOrUrl1 << " and " << pathOrUrl2 << endl;
+ s << cmd << pathOrUrl1 << pathOrUrl2 << rev1 << revKind1 << rev2 << revKind2 << recurse;
+ s << pegdiff;
+ KIO::SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotDiffResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, pathOrUrl1.prettyURL(), pathOrUrl2.prettyURL() );
+}
+
+void subversionCore::commit( const KURL::List& list, bool recurse, bool keeplocks ) {
+ KURL servURL = m_part->baseURL();
+ if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/";
+ if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) {
+ servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn"
+ }
+ kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl;
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 103;
+ s << cmd << recurse << keeplocks;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(9036) << "adding to list: " << (*it).prettyURL() << endl;
+ s << *it;
+ }
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ if( list.count() == 1 )
+ initProcessDlg( (KIO::Job*)job, (*(list.begin())).prettyURL() , i18n("Commit to remote repository") );
+ else if( list.count() > 1 )
+ initProcessDlg( (KIO::Job*)job, i18n("From working copy") , i18n("Commit to remote repository") );
+}
+// Right now, only one item for each action.
+void subversionCore::svnLog( const KURL::List& list,
+ int revstart, QString revKindStart, int revend, QString revKindEnd,
+ bool discorverChangedPath, bool strictNodeHistory )
+{
+ // ensure that part has repository information. This info is used to retrieve root repository URL
+ if( m_part->m_prjInfoMap.count() < 1 )
+ clientInfo( KURL(m_part->project()->projectDirectory()), false, m_part->m_prjInfoMap );
+ KURL servURL = m_part->baseURL();
+ if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/";
+ if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) {
+ servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn"
+ }
+ kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl;
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 4;
+// int revstart = -1, revend = 0;
+// QString revKindStart = "HEAD", revKindEnd = "";
+// bool repositLog = true, discorverChangedPath = true, strictNodeHistory = true;
+ s << cmd << revstart << revKindStart << revend << revKindEnd;
+ s << discorverChangedPath << strictNodeHistory;
+ for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) {
+ kdDebug(9036) << "svnCore: adding to list: " << (*it).prettyURL() << endl;
+ s << *it;
+ }
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotLogResult( KIO::Job * ) ) );
+ // progress info. LogView is allowed and meaninful only for one url in KDev3.4
+ initProcessDlg( (KIO::Job*)job, (*(list.begin())).prettyURL() , i18n("Subversion Log View") );
+}
+
+void subversionCore::blame( const KURL &url, UrlMode mode, int revstart, QString revKindStart, int revend, QString revKindEnd )
+{
+ KURL servURL = m_part->baseURL();
+ if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/";
+ if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) {
+ servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn"
+ }
+ kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl;
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 14;
+ s << cmd << url << (int)mode ;
+ s << revstart << revKindStart << revend << revKindEnd ;
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotBlameResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, url.prettyURL() , i18n("Subversion Blame") );
+}
+
+void subversionCore::add( const KURL::List& list ) {
+
+ KURL servURL = "kdevsvn+svn://blah/";
+ kdDebug(9036) << "Deleting servURL : " << servURL.prettyURL() << endl;
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 6;
+ s << cmd << list;
+ // add/delete/revert works on local copy. Don't need to show progress dialog
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ job->setWindow( m_part->mainWindow()->main() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+}
+
+void subversionCore::del( const KURL::List& list ) {
+ KURL servURL = "kdevsvn+svn://blah/";
+ kdDebug(9036) << "Deleting servURL : " << servURL.prettyURL() << endl;
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 7;
+ s << cmd << list;
+ // add/delete/revert works on local copy. Don't need to show progress dialog
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ job->setWindow( m_part->mainWindow()->main() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+}
+
+void subversionCore::revert( const KURL::List& list ) {
+ KURL servURL = "kdevsvn+svn://blah/";
+ kdDebug(9036) << "Reverting servURL : " << servURL.prettyURL() << endl;
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 8;
+ s << cmd << list;
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ job->setWindow( m_part->mainWindow()->main() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+}
+
+void subversionCore::checkout() {
+ svn_co checkoutDlg;
+
+ if ( checkoutDlg.exec() == QDialog::Accepted ) {
+ //checkout :)
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ KURL servURL ( checkoutDlg.serverURL->url() );
+ wcPath = checkoutDlg.localDir->url() + "/" + checkoutDlg.newDir->text();
+ int cmd = 1;
+ int rev = -1;
+ s << cmd << servURL << KURL( wcPath ) << rev << QString( "HEAD" );
+ servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn"
+ SimpleJob * job = KIO::special(servURL,parms, true);
+ job->setWindow( m_part->mainWindow()->main() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotEndCheckout( KIO::Job * ) ) );
+ }
+}
+
+void subversionCore::switchTree( const KURL &path, const KURL &repositUrl,
+ int revNum, const QString &revKind, bool recurse )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 12;
+ s << cmd << path << repositUrl ;
+ s << recurse << revNum << revKind;
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, repositUrl.prettyURL() , path.prettyURL() );
+}
+
+void subversionCore::switchRelocate( const KURL &path,
+ const KURL &currentUrl, const KURL &newUrl, bool recurse )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 16;
+ s << cmd << path << currentUrl << newUrl << recurse;
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ // this doesn't contact repository
+}
+
+void subversionCore::svnCopy( const KURL &src, int srcRev, const QString &srcRevKind,
+ const KURL &dest )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 17;
+ s << cmd << src << srcRev << srcRevKind << dest;
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, src.prettyURL(), dest.prettyURL() );
+}
+
+void subversionCore::merge( const KURL &src1, int rev1, QString revKind1,
+ const KURL &src2, int rev2, QString revKind2, const KURL &wc_path,
+ bool recurse, bool ignore_ancestry, bool force, bool dry_run )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ // prepare arguments
+ int cmd = 18;
+ s << cmd << src1 << rev1 << revKind1 << src2 << rev2 << revKind2 << wc_path;
+ s << recurse << ignore_ancestry << force << dry_run;
+
+ SimpleJob * job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ initProcessDlg( (KIO::Job*)job, src1.prettyURL() + "\n" + src2.prettyURL() ,
+ wc_path.prettyURL() );
+}
+
+bool subversionCore::clientInfo( KURL path_or_url, bool recurse, QMap< KURL, SvnInfoHolder> &holderMap )
+{
+ KURL servURL = "kdevsvn+svn://blah/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 15;
+ s << cmd << path_or_url << -1 << QString("UNSPECIFIED") << -1 << QString("UNSPECIFIED") << recurse;
+ SimpleJob *job = KIO::special( servURL, parms, false );
+
+ QMap<QString,QString> ma;
+ KIO::NetAccess::synchronousRun(job, 0, 0, 0, &ma ); // synchronize
+
+ QValueList<QString> keys = ma.keys();
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+ int curIdx, lastIdx;
+ QRegExp rx( "([0-9]*)(.*)" );
+
+ for ( it = begin; it != end; /*++it*/) {
+ kdDebug(9036) << "METADATA key: " << *it << " value: " << ma[ *it ] << endl;
+ if ( rx.search( *it ) == -1 ) return false; // something is wrong ! :)
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ SvnInfoHolder holder;
+
+ while ( curIdx == lastIdx ) {
+ if ( rx.cap( 2 ) == "PATH" )
+ holder.path = KURL( ma[ *it ] );
+ else if ( rx.cap( 2 ) == "URL" )
+ holder.url = KURL( ma[*it] );
+ else if ( rx.cap( 2 ) == "REV" )
+ holder.rev= ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "KIND" )
+ holder.kind = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "REPOS_ROOT_URL" )
+ holder.reposRootUrl = KURL( ma[*it] );
+ else if ( rx.cap( 2 ) == "REPOS_UUID" )
+ holder.reposUuid = ma[ *it ];
+
+ ++it;
+ if ( it == end )
+ break;
+ if ( rx.search( *it ) == -1 ) return false; // something is wrong ! :)
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ holderMap.insert( holder.path, holder );
+ }
+ return true;;
+}
+
+void subversionCore::slotEndCheckout( KIO::Job * job ) {
+ if ( job->error() ) {
+ job->showErrorDialog( m_part->mainWindow()->main() );
+ emit checkoutFinished( QString::null );
+ } else
+ emit checkoutFinished(wcPath);
+}
+
+void subversionCore::slotResult( KIO::Job * job ) {
+ if ( job->error() ){
+ job->showErrorDialog( m_part->mainWindow()->main() );
+ if( job->error() == ERR_CANNOT_LAUNCH_PROCESS )
+ KMessageBox::error( m_part->mainWindow()->main(),
+ i18n("If you have just have installed a new version of KDevelop,"
+ " and the error message was 'unknown protocol kdevsvn+*',"
+ " try restarting KDE."
+ ) );
+ return;
+ }
+ KIO::MetaData ma = job->metaData();
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+
+ for ( it = begin; it != end; ++it ) {
+// kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
+ if ( ( *it ).endsWith( "string" ) ) {
+ m_part->mainWindow()->raiseView(processWidget());
+ processWidget()->append( ma[ *it ] );
+ }
+ //extra check to retrieve the diff output in case with run a diff command
+ if ( ( *it ).endsWith( "diffresult" ) ) {
+ diffresult << ma[ *it ];
+ }
+ }
+}
+void subversionCore::slotLogResult( KIO::Job * job )
+{
+ if ( job->error() ){
+ job->showErrorDialog( m_part->mainWindow()->main() );
+ if( job->error() == ERR_CANNOT_LAUNCH_PROCESS )
+ KMessageBox::error( m_part->mainWindow()->main(),
+ i18n("If you have just have installed a new version of KDevelop,"
+ " and the error message was 'unknown protocol kdevsvn+*',"
+ " try restarting KDE."
+ ) );
+ return;
+ }
+
+ QValueList<SvnLogHolder> holderList;
+
+ KIO::MetaData ma = job->metaData();
+ QValueList<QString> keys = ma.keys();
+ QRegExp rx( "([0-9]*)(.*)" );
+ int curIdx, lastIdx;
+ QString requestedUrl;
+
+ for (QValueList<QString>::Iterator it = keys.begin(); it != keys.end(); /*++it*/ ){
+ if ( rx.search( *it ) == -1 ){
+ kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl;
+ return; // something is wrong ! :)
+ }
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ SvnLogHolder logHolder;
+ while ( curIdx == lastIdx ) {
+ kdDebug(9036) << "svn log MetaData: " << *it << ":" << ma[ *it ] << endl;
+
+ if ( rx.cap( 2 ) == "author" )
+ logHolder.author = ma[*it];
+ else if ( rx.cap( 2 ) == "date" )
+ logHolder.date = ma[*it];
+ else if ( rx.cap( 2 ) == "logmsg" )
+ logHolder.logMsg = ma[*it];
+ else if ( rx.cap( 2 ) == "pathlist" )
+ logHolder.pathList = ma[*it];
+ else if ( rx.cap( 2 ) == "rev" )
+ logHolder.rev = ma[*it];
+ else if ( rx.cap( 2 ) == "requrl" )
+ requestedUrl = ma[*it];
+
+ ++it;
+ if ( it == keys.end() )
+ break;
+ if ( rx.search( *it ) == -1 ){
+ kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl;
+ break; // something is wrong ! :)
+ }
+ curIdx = rx.cap( 1 ).toInt();
+ }//end of while
+ holderList.append( logHolder );
+ }
+ processWidget()->showLogResult( &holderList, requestedUrl );
+ m_part->mainWindow()->raiseView(processWidget());
+
+}
+
+void subversionCore::slotBlameResult( KIO::Job * job )
+{
+ if ( job->error() ){
+ job->showErrorDialog( m_part->mainWindow()->main() );
+ if( job->error() == ERR_CANNOT_LAUNCH_PROCESS )
+ KMessageBox::error( m_part->mainWindow()->main(),
+ i18n("If you have just have installed a new version of KDevelop,"
+ " and the error message was 'unknown protocol kdevsvn+*',"
+ " try restarting KDE."
+ ) );
+ return;
+ }
+ QValueList<SvnBlameHolder> blameList;
+
+ KIO::MetaData ma = job->metaData();
+ QValueList<QString> keys = ma.keys();
+ QRegExp rx( "([0-9]*)(.*)" );
+ int curIdx, lastIdx;
+
+ for (QValueList<QString>::Iterator it = keys.begin(); it != keys.end(); /*++it*/ ){
+ if ( rx.search( *it ) == -1 ){
+ kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl;
+ return; // something is wrong ! :)
+ }
+
+ // if metadata has action key, that means a notification for svn_wc_notify_blame_completed
+ // Thus, consume this notification
+ if ( rx.cap( 2 ) == "action" ){
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ){
+ ++it;
+ if ( it == keys.end() ) break;
+ if ( rx.search( *it ) == -1 ) continue; // something is wrong
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ continue;
+ }
+ // get actual blame data
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ SvnBlameHolder blameHolder;
+ while ( curIdx == lastIdx ) {
+ kdDebug(9036) << "svn blame MetaData: " << *it << ":" << ma[ *it ] << endl;
+
+ if ( rx.cap( 2 ) == "LINE" )
+ blameHolder.line= (ma[*it]).toInt();
+ else if ( rx.cap( 2 ) == "REV" )
+ blameHolder.rev = (ma[*it]).toLongLong();
+ else if ( rx.cap( 2 ) == "AUTHOR" )
+ blameHolder.author= ma[*it];
+ else if ( rx.cap( 2 ) == "DATE" )
+ blameHolder.date= ma[*it];
+ else if ( rx.cap( 2 ) == "CONTENT" )
+ blameHolder.content = ma[*it];
+
+ ++it;
+ if ( it == keys.end() )
+ break;
+ if ( rx.search( *it ) == -1 ){
+ kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl;
+ break; // something is wrong ! :)
+ }
+ curIdx = rx.cap( 1 ).toInt();
+ }//end of while
+ blameList.append( blameHolder );
+// blameList.insert( blameHolder.line, blameHolder );
+ }
+ processWidget()->showBlameResult( &blameList );
+ m_part->mainWindow()->raiseView(processWidget());
+}
+
+void subversionCore::slotDiffResult( KIO::Job * job )
+{
+ if ( job->error() ){
+ job->showErrorDialog( m_part->mainWindow()->main() );
+ if( job->error() == ERR_CANNOT_LAUNCH_PROCESS )
+ KMessageBox::error( m_part->mainWindow()->main(),
+ i18n("If you have just have installed a new version of KDevelop,"
+ " and the error message was 'unknown protocol kdevsvn+*',"
+ " try restarting KDE."
+ ) );
+ return;
+ }
+ KIO::MetaData ma = job->metaData();
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+ QStringList diffList;
+
+ for ( it = begin; it != end; ++it ) {
+// kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
+ if ( ( *it ).endsWith( "diffresult" ) ) {
+ diffList << ma[ *it ];
+ }
+ }
+
+ if ( diffList.count() > 0 ) {
+ //check kompare is available
+ if ( !KStandardDirs::findExe( "kompare" ).isNull() ) {
+ KTempFile *tmp = new KTempFile;
+ tmp->setAutoDelete(true);
+ QTextStream *stream = tmp->textStream();
+ stream->setCodec( QTextCodec::codecForName( "utf8" ) );
+ for ( QStringList::Iterator it2 = diffList.begin();it2 != diffList.end() ; ++it2 ) {
+ ( *stream ) << ( *it2 ) << "\n";
+ }
+ tmp->close();
+ KProcess *p = new KProcess;
+ *p << "kompare" << "-n" << "-o" << tmp->name();
+ p->start();
+
+ } else { //else do it with message box
+ KMessageBox::information( NULL, i18n("You do not have kompare installed. We recommend you install kompare to view differences graphically.") + "\nhttp://www.caffeinated.me.uk/kompare/" , QString::null , "userDoesNotWantKompare" );
+ Subversion_Diff df;
+ for ( QStringList::Iterator it2 = diffList.begin();it2 != diffList.end() ; ++it2 ) {
+ df.text->append( *it2 );
+ }
+ QFont f = df.font();
+ f.setFixedPitch( true );
+ df.text->setFont( f );
+ df.exec();
+ }
+ }
+ else{
+ KMessageBox::information( 0, i18n("No subversion differences") );
+ }
+}
+
+void subversionCore::initProcessDlg( KIO::Job *job, const QString &src, const QString &dest )
+{
+ SvnProgressDlg *progress = new SvnProgressDlg( true );
+ progress->setSourceUrl( src );
+ progress->setDestUrl( dest );
+ progress->setJob( job );
+ connect( job, SIGNAL( totalSize(KIO::Job*, KIO::filesize_t) ),
+ progress, SLOT( slotTotalSize (KIO::Job*, KIO::filesize_t) ) );
+ connect( job, SIGNAL( processedSize(KIO::Job*, KIO::filesize_t) ),
+ progress, SLOT( slotProcessedSize(KIO::Job*, KIO::filesize_t) ) );
+}
+
+void subversionCore::createNewProject( const QString& // dirName
+ , const KURL& // importURL
+ , bool // init
+ ) {
+
+}
+
+#include "subversion_core.moc"
diff --git a/vcs/subversion/subversion_core.h b/vcs/subversion/subversion_core.h
new file mode 100644
index 00000000..c879fce6
--- /dev/null
+++ b/vcs/subversion/subversion_core.h
@@ -0,0 +1,105 @@
+/**
+
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SUBVERSION_CORE_H__
+#define __SUBVERSION_CORE_H__
+
+#include <qobject.h>
+#include <qwidget.h>
+#include <kio/job.h>
+#include <kurl.h>
+#include <ktempdir.h>
+#include "subversion_fileinfo.h"
+#include "subversion_global.h"
+
+class KDevProject;
+class subversionPart;
+class subversionWidget;
+class KApplication;
+class SvnBlameHolder;
+class SvnLogHolder;
+class SvnLogViewWidget;
+
+// class subversionCore : public QObject, public DCOPObject
+class subversionCore : public QObject {
+ Q_OBJECT
+// K_DCOP
+
+public:
+
+ subversionCore(subversionPart *part);
+ ~subversionCore();
+ subversionWidget *processWidget() const;
+// SvnLogViewWidget *processWidget() const;
+ void update( const KURL::List&);
+ void commit( const KURL::List&, bool recurse, bool keeplocks );
+ void svnLog( const KURL::List& list,
+ int revstart, QString revKindStart, int revend, QString revKindEnd,
+ bool discorverChangedPath, bool strictNodeHistory );
+ void blame( const KURL &url, SvnGlobal::UrlMode mode, int revstart, QString revKindStart, int revend, QString revKindEnd );
+ void add( const KURL::List&);
+ void del( const KURL::List&);
+ void diff( const KURL::List&, const QString& where);
+ void diffAsync( const KURL &pathOrUrl1, const KURL &pathOrUrl2,
+ int rev1, QString revKind1, int rev2, QString revKind2,
+ bool recurse, bool pegdiff = false );
+ void revert( const KURL::List&);
+ void resolve( const KURL::List&);
+ void checkout();
+ void switchTree( const KURL &path, const KURL &repositUrl,
+ int revNum, const QString &revKind, bool recurse );
+ void switchRelocate( const KURL &path, const KURL &currentUrl, const KURL &newUrl, bool recurse );
+ void svnCopy( const KURL &src, int srcRev, const QString &srcRevKind, const KURL &dest );
+ void merge( const KURL &src1, int rev1, QString revKind1, const KURL &src2, int rev2, QString revKind2, const KURL &wc_path,
+ bool recurse, bool ignore_ancestry, bool force, bool dry_run );
+ // This is blocking function. But the GUI is not blocked.
+ // Information will be pulled solely from the working copy.Thus no network connections will be made.
+ // Parameter holderMap is the map to be filled out by this method. Callers should preallocate this object.
+ // Return true on success. Otherwise return false.
+ bool clientInfo( KURL path_or_url, bool recurse, QMap< KURL, SvnGlobal::SvnInfoHolder> &holderMap );
+ void createNewProject( const QString& dirName, const KURL& importURL, bool init );
+ KDevVCSFileInfoProvider *fileInfoProvider() const;
+
+ void initProcessDlg( KIO::Job *job, const QString &src, const QString &dest );
+// k_dcop:
+// void notification( const QString&, int,int, const QString&, int,int ,long int, const QString& );
+
+private slots:
+ void slotEndCheckout( KIO::Job * job );
+ void slotResult( KIO::Job * job );
+ void slotLogResult( KIO::Job * job );
+ void slotBlameResult( KIO::Job * job );
+ void slotDiffResult( KIO::Job * job );
+
+signals:
+ void checkoutFinished( QString dir );
+
+private:
+ QGuardedPtr<subversionWidget> m_widget;
+ subversionPart *m_part;
+ QString wcPath;
+ SVNFileInfoProvider *m_fileInfoProvider;
+ QStringList diffresult; //for diff commands ;)
+ // be nice about tmp diff files: delete all of them when exiting.
+ KTempDir* diffTmpDir;
+
+};
+
+#endif
diff --git a/vcs/subversion/subversion_fileinfo.cpp b/vcs/subversion/subversion_fileinfo.cpp
new file mode 100644
index 00000000..c9fb9ee6
--- /dev/null
+++ b/vcs/subversion/subversion_fileinfo.cpp
@@ -0,0 +1,507 @@
+/**
+ Copyright (C) 2004-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#include "subversion_fileinfo.h"
+#include "subversion_core.h"
+#include <kdebug.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <kdevproject.h>
+#include <unistd.h>
+#include <kapplication.h>
+#include <kdevmainwindow.h>
+#include <kmainwindow.h>
+#include <qregexp.h>
+
+#include <kio/netaccess.h>
+#include <klocale.h>
+
+SVNFileInfoProvider::SVNFileInfoProvider(subversionPart *parent, const char *name)
+ : KDevVCSFileInfoProvider( parent, "svnfileinfoprovider" ),
+ m_cachedDirEntries( 0 ), m_recursiveDirEntries(0) {
+ Q_UNUSED(name);
+ m_part = parent;
+}
+
+SVNFileInfoProvider::~SVNFileInfoProvider() {
+ delete m_cachedDirEntries;
+ m_cachedDirEntries = 0;
+ delete m_recursiveDirEntries;
+ m_recursiveDirEntries = 0;
+}
+
+//synchronous
+const VCSFileInfoMap *SVNFileInfoProvider::status( const QString &dirPath ) {
+ if ( !m_cachedDirEntries )
+ m_cachedDirEntries = new VCSFileInfoMap;
+// return m_cachedDirEntries;
+
+ kdDebug(9036) << "svn provider : status " << dirPath << endl;
+
+ if ( dirPath != m_previousDirPath ) {
+ m_previousDirPath = dirPath;
+ KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 9;
+ QString rPath = projectDirectory( );
+ rPath += QDir::separator() + dirPath;
+ kdDebug(9036) << "DIR : " << rPath << " " << KURL( QFileInfo( rPath ).absFilePath() ) << endl;
+
+// s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << true << true; //original line
+
+ // Dukju Ahn: if checkRepos is set, status() accesses remote repository,
+ // which causes significant delaym_owner especially when network speed is not fast enough.
+ // Of course, the user cannot get information about the out-of-dateness of his local copy.
+ s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << false/*checkRepos*/ << false /*fullRecurse*/;
+
+ KIO::SimpleJob *job2 = KIO::special(servURL, parms, false);
+ job2->setWindow( m_part->mainWindow()->main() );
+
+
+ QMap<QString,QString> ma;
+
+ KIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma );
+
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+
+ QString path;
+ int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
+ long int rev = 0;
+ int curIdx, lastIdx;
+
+ QRegExp rx( "([0-9]*)(.*)" );
+ for ( it = begin; it != end; ) {
+ kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
+ if ( rx.search( *it ) == -1 ) return m_cachedDirEntries; // something is wrong ! :)
+ /* if some notification comes here, consume these notification metadatas */
+ if ( rx.cap( 2 ) == "action" ){
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ){
+ ++it;
+ if ( it == end ) break;
+ if ( rx.search( *it ) == -1 ) continue; // something is wrong
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ continue;
+ }
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ) {
+ if ( rx.cap( 2 ) == "path" )
+ path = ma[ *it ];
+ else if ( rx.cap( 2 ) == "text" )
+ text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "prop" )
+ prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "reptxt" )
+ repos_text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "repprop" )
+ repos_prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "rev" )
+ rev = ma[ *it ].toLong();
+ ++it;
+ if ( it == end )
+ break;
+ if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
+ }
+ }
+ kdDebug(9036) << " Returning VcsFileInfoMap. provider::status() finished " << endl;
+ return m_cachedDirEntries;
+}
+
+bool SVNFileInfoProvider::requestStatus( const QString &dirPath, void *callerData, bool recursive, bool checkRepos ) {
+ kdDebug(9036) << "##################################################################################### svn provider : request status" << endl;
+ m_savedCallerData = callerData;
+ // Flush old cache
+ if (m_cachedDirEntries)
+ {
+ delete m_cachedDirEntries;
+ m_cachedDirEntries = 0;
+ m_previousDirPath = dirPath;
+ }
+
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 9;
+ QString rPath = projectDirectory( );
+ rPath += QDir::separator() + dirPath;
+
+ if( ! m_part->isValidDirectory( rPath ) ){
+ return false;
+ }
+
+ kdDebug(9036) << "DIR : " << rPath << " " << QFileInfo( rPath ).absFilePath() << endl;
+ s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << checkRepos << recursive;
+ KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
+ job = KIO::special(servURL, parms, false);
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) );
+ if( checkRepos )
+ m_part->svncore()->initProcessDlg( job, dirPath, i18n("Subversion File/Directory Status") );
+ return true;
+}
+
+void SVNFileInfoProvider::slotResult( KIO::Job *j ) {
+ if ( j->error() )
+ j->showErrorDialog( m_part->mainWindow()->main() );
+
+ KIO::MetaData ma = j->metaData();
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+
+ QString path;
+ int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
+ long int rev = 0;
+ int curIdx, lastIdx;
+
+ QRegExp rx( "([0-9]*)(.*)" );
+ for ( it = begin; it != end; ) {
+ kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
+ if ( rx.search( *it ) == -1 ) return; // something is wrong ! :)
+ /* if some notification comes here, consume these notification metadatas */
+ if ( rx.cap( 2 ) == "action" ){
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ){
+ ++it;
+ if ( it == end ) break;
+ if ( rx.search( *it ) == -1 ) continue; // something is wrong
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ continue;
+ }
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ) {
+ if ( rx.cap( 2 ) == "path" )
+ path = ma[ *it ];
+ else if ( rx.cap( 2 ) == "text" )
+ text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "prop" )
+ prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "reptxt" )
+ repos_text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "repprop" )
+ repos_prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "rev" )
+ rev = ma[ *it ].toLong();
+ ++it;
+ if ( it == end )
+ break;
+ if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
+ }
+
+ if ( m_cachedDirEntries )
+ emit statusReady(*m_cachedDirEntries, m_savedCallerData);
+}
+
+void SVNFileInfoProvider::slotStatus( const QString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) {
+// kdDebug(9036) << "##################################################################################### svn provider : slotstatus"
+// << " path " << path << " text_status " << text_status << " prop_status " << prop_status << " repos_text_status " << repos_text_status
+// << " repos_prop_status " << repos_prop_status << " rev " << rev
+// << endl;
+
+ if ( !m_cachedDirEntries )
+ m_cachedDirEntries = new VCSFileInfoMap;
+
+ QString wRev = QString::number( rev ); //work rev
+ QString rRev = QString::number( rev );// repo rev
+ VCSFileInfo::FileState state = VCSFileInfo::Unknown;
+
+ switch ( text_status ) {
+ case 1:
+ break;
+ case 2:
+ break;
+ case 3:
+ state = VCSFileInfo::Uptodate;
+ break;
+ case 4:
+ state = VCSFileInfo::Added;
+ break;
+ case 5:
+ break;
+ case 6: //deleted
+ state = VCSFileInfo::Deleted;
+ break;
+ case 7: //replaced
+ state = VCSFileInfo::Replaced;
+ break;
+ case 8: //modified
+ state = VCSFileInfo::Modified;
+ break;
+ case 9: //merged
+ break;
+ case 10: //conflicted
+ state = VCSFileInfo::Conflict;
+ break;
+ case 11: //ignored
+ break;
+ case 12: //obstructed
+ break;
+ case 13: //external
+ break;
+ case 14: //incomplete
+ break;
+ }
+ switch( prop_status ) {
+ case 8:
+ state = VCSFileInfo::Modified;
+ break;
+ }
+ switch ( repos_text_status ) {
+ case 1:
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ case 4:
+ break;
+ case 5:
+ break;
+ case 6: //deleted
+ break;
+ case 7: //replaced
+ break;
+ case 8: //modified
+ state = VCSFileInfo::NeedsPatch;
+ break;
+ case 9: //merged
+ break;
+ case 10: //conflicted
+ break;
+ case 11: //ignored
+ break;
+ case 12: //obstructed
+ break;
+ case 13: //external
+ break;
+ case 14: //incomplete
+ break;
+ }
+
+ VCSFileInfo info(QFileInfo( path ).fileName(),wRev,rRev,state);
+ kdDebug(9036) << "Inserting " << info.toString() << endl;
+ m_cachedDirEntries->insert( QFileInfo( path ).fileName(), info);
+}
+
+QString SVNFileInfoProvider::projectDirectory() const {
+ return owner()->project()->projectDirectory();
+}
+
+const VCSFileInfoMap *SVNFileInfoProvider::statusExt( const QString &dirPath,
+ bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore )
+{
+ if ( !m_recursiveDirEntries )
+ m_recursiveDirEntries = new VCSFileInfoMap;
+
+// if ( dirPath != m_recursivePreviousDirPath ) {
+ m_recursiveDirEntries->clear();
+ m_recursivePreviousDirPath = dirPath;
+ KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/";
+ QByteArray parms;
+ QDataStream s( parms, IO_WriteOnly );
+ int cmd = 109;
+ QString rPath = projectDirectory( );
+ rPath += QDir::separator() + dirPath;
+ kdDebug(9036) << "DIR : " << rPath << " " << KURL( QFileInfo( rPath ).absFilePath() ) << endl;
+ s << cmd << checkRepos << fullRecurse << getAll << noIgnore << -1 << "WORKING" << KURL( QFileInfo( rPath ).absFilePath() );
+ KIO::SimpleJob *job2 = KIO::special(servURL, parms, false);
+ job2->setWindow( m_part->mainWindow()->main() );
+
+
+ QMap<QString,QString> ma;
+ KIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma );
+
+ QValueList<QString> keys = ma.keys();
+ qHeapSort( keys );
+ QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it;
+
+ QString path;
+ int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0;
+ long int rev = 0;
+ int curIdx, lastIdx;
+
+ QRegExp rx( "([0-9]*)(.*)" );
+ for ( it = begin; it != end; ) {
+ kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl;
+ if ( rx.search( *it ) == -1 ) return m_recursiveDirEntries; // something is wrong ! :)
+ /* if some notification comes here, consume these notification metadatas */
+ if ( rx.cap( 2 ) == "action" ){
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ){
+ ++it;
+ if ( it == end ) break;
+ if ( rx.search( *it ) == -1 ) continue; // something is wrong
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ continue;
+ }
+ /* get properties */
+ curIdx = lastIdx = rx.cap( 1 ).toInt();
+ while ( curIdx == lastIdx ) {
+ if ( rx.cap( 2 ) == "path" )
+ path = ma[ *it ];
+ else if ( rx.cap( 2 ) == "text" )
+ text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "prop" )
+ prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "reptxt" )
+ repos_text_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "repprop" )
+ repos_prop_status = ma[ *it ].toInt();
+ else if ( rx.cap( 2 ) == "rev" )
+ rev = ma[ *it ].toLong();
+ ++it;
+ if ( it == end )
+ break;
+ if ( rx.search( *it ) == -1 ) break; // something is wrong ! :)
+ curIdx = rx.cap( 1 ).toInt();
+ }
+ slotStatusExt(dirPath, path, text_status, prop_status, repos_text_status, repos_prop_status, rev);
+ }
+// }
+
+ return m_recursiveDirEntries;
+}
+
+void SVNFileInfoProvider::slotStatusExt(
+ const QString& reqPath, const QString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev)
+{
+
+ if ( !m_recursiveDirEntries )
+ m_recursiveDirEntries = new VCSFileInfoMap;
+
+ QString wRev = QString::number( rev ); //work rev
+ QString rRev = QString::number( rev );// repo rev
+ VCSFileInfo::FileState state = VCSFileInfo::Unknown;
+
+ switch ( text_status ) {
+ case 1: // does not exist
+ break;
+ case 2: // unversioned
+ break;
+ case 3:
+ state = VCSFileInfo::Uptodate;
+ break;
+ case 4:
+ state = VCSFileInfo::Added;
+ break;
+ case 5: // missing
+ break;
+ case 6: //deleted
+ state = VCSFileInfo::Deleted;
+ break;
+ case 7: //replaced
+ state = VCSFileInfo::Replaced;
+ break;
+ case 8: //modified
+ state = VCSFileInfo::Modified;
+ break;
+ case 9: //merged
+ break;
+ case 10: //conflicted
+ state = VCSFileInfo::Conflict;
+ break;
+ case 11: //ignored
+ break;
+ case 12: //obstructed
+ break;
+ case 13: //external
+ break;
+ case 14: //incomplete
+ break;
+ }
+ switch( prop_status ) {
+ case 8:
+ state = VCSFileInfo::Modified;
+ break;
+ }
+ switch ( repos_text_status ) {
+ case 1:
+ break;
+ case 2:
+ break;
+ case 3:
+ break;
+ case 4:
+ break;
+ case 5:
+ break;
+ case 6: //deleted
+ break;
+ case 7: //replaced
+ break;
+ case 8: //modified
+ state = VCSFileInfo::NeedsPatch;
+ break;
+ case 9: //merged
+ break;
+ case 10: //conflicted
+ break;
+ case 11: //ignored
+ break;
+ case 12: //obstructed
+ break;
+ case 13: //external
+ break;
+ case 14: //incomplete
+ break;
+ }
+
+ QString relativeReqPath;
+ if (reqPath == "./"){
+ // case of project top directory
+ QString reqAbsPath = projectDirectory();
+
+ if( path == reqAbsPath ){
+ //key of VCSInfo is project directory itself. So it is set to .
+ relativeReqPath = ".";
+ }
+ else{
+ relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 );
+ }
+ }
+ else {
+ QString reqAbsPath = projectDirectory() + QDir::separator() + reqPath;
+ relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 );
+
+ if (relativeReqPath == reqAbsPath){
+ // case of requested directory itself.
+ relativeReqPath = ".";
+ }
+ }
+
+ VCSFileInfo info(relativeReqPath, wRev, rRev, state);
+ m_recursiveDirEntries->insert( relativeReqPath, info );
+
+// VCSFileInfo info(QFileInfo( path ).fileName(),wRev,rRev,state);
+ kdDebug(9036) << "Inserting " << info.toString() << endl;
+// m_recursiveDirEntries->insert( QFileInfo( path ).fileName(), info);
+}
+
+#include "subversion_fileinfo.moc"
+
diff --git a/vcs/subversion/subversion_fileinfo.h b/vcs/subversion/subversion_fileinfo.h
new file mode 100644
index 00000000..e2ab1b70
--- /dev/null
+++ b/vcs/subversion/subversion_fileinfo.h
@@ -0,0 +1,73 @@
+/**
+
+ Copyright (C) 2004-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SVNFILEINFOPROVIDER_H
+#define SVNFILEINFOPROVIDER_H
+
+#include <qmap.h>
+
+#include <kdevversioncontrol.h>
+#include <kio/job.h>
+#include <dcopclient.h>
+#include <dcopobject.h>
+#include <subversion_part.h>
+
+/**
+Provider for SVN file information
+
+@author Mickael Marchand
+*/
+class SVNFileInfoProvider : public KDevVCSFileInfoProvider, public DCOPObject/*, virtual public DCOPClient*/
+{
+ Q_OBJECT
+ K_DCOP
+
+public:
+ SVNFileInfoProvider( subversionPart *parent, const char *name = 0);
+ virtual ~SVNFileInfoProvider();
+
+// -- Sync interface
+ virtual const VCSFileInfoMap *status( const QString &dirPath );
+// -- These two are used for subversionPart and subversionCore. Of couruse, others can use it.
+ const VCSFileInfoMap* statusExt( const QString &dirPath, bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore );
+ void slotStatusExt( const QString&, const QString& , int, int, int, int, long int ) ;
+
+// -- Async interface for requesting data
+ virtual bool requestStatus( const QString &dirPath, void *callerData, bool recursive = true, bool checkRepos = true );
+
+ QString projectDirectory() const;
+
+k_dcop:
+ void slotStatus( const QString& , int, int, int, int, long int ) ;
+
+public slots:
+ void slotResult( KIO::Job * );
+
+private:
+ mutable void *m_savedCallerData;
+ mutable QString m_previousDirPath;
+ mutable QString m_recursivePreviousDirPath;
+ mutable VCSFileInfoMap *m_cachedDirEntries;
+ mutable VCSFileInfoMap *m_recursiveDirEntries;
+ KIO::SimpleJob *job;
+ subversionPart *m_part;
+};
+
+#endif
diff --git a/vcs/subversion/subversion_global.h b/vcs/subversion/subversion_global.h
new file mode 100644
index 00000000..062d7fe9
--- /dev/null
+++ b/vcs/subversion/subversion_global.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+#ifndef SUBVERSION_GLOBAL_H
+#define SUBVERSION_GLOBAL_H
+
+#include <kurl.h>
+#include <qdatetime.h>
+
+namespace SvnGlobal
+{
+
+typedef enum {
+ path_to_reposit = 0,
+ path_to_path = 1,
+ dont_touch = 2
+} UrlMode;
+
+/// A structure which describes various system-generated metadata about
+/// a working-copy path or URL.
+class SvnInfoHolder {
+public:
+ // the requested path
+ KURL path;
+ /* Where the item lives in the repository. */
+ KURL url;
+ // The revision of the object. If path_or_url is a working-copy
+ // path, then this is its current working revnum. If path_or_url
+ // is a URL, then this is the repos revision that path_or_url lives in. */
+ int rev;
+ int kind;
+ /* The root URL of the repository. */
+ KURL reposRootUrl;
+ QString reposUuid;
+};
+
+class SvnRevision{
+public:
+ int revNum;
+ QString revKind;
+ QDateTime revDate;
+};
+
+} // end of namespace SvnGlobal
+#endif
diff --git a/vcs/subversion/subversion_part.cpp b/vcs/subversion/subversion_part.cpp
new file mode 100644
index 00000000..f918ea44
--- /dev/null
+++ b/vcs/subversion/subversion_part.cpp
@@ -0,0 +1,569 @@
+/**
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+#include "subversion_part.h"
+
+#include <qwhatsthis.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdevgenericfactory.h>
+#include <kaction.h>
+#include <kpopupmenu.h>
+
+#include "kdevcore.h"
+#include "kdevmainwindow.h"
+#include "subversion_core.h"
+#include "subversion_widget.h"
+#include "subversionprojectwidget.h"
+#include "subversion_fileinfo.h"
+#include "subversion_global.h"
+#include "kdevversioncontrol.h"
+#include "svn_fileselectdlg_commit.h"
+#include "svn_logviewwidget.h"
+#include "svn_switchwidget.h"
+#include "svn_copywidget.h"
+#include "svn_mergewidget.h"
+
+#include "urlutil.h"
+#include <qvbox.h>
+#include <kdialogbase.h>
+#include <kparts/part.h>
+#include <kdevpartcontroller.h>
+#include <kdevproject.h>
+#include <domutil.h>
+#include <kurlrequester.h>
+#include <qradiobutton.h>
+#include <kdebug.h>
+#include <qwidget.h>
+#include <kdevplugininfo.h>
+
+#include <kmessagebox.h>
+
+using namespace SvnGlobal;
+
+static const KDevPluginInfo data("kdevsubversion");
+
+typedef KDevGenericFactory<subversionPart> subversionFactory;
+K_EXPORT_COMPONENT_FACTORY( libkdevsubversion, subversionFactory( data ) )
+
+//bool g_projectWasJustCreated = false;
+
+subversionPart::subversionPart(QObject *parent, const char *name, const QStringList& )
+ : KDevVersionControl(&data, parent, name ? name : "Subversion" ) {
+ setInstance(subversionFactory::instance());
+ m_projWidget = 0;
+
+ m_impl = new subversionCore( this );
+
+ //m_impl->processWidget()->setIcon( SmallIcon("db") );
+
+ setupActions();
+
+ connect( m_impl, SIGNAL(checkoutFinished(QString)), SIGNAL(finishedFetching(QString)) );
+
+ // Context menu
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+ connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), this, SLOT(projectConfigWidget(KDialogBase*)) );
+ connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)), this, SLOT(slotStopButtonClicked(KDevPlugin*)) );
+ connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) );
+ connect( core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) );
+
+ m_impl->processWidget()->setCaption(i18n( "Subversion Output" ));
+ mainWindow()->embedOutputView( (QWidget*)m_impl->processWidget(), i18n( "Subversion" ), i18n( "Subversion messages" ) );
+ QWhatsThis::add((QWidget*)m_impl->processWidget(), i18n("<b>Subversion</b><p>Subversion operations window."));
+
+}
+
+subversionPart::~subversionPart() {
+ if ( m_projWidget ){
+ delete (subversionProjectWidget*) m_projWidget;
+ m_projWidget = 0;
+ }
+ delete m_impl;
+}
+
+void subversionPart::setupActions() {
+ actionCommit = new KAction( i18n("&Commit to Repository..."), 0, this, SLOT(slotActionCommit()), actionCollection(), "subversion_commit" );
+ actionCommit->setToolTip( i18n("Commit file(s)") );
+ actionCommit->setWhatsThis( i18n("<b>Commit file(s)</b><p>Commits file to repository if modified.") );
+
+ /* actionDiff = new KAction( i18n("&Difference Between Revisions"), 0, this, SLOT(slotActionDiff()),
+ actionCollection(), "subversion_diff" );
+ actionDiff->setToolTip( i18n("Build difference") );
+ actionDiff->setWhatsThis( i18n("<b>Build difference</b><p>Builds difference between releases.") );
+ */
+ actionAdd = new KAction( i18n("&Add to Repository"), 0, this, SLOT(slotActionAdd()), actionCollection(), "subversion_add" );
+ actionAdd->setToolTip( i18n("Add file to repository") );
+ actionAdd->setWhatsThis( i18n("<b>Add file to repository</b><p>Adds file to repository.") );
+
+ actionLog = new KAction( i18n("Show logs..."), 0, this, SLOT(slotLog()), actionCollection(), "subversion_log" );
+ actionBlame = new KAction( i18n("Blame..."), 0, this, SLOT(slotBlame()), actionCollection(), "subversion_blame");
+
+ actionRemove = new KAction( i18n("&Remove From Repository"), 0, this, SLOT(slotActionDel()), actionCollection(), "subversion_remove" );
+ actionRemove->setToolTip( i18n("Remove from repository") );
+ actionRemove->setWhatsThis( i18n("<b>Remove from repository</b><p>Removes file(s) from repository.") );
+
+ actionUpdate = new KAction( i18n("&Update"), 0, this, SLOT(slotActionUpdate()), actionCollection(), "subversion_update" );
+ actionUpdate->setToolTip( i18n("Update") );
+ actionUpdate->setWhatsThis( i18n("<b>Update</b><p>Updates file(s) from repository.") );
+
+ actionDiffLocal = new KAction( i18n("&Diff to BASE"), 0, this, SLOT(slotActionDiffLocal()), actionCollection(), "subversion_diff_local" );
+ actionDiffLocal->setToolTip( i18n("Diff to BASE") );
+ actionDiffLocal->setWhatsThis( i18n("<b>Diff to disk</b><p>Diff current file to the BASE checked out copy.") );
+
+ actionDiffHead = new KAction( i18n("&Diff to HEAD"), 0, this, SLOT(slotActionDiffLocal()), actionCollection(), "subversion_diff_head" );
+ actionDiffHead->setToolTip( i18n("Diff to HEAD") );
+ actionDiffHead->setWhatsThis( i18n("<b>Diff HEAD</b><p>Diff the current file to HEAD in svn.") );
+
+
+ actionRevert = new KAction( i18n("&Revert"), 0, this, SLOT(slotActionRevert()), actionCollection(), "subversion_revert" );
+ actionRevert->setToolTip( i18n("Revert") );
+ actionRevert->setWhatsThis( i18n("<b>Revert</b><p>Undo local changes.") );
+
+ /*
+ actionAddToIgnoreList = new KAction( i18n("&Ignore in Subversion Operations"), 0,
+ this, SLOT(slotActionAddToIgnoreList()), actionCollection(), "subversion_ignore" );
+ actionAddToIgnoreList->setToolTip( i18n("Ignore in Subversion operations") );
+ actionAddToIgnoreList->setWhatsThis( i18n("<b>Ignore in Subversion operations</b><p>Ignores file(s).") );
+
+ actionRemoveFromIgnoreList = new KAction( i18n("Do &Not Ignore in Subversion Operations"), 0,
+ this, SLOT(slotActionRemoveFromIgnoreList()), actionCollection(), "subversion_donot_ignore" );
+ actionRemoveFromIgnoreList->setToolTip( i18n("Do not ignore in Subversion operations") );
+ actionRemoveFromIgnoreList->setWhatsThis( i18n("<b>Do not ignore in Subversion operations</b><p>Do not ignore file(s).") );
+ */
+ actionResolve = new KAction( i18n("Re&solve Conflicting State"), 0,
+ this, SLOT(slotActionResolve()), actionCollection(), "subversion_resolve" );
+ actionResolve->setToolTip( i18n("Resolve the conflicting state of a file after a merge") );
+ actionResolve->setWhatsThis( i18n("<b>Resolve the conflicting state</b><p>Remove the conflict state that can be set on a file after a merge failed.") );
+ actionSwitch = new KAction( i18n("Switch this working copy to URL.."), 0,
+ this, SLOT(slotSwitch()), actionCollection(), "subversion_switch" );
+ // warn slogCopy(), slotMerge only works on context menu. There is no main-menu action
+ actionCopy = new KAction( i18n("Copy this working copy to URL.."), 0,
+ this, SLOT(slotCopy()), actionCollection(), "subversion_copy" );
+ actionMerge = new KAction( i18n("Merge difference to working copy"), 0,
+ this, SLOT(slotMerge()), actionCollection(), "subversion_merge" );
+}
+
+QWidget* subversionPart::newProjectWidget( QWidget* parent ) {
+ if ( !m_projWidget )
+ m_projWidget = new subversionProjectWidget(parent,"projectwidget");
+ return m_projWidget;
+}
+
+void subversionPart::createNewProject( const QString& dirname ) {
+ if ( !m_projWidget ) return;
+
+ m_impl->createNewProject( dirname, KURL( m_projWidget->importURL->url() ), m_projWidget->yes->isChecked() );
+
+}
+
+bool subversionPart::fetchFromRepository() {
+ m_impl->checkout();
+ return true;
+}
+
+KDevVCSFileInfoProvider * subversionPart::fileInfoProvider() const {
+ return m_impl->fileInfoProvider();
+}
+
+void subversionPart::contextMenu( QPopupMenu *popup, const Context *context ) {
+ //no project, no subversion. Don't test on projectDirectory() here. If the user wants this project to have subversion support
+ //give it to him. e.g. for out of root subprojects like with qmake
+if(!project())
+ return;
+
+ kdDebug(9036) << "contextMenu()" << endl;
+ if (context->hasType( Context::FileContext ) ||
+ context->hasType( Context::EditorContext ))
+ {
+
+ if (context->hasType( Context::FileContext ))
+ {
+ kdDebug(9036) << "Requested for a FileContext" << endl;
+ const FileContext *fcontext = static_cast<const FileContext*>( context );
+ m_urls = fcontext->urls();
+ }
+ else
+ {
+ kdDebug(9036) << "Requested for an EditorContext" << endl;
+ const EditorContext *editorContext = static_cast<const EditorContext*>( context );
+ m_urls = editorContext->url();
+ }
+ // THis stuff should end up into prepareOperation()
+ URLUtil::dump( m_urls );
+ if (m_urls.count() <= 0)
+ return;
+
+ KPopupMenu *subMenu = new KPopupMenu( popup );
+ if (context->hasType( Context::FileContext ))
+ popup->insertSeparator();
+
+ int id = subMenu->insertItem( actionCommit->text(), this, SLOT(slotCommit()) );
+ // CvsService let to do log and diff operations only on one file (or directory) at time
+ /* if (m_urls.count() == 1)
+ {
+ subMenu->insertItem( actionDiff->text(), this, SLOT(slotDiff()) );
+ subMenu->insertItem( actionLog->text(), this, SLOT(slotLog()) );
+ }*/
+ subMenu->setWhatsThis(id, i18n("<b>Commit file(s)</b><p>Commits file to repository if modified."));
+ id = subMenu->insertItem( actionAdd->text(), this, SLOT(slotAdd()) );
+ subMenu->setWhatsThis(id, i18n("<b>Add file to repository</b><p>Adds file to repository."));
+ id = subMenu->insertItem( actionRemove->text(), this, SLOT(slotDel()) );
+ subMenu->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Removes file(s) from repository."));
+ id = subMenu->insertItem( actionLog->text(), this, SLOT(slotLog()) );
+ subMenu->setWhatsThis(id, i18n("<b>Show logs..</b><p>View Logs"));
+ id = subMenu->insertItem( actionBlame->text(), this, SLOT(slotBlame()) );
+ subMenu->setWhatsThis(id, i18n("<b>Blame 0:HEAD </b><p>Show Annotate"));
+
+ subMenu->insertSeparator();
+ id = subMenu->insertItem( actionDiffLocal->text(), this, SLOT(slotDiffLocal()) );
+ subMenu->setWhatsThis(id, i18n("<b>Diff</b><p>Diff file to local disk."));
+
+ id = subMenu->insertItem( actionDiffHead->text(), this, SLOT(slotDiffHead()) );
+ subMenu->setWhatsThis(id, i18n("<b>Diff</b><p>Diff file to repository."));
+
+ id = subMenu->insertItem( actionUpdate->text(), this, SLOT(slotUpdate()) );
+ subMenu->setWhatsThis(id, i18n("<b>Update</b><p>Updates file(s) from repository."));
+ id = subMenu->insertItem( actionRevert->text(), this, SLOT(slotRevert()) );
+ subMenu->setWhatsThis(id, i18n("<b>Revert</b><p>Undo local changes.") );
+ id = subMenu->insertItem( actionResolve->text(), this, SLOT(slotResolve()) );
+ subMenu->setWhatsThis(id, i18n("<b>Resolve</b><p>Resolve conflicting state.") );
+ id = subMenu->insertItem( actionSwitch->text(), this, SLOT(slotSwitch()) );
+ subMenu->setWhatsThis(id, i18n("<b>Switch</b><p>Switch working tree.") );
+ id = subMenu->insertItem( actionCopy->text(), this, SLOT(slotCopy()) );
+ subMenu->setWhatsThis(id, i18n("<b>Copy</b><p>Copy from/between path/URLs") );
+ id = subMenu->insertItem( actionMerge->text(), this, SLOT(slotMerge()) );
+ subMenu->setWhatsThis(id, i18n("<b>Merge</b><p>Merge difference to working copy") );
+
+ /*
+ subMenu->insertSeparator();
+ id = subMenu->insertItem( actionAddToIgnoreList->text(), this, SLOT(slotAddToIgnoreList()) );
+ subMenu->setWhatsThis(id, i18n("<b>Ignore in Subversion operations</b><p>Ignores file(s)."));
+ id = subMenu->insertItem( actionRemoveFromIgnoreList->text(), this, SLOT(slotRemoveFromIgnoreList()) );
+ subMenu->setWhatsThis(id, i18n("<b>Do not ignore in Subversion operations</b><p>Do not ignore file(s)."));
+*/
+ // Now insert in parent menu
+ popup->insertItem( i18n("Subversion"), subMenu );
+ }
+}
+
+bool subversionPart::urlFocusedDocument( KURL &url ) {
+ KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() );
+ if ( part ) {
+ if (part->url().isLocalFile() ) {
+ url = part->url();
+ return true;
+ }
+ }
+ return false;
+}
+
+void subversionPart::slotActionUpdate() {
+ kdDebug(9036) << "subversion: slotActionUpdate()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->update( doc );
+ }
+}
+
+void subversionPart::slotUpdate() {
+ m_impl->update (m_urls);
+}
+
+void subversionPart::slotActionResolve() {
+ kdDebug(9036) << "subversion: slotActionResolve()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->resolve( doc );
+ }
+}
+
+void subversionPart::slotResolve() {
+ m_impl->resolve (m_urls);
+}
+
+void subversionPart::slotSwitch()
+{
+ if( m_urls.count() > 1 ){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Please select only one item for subversion switch") );
+ return;
+ }
+ if( m_urls.count() < 1 ) return;
+
+ // retrieve repository info from local-copy metadata which will be displayed in dialog box
+ KURL wcPath = m_urls.first();
+ QMap< KURL, SvnGlobal::SvnInfoHolder> holderMap;
+ SvnGlobal::SvnInfoHolder holder;
+
+ m_impl->clientInfo( wcPath, false, holderMap );
+ QValueList< SvnGlobal::SvnInfoHolder > holderList = holderMap.values();
+ holder = holderList.first();
+ // invoke dialog box
+ SvnSwitchDlg dlg( &holder, wcPath.path(), (QWidget*)project()->mainWindow()->main() );
+
+ if( dlg.exec() != QDialog::Accepted ){
+ return;
+ }
+ // check target url's validity
+ KURL repositUrl = KURL( dlg.destUrl() );
+ if( !repositUrl.isValid() ){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("The destination URL is invalid") );
+ return;
+ }
+ // call core
+ if( dlg.switchOnly() )
+ m_impl->switchTree( wcPath, repositUrl, -1, "HEAD", dlg.recursive() );
+ else if( dlg.relocation() )
+ m_impl->switchRelocate( wcPath, dlg.currentUrl(), repositUrl, dlg.recursive() );
+ else
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Fail to conduct subversion switch. No action was selected") );
+}
+
+void subversionPart::slotCopy()
+{
+ // error check
+ if( m_urls.count() > 1 ){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Please select only one item for subversion switch") );
+ return;
+ }
+ if( m_urls.count() < 1 ) return;
+
+ // retrieve repository info from local-copy metadata which will be displayed in dialog box
+ KURL wcPath = m_urls.first();
+ QMap< KURL, SvnGlobal::SvnInfoHolder> holderMap;
+ SvnGlobal::SvnInfoHolder holder;
+ m_impl->clientInfo( wcPath, false, holderMap );
+ QValueList< SvnGlobal::SvnInfoHolder > holderList = holderMap.values();
+ holder = holderList.first();
+ // start input dialog
+ SvnCopyDialog dlg( wcPath.prettyURL(),
+ &holder,
+ (QWidget*)project()->mainWindow()->main());
+
+ if( dlg.exec() != QDialog::Accepted )
+ return;
+ // retrieve user input
+ KURL srcUrl = dlg.sourceUrl();
+ int rev = dlg.revision();
+ QString revKind = dlg.revKind();
+ KURL dest = dlg.destUrl();
+
+ kdDebug(9036) << " SRC: " << srcUrl << " DEST: " << dest << " Revnum: " << rev << " RevKind: " << revKind << endl;
+
+ m_impl->svnCopy( srcUrl, rev, revKind, dest );
+}
+
+void subversionPart::slotMerge()
+{
+ // error check
+ if( m_urls.count() > 1 ){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Please select only one item for subversion merge") );
+ return;
+ }
+ if( m_urls.count() < 1 ) return;
+
+ KURL wcTarget= m_urls.first();
+ SvnMergeDialog dlg( wcTarget, (QWidget*)project()->mainWindow()->main() );
+ if( dlg.exec() != QDialog::Accepted ) return;
+
+ KURL src1 = dlg.source1();
+ SvnRevision rev1 = dlg.rev1();
+ KURL src2 = dlg.source2();
+ SvnRevision rev2 = dlg.rev2();
+
+ m_impl->merge( src1, rev1.revNum, rev1.revKind, src2, rev2.revNum, rev2.revKind, wcTarget,
+ dlg.recurse(), dlg.ignoreAncestry(), dlg.force(), dlg.dryRun() );
+}
+
+void subversionPart::slotActionCommit() {
+ kdDebug(9036) << "subversion: slotActionCommit()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->commit( doc, true, true );
+ }
+}
+
+void subversionPart::slotActionAdd() {
+ kdDebug(9036) << "subversion: slotActionAdd()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->add( doc );
+ }
+}
+
+void subversionPart::slotActionDel() {
+ kdDebug(9036) << "subversion: slotActionDel()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->del( doc );
+ }
+}
+
+void subversionPart::slotActionRevert() {
+ kdDebug(9036) << "subversion: slotActionRevert()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->revert( doc );
+ }
+}
+
+void subversionPart::slotActionDiffLocal() {
+ kdDebug(9036) << "subversion: slotActionDiffLocal()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->diff( doc, "BASE" );
+ }
+}
+void subversionPart::slotActionDiffHead() {
+ kdDebug(9036) << "subversion: slotActionDiffHead()" << endl;
+ KURL doc;
+ if (urlFocusedDocument( doc )) {
+ m_impl->diff( doc, "HEAD" );
+ }
+}
+void subversionPart::slotCommit()
+{
+ SVNFileSelectDlgCommit dialog( m_urls, this, 0 );
+ if( dialog.exec() == QDialog::Accepted ){
+ KURL::List tobeCommittedUrls = dialog.checkedUrls();
+ bool recursive = dialog.recursive();
+ bool keepLocks = dialog.keepLocks();
+ m_impl->commit(tobeCommittedUrls, recursive, keepLocks );
+ }
+}
+void subversionPart::slotAdd() {
+ m_impl->add( m_urls );
+}
+
+void subversionPart::slotLog()
+{
+ if (m_urls.count() > 1){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Please select only one item for subversion log") );
+ return;
+ }
+ SvnLogViewOptionDlg dlg;
+ if( dlg.exec() ){
+ int revstart = dlg.revstart();
+ QString revkindstart = dlg.revKindStart();
+ int revend = dlg.revend();
+ QString revkindend = dlg.revKindEnd();
+ bool strictNode = dlg.strictNode();
+ m_impl->svnLog (m_urls, revstart, revkindstart, revend, revkindend, true/*changedPath*/, strictNode);
+ } else{
+ return;
+ }
+}
+void subversionPart::slotBlame()
+{
+ if (m_urls.count() > 1){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Please select only one item to see annotate") );
+ return;
+ }
+ if (m_urls.count() < 1){
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Select file to see blame") );
+ return;
+ }
+ KURL url = m_urls.first();
+ m_impl->blame(url, SvnGlobal::path_to_reposit, 0, "", -1, "BASE");
+}
+
+void subversionPart::slotDel() {
+ m_impl->del (m_urls);
+}
+
+// note: currently diffAsync does not support merging. But svncore::diff()
+// cannot be invoked on directory, while diffAsync can.
+void subversionPart::slotDiffLocal() {
+// m_impl->diff (m_urls, "BASE");
+ if( m_urls.count() < 1 ){
+ // Impossible to reach here but..
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Select file or directory to see diff") );
+ return;
+ }
+ m_impl->diffAsync( *(m_urls.begin()), *(m_urls.begin()), -1, "BASE", -1, "WORKING", true );
+}
+void subversionPart::slotDiffHead() {
+// m_impl->diff (m_urls, "HEAD");
+ if( m_urls.count() < 1 ){
+ // Impossible to reach here but..
+ KMessageBox::error( (QWidget*)project()->mainWindow()->main(),
+ i18n("Select file or directory to see diff") );
+ return;
+ }
+ m_impl->diffAsync( *(m_urls.begin()), *(m_urls.begin()), -1, "WORKING", -1, "HEAD", true );
+}
+
+void subversionPart::slotRevert() {
+ m_impl->revert (m_urls);
+}
+
+void subversionPart::slotProjectOpened() {
+ kdDebug(9036) << "subversion :projectOpened" << endl;
+/* if ( g_projectWasJustCreated ) {
+ //saveOptions();
+ g_projectWasJustCreated = false;
+ } */
+ //loadOptions();
+ /// \FIXME slots
+ //connect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) );
+ //connect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) );
+}
+
+void subversionPart::slotProjectClosed() {
+ kdDebug(9036) << "subversion :projectClosed" << endl;
+ //saveOptions();
+ /// \FIXME slots
+ //disconnect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) );
+ //disconnect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) );
+}
+
+void subversionPart::savePartialProjectSession(QDomElement* dom) {
+ kdDebug(9036) << "subversion : savePartialProjectSession" << endl;
+ QDomDocument doc = dom->ownerDocument();
+ QDomElement svn = doc.createElement( "subversion" );
+ svn.setAttribute( "base", base.url() );
+ dom->appendChild( svn );
+}
+
+void subversionPart::restorePartialProjectSession(const QDomElement* dom) {
+ kdDebug(9036) << "subversion : restorePartialProjectSession" << endl;
+ QDomElement svn = dom->namedItem("subversion").toElement();
+ base = svn.attribute( "base", "" );
+}
+
+bool subversionPart::isValidDirectory( const QString &dirPath) const {
+ QString svn = "/.svn/";
+ QDir svndir( dirPath + svn );
+ QString entriesFileName = dirPath + svn + "entries";
+
+ kdDebug(9036) << "dirpath " << dirPath+"/.svn/" << " exists:" << svndir.exists() << endl;
+ kdDebug(9036) << "entries " << entriesFileName << " exists:" << QFile::exists( entriesFileName ) << endl;
+ return svndir.exists() &&
+ QFile::exists( entriesFileName );
+}
+
+#include "subversion_part.moc"
diff --git a/vcs/subversion/subversion_part.h b/vcs/subversion/subversion_part.h
new file mode 100644
index 00000000..911f8f7e
--- /dev/null
+++ b/vcs/subversion/subversion_part.h
@@ -0,0 +1,119 @@
+/* Copyright (C) 2003
+ Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+#ifndef __KDEVPART_SUBVERSION_H__
+#define __KDEVPART_SUBVERSION_H__
+
+
+#include <qguardedptr.h>
+#include <kdevplugin.h>
+#include <kurl.h>
+#include <qpopupmenu.h>
+#include <kdialogbase.h>
+#include "kdevversioncontrol.h"
+
+class subversionCore;
+class subversionOptionsWidget;
+class subversionProjectWidget;
+class Context;
+namespace SvnGlobal
+{
+class SvnInfoHolder;
+};
+
+class subversionPart : public KDevVersionControl
+{
+ Q_OBJECT
+
+public:
+ subversionPart(QObject *parent, const char *name, const QStringList &);
+ virtual ~subversionPart();
+
+ void setupActions();
+ QWidget* newProjectWidget( QWidget* parent );
+ void createNewProject( const QString& dirname );
+ bool fetchFromRepository();
+ KDevVCSFileInfoProvider * fileInfoProvider() const;
+ bool urlFocusedDocument( KURL &url );
+ void restorePartialProjectSession(const QDomElement* );
+ void savePartialProjectSession(QDomElement* );
+ void setBaseURL(const KURL& url ) { base = url; }
+ KURL baseURL() { return base; }
+ virtual bool isValidDirectory( const QString &dirPath ) const;
+ KURL::List urls() { return m_urls; }
+ subversionCore* svncore() { return m_impl; }
+
+signals:
+// void finishedFetching( QString destinationDir );
+
+private slots:
+ void contextMenu( QPopupMenu *popup, const Context *context );
+ void slotActionUpdate();
+ void slotActionRevert();
+ void slotActionCommit();
+ void slotActionAdd();
+ void slotActionDel();
+ void slotActionDiffHead();
+ void slotActionDiffLocal();
+ void slotActionResolve();
+ void slotUpdate();
+ void slotRevert();
+ void slotCommit();
+ void slotAdd();
+ void slotDel();
+ void slotLog();
+ void slotBlame();
+ void slotDiffLocal();
+ void slotDiffHead();
+ void slotResolve();
+ void slotSwitch();
+ void slotCopy();
+ void slotMerge();
+ void slotProjectClosed();
+ void slotProjectOpened();
+
+private:
+ QGuardedPtr<subversionCore> m_impl;
+ KURL::List m_urls;
+
+ KAction *actionCommit,
+ *actionDiffHead,
+ *actionDiffLocal,
+ *actionAdd,
+ *actionLog,
+ *actionBlame,
+ *actionRemove,
+ *actionUpdate,
+ //*actionAddToIgnoreList,
+ //*actionRemoveFromIgnoreList,
+ *actionRevert,
+ *actionResolve,
+ *actionSwitch,
+ *actionCopy,
+ *actionMerge;
+
+ QGuardedPtr<subversionProjectWidget> m_projWidget;
+ KURL base;
+
+public:
+ QMap< KURL, SvnGlobal::SvnInfoHolder > m_prjInfoMap;
+
+};
+
+
+#endif
diff --git a/vcs/subversion/subversion_widget.cpp b/vcs/subversion/subversion_widget.cpp
new file mode 100644
index 00000000..af1ca14f
--- /dev/null
+++ b/vcs/subversion/subversion_widget.cpp
@@ -0,0 +1,136 @@
+/**
+ Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#include <kparts/part.h>
+#include <kdevcore.h>
+#include <kdebug.h>
+#include <klineedit.h>
+
+#include "subversion_part.h"
+#include "subversion_widget.h"
+#include <ktextedit.h>
+#include <klocale.h>
+#include <qtoolbutton.h>
+#include <qpushbutton.h>
+
+subversionWidget::subversionWidget( subversionPart *part, QWidget *parent, const char* name )
+ : KTabWidget(parent)
+{
+ m_part = part;
+ m_edit = new KTextEdit( this );
+ m_edit->setReadOnly( TRUE );
+ tab()->addTab( m_edit, i18n("Notification") );
+ m_closeButton = new QPushButton( tab() );
+ m_closeButton->setText( i18n("Close") );
+ tab()->setCornerWidget(m_closeButton);
+ connect( m_closeButton, SIGNAL(clicked()), this, SLOT(closeCurrentTab()) );
+}
+
+subversionWidget::~subversionWidget()
+{}
+
+void subversionWidget::append( QString notifications )
+{
+ if( !m_edit ){
+ // should not happen
+ m_edit = new KTextEdit(this);
+ }
+ m_edit->append( notifications );
+ showPage( m_edit );
+}
+
+void subversionWidget::showLogResult( QValueList<SvnLogHolder> *holderList, QString reqUrl )
+{
+ SvnLogViewWidget *widget = new SvnLogViewWidget( m_part, this );
+ widget->setLogResult( holderList );
+ widget->setRequestedUrl( reqUrl );
+ tab()->addTab( widget, i18n("Log History") );
+ tab()->setTabEnabled( widget, true );
+ tab()->showPage( widget );
+}
+
+void subversionWidget::showBlameResult( QValueList<SvnBlameHolder> *blamelist )
+{
+ SvnBlameWidget *widget = new SvnBlameWidget( this );
+ widget->copyBlameData( blamelist );
+ tab()->addTab( widget, i18n("Blame") );
+ tab()->setTabEnabled( widget, true );
+ tab()->showPage( widget );
+}
+void subversionWidget::closeCurrentTab()
+{
+ QWidget *current = tab()->currentPage();
+ KTextEdit *edit = static_cast<KTextEdit*>(current);
+ if( edit ){
+ if( edit == m_edit ) // main notification output should not be deleted
+ return;
+ }
+ tab()->removePage( current );
+ delete current;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+SvnIntSortListItem::SvnIntSortListItem( QListView* parent )
+ :QListViewItem(parent)
+{}
+SvnIntSortListItem::~SvnIntSortListItem()
+{}
+
+int SvnIntSortListItem::compare( QListViewItem *item, int col, bool ascending ) const
+{
+
+ unsigned int myVal = this->text(col).toUInt();
+ unsigned int yourVal = item->text(col).toUInt();
+ if( myVal < yourVal ) return -1;
+ if( myVal > yourVal ) return 1;
+ return 0;
+}
+
+SvnLogViewItem::SvnLogViewItem( QListView * parent )
+ :SvnIntSortListItem( parent )
+{
+ m_pathList = "";
+ m_message = "";
+}
+SvnLogViewItem ::~SvnLogViewItem ()
+{}
+
+////////////////////////////////////////////////////////////////////////
+
+SvnProgressDlg::SvnProgressDlg( bool showNow )
+ : KIO::DefaultProgress( showNow )
+{
+ setStopOnClose( true );
+ setCaption( i18n("Subversion Job Progress") );
+}
+
+SvnProgressDlg::~SvnProgressDlg()
+{}
+
+void SvnProgressDlg::setSourceUrl( const QString &src )
+{
+ sourceEdit->setText( src );
+}
+void SvnProgressDlg::setDestUrl( const QString &dest )
+{
+ destEdit->setText( dest );
+}
+
+#include "subversion_widget.moc"
diff --git a/vcs/subversion/subversion_widget.h b/vcs/subversion/subversion_widget.h
new file mode 100644
index 00000000..4a21b636
--- /dev/null
+++ b/vcs/subversion/subversion_widget.h
@@ -0,0 +1,95 @@
+/* Copyright (C) 2003
+ Mickael Marchand <marchand@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SUBVERSION_WIDGET_H__
+#define __SUBVERSION_WIDGET_H__
+
+#include <qlistview.h>
+#include "svn_blamewidget.h"
+#include "svn_logviewwidget.h"
+#include <qvaluelist.h>
+
+class subversionPart;
+#include <ktabwidget.h>
+#include <kio/defaultprogress.h>
+#include <qguardedptr.h>
+class KTextEdit;
+class SvnLogHolder;
+class SvnBlameHolder;
+class SvnLogViewWidget;
+class QToolButton;
+class QPushButton;
+
+/** The main Subversion DockWidget. Contains logview-output, blame-output, status and etc */
+// class subversionWidget : public SvnOutputWidgetBase
+class subversionWidget : public KTabWidget
+{
+ Q_OBJECT
+public:
+ subversionWidget(subversionPart *part, QWidget *parent, const char* name);
+ ~subversionWidget();
+
+ // append what?. Append any text status outputs
+ void append( QString notifications );
+ void showLogResult( QValueList<SvnLogHolder> *holderList, QString reqUrl );
+ void showBlameResult( QValueList<SvnBlameHolder> *blamelist );
+
+protected slots:
+ void closeCurrentTab();
+
+private:
+ KTabWidget* tab(){ return this; }
+ subversionPart *m_part;
+
+ QGuardedPtr<KTextEdit> m_edit;
+ QPushButton *m_closeButton;
+
+};
+/**
+ * reimplement compare(), to be able to sort any item by integer
+ */
+class SvnIntSortListItem : public QListViewItem {
+public:
+ SvnIntSortListItem ( QListView* parent=0 );
+ ~SvnIntSortListItem ();
+ /** Returns < 0 if this item is less than i, 0 if they are equal and > 0 if this item is greater than i.
+ */
+ virtual int compare( QListViewItem* i, int col, bool ascending ) const;
+};
+
+class SvnLogViewItem : public SvnIntSortListItem {
+ public:
+ SvnLogViewItem( QListView* parent );
+ ~SvnLogViewItem();
+
+ QString m_pathList;
+ QString m_message;
+};
+
+/////////////////////////////////////////////////////////////
+/// Subversion Progress Display Widget
+class SvnProgressDlg : public KIO::DefaultProgress {
+public:
+ SvnProgressDlg( bool showNow = true );
+ ~SvnProgressDlg();
+ void setSourceUrl( const QString & );
+ void setDestUrl( const QString & );
+};
+
+#endif
diff --git a/vcs/subversion/subversiondiff.ui b/vcs/subversion/subversiondiff.ui
new file mode 100644
index 00000000..dab4ca0e
--- /dev/null
+++ b/vcs/subversion/subversiondiff.ui
@@ -0,0 +1,100 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>Subversion_Diff</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>Subversion_Diff</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>282</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Diff</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QTextBrowser">
+ <property name="name">
+ <cstring>text</cstring>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="wordWrap">
+ <enum>NoWrap</enum>
+ </property>
+ <property name="autoFormatting">
+ <set>AutoAll</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>Subversion_Diff</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/subversion/subversionprojectwidget.ui b/vcs/subversion/subversionprojectwidget.ui
new file mode 100644
index 00000000..3977ce4c
--- /dev/null
+++ b/vcs/subversion/subversionprojectwidget.ui
@@ -0,0 +1,89 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>subversionProjectWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>subversionProjectWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>438</width>
+ <height>149</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>New Subversion Project</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Import address:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>importURL</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>importURL</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>init</cstring>
+ </property>
+ <property name="title">
+ <string>Create &amp;Standard Directories (tags/trunk/branches/)?</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>yes</cstring>
+ </property>
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>no</cstring>
+ </property>
+ <property name="text">
+ <string>No</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_blamewidget.cpp b/vcs/subversion/svn_blamewidget.cpp
new file mode 100644
index 00000000..5d186177
--- /dev/null
+++ b/vcs/subversion/svn_blamewidget.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+#include "svn_blamewidget.h"
+#include "subversion_widget.h"
+#include <qmap.h>
+#include <qlistview.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qstringlist.h>
+#include <qfont.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+SvnBlameWidget::SvnBlameWidget( QWidget *parent, const char* name, bool modal, WFlags f )
+ :QWidget( parent )
+{
+ m_layout = new QVBoxLayout( this, 1, 1 );
+ m_layout->setMargin(1);
+
+ m_listView = new QListView( this );
+ outView()->setAllColumnsShowFocus( TRUE );
+ outView()->addColumn( i18n("Line") );
+ outView()->addColumn( i18n("Rev") );
+ outView()->addColumn( i18n("Date") );
+ outView()->addColumn( i18n("Author") );
+ outView()->addColumn( i18n("Content") );
+
+ m_layout->addWidget( m_listView );
+}
+SvnBlameWidget::~SvnBlameWidget()
+{}
+
+void SvnBlameWidget::copyBlameData( QValueList<SvnBlameHolder> *blamelist )
+{
+ m_blamelist = *blamelist;
+}
+
+void SvnBlameWidget::show()
+{
+ outView()->clear();
+ outView()->setSortColumn(0);
+
+ QFont f = outView()->font();
+ f.setFixedPitch( true );
+ outView()->setFont( f );
+
+ QValueList<SvnBlameHolder>::Iterator it;
+
+ for( it = m_blamelist.begin(); it != m_blamelist.end(); ++it ){
+
+ SvnBlameHolder holder = *it;
+ SvnIntSortListItem *item = new SvnIntSortListItem(outView());
+
+ QString prettyDate = holder.date.left(16).replace(10, 1, ' ');
+
+ item->setText(0, QString::number( holder.line+1 ) );
+ item->setText(1, QString::number(holder.rev) );
+ item->setText(2, prettyDate );
+ item->setText(3, holder.author );
+ item->setText(4, holder.content );
+
+ }
+ outView()->sort();
+ QWidget::show();
+}
+
+QListView* SvnBlameWidget::outView()
+{
+ return m_listView;
+}
+
+/////////////////////////////////////////////////////////////
+
+SvnBlameFileSelectDlg::SvnBlameFileSelectDlg( QWidget *parent )
+ : QDialog( parent )
+{
+ m_selected = "";
+ setCaption( i18n("Select one file to view annotation") );
+
+ m_layout = new QGridLayout( this, 2, 2 );
+ m_view = new QListView( this );
+ m_view->addColumn( i18n("files") );
+ m_okBtn = new QPushButton( i18n("OK"), this );
+ m_cancelBtn = new QPushButton( i18n("Cancel"), this );
+ m_layout->addMultiCellWidget( m_view, 0, 0, 0, 1 );
+ m_layout->addWidget( m_okBtn, 1, 0 );
+ m_layout->addWidget( m_cancelBtn, 1, 1 );
+
+ connect( m_okBtn, SIGNAL(clicked()), this, SLOT(accept()) );
+ connect( m_cancelBtn, SIGNAL(clicked()), this, SLOT(reject()) );
+}
+SvnBlameFileSelectDlg::~SvnBlameFileSelectDlg()
+{}
+
+void SvnBlameFileSelectDlg::setCandidate( QStringList *list )
+{
+ for( QValueList<QString>::iterator it = list->begin(); it != list->end(); ++it ){
+ QListViewItem *item = new QListViewItem( m_view, *it );
+ }
+}
+
+QString SvnBlameFileSelectDlg::selected()
+{
+ return m_selected;
+}
+
+void SvnBlameFileSelectDlg::accept()
+{
+ while( true ){
+ QListViewItem *item = m_view->currentItem();
+ if( item ){
+ m_selected = item->text(0);
+ break;
+ }
+ else{
+ KMessageBox::error( this, i18n("Select file from list to view annotation") );
+ }
+ }
+ QDialog::accept();
+}
+
+#include "svn_blamewidget.moc"
diff --git a/vcs/subversion/svn_blamewidget.h b/vcs/subversion/svn_blamewidget.h
new file mode 100644
index 00000000..26bd0fa2
--- /dev/null
+++ b/vcs/subversion/svn_blamewidget.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+
+#ifndef SVN_BLAMEWIDGET_H
+#define SVN_BLAMEWIDGET_H
+
+#include <qwidget.h>
+#include <qdialog.h>
+#include <qvaluelist.h>
+class QVBoxLayout;
+class QListView;
+class QGridLayout;
+class QPushButton;
+class QStringList;
+
+class SvnBlameHolder {
+public:
+// SvnBlameHolder(){};
+// ~SvnBlameHolder(){};
+ unsigned int line;
+ long int rev;
+ QString date;
+ QString author;
+ QString content;
+};
+
+class QListView;
+
+class SvnBlameWidget : public QWidget {
+ Q_OBJECT
+public:
+ SvnBlameWidget( QWidget * parent = 0, const char * name = 0, bool modal = FALSE, WFlags f = 0 );
+ virtual ~SvnBlameWidget();
+ void copyBlameData( QValueList<SvnBlameHolder> *blamelist );
+ void show();
+ QListView* outView();
+protected:
+ QValueList <SvnBlameHolder> m_blamelist;
+
+ QVBoxLayout *m_layout;
+ QListView *m_listView;
+};
+
+class SvnBlameFileSelectDlg : public QDialog {
+ Q_OBJECT
+public:
+ SvnBlameFileSelectDlg( QWidget *parent = 0L );
+ virtual ~SvnBlameFileSelectDlg();
+ void setCandidate( QStringList *modifies );
+ QString selected();
+
+protected:
+ virtual void accept();
+
+private:
+ QGridLayout *m_layout;
+ QListView *m_view;
+ QPushButton *m_okBtn;
+ QPushButton *m_cancelBtn;
+
+ QStringList *m_candidates;
+ QString m_selected;
+};
+
+#endif
diff --git a/vcs/subversion/svn_co.ui b/vcs/subversion/svn_co.ui
new file mode 100644
index 00000000..4ea22290
--- /dev/null
+++ b/vcs/subversion/svn_co.ui
@@ -0,0 +1,335 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>svn_co</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>svn_co</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>509</width>
+ <height>360</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="caption">
+ <string>Subversion Module Checkout</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>server</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Server Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Checkout &amp;from:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>serverURL</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>serverURL</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Revision:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>revision</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>revision</cstring>
+ </property>
+ <property name="text">
+ <string>HEAD</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>WinPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>This Project has Standard &amp;Trunk/Branches/Tags/Directories</string>
+ </property>
+ <property name="exclusive">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>isStandard</cstring>
+ </property>
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton1_2</cstring>
+ </property>
+ <property name="text">
+ <string>No</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>local</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Local Directory</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;heckout in:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>localDir</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>localDir</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Name of the newly created directory:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>newDir</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>newDir</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>191</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>ok</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>cancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>ok</sender>
+ <signal>clicked()</signal>
+ <receiver>svn_co</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancel</sender>
+ <signal>clicked()</signal>
+ <receiver>svn_co</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_commitdlgbase.ui b/vcs/subversion/svn_commitdlgbase.ui
new file mode 100644
index 00000000..9151d566
--- /dev/null
+++ b/vcs/subversion/svn_commitdlgbase.ui
@@ -0,0 +1,131 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnCommitDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnCommitDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>514</width>
+ <height>305</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView" row="0" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string>Column 1</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ <property name="pixmap">
+ <pixmap></pixmap>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>listView1</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>335</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>keepLocksChk</cstring>
+ </property>
+ <property name="text">
+ <string>Keep Locks</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="2">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton3</cstring>
+ </property>
+ <property name="text">
+ <string>O&amp;K</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>pushButton3_2</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;ancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox" row="1" column="1">
+ <property name="name">
+ <cstring>recursiveChk</cstring>
+ </property>
+ <property name="text">
+ <string>Recursive</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>pushButton3</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnCommitDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>pushButton3_2</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnCommitDlgBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/vcs/subversion/svn_copydlgwidget.ui b/vcs/subversion/svn_copydlgwidget.ui
new file mode 100644
index 00000000..00a4d5c7
--- /dev/null
+++ b/vcs/subversion/svn_copydlgwidget.ui
@@ -0,0 +1,238 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnCopyDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnCopyDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>439</width>
+ <height>433</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Copy</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>reqEdit</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="5" column="1">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <spacer row="5" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>110</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="5" column="2">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>buttonGroup3</cstring>
+ </property>
+ <property name="title">
+ <string>Destination</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KURLRequester" row="1" column="0">
+ <property name="name">
+ <cstring>destRequester</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Specify either the full repository URL or local working path</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Requested Local Path</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Source Revision</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>revnumInput</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>revnumRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Specify by number:</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>revkindRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Specify by keyword:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>HEAD</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>BASE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WORKING</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>revkindCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Source</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KLineEdit" row="2" column="0">
+ <property name="name">
+ <cstring>srcEdit</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>urlRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Specify by the repository URL of this item</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>pathRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Specify by local path of this item</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnCopyDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnCopyDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_copywidget.cpp b/vcs/subversion/svn_copywidget.cpp
new file mode 100644
index 00000000..a5d74bcb
--- /dev/null
+++ b/vcs/subversion/svn_copywidget.cpp
@@ -0,0 +1,75 @@
+#include "svn_copywidget.h"
+#include <klineedit.h>
+#include <kurl.h>
+#include "subversion_global.h"
+#include <kurlrequester.h>
+#include <knuminput.h>
+#include <kcombobox.h>
+#include <qradiobutton.h>
+
+SvnCopyDialog::SvnCopyDialog( const QString &reqPath, SvnGlobal::SvnInfoHolder *holder, QWidget *parent )
+ : SvnCopyDialogBase( parent )
+ , m_holder(holder)
+{
+ reqEdit->setText( reqPath );
+
+ connect( urlRadio, SIGNAL(clicked()), this, SLOT(setSourceAsUrl()) );
+ connect( pathRadio, SIGNAL(clicked()), this, SLOT(setSourceAsLocalPath()) );
+ connect( revnumRadio, SIGNAL(toggled(bool)), revnumInput, SLOT(setEnabled(bool)) );
+ connect( revnumRadio, SIGNAL(toggled(bool)), revkindCombo, SLOT(setDisabled(bool)) );
+
+ // In many cases, users copy from reository to repository. This is for making tag/branche.
+ // The case where copying from local path to repository may be lesser than the above one.
+ // Thus, by default retrieve the repository URL of the given local path
+ urlRadio->setChecked( true );
+ srcEdit->setText( m_holder->url.prettyURL() );
+ // Also, revision is set to HEAD by default
+ revkindRadio->setChecked( true );
+ revkindCombo->insertItem( "HEAD" );
+}
+
+SvnCopyDialog::~SvnCopyDialog()
+{
+}
+
+KURL SvnCopyDialog::sourceUrl()
+{
+ return KURL( srcEdit->text() );
+}
+
+int SvnCopyDialog::revision()
+{
+ if( revnumRadio->isChecked() )
+ return revnumInput->value();
+ else
+ return -1;
+}
+
+QString SvnCopyDialog::revKind()
+{
+ if( revkindRadio->isChecked() )
+ return revkindCombo->currentText();
+ else
+ return QString("");
+}
+
+KURL SvnCopyDialog::destUrl()
+{
+ return KURL( destRequester->url() );
+}
+
+void SvnCopyDialog::setSourceAsUrl()
+{
+ srcEdit->setText( m_holder->url.prettyURL() );
+ revkindCombo->clear();
+ revkindCombo->insertItem( "HEAD" );
+}
+
+void SvnCopyDialog::setSourceAsLocalPath()
+{
+ srcEdit->setText( reqEdit->text() );
+ revkindCombo->clear();
+ revkindCombo->insertItem( "WORKING" );
+}
+
+#include "svn_copywidget.moc"
diff --git a/vcs/subversion/svn_copywidget.h b/vcs/subversion/svn_copywidget.h
new file mode 100644
index 00000000..cc00636d
--- /dev/null
+++ b/vcs/subversion/svn_copywidget.h
@@ -0,0 +1,32 @@
+#ifndef SVN_COPYWIDGET_H
+#define SVN_COPYWIDGET_H
+
+#include "svn_copydlgwidget.h"
+
+namespace SvnGlobal
+{
+ class SvnInfoHolder;
+}
+class KURL;
+
+class SvnCopyDialog : public SvnCopyDialogBase
+{
+ Q_OBJECT
+public:
+ SvnCopyDialog( const QString &reqPath, SvnGlobal::SvnInfoHolder *holder, QWidget *parent );
+ ~SvnCopyDialog();
+
+ KURL sourceUrl();
+ int revision();
+ QString revKind();
+ KURL destUrl();
+
+public slots:
+ void setSourceAsUrl();
+ void setSourceAsLocalPath();
+
+private:
+ SvnGlobal::SvnInfoHolder *m_holder;
+};
+
+#endif
diff --git a/vcs/subversion/svn_fileselectdlg_commit.cpp b/vcs/subversion/svn_fileselectdlg_commit.cpp
new file mode 100644
index 00000000..4f4cdceb
--- /dev/null
+++ b/vcs/subversion/svn_fileselectdlg_commit.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#include "svn_fileselectdlg_commit.h"
+#include "subversion_fileinfo.h"
+#include "subversion_part.h"
+#include <kurl.h>
+#include <qstring.h>
+#include <qlistview.h>
+#include <qfileinfo.h>
+#include <qcheckbox.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include "kdevmainwindow.h"
+#include <klocale.h>
+
+#include <kdevproject.h>
+
+SVNFileSelectDlgCommit::SVNFileSelectDlgCommit( KURL::List &urls, subversionPart *part, QWidget* parent)
+ :SvnCommitDlgBase( parent, "svnfileselectcommitdlg", true )
+ ,m_part(part)
+{
+ this->setCaption(i18n("Select Files to Commit"));
+ listView()->clear();
+ listView()->setColumnText(0, i18n("select") ); //col 0
+ listView()->addColumn( i18n("status") ); //col 1
+ listView()->addColumn( i18n("URL to commit") ); //col 2
+ listView()->setColumnWidthMode( 2, QListView::Maximum );
+ listView()->setSorting( 2, true );
+ recursiveChk->setChecked(false);
+ keepLocksChk->setChecked(false);
+
+
+ const VCSFileInfoMap *vcsMap;
+ VCSFileInfo vcsInfo;
+ KURL::List tobeCommittedUrls;
+
+ for( QValueListConstIterator<KURL> it = urls.begin(); it != urls.end(); ++it ){
+ KURL oneUrl(*it);
+ QFileInfo fileInfo(oneUrl.path());
+ //fileInfo.convertToAbs();
+
+ if (fileInfo.isFile()){
+ KURL base_url( part->project()->projectDirectory()+"/" );
+ QString dirPath = KURL::relativeURL( base_url, fileInfo.dirPath(TRUE) );
+ vcsMap = ((SVNFileInfoProvider*)part->fileInfoProvider()) ->
+ statusExt(dirPath, false/*repository access*/, true/*recurse*/, false/*getall*/, true/*noIgnore*/);
+ vcsInfo = (*vcsMap)[fileInfo.fileName()];
+ if( vcsInfo.state == VCSFileInfo::Added || vcsInfo.state == VCSFileInfo::Modified ||
+ vcsInfo.state == VCSFileInfo::Deleted || vcsInfo.state == VCSFileInfo::Replaced ){
+
+ this->insertItem( VCSFileInfo::state2String( vcsInfo.state ), oneUrl );
+// tobeCommittedUrls.push_back(oneUrl);
+// kdDebug(9036) << "slotCommit() : added AS FILE: " << oneUrl.prettyURL() << endl;
+
+ }
+ else{
+ kdDebug(9036) << "slotCommit() @ FileCase ignoring " << oneUrl.prettyURL() << endl;
+ }
+ }
+ else if (fileInfo.isDir()){
+ KURL base_url( part->project()->projectDirectory()+"/" );
+ QString dirPath = KURL::relativeURL( base_url, fileInfo.absFilePath() );
+ vcsMap = ((SVNFileInfoProvider*)part->fileInfoProvider()) ->
+ statusExt(dirPath, false/*repository access*/, true/*recurse*/, false/*getall*/, true/*noIgnore*/);
+ for (VCSFileInfoMap::ConstIterator it=vcsMap->begin(); it!=vcsMap->end(); ++it){
+
+ vcsInfo = it.data();
+// QString absPathStr( fileInfo.absFilePath() + "/" + it.key() );
+ QString absPathStr( fileInfo.filePath() + "/" + it.key() );
+ KURL urlFromStatus( absPathStr );
+ if( vcsInfo.state == VCSFileInfo::Added || vcsInfo.state == VCSFileInfo::Modified ||
+ vcsInfo.state == VCSFileInfo::Deleted || vcsInfo.state == VCSFileInfo::Replaced){
+
+ this->insertItem( VCSFileInfo::state2String( vcsInfo.state ), urlFromStatus );
+
+// tobeCommittedUrls.push_back( urlFromStatus );
+// kdDebug(9036) << "slotCommit() @ DirCase adding " << urlFromStatus.prettyURL() << endl;
+ }
+ else{
+ kdDebug(9036) << "slotCommit() @ DirCase ignoring " << urlFromStatus.prettyURL() << endl;
+ }
+
+ }
+ }
+ else if ( !fileInfo.exists() ){
+ // maybe deleted files
+ this->insertItem( VCSFileInfo::state2String( VCSFileInfo::Deleted ), oneUrl );
+ }
+ }
+
+}
+SVNFileSelectDlgCommit::~SVNFileSelectDlgCommit()
+{
+}
+
+int SVNFileSelectDlgCommit::exec()
+{
+ if (listView()->childCount() <= 0){
+ //TODO if klauncher fails, this spot is also reached. We should show correct error message to user
+ KMessageBox::information( (QWidget*)m_part->project()->mainWindow()->main(), i18n("No added/modified/deleted file(s) to commit") );
+ return QDialog::Rejected;
+ }
+ else{
+ return SvnCommitDlgBase::exec();
+ }
+}
+void SVNFileSelectDlgCommit::insertItem( QString status, KURL url )
+{
+ QCheckListItem *item = new QCheckListItem( listView(), "", QCheckListItem::CheckBox );
+ item->setText( 1, status );
+ item->setText( 2, url.path() );
+ item->setOn(true);
+}
+KURL::List SVNFileSelectDlgCommit::checkedUrls()
+{
+ QPtrList<QListViewItem> lst;
+ QListViewItemIterator it( listView() );
+ KURL::List tobeCommittedUrls;
+
+ for ( ; it.current() ; ++it ) {
+ if ( ((QCheckListItem*)(it.current()))->isOn() ){
+ KURL tmpurl( it.current()->text(2) );
+ tobeCommittedUrls.push_back( tmpurl );
+ }
+ }
+ return tobeCommittedUrls;
+
+}
+QListView* SVNFileSelectDlgCommit::listView()
+{
+ return listView1;
+}
+
+bool SVNFileSelectDlgCommit::recursive()
+{
+ return recursiveChk->isChecked();
+}
+bool SVNFileSelectDlgCommit::keepLocks()
+{
+ return keepLocksChk->isChecked();
+}
+
+#include "svn_fileselectdlg_commit.moc"
+
diff --git a/vcs/subversion/svn_fileselectdlg_commit.h b/vcs/subversion/svn_fileselectdlg_commit.h
new file mode 100644
index 00000000..acd95ebb
--- /dev/null
+++ b/vcs/subversion/svn_fileselectdlg_commit.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _svnfileselectdlgcommit_
+#define _svnfileselectdlgcommit_
+
+#include "svn_commitdlgbase.h"
+#include <qdialog.h>
+#include <kurl.h>
+
+class QString;
+class KURL;
+class QListView;
+class subversionPart;
+
+class SVNFileSelectDlgCommit : public SvnCommitDlgBase{
+
+Q_OBJECT
+
+public:
+ SVNFileSelectDlgCommit( KURL::List&, subversionPart* part, QWidget* parent = 0 );
+ ~SVNFileSelectDlgCommit();
+ void insertItem( QString status, KURL url );
+ KURL::List checkedUrls();
+ bool recursive();
+ bool keepLocks();
+
+public slots:
+ int exec();
+protected:
+ QListView* listView();
+ subversionPart *m_part;
+};
+
+#endif
diff --git a/vcs/subversion/svn_kio.cpp b/vcs/subversion/svn_kio.cpp
new file mode 100644
index 00000000..c5c8dfe6
--- /dev/null
+++ b/vcs/subversion/svn_kio.cpp
@@ -0,0 +1,2155 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qcstring.h>
+#include <qsocket.h>
+#include <qdatetime.h>
+#include <qbitarray.h>
+
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kinstance.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <ksock.h>
+#include <dcopclient.h>
+#include <qcstring.h>
+
+#include <subversion-1/svn_sorts.h>
+#include <subversion-1/svn_path.h>
+#include <subversion-1/svn_utf.h>
+#include <subversion-1/svn_ra.h>
+#include <subversion-1/svn_time.h>
+#include <subversion-1/svn_cmdline.h>
+
+#include <kmimetype.h>
+#include <qfile.h>
+
+#include "svn_kio.h"
+#include <apr_portable.h>
+// #include "commitdlg.h"
+#include <ktextedit.h>
+
+using namespace KIO;
+using namespace SvnGlobal;
+
+typedef struct
+{
+ /* Holds the directory that corresponds to the REPOS_URL at RA->open()
+ * time. When callbacks specify a relative path, they are joined with
+ * this base directory. */
+ const char *base_dir;
+ svn_wc_adm_access_t *base_access;
+
+ /* An array of svn_client_commit_item_t * structures, present only
+ * during working copy commits. */
+ apr_array_header_t *commit_items;
+
+ /* A hash of svn_config_t's, keyed off file name (i.e. the contents of
+ * ~/.subversion/config end up keyed off of 'config'). */
+ apr_hash_t *config;
+
+ /* The pool to use for session-related items. */
+ apr_pool_t *pool;
+
+} svn_client__callback_baton_t;
+
+static svn_error_t *
+open_tmp_file (apr_file_t **fp,
+ void *callback_baton,
+ apr_pool_t *pool)
+{
+ svn_client__callback_baton_t *cb = (svn_client__callback_baton_t *) callback_baton;
+ const char *truepath;
+ const char *ignored_filename;
+
+ if (cb->base_dir)
+ truepath = apr_pstrdup (pool, cb->base_dir);
+ else
+ truepath = "";
+
+ /* Tack on a made-up filename. */
+ truepath = svn_path_join (truepath, "tempfile", pool);
+
+ /* Open a unique file; use APR_DELONCLOSE. */
+ SVN_ERR (svn_io_open_unique_file (fp, &ignored_filename,
+ truepath, ".tmp", TRUE, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *write_to_string(void *baton, const char *data, apr_size_t *len) {
+ kbaton *tb = ( kbaton* )baton;
+ svn_stringbuf_appendbytes(tb->target_string, data, *len);
+ return SVN_NO_ERROR;
+}
+
+static int
+compare_items_as_paths (const svn_sort__item_t*a, const svn_sort__item_t*b) {
+ return svn_path_compare_paths ((const char *)a->key, (const char *)b->key);
+}
+
+kio_svnProtocol::kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket)
+ : SlaveBase("kio_svn", pool_socket, app_socket) {
+ kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol()" << endl;
+
+ m_counter = 0;
+
+ apr_initialize();
+ // Make sure to properly initialize svn client, besides other things, this sets up
+ // NLS support for environments that don't use UTF-8
+ svn_cmdline_init("kdevsvnd",NULL);
+ // CleanUP ctx preventing crash in svn_client_update and other
+ memset(&ctx, 0, sizeof(ctx));
+ pool = svn_pool_create (NULL);
+
+ svn_error_t *err = svn_client_create_context(&ctx, pool);
+ if ( err ) {
+ kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol() create_context ERROR" << endl;
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ return;
+ }
+
+ err = svn_config_ensure (NULL,pool);
+ if ( err ) {
+ kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol() configensure ERROR" << endl;
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ return;
+ }
+ svn_config_get_config (&ctx->config, NULL, pool);
+
+ ctx->log_msg_func = kio_svnProtocol::commitLogPrompt;
+ ctx->log_msg_baton = this; //pass this so that we can get a dcopClient from it
+ //TODO
+ ctx->cancel_func = NULL;
+ // progress notifications
+ ctx->progress_func = kio_svnProtocol::progressCallback;
+ ctx->progress_baton = this;
+
+ apr_array_header_t *providers = apr_array_make(pool, 15, sizeof(svn_auth_provider_object_t *));
+
+ svn_auth_provider_object_t *provider;
+
+ //disk cache
+ svn_client_get_simple_provider(&provider,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+ svn_client_get_username_provider(&provider,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+
+ //interactive prompt
+ svn_client_get_simple_prompt_provider (&provider,kio_svnProtocol::checkAuth,this,2,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;
+ //we always ask user+pass, no need for a user only question
+/* svn_client_get_username_prompt_provider
+ * (&provider,kio_svnProtocol::checkAuth,this,2,pool);
+ APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;*/
+
+ //SSL disk cache, keep that one, because it does nothing bad :)
+ svn_client_get_ssl_server_trust_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_pw_file_provider (&provider, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ //SSL interactive prompt, where things get hard
+ svn_client_get_ssl_server_trust_prompt_provider (&provider, kio_svnProtocol::trustSSLPrompt, (void*)this, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_prompt_provider (&provider, kio_svnProtocol::clientCertSSLPrompt, (void*)this, 2, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+ svn_client_get_ssl_client_cert_pw_prompt_provider (&provider, kio_svnProtocol::clientCertPasswdPrompt, (void*)this, 2, pool);
+ APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider;
+
+ svn_auth_open(&ctx->auth_baton, providers, pool);
+}
+
+kio_svnProtocol::~kio_svnProtocol(){
+ kdDebug(9036) << "kio_svnProtocol::~kio_svnProtocol()" << endl;
+ svn_pool_destroy(pool);
+ apr_terminate();
+}
+
+void kio_svnProtocol::initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool) {
+ m_counter=0;//reset counter
+ ctx->notify_func = kio_svnProtocol::notify;
+ struct notify_baton *nb = ( struct notify_baton* )apr_palloc(spool, sizeof( struct notify_baton ) );
+ nb->master = this;
+ nb->received_some_change = FALSE;
+ nb->sent_first_txdelta = FALSE;
+ nb->is_checkout = is_checkout;
+ nb->is_export = is_export;
+ nb->suppress_final_line = suppress_final_line;
+ nb->in_external = FALSE;
+ nb->had_print_error = FALSE;
+ nb->pool = svn_pool_create (spool);
+
+ ctx->notify_baton = nb;
+}
+
+svn_error_t* kio_svnProtocol::checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool) {
+ kdDebug(9036) << "kio_svnProtocol::checkAuth() " << endl;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+ svn_auth_cred_simple_t *ret = (svn_auth_cred_simple_t*)apr_pcalloc (pool, sizeof (*ret));
+
+ p->info.keepPassword = true;
+ p->info.verifyPath=true;
+ kdDebug(9036 ) << "auth current URL : " << p->myURL.url() << endl;
+ p->info.url = p->myURL;
+ p->info.username = username; //( const char* )svn_auth_get_parameter( p->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_USERNAME );
+ if (realm) {
+ p->info.prompt = i18n("Username and Password for %1.").arg(realm);
+ }
+
+// if ( !p->checkCachedAuthentication( p->info ) ){
+ p->openPassDlg( p->info );
+// }
+ ret->username = apr_pstrdup(pool, p->info.username.utf8());
+ ret->password = apr_pstrdup(pool, p->info.password.utf8());
+ if (may_save) ret->may_save = p->info.keepPassword;
+ *cred = ret;
+ return SVN_NO_ERROR;
+}
+
+void kio_svnProtocol::recordCurrentURL(const KURL& url) {
+ myURL = url;
+}
+
+//don't implement mimeType() until we don't need to download the whole file
+
+void kio_svnProtocol::get(const KURL& url ){
+ kdDebug(9036) << "kio_svn::get(const KURL& url)" << endl ;
+
+ QString remoteServer = url.host();
+ infoMessage(i18n("Looking for %1...").arg( remoteServer ) );
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ kbaton *bt = (kbaton*)apr_pcalloc(subpool, sizeof(*bt));
+ bt->target_string = svn_stringbuf_create("", subpool);
+ bt->string_stream = svn_stream_create(bt,subpool);
+ svn_stream_set_write(bt->string_stream,write_to_string);
+
+ QString target = makeSvnURL( url );
+ kdDebug(9036) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+#if 0
+ kdDebug(9036) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(9036) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(9036) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool );
+ target = target.left( idx );
+ kdDebug(9036) << "new target : " << target << endl;
+ } else {
+ kdDebug(9036) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+ initNotifier(false, false, false, subpool);
+
+ svn_error_t *err = svn_client_cat (bt->string_stream, svn_path_canonicalize( target.utf8(),subpool ),&rev,ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ svn_pool_destroy( subpool );
+ return;
+ }
+
+ // Send the mimeType as soon as it is known
+ QByteArray *cp = new QByteArray();
+ cp->setRawData( bt->target_string->data, bt->target_string->len );
+ KMimeType::Ptr mt = KMimeType::findByContent(*cp);
+ kdDebug(9036) << "KMimeType returned : " << mt->name() << endl;
+ mimeType( mt->name() );
+
+ totalSize(bt->target_string->len);
+
+ //send data
+ data(*cp);
+
+ data(QByteArray()); // empty array means we're done sending the data
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::stat(const KURL & url){
+ kdDebug(9036) << "kio_svn::stat(const KURL& url) : " << url.url() << endl ;
+
+ void *ra_baton, *session;
+ svn_ra_plugin_t *ra_lib;
+ svn_node_kind_t kind;
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ QString target = makeSvnURL( url);
+ kdDebug(9036) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+#if 0
+ kdDebug(9036) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(9036) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(9036) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8( ), subpool );
+ target = target.left( idx );
+ kdDebug(9036) << "new target : " << target << endl;
+ } else {
+ kdDebug(9036) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ //init
+ svn_error_t *err = svn_ra_init_ra_libs(&ra_baton,subpool);
+ if ( err ) {
+ kdDebug(9036) << "init RA libs failed : " << err->message << endl;
+ return;
+ }
+ //find RA libs
+ err = svn_ra_get_ra_library(&ra_lib,ra_baton,svn_path_canonicalize( target.utf8(), subpool ),subpool);
+ if ( err ) {
+ kdDebug(9036) << "RA get libs failed : " << err->message << endl;
+ return;
+ }
+ kdDebug(9036) << "RA init completed" << endl;
+
+ //start session
+ svn_ra_callbacks_t *cbtable = (svn_ra_callbacks_t*)apr_pcalloc(subpool, sizeof(*cbtable));
+ kio_svn_callback_baton_t *callbackbt = (kio_svn_callback_baton_t*)apr_pcalloc(subpool, sizeof( *callbackbt ));
+
+ cbtable->open_tmp_file = open_tmp_file;
+ cbtable->get_wc_prop = NULL;
+ cbtable->set_wc_prop = NULL;
+ cbtable->push_wc_prop = NULL;
+ cbtable->auth_baton = ctx->auth_baton;
+
+ callbackbt->base_dir = target.utf8();
+ callbackbt->pool = subpool;
+ callbackbt->config = ctx->config;
+
+ err = ra_lib->open(&session,svn_path_canonicalize( target.utf8(), subpool ),cbtable,callbackbt,ctx->config,subpool);
+ if ( err ) {
+ kdDebug(9036)<< "Open session " << err->message << endl;
+ return;
+ }
+ kdDebug(9036) << "Session opened to " << target << endl;
+ //find number for HEAD
+ if (rev.kind == svn_opt_revision_head) {
+ err = ra_lib->get_latest_revnum(session,&rev.value.number,subpool);
+ if ( err ) {
+ kdDebug(9036)<< "Latest RevNum " << err->message << endl;
+ return;
+ }
+ kdDebug(9036) << "Got rev " << rev.value.number << endl;
+ }
+
+ //get it
+ ra_lib->check_path(session,"",rev.value.number,&kind,subpool);
+ kdDebug(9036) << "Checked Path" << endl;
+ UDSEntry entry;
+ switch ( kind ) {
+ case svn_node_file:
+ kdDebug(9036) << "::stat result : file" << endl;
+ createUDSEntry(url.filename(),"",0,false,0,entry);
+ statEntry( entry );
+ break;
+ case svn_node_dir:
+ kdDebug(9036) << "::stat result : directory" << endl;
+ createUDSEntry(url.filename(),"",0,true,0,entry);
+ statEntry( entry );
+ break;
+ case svn_node_unknown:
+ case svn_node_none:
+ //error XXX
+ default:
+ kdDebug(9036) << "::stat result : UNKNOWN ==> WOW :)" << endl;
+ ;
+ }
+ finished();
+ svn_pool_destroy( subpool );
+}
+
+void kio_svnProtocol::listDir(const KURL& url){
+ kdDebug(9036) << "kio_svn::listDir(const KURL& url) : " << url.url() << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_hash_t *dirents;
+
+ QString target = makeSvnURL( url);
+ kdDebug(9036) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ svn_opt_revision_t endrev;
+ int idx = target.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = target.mid( idx+5 );
+ svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool );
+#if 0
+ kdDebug(9036) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(9036) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(9036) << "revision searched : " << rev.value.number << endl;
+ }
+#endif
+ target = target.left( idx );
+ kdDebug(9036) << "new target : " << target << endl;
+ } else {
+ kdDebug(9036) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_ls (&dirents, svn_path_canonicalize( target.utf8(), subpool ), &rev, false, ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ svn_pool_destroy( subpool );
+ return;
+ }
+
+ apr_array_header_t *array;
+ int i;
+
+ array = svn_sort__hash (dirents, compare_items_as_paths, subpool);
+
+ UDSEntry entry;
+ for (i = 0; i < array->nelts; ++i) {
+ entry.clear();
+ const char *utf8_entryname, *native_entryname;
+ svn_dirent_t *dirent;
+ svn_sort__item_t *item;
+
+ item = &APR_ARRAY_IDX (array, i, svn_sort__item_t);
+
+ utf8_entryname = (const char*)item->key;
+
+ dirent = (svn_dirent_t*)apr_hash_get (dirents, utf8_entryname, item->klen);
+
+ svn_utf_cstring_from_utf8 (&native_entryname, utf8_entryname, subpool);
+ const char *native_author = NULL;
+
+ //XXX BUGGY
+/* apr_time_exp_t timexp;
+ apr_time_exp_lt(&timexp, dirent->time);
+ apr_os_exp_time_t *ostime;
+ apr_os_exp_time_get( &ostime, &timexp);
+
+ time_t mtime = mktime( ostime );*/
+
+ if (dirent->last_author)
+ svn_utf_cstring_from_utf8 (&native_author, dirent->last_author, subpool);
+
+ if ( createUDSEntry(QString( native_entryname ), QString( native_author ), dirent->size,
+ dirent->kind==svn_node_dir ? true : false, 0, entry) )
+ listEntry( entry, false );
+ }
+ listEntry( entry, true );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+bool kio_svnProtocol::createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, UDSEntry& entry) {
+ kdDebug(9036) << "MTime : " << ( long )mtime << endl;
+ kdDebug(9036) << "UDS filename : " << filename << endl;
+ UDSAtom atom;
+ atom.m_uds = KIO::UDS_NAME;
+ atom.m_str = filename;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_FILE_TYPE;
+ atom.m_long = isdir ? S_IFDIR : S_IFREG;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_SIZE;
+ atom.m_long = size;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_MODIFICATION_TIME;
+ atom.m_long = mtime;
+ entry.append( atom );
+
+ atom.m_uds = KIO::UDS_USER;
+ atom.m_str = user;
+ entry.append( atom );
+
+ return true;
+}
+
+// not used, at least for KDevelop
+// void kio_svnProtocol::copy(const KURL & src, const KURL& dest, int /*permissions*/, bool /*overwrite*/) {
+// kdDebug(9036) << "kio_svnProtocol::copy() Source : " << src.url() << " Dest : " << dest.url() << endl;
+//
+// apr_pool_t *subpool = svn_pool_create (pool);
+// svn_client_commit_info_t *commit_info = NULL;
+//
+// KURL nsrc = src;
+// KURL ndest = dest;
+// nsrc.setProtocol( chooseProtocol( src.protocol() ) );
+// ndest.setProtocol( chooseProtocol( dest.protocol() ) );
+// QString srcsvn = nsrc.url();
+// QString destsvn = ndest.url();
+//
+// recordCurrentURL( nsrc );
+//
+// //find the requested revision
+// svn_opt_revision_t rev;
+// int idx = srcsvn.findRev( "?rev=" );
+// if ( idx != -1 ) {
+// QString revstr = srcsvn.mid( idx+5 );
+// kdDebug(9036) << "revision string found " << revstr << endl;
+// if ( revstr == "HEAD" ) {
+// rev.kind = svn_opt_revision_head;
+// kdDebug(9036) << "revision searched : HEAD" << endl;
+// } else {
+// rev.kind = svn_opt_revision_number;
+// rev.value.number = revstr.toLong();
+// kdDebug(9036) << "revision searched : " << rev.value.number << endl;
+// }
+// srcsvn = srcsvn.left( idx );
+// kdDebug(9036) << "new src : " << srcsvn << endl;
+// } else {
+// kdDebug(9036) << "no revision given. searching HEAD " << endl;
+// rev.kind = svn_opt_revision_head;
+// }
+//
+// initNotifier(false, false, false, subpool);
+// svn_error_t *err = svn_client_copy(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), ctx, subpool);
+// if ( err ) {
+// error( KIO::ERR_SLAVE_DEFINED, err->message );
+// svn_pool_destroy (subpool);
+// }
+//
+// finished();
+// svn_pool_destroy (subpool);
+// }
+
+void kio_svnProtocol::mkdir( const KURL::List& list, int /*permissions*/ ) {
+ kdDebug(9036) << "kio_svnProtocol::mkdir(LIST) : " << list << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ recordCurrentURL( list[ 0 ] );
+
+ apr_array_header_t *targets = apr_array_make(subpool, list.count()+1, sizeof(const char *));
+
+ KURL::List::const_iterator it = list.begin(), end = list.end();
+ for ( ; it != end; ++it ) {
+ QString cur = makeSvnURL( *it );
+ kdDebug( 9036 ) << "kio_svnProtocol::mkdir raw url for subversion : " << cur << endl;
+ const char *_target = apr_pstrdup( subpool, svn_path_canonicalize( apr_pstrdup( subpool, cur.utf8() ), subpool ) );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = _target;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_COULD_NOT_MKDIR, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::mkdir( const KURL& url, int /*permissions*/ ) {
+ kdDebug(9036) << "kio_svnProtocol::mkdir() : " << url.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ QString target = makeSvnURL( url);
+ kdDebug(9036) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *));
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_COULD_NOT_MKDIR, err->message );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::del( const KURL& url, bool /*isfile*/ ) {
+ kdDebug(9036) << "kio_svnProtocol::del() : " << url.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ QString target = makeSvnURL(url);
+ kdDebug(9036) << "SvnURL: " << target << endl;
+ recordCurrentURL( KURL( target ) );
+
+ apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *));
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_delete(&commit_info,targets,false/*force remove locally modified files in wc*/,ctx,subpool);
+ if ( err ) {
+ error( KIO::ERR_CANNOT_DELETE, err->message );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::rename(const KURL& src, const KURL& dest, bool /*overwrite*/) {
+ kdDebug(9036) << "kio_svnProtocol::rename() Source : " << src.url() << " Dest : " << dest.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ KURL nsrc = src;
+ KURL ndest = dest;
+ nsrc.setProtocol( chooseProtocol( src.protocol() ) );
+ ndest.setProtocol( chooseProtocol( dest.protocol() ) );
+ QString srcsvn = nsrc.url();
+ QString destsvn = ndest.url();
+
+ recordCurrentURL( nsrc );
+
+ //find the requested revision
+ svn_opt_revision_t rev;
+ int idx = srcsvn.findRev( "?rev=" );
+ if ( idx != -1 ) {
+ QString revstr = srcsvn.mid( idx+5 );
+ kdDebug(9036) << "revision string found " << revstr << endl;
+ if ( revstr == "HEAD" ) {
+ rev.kind = svn_opt_revision_head;
+ kdDebug(9036) << "revision searched : HEAD" << endl;
+ } else {
+ rev.kind = svn_opt_revision_number;
+ rev.value.number = revstr.toLong();
+ kdDebug(9036) << "revision searched : " << rev.value.number << endl;
+ }
+ srcsvn = srcsvn.left( idx );
+ kdDebug(9036) << "new src : " << srcsvn << endl;
+ } else {
+ kdDebug(9036) << "no revision given. searching HEAD " << endl;
+ rev.kind = svn_opt_revision_head;
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_move(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), false/*force remove locally modified files in wc*/, ctx, subpool);
+ if ( err ) {
+ error( KIO::ERR_CANNOT_RENAME, err->message );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::special( const QByteArray& data ) {
+// kdDebug(9036) << "kio_svnProtocol::special" << endl;
+
+ QDataStream stream(data, IO_ReadOnly);
+ int tmp;
+
+ stream >> tmp;
+ kdDebug(9036) << "kio_svnProtocol::special " << tmp << endl;
+
+ switch ( tmp ) {
+ case SVN_CHECKOUT:
+ {
+ KURL repository, wc;
+ int revnumber;
+ QString revkind;
+ stream >> repository;
+ stream >> wc;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(9036) << "kio_svnProtocol CHECKOUT from " << repository.url() << " to " << wc.url() << " at " << revnumber << " or " << revkind << endl;
+ checkout( repository, wc, revnumber, revkind );
+ break;
+ }
+ case SVN_UPDATE:
+ {
+ KURL::List list;
+ int revnumber;
+ QString revkind;
+ stream >> list;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(9036) << "kio_svnProtocol UPDATE " << endl;
+ update( list, revnumber, revkind );
+ break;
+ }
+ case SVN_COMMIT:
+ {
+ KURL::List wclist;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ wclist << tmp;
+ }
+ kdDebug(9036) << "kio_svnProtocol COMMIT" << endl;
+ commit( wclist );
+ break;
+ }
+ case SVN_COMMIT_2:
+ {
+ bool recurse, keeplocks;
+ KURL::List wclist;
+ stream >> recurse;
+ stream >> keeplocks;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ wclist << tmp;
+ }
+ kdDebug(9036) << "kio_svnProtocol COMMIT2" << endl;
+ commit2( recurse, keeplocks, wclist );
+ break;
+ }
+ case SVN_LOG:
+ {
+ kdDebug(9036) << "kio_svnProtocol LOG" << endl;
+ int revstart, revend;
+ QString revkindstart, revkindend;
+ bool discorverChangedPath, strictNodeHistory;
+ KURL::List targets;
+
+ stream >> revstart;
+ stream >> revkindstart;
+ stream >> revend;
+ stream >> revkindend;
+ stream >> discorverChangedPath;
+ stream >> strictNodeHistory;
+ while ( !stream.atEnd() ) {
+ KURL tmp;
+ stream >> tmp;
+ targets << tmp;
+ }
+ svn_log( revstart, revkindstart, revend, revkindend,
+ discorverChangedPath, strictNodeHistory, targets );
+ break;
+ }
+ case SVN_IMPORT:
+ {
+ KURL wc,repos;
+ stream >> repos;
+ stream >> wc;
+ kdDebug(9036) << "kio_svnProtocol IMPORT" << endl;
+ import(repos,wc);
+ break;
+ }
+ case SVN_ADD:
+ {
+ KURL::List wcList;
+ stream >> wcList;
+ kdDebug(9036) << "kio_svnProtocol ADD" << endl;
+ add(wcList);
+ break;
+ }
+ case SVN_DEL:
+ {
+ KURL::List wclist;
+ stream >> wclist;
+ kdDebug(9036) << "kio_svnProtocol DEL" << endl;
+ wc_delete(wclist);
+ break;
+ }
+ case SVN_REVERT:
+ {
+ KURL::List wclist;
+ stream >> wclist;
+ kdDebug(9036) << "kio_svnProtocol REVERT" << endl;
+ wc_revert(wclist);
+ break;
+ }
+ case SVN_STATUS:
+ {
+ KURL wc;
+ bool checkRepos=false;
+ bool fullRecurse=false;
+ stream >> wc;
+ stream >> checkRepos;
+ stream >> fullRecurse;
+ wc_status(wc,checkRepos,fullRecurse);
+ break;
+ }
+ case SVN_STATUS_2:
+ {
+ KURL wc;
+ QString revkind;
+ int revnumber;
+ bool checkRepos, fullRecurse, getAll, noIgnore;
+ stream >> checkRepos;
+ stream >> fullRecurse;
+ stream >> getAll;
+ stream >> noIgnore;
+ stream >> revnumber;
+ stream >> revkind;
+ stream >> wc;
+ wc_status2(wc,checkRepos,fullRecurse, getAll, noIgnore, revnumber, revkind);
+ break;
+ }
+ case SVN_MKDIR:
+ {
+ KURL::List list;
+ stream >> list;
+ kdDebug(9036) << "kio_svnProtocol MKDIR" << endl;
+ mkdir(list,0);
+ break;
+ }
+ case SVN_RESOLVE:
+ {
+ KURL url;
+ bool recurse;
+ stream >> url;
+ stream >> recurse;
+ kdDebug(9036) << "kio_svnProtocol RESOLVE" << endl;
+ wc_resolve(url,recurse);
+ break;
+ }
+ case SVN_SWITCH:
+ {
+ KURL wc,url;
+ bool recurse;
+ int revnumber;
+ QString revkind;
+ stream >> wc;
+ stream >> url;
+ stream >> recurse;
+ stream >> revnumber;
+ stream >> revkind;
+ kdDebug(9036) << "kio_svnProtocol SWITCH" << endl;
+ svn_switch(wc,url,revnumber,revkind,recurse);
+ break;
+ }
+ case SVN_SWITCH_RELOCATE:
+ {
+ KURL wc, origUrl, newUrl;
+ bool recurse;
+ stream >> wc;
+ stream >> origUrl;
+ stream >> newUrl;
+ stream >> recurse;
+ svn_switch_relocate( wc, origUrl, newUrl, recurse );
+ break;
+ }
+ case SVN_DIFF:
+ {
+ KURL url1,url2;
+ int rev1, rev2;
+ bool recurse, pegdiff;
+ QString revkind1, revkind2;
+ stream >> url1;
+ stream >> url2;
+ stream >> rev1;
+ stream >> revkind1;
+ stream >> rev2;
+ stream >> revkind2;
+ stream >> recurse >> pegdiff;
+ kdDebug(9036) << "kio_svnProtocol DIFF" << endl;
+ svn_diff(url1,url2,rev1,rev2,revkind1,revkind2,recurse,pegdiff);
+ break;
+ }
+ case SVN_BLAME:
+ {
+ KURL url;
+ int urlMode;
+ int pegRev, startRev, endRev;
+ QString pegRevKind, startRevKind, endRevKind;
+ stream >> url;
+ stream >> urlMode;
+// stream >> pegRev;
+// stream >> pegRevKind;
+ stream >> startRev;
+ stream >> startRevKind;
+ stream >> endRev;
+ stream >> endRevKind;
+
+ blame(url, (UrlMode)urlMode, startRev, startRevKind, endRev, endRevKind);
+ break;
+ }
+ case SVN_INFO:
+ {
+ KURL pathOrUrl;
+ int pegRev, rev;
+ QString pegRevKind, revKind;
+ bool recurse = false;
+ stream >> pathOrUrl;
+ stream >> pegRev;
+ stream >> pegRevKind;
+ stream >> rev;
+ stream >> revKind;
+ stream >> recurse;
+ svn_info( pathOrUrl, pegRev, pegRevKind, rev, revKind, recurse );
+ break;
+ }
+ case SVN_COPY:
+ {
+ KURL src, dest;
+ int srcRev;
+ QString srcRevKind;
+ stream >> src;
+ stream >> srcRev;
+ stream >> srcRevKind;
+ stream >> dest;
+ svn_copy( src, srcRev, srcRevKind, dest );
+ break;
+ }
+ case SVN_MERGE:
+ {
+ KURL src1, src2, wc_target;
+ int rev1, rev2;
+ QString revKind1, revKind2;
+ bool recurse, ignore_ancestry, force, dry_run;
+ stream >> src1 >> rev1 >> revKind1;
+ stream >> src2 >> rev2 >> revKind2;
+ stream >> wc_target;
+ stream >> recurse >> ignore_ancestry >> force >> dry_run;
+ svn_merge( src1, rev1, revKind1, src2, rev2, revKind2, wc_target,
+ recurse, ignore_ancestry, force, dry_run );
+ break;
+ }
+ default:
+ {
+ kdDebug(9036) << "kio_svnProtocol DEFAULT" << endl;
+ break;
+ }
+ }
+}
+/**
+ * not used anywhere, anymore
+*/
+void kio_svnProtocol::popupMessage( const QString& message ) {
+// QByteArray params;
+// QDataStream stream(params, IO_WriteOnly);
+// stream << message;
+//
+// if ( !dcopClient()->send( "kded","ksvnd","popupMessage(QString)", params ) )
+// kdWarning() << "Communication with KDED:KSvnd failed" << endl;
+}
+
+void kio_svnProtocol::blame( KURL url, UrlMode /*mode*/,/* int pegRev, QString pegRevKind,*/ int startRev, QString startRevKind, int endRev, QString endRevKind )
+{
+ kdDebug(9036) << " __TIME__ " << __TIME__ << endl;
+// kdDebug(9036) << " PegRev " << pegRev << pegRevKind << endl;
+ kdDebug(9036) << " StartRev" << startRev << startRevKind << endl;
+ kdDebug(9036) << " EndRev" << endRev << endRevKind << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ const char* path_or_url = apr_pstrdup( subpool, url.pathOrURL().utf8() );;
+
+ svn_opt_revision_t rev1 = createRevision( startRev, startRevKind, subpool );
+ svn_opt_revision_t rev2 = createRevision( endRev, endRevKind, subpool );
+// svn_opt_revision_t revPeg = createRevision( pegRev, pegRevKind, subpool );
+
+ //initNotifier(false, false, false, subpool);
+ svn_client_blame_receiver_t receiver = kio_svnProtocol::blameReceiver;
+ svn_error_t *err = svn_client_blame( path_or_url, &rev1, &rev2, receiver, (void*)this, ctx, subpool );
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ finished();
+ svn_pool_destroy (subpool);
+
+}
+
+svn_error_t* kio_svnProtocol::blameReceiver( void *baton, apr_int64_t line_no, svn_revnum_t rev, const char *author, const char *date, const char *line, apr_pool_t *pool )
+{
+ kio_svnProtocol *p = (kio_svnProtocol*)baton;
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "LINE", QString::number(line_no) );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REV", QString::number(rev) );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "AUTHOR", author );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "DATE", date );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "CONTENT", QString::fromLocal8Bit(line) );
+
+ p->incCounter();
+ return SVN_NO_ERROR;
+}
+
+/**
+ KDevelop has no way to retrieve URL of working copy.
+ Thus retreiving URL from WC should be done here, using subversion native API.
+ Thus, svn_log should get another flag (bool repositHistory )specifying between file:/// or URL
+*/
+void kio_svnProtocol::svn_log( int revstart, const QString& revkindstart, int revend, const QString& revkindend,
+ bool discorverChangedPaths, bool strictNodeHistory,
+ const KURL::List& urls )
+{
+// kdDebug(9036) << " from revision " << revstart << " or " << revkindstart << " to " << " revision " << revend << " or " << revkindend << endl;
+ kdDebug(9036) << " __TIME__ " << __TIME__ << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ // TODO HEAD:1 was removed from SVN API 1.2, instead callers should specify HEAD:0
+ svn_opt_revision_t rev1 = createRevision( revstart, revkindstart, subpool );
+ svn_opt_revision_t rev2 = createRevision( revend, revkindend, subpool );
+
+ m_counter = 0;
+ apr_array_header_t *targets = apr_array_make(subpool, 1+urls.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = urls.begin(); it != urls.end() ; ++it ) {
+ KURL nurl = *it;
+ const char *path =
+ apr_pstrdup( subpool, svn_path_canonicalize( nurl.pathOrURL().utf8(), subpool ) );
+ kdDebug(9036) << path << endl;
+ *(( const char ** )apr_array_push(( apr_array_header_t* )targets)) = path;
+
+ setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "requrl", nurl.pathOrURL() );
+ incCounter();
+ }
+
+ svn_log_message_receiver_t receiver = kio_svnProtocol::receiveLogMessage;
+ svn_error_t *err = svn_client_log2(targets, &rev1, &rev2, 0, discorverChangedPaths, strictNodeHistory, receiver, this, ctx, subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+// save for one revision
+svn_error_t* kio_svnProtocol::receiveLogMessage(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision,
+ const char *author, const char *date, const char *message, apr_pool_t *pool )
+{
+ kio_svnProtocol *p = (kio_svnProtocol*)baton;
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number(revision) );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "author", author );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "date", date );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "logmsg", QString::fromLocal8Bit(message) );
+ if( changed_paths != NULL ){
+ QString pathlist;
+ void *onePath;
+ const char *pathkey;
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi)) {
+ apr_hash_this(hi, (const void**) &pathkey, NULL, &onePath);
+ svn_log_changed_path_t *cp = (svn_log_changed_path_t*)onePath;
+ kdDebug(9036) << "OnePath: " << cp->copyfrom_path << " and key: " << pathkey << endl;
+ pathlist += cp->action;
+ pathlist += " ";
+// pathlist += cp->copyfrom_path;
+ pathlist += pathkey;
+ pathlist += "\n";
+ }
+ kdDebug(9036) << "pathlist: " << pathlist <<endl;
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "pathlist", pathlist );
+ }
+ p->incCounter();
+ return SVN_NO_ERROR;
+}
+
+svn_opt_revision_t kio_svnProtocol::createRevision( int revision, const QString& revkind, apr_pool_t *pool ) {
+ svn_opt_revision_t result;//,endrev;
+ // TODO support svn_opt_revision_date
+ if ( revision != -1 ) {
+ result.value.number = revision;
+ result.kind = svn_opt_revision_number;
+ } else if ( revkind == "WORKING" ) {
+ result.kind = svn_opt_revision_working;
+ } else if ( revkind == "BASE" ) {
+ result.kind = svn_opt_revision_base;
+ } else if ( revkind == "HEAD" ) {
+ result.kind = svn_opt_revision_head;
+ } else if ( revkind == "COMMITTED" ) {
+ result.kind = svn_opt_revision_committed;
+ } else if ( revkind == "PREV" ) {
+ result.kind = svn_opt_revision_previous;
+ }
+// } else if ( !revkind.isNull() ) {
+// svn_opt_parse_revision(&result,&endrev,revkind.utf8(),pool);
+ else if ( revkind == "UNSPECIFIED" ){
+ result.kind = svn_opt_revision_unspecified;
+ }
+ else {
+ result.kind = svn_opt_revision_unspecified;
+ }
+ return result;
+}
+
+void kio_svnProtocol::svn_diff(const KURL & url1, const KURL& url2,int rev1, int rev2,const QString& revkind1,const QString& revkind2,bool recurse, bool pegdiff )
+{
+ kdDebug(9036) << "kio_svn::diff : " << url1.path() << " at revision " << rev1 << " or " << revkind1 << " with "
+ << url2.path() << " at revision " << rev2 << " or " << revkind2
+ << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", TRUE, subpool );
+
+// KURL nurl1 = url1;
+// KURL nurl2 = url2;
+// nurl1.setProtocol( chooseProtocol( url1.protocol() ) ); //svn+https -> https for eg
+// nurl2.setProtocol( chooseProtocol( url2.protocol() ) );
+// recordCurrentURL( nurl1 );
+// QString source = makeSvnURL( nurl1 );
+// QString target = makeSvnURL( nurl2 );
+
+// const char *path1 = svn_path_canonicalize( apr_pstrdup( subpool, source.utf8() ), subpool );
+// const char *path2 = svn_path_canonicalize( apr_pstrdup( subpool, target.utf8() ), subpool );
+
+ //remove file:/// so we can diff for working copies, needs a better check (so we support URL for file:/// _repositories_ )
+// if ( nurl1.protocol() == "file" ) {
+// path1 = svn_path_canonicalize( apr_pstrdup( subpool, nurl1.path().utf8() ), subpool );
+// }
+// if ( nurl2.protocol() == "file" ) {
+// path2 = svn_path_canonicalize( apr_pstrdup( subpool, nurl2.path().utf8() ), subpool );
+// }
+
+ // all the commentted codes above are redundancy. url1/url2 is only file:// , svn:// or https://
+ // svn+https etc. are not handed out here.
+ const char *path1 = apr_pstrdup( subpool, url1.pathOrURL().utf8() );
+ const char *path2 = apr_pstrdup( subpool, url2.pathOrURL().utf8() );;
+
+ kdDebug( 9036 ) << "1 : " << path1 << " 2: " << path2 << endl;
+
+ svn_opt_revision_t revision1,revision2;
+ revision1 = createRevision(rev1, revkind1, subpool);
+ revision2 = createRevision(rev2, revkind2, subpool);
+
+ char *templ;
+ templ = apr_pstrdup ( subpool, "/tmp/tmpfile_XXXXXX" );
+ apr_file_t *outfile = NULL;
+ apr_file_mktemp( &outfile, templ , APR_READ|APR_WRITE|APR_CREATE|APR_TRUNCATE, subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = 0;
+ if( pegdiff ){
+ svn_opt_revision_t peg_rev = createRevision(-1, "BASE", subpool );
+ err = svn_client_diff_peg( options, path1, &peg_rev, &revision1, &revision2,
+ recurse, false, false, outfile, NULL, ctx, subpool );
+ } else{
+ err = svn_client_diff( options, path1, &revision1, path2, &revision2, recurse,
+ false, false, outfile, NULL, ctx, subpool );
+ }
+
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+ //read the content of the outfile now
+ QStringList tmp;
+ apr_file_close(outfile);
+ QFile file(templ);
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine();
+ tmp << line;
+ }
+ file.close();
+ }
+ for ( QStringList::Iterator itt = tmp.begin(); itt != tmp.end(); itt++ ) {
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "diffresult", ( *itt ) );
+ m_counter++;
+ }
+ //delete temp file
+ file.remove();
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::svn_switch( const KURL& wc, const KURL& repos, int revnumber, const QString& revkind, bool recurse) {
+ kdDebug(9036) << "kio_svn::switch : " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ KURL nurl = repos;
+ KURL dest = wc;
+ nurl.setProtocol( chooseProtocol( repos.protocol() ) );
+ dest.setProtocol( "file" );
+// recordCurrentURL( nurl );
+// QString source = dest.path();
+// QString target = makeSvnURL( repos );
+
+ const char *path = svn_path_canonicalize( apr_pstrdup( subpool, dest.path().utf8() ), subpool );
+ const char *url = svn_path_canonicalize( apr_pstrdup( subpool, nurl.url().utf8() ), subpool );
+ kdDebug(9036) << " WC path: " << path << " Repository URL: " << url << endl;
+
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_switch (NULL/*result revision*/, path, url, &rev, recurse, ctx, subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::svn_switch_relocate( const KURL &wc, const KURL &origUrl, const KURL &newUrl,
+ bool recurse )
+{
+ apr_pool_t *subpool = svn_pool_create( pool );
+
+ const char *wcPath = svn_path_canonicalize( apr_pstrdup( subpool, wc.path().utf8() ), subpool );
+ const char *fromUrl = apr_pstrdup( subpool, origUrl.url().utf8() );
+ const char *toUrl = apr_pstrdup( subpool, newUrl.url().utf8() );
+ kdDebug(9036) << " WC path: " << wcPath << " from: " << fromUrl << " to: " << toUrl << endl;
+
+ svn_error_t *err = svn_client_relocate( wcPath, fromUrl, toUrl, recurse, ctx, pool );
+
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+ m_counter = 0L;
+ setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string",
+ QString("switched to %1").arg( toUrl ) );
+ finished();
+ svn_pool_destroy( subpool );
+}
+
+void kio_svnProtocol::update( const KURL::List &list, int revnumber, const QString& revkind ) {
+ kdDebug(9036) << "kio_svn::update : __TIME__" << __TIME__ << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1+list.count(), sizeof(const char *));
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ for( QValueList<KURL>::ConstIterator it = list.begin(); it != list.end(); ++it ){
+ KURL nurl = *it;
+ *( const char ** )apr_array_push(targets) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_update2( NULL, targets, &rev,
+ true/*recurse*/, false/*ignore_external*/,
+ ctx, subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::import( const KURL& repos, const KURL& wc ) {
+ kdDebug(9036) << "kio_svnProtocol::import() : " << wc.url() << " into " << repos.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+// svn_client_commit_info_t *commit_info =
+// (svn_client_commit_info_t*) apr_palloc( subpool, sizeof(svn_client_commit_info_t) );
+ svn_commit_info_t *commit_info = svn_create_commit_info( subpool );
+ bool nonrecursive = false;
+
+ const char *path = apr_pstrdup( subpool, svn_path_canonicalize( wc.path().utf8(), subpool ) );
+ const char *url = apr_pstrdup( subpool, svn_path_canonicalize( repos.url().utf8(), subpool ) );
+
+ initNotifier(false, false, false, subpool);
+ kdDebug(9036) << " Executing import: " << path << " to " << url << endl;
+
+ svn_error_t *err = svn_client_import2(&commit_info, path, url, nonrecursive, false, ctx, subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ svn_pool_destroy (subpool);
+ finished();
+}
+
+void kio_svnProtocol::checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind ) {
+ kdDebug(9036) << "kio_svn::checkout : " << repos.url() << " into " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ KURL nurl = repos;
+ KURL dest = wc;
+ nurl.setProtocol( chooseProtocol( repos.protocol() ) );
+ dest.setProtocol( "file" );
+ QString target = makeSvnURL( repos );
+ recordCurrentURL( nurl );
+ QString dpath = dest.path();
+
+ //find the requested revision
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(true, false, false, subpool);
+ svn_error_t *err = svn_client_checkout (NULL/* rev actually checkedout */, svn_path_canonicalize( target.utf8(), subpool ), svn_path_canonicalize ( dpath.utf8(), subpool ), &rev, true, ctx, subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::commit(const KURL::List& wc)
+{
+ commit2(true, true, wc);
+}
+
+void kio_svnProtocol::commit2(bool recurse, bool keeplocks, const KURL::List& wc) {
+ kdDebug(9036) << "kio_svnProtocol::commit2() : " << wc << endl;
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ kdDebug(9036) << "recurse: " << recurse << " keeplocks: " << keeplocks <<endl;
+ svn_error_t *err = svn_client_commit2(&commit_info,targets,recurse,keeplocks,ctx,subpool);
+
+ if ( err ){
+ char errbuf[512];
+ svn_strerror(err->apr_err, errbuf, 512);
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) + "\n: " + QString::fromLocal8Bit(errbuf) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ if ( commit_info ) {
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+
+ QString userstring = i18n ( "Nothing to commit." );
+ if ( SVN_IS_VALID_REVNUM( commit_info->revision ) )
+ userstring = i18n( "Committed revision %1." ).arg(commit_info->revision);
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "path", nurl.path() );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "action", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "kind", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "mime_t", "" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "content", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "prop", "0" );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "rev" , QString::number( commit_info->revision ) );
+ setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "string", userstring );
+ m_counter++;
+ }
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::add(const KURL::List& list) {
+ kdDebug(9036) << "kio_svnProtocol::add() __TIME__" << __TIME__ << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ bool nonrecursive = false;
+ initNotifier(false, false, false, subpool);
+
+ svn_error_t *err = NULL;
+ for( QValueList<KURL>::ConstIterator it = list.begin(); it != list.end(); ++it ){
+
+ KURL nurl = (*it);
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ kdDebug(9036) << " Schedule to Add: " << nurl.path().utf8() << endl;
+ err = svn_client_add( svn_path_canonicalize( nurl.path().utf8(), subpool ),
+ nonrecursive, ctx, subpool);
+ if( err ) break;
+ }
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_delete(const KURL::List& wc) {
+ kdDebug(9036) << "kio_svnProtocol::wc_delete() : " << wc << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_client_commit_info_t *commit_info = NULL;
+ bool force = false;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_delete(&commit_info,targets,force,ctx,subpool);
+
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_revert(const KURL::List& wc) {
+ kdDebug(9036) << "kio_svnProtocol::revert() : " << wc << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ bool nonrecursive = false;
+
+ apr_array_header_t *targets = apr_array_make(subpool, 1 + wc.count(), sizeof(const char *));
+
+ for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) {
+ KURL nurl = *it;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+ (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool );
+ }
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_revert(targets,nonrecursive,ctx,subpool);
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::wc_status(const KURL& wc, bool checkRepos, bool fullRecurse, bool getAll, int revnumber, const QString& revkind) {
+ kdDebug(9036) << "kio_svnProtocol::wc_status() : " << wc.url() << " checkRepos " << checkRepos << " fullRecurse " << fullRecurse << " getAll " << getAll << endl;
+
+ wc_status2( wc, checkRepos, fullRecurse, getAll, false, revnumber, revkind );
+}
+
+void kio_svnProtocol::wc_status2(const KURL& wc, bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore, int revnumber, const QString& revkind) {
+ kdDebug(9036) << "kio_svnProtocol::wc_status2() : " << wc.url() << " checkRepos " << checkRepos << " fullRecurse " << fullRecurse << " getAll " << getAll << " noIgnore " << noIgnore << " revnumber " << revnumber << " revkind " << revkind << endl;
+ kdDebug(9036) << " __TIME__ " << __TIME__ << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_revnum_t result_rev;
+
+ KURL nurl = wc;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+
+ svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool );
+
+ initNotifier(false, false, false, subpool);
+
+ svn_error_t *err = svn_client_status(&result_rev, svn_path_canonicalize( nurl.path().utf8(), subpool ), &rev, kio_svnProtocol::status, this, fullRecurse, getAll, checkRepos, noIgnore, ctx, subpool);
+
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::svn_info( KURL pathOrUrl, int pegRev, QString pegRevKind, int rev, QString revKind, bool recurse )
+{
+ kdDebug(9036) << " kio_svnProtocol::svn_info(): pegRev " << pegRev << " pegKind " << pegRevKind << " rev " << rev << " revKind " << revKind << " recurse " << recurse << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_opt_revision_t peg_rev = createRevision( pegRev, pegRevKind, subpool );
+ svn_opt_revision_t revision = createRevision( rev, revKind, subpool );
+
+ svn_error_t *err = svn_client_info( pathOrUrl.pathOrURL().utf8(),
+ &peg_rev, &revision,
+ kio_svnProtocol::infoReceiver,
+ this,
+ recurse,
+ ctx, pool );
+
+ if ( err ){
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+ svn_pool_destroy( subpool );
+ finished();
+}
+
+svn_error_t* kio_svnProtocol::infoReceiver( void *baton, const char *path,
+ const svn_info_t *info, apr_pool_t *pool)
+{
+ kio_svnProtocol *p= (kio_svnProtocol*)baton ;
+ if( !p )
+ return SVN_NO_ERROR;
+
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "PATH", QString::fromUtf8( path ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "URL", QString( info->URL ) );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REV", QString::number( info->rev ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "KIND", QString::number( info->kind ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REPOS_ROOT_URL", QString( info->repos_root_URL ) );
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REPOS_UUID", QString(info->repos_UUID) );
+ p->incCounter();
+
+ return SVN_NO_ERROR;
+}
+
+void kio_svnProtocol::svn_copy( const KURL &srcUrl, int srcRev, const QString &srcRevKind,
+ const KURL &destUrl )
+{
+ kdDebug(9036) << " kio: svn_copy src: " << srcUrl << " Dest Url: " << destUrl << " revnum: " << srcRev << " revKind: " << srcRevKind << endl;
+ apr_pool_t *subpool = svn_pool_create (pool);
+ svn_commit_info_t *commit_info = svn_create_commit_info( subpool );
+
+ svn_opt_revision_t rev = createRevision( srcRev, srcRevKind, subpool );
+
+ // TODO more elegant notification mechanism
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_copy2( &commit_info,
+ srcUrl.pathOrURL().utf8(), &rev,
+ destUrl.pathOrURL().utf8(),
+ ctx, subpool);
+
+ if ( err ) {
+ apr_status_t errcode = err->apr_err;
+ char buf[512];
+ svn_strerror(errcode, buf, 512);
+ error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(buf) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ if( commit_info ){
+ setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string",
+ i18n("Copied Revision %1").arg( commit_info->revision) );
+ } else {
+ setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string",
+ i18n("Copied") );
+ }
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+void kio_svnProtocol::svn_merge(const KURL &src1, int revNum1, QString revKind1,
+ const KURL &src2, int revNum2, QString revKind2,
+ const KURL &target_wc,
+ bool recurse, bool ignore_ancestry, bool force, bool dry_run )
+{
+ kdDebug(9036) << " KIO::svn_merge src1 " << src1.pathOrURL().utf8() << " src2 " << src2.pathOrURL().utf8() << " target " << target_wc.pathOrURL().utf8() << endl;
+ apr_pool_t *subpool = svn_pool_create( pool );
+
+ svn_opt_revision_t rev1 = createRevision( revNum1, revKind1, subpool );
+ svn_opt_revision_t rev2 = createRevision( revNum2, revKind2, subpool );
+
+ initNotifier( false, false, false, subpool );
+ svn_error_t *err = svn_client_merge( src1.pathOrURL().utf8(), &rev1,
+ src2.pathOrURL().utf8(), &rev2,
+ target_wc.pathOrURL().utf8(),
+ recurse, ignore_ancestry, force, dry_run,
+ ctx, pool );
+ if ( err ) {
+ apr_status_t errcode = err->apr_err;
+ char buf[512];
+ svn_strerror(errcode, buf, 512);
+ error( KIO::ERR_SLAVE_DEFINED,
+ QString::fromLocal8Bit(err->message) + "\n "+ QString::fromLocal8Bit(buf) );
+ svn_pool_destroy (subpool);
+ return;
+ }
+
+ finished();
+ svn_pool_destroy( subpool );
+}
+
+//change the proto and remove trailing /
+//remove double / also
+QString kio_svnProtocol::makeSvnURL ( const KURL& url ) const {
+ QString kproto = url.protocol();
+ KURL tpURL = url;
+ tpURL.cleanPath( true );
+ QString svnUrl;
+ if ( kproto == "kdevsvn+http" ) {
+ kdDebug(9036) << "http:/ " << url.url() << endl;
+ tpURL.setProtocol("http");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "kdevsvn+https" ) {
+ kdDebug(9036) << "https:/ " << url.url() << endl;
+ tpURL.setProtocol("https");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "kdevsvn+ssh" ) {
+ kdDebug(9036) << "svn+ssh:/ " << url.url() << endl;
+ tpURL.setProtocol("svn+ssh");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "kdevsvn+svn" ) {
+ kdDebug(9036) << "svn:/ " << url.url() << endl;
+ tpURL.setProtocol("svn");
+ svnUrl = tpURL.url(-1);
+ return svnUrl;
+ }
+ else if ( kproto == "kdevsvn+file" ) {
+ kdDebug(9036) << "file:/ " << url.url() << endl;
+ tpURL.setProtocol("file");
+ svnUrl = tpURL.url(-1);
+ //hack : add one more / after file:/
+ int idx = svnUrl.find("/");
+ svnUrl.insert( idx, "//" );
+ return svnUrl;
+ }
+ return tpURL.url(-1);
+}
+
+QString kio_svnProtocol::chooseProtocol ( const QString& kproto ) const {
+ if ( kproto == "svn+http" ) return QString( "http" );
+ else if ( kproto == "svn+https" ) return QString( "https" );
+ else if ( kproto == "svn+ssh" ) return QString( "svn+ssh" );
+ else if ( kproto == "svn" ) return QString( "svn" );
+ else if ( kproto == "svn+file" ) return QString( "file" );
+ return kproto;
+}
+/** Certificate is not yet valid. */
+#define SVN_AUTH_SSL_NOTYETVALID 0x00000001
+/** Certificate has expired. */
+#define SVN_AUTH_SSL_EXPIRED 0x00000002
+/** Certificate's CN (hostname) does not match the remote hostname. */
+#define SVN_AUTH_SSL_CNMISMATCH 0x00000004
+/** @brief Certificate authority is unknown (i.e. not trusted) */
+#define SVN_AUTH_SSL_UNKNOWNCA 0x00000008
+/** @brief Other failure. This can happen if neon has introduced a new
+ * failure bit that we do not handle yet. */
+#define SVN_AUTH_SSL_OTHER 0x40000000
+svn_error_t *kio_svnProtocol::trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *baton, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *ci, svn_boolean_t may_save, apr_pool_t *pool)
+{
+ kio_svnProtocol *p = (kio_svnProtocol*)baton;
+ // prepare params.
+ QByteArray params, replyData;
+ QCString replyType;
+ QDataStream arg(params, IO_WriteOnly);
+
+ arg << i18n( "The certificate from the server could not be trusted automatically. Do you want to trust this certificate? " );
+ arg << QString::fromLocal8Bit(ci->hostname);
+ arg << QString::fromLocal8Bit(ci->fingerprint);
+ arg << QString::fromLocal8Bit(ci->valid_from) << QString::fromLocal8Bit(ci->valid_until);
+ arg << QString::fromLocal8Bit(ci->issuer_dname) << QString::fromLocal8Bit(ci->ascii_cert) ;
+ // call dcop
+ int ret = p->dcopClient()->call( "kded", "kdevsvnd",
+ "sslServerTrustPrompt(QString, QString, QString, QString, QString, QString, QString)",
+ params, replyType, replyData );
+ if (!ret){
+ kdWarning() << " failed to prompt SSL_Server_Trust_Prompt " << endl;
+ return SVN_NO_ERROR;
+ }
+ if (replyType != "int"){
+ kdWarning() << " abnormal reply type " << endl;
+ return SVN_NO_ERROR;
+ }
+ int resultCode;
+ QDataStream replyStream( replyData, IO_ReadOnly );
+ replyStream >> resultCode;
+
+ if( resultCode == -1 ){
+ kdWarning() << " SSL server trust rejected " << endl;
+ *cred_p = 0L; //FIXME when rejected, maybe more elegant methods..
+ } else if( resultCode == 0 ){ //accept once
+ *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (svn_auth_cred_ssl_server_trust_t));
+ kdDebug(9036) << " accept once " << endl;
+ (*cred_p)->may_save = false;
+ (*cred_p)->accepted_failures = 0;
+ } else if( resultCode == 1 ){ //accept permanently
+ *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (svn_auth_cred_ssl_server_trust_t));
+ kdDebug(9036) << " accept permanently " << endl;
+ (*cred_p)->may_save = true;
+ (*cred_p)->accepted_failures = failures;
+ } else{
+ kdWarning() << " SSL server trust failed for some reason" << endl;
+ *cred_p = 0L;
+ }
+
+ return SVN_NO_ERROR;
+}
+/** TODO fully implemented, but there is no way to test this yet.*/
+svn_error_t *kio_svnProtocol::clientCertSSLPrompt(
+ svn_auth_cred_ssl_client_cert_t **cred_p, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
+{
+ kdDebug(9036) << " clientCertSSLPrompt " << endl;
+// kio_svnProtocol *p = (kio_svnProtocol*)baton;
+// QByteArray reply;
+// QByteArray params;
+// QCString replyType;
+// call dcop
+// if (!p->dcopClient()->call("kded","kdevsvnd", "sslCertFile()",params,replyType,reply)) {
+// kdWarning()<<" Communication with dcop failed - fail to get certfile "<<endl;
+// return SVN_NO_ERROR;
+// }
+// if (replyType != "QString") {
+// kdWarning()<<" unexpected reply type "<<endl;
+// return SVN_NO_ERROR;
+// }
+// save reply data
+// QString fileName;
+// QDataStream replyStream( reply, IO_ReadOnly );
+// replyStream >> fileName;
+// allocate memory
+// *cred_p = (svn_auth_cred_ssl_client_cert_t*) apr_palloc (pool, sizeof(svn_auth_cred_ssl_client_cert_t));
+// (*cred_p)->cert_file = apr_pstrdup( pool, fileName.utf8() );
+// (*cred_p)->may_save = may_save;
+ return SVN_NO_ERROR;
+}
+
+/** TODO fully implemented, but there is no way to test this yet.*/
+svn_error_t *kio_svnProtocol::clientCertPasswdPrompt(
+ svn_auth_cred_ssl_client_cert_pw_t **cred_p, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
+{
+ kdDebug(9036) << " Password Prompt Callback " << endl;
+ kdDebug(9036) << " realm " << realm << " <--realm " << endl;
+// kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+// // prepare dcop
+// QByteArray reply;
+// QByteArray params;
+// QCString replyType;
+// QDataStream arg( params, IO_WriteOnly );
+// arg << i18n( "Enter password for subversion repository access" ) + "\n" + QString(realm);
+// // call dcop
+// if (!p->dcopClient()->call("kded","kdevsvnd", "sslPasswdDlg(QString)",params,replyType,reply)) {
+// kdWarning()<<" Communication with dcop failed - fail to show passwd dlg"<<endl;
+// return SVN_NO_ERROR;
+// }
+// if (replyType != "QCString") {
+// kdWarning()<<" unexpected reply type "<<endl;
+// return SVN_NO_ERROR;
+// }
+// // save reply data
+// QCString retstr, passwd;
+// QDataStream replyStream( reply, IO_ReadOnly );
+// replyStream >> retstr;
+//
+// if( retstr.left(1) == "-1" ){
+// kdDebug(9036) << " Null string received for passwd " << endl;
+// } else{
+// passwd = retstr.right( retstr.length() - 1 );
+// kdDebug(9036) << " PassWD : " << passwd << endl;
+// }
+//
+// svn_auth_cred_ssl_client_cert_pw_t *newcred = (svn_auth_cred_ssl_client_cert_pw_t*) apr_palloc (pool, sizeof (svn_auth_cred_ssl_client_cert_pw_t ) );
+//
+// newcred->password = apr_pstrdup(pool, (const char*) passwd );
+// newcred->may_save = false;
+// *cred_p = newcred;
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *kio_svnProtocol::commitLogPrompt( const char **log_msg, const char **file,
+ apr_array_header_t *commit_items, void *baton, apr_pool_t *pool )
+{
+ *file = NULL; // if omitting this, it will segfault at import operation.
+ QCString replyType;
+ QByteArray params;
+ QByteArray reply;
+ QString result;// slist;
+ QStringList slist;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+ svn_stringbuf_t *message = NULL;
+
+ for (int i = 0; i < commit_items->nelts; i++) {
+ QString list;
+ svn_client_commit_item_t *item = ((svn_client_commit_item_t **) commit_items->elts)[i];
+ const char *path = item->path;
+ char text_mod = '_', prop_mod = ' ';
+
+ if (! path)
+ path = item->url;
+ else if (! *path)
+ path = ".";
+
+ if (! path)
+ path = ".";
+
+ if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
+ text_mod = 'R';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
+ text_mod = 'A';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
+ text_mod = 'D';
+ else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
+ text_mod = 'M';
+ if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
+ prop_mod = 'M';
+
+ list += text_mod;
+ list += " ";
+ list += prop_mod;
+ list += " ";
+ list += path;
+ kdDebug(9036) << " Commiting items : " << list << endl;
+ slist << list;
+// slist += list;
+ }
+
+ QDataStream stream(params, IO_WriteOnly);
+ stream << slist.join("\n");
+
+ kdDebug(9036) << " __TIME__ " << __TIME__ << endl;
+ if ( !p->dcopClient()->call( "kded","kdevsvnd","commitDialog(QString)", params, replyType, reply ) ) {
+ kdWarning() << "Communication with KDED:KDevSvnd failed" << endl;
+ svn_error_t *err = svn_error_create( SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ apr_pstrdup( pool, "Fail to call kded_kdevsvnd via DCOP. If this is your first problem, try to restart KDE" ) );
+ return err;
+ }
+
+ if ( replyType != "QString" ) {
+ kdWarning() << "Unexpected reply type" << endl;
+ svn_error_t *err = svn_error_create( SVN_ERR_EXTERNAL_PROGRAM, NULL,
+ apr_pstrdup( pool, "Fail to call kded_kdevsvnd via DCOP." ) );
+ return err;
+ }
+
+ QDataStream stream2 ( reply, IO_ReadOnly );
+ stream2 >> result;
+
+ if ( result.isNull() ) { //cancelled
+ *log_msg = NULL;
+ svn_error_t *err = svn_error_create( SVN_ERR_CANCELLED, NULL,
+ apr_pstrdup( pool, "Commit interruppted" ) );
+ return err;
+ }
+
+ message = svn_stringbuf_create( result.utf8(), pool );
+ *log_msg = message->data;
+
+ return SVN_NO_ERROR;
+}
+
+void kio_svnProtocol::notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision) {
+ kdDebug(9036) << "NOTIFY : " << path << " updated at revision " << revision << " action : " << action << ", kind : " << kind << " , content_state : " << content_state << ", prop_state : " << prop_state << endl;
+
+ QString userstring;
+ struct notify_baton *nb = ( struct notify_baton* ) baton;
+
+ //// Convert notification to a user readable string
+ switch ( action ) {
+ case svn_wc_notify_add : //add
+ if (mime_type && (svn_mime_type_is_binary (mime_type)))
+ userstring = i18n( "A (bin) %1" ).arg( path );
+ else
+ userstring = i18n( "A %1" ).arg( path );
+ break;
+ case svn_wc_notify_copy: //copy
+ userstring = i18n( "Copied %1 " ).arg( path );
+ break;
+ case svn_wc_notify_delete: //delete
+ nb->received_some_change = TRUE;
+ userstring = i18n( "D %1" ).arg( path );
+ break;
+ case svn_wc_notify_restore : //restore
+ userstring=i18n( "Restored %1." ).arg( path );
+ break;
+ case svn_wc_notify_revert : //revert
+ userstring=i18n( "Reverted %1." ).arg( path );
+ break;
+ case svn_wc_notify_failed_revert: //failed revert
+ userstring=i18n( "Failed to revert %1.\nTry updating instead." ).arg( path );
+ break;
+ case svn_wc_notify_resolved: //resolved
+ userstring=i18n( "Resolved conflicted state of %1." ).arg( path );
+ break;
+ case svn_wc_notify_skip: //skip
+ if ( content_state == svn_wc_notify_state_missing )
+ userstring=i18n("Skipped missing target %1.").arg( path );
+ else
+ userstring=i18n("Skipped %1.").arg( path );
+ break;
+ case svn_wc_notify_update_delete: //update_delete
+ nb->received_some_change = TRUE;
+ userstring=i18n( "D %1" ).arg( path );
+ break;
+ case svn_wc_notify_update_add: //update_add
+ nb->received_some_change = TRUE;
+ userstring=i18n( "A %1" ).arg( path );
+ break;
+ case svn_wc_notify_update_update: //update_update
+ {
+ /* If this is an inoperative dir change, do no notification.
+ An inoperative dir change is when a directory gets closed
+ without any props having been changed. */
+ if (! ((kind == svn_node_dir)
+ && ((prop_state == svn_wc_notify_state_inapplicable)
+ || (prop_state == svn_wc_notify_state_unknown)
+ || (prop_state == svn_wc_notify_state_unchanged)))) {
+ nb->received_some_change = TRUE;
+
+ if (kind == svn_node_file) {
+ if (content_state == svn_wc_notify_state_conflicted)
+ userstring = "C";
+ else if (content_state == svn_wc_notify_state_merged)
+ userstring = "G";
+ else if (content_state == svn_wc_notify_state_changed)
+ userstring = "U";
+ }
+
+ if (prop_state == svn_wc_notify_state_conflicted)
+ userstring += "C";
+ else if (prop_state == svn_wc_notify_state_merged)
+ userstring += "G";
+ else if (prop_state == svn_wc_notify_state_changed)
+ userstring += "U";
+ else
+ userstring += " ";
+
+ if (! ((content_state == svn_wc_notify_state_unchanged
+ || content_state == svn_wc_notify_state_unknown)
+ && (prop_state == svn_wc_notify_state_unchanged
+ || prop_state == svn_wc_notify_state_unknown)))
+ userstring += QString( " " ) + path;
+ }
+ break;
+ }
+ case svn_wc_notify_update_completed: //update_completed
+ {
+ if (! nb->suppress_final_line) {
+ if (SVN_IS_VALID_REVNUM (revision)) {
+ if (nb->is_export) {
+ if ( nb->in_external )
+ userstring = i18n("Exported external at revision %1.").arg( revision );
+ else
+ userstring = i18n("Exported revision %1.").arg( revision );
+ } else if (nb->is_checkout) {
+ if ( nb->in_external )
+ userstring = i18n("Checked out external at revision %1.").arg( revision );
+ else
+ userstring = i18n("Checked out revision %1.").arg( revision);
+ } else {
+ if (nb->received_some_change) {
+ if ( nb->in_external )
+ userstring=i18n("Updated external to revision %1.").arg( revision );
+ else
+ userstring = i18n("Updated to revision %1.").arg( revision);
+ } else {
+ if ( nb->in_external )
+ userstring = i18n("External at revision %1.").arg( revision );
+ else
+ userstring = i18n("At revision %1.").arg( revision);
+ }
+ }
+ } else /* no revision */ {
+ if (nb->is_export) {
+ if ( nb->in_external )
+ userstring = i18n("External export complete.");
+ else
+ userstring = i18n("Export complete.");
+ } else if (nb->is_checkout) {
+ if ( nb->in_external )
+ userstring = i18n("External checkout complete.");
+ else
+ userstring = i18n("Checkout complete.");
+ } else {
+ if ( nb->in_external )
+ userstring = i18n("External update complete.");
+ else
+ userstring = i18n("Update complete.");
+ }
+ }
+ }
+ }
+ if (nb->in_external)
+ nb->in_external = FALSE;
+ break;
+ case svn_wc_notify_update_external: //update_external
+ nb->in_external = TRUE;
+ userstring = i18n("Fetching external item into %1." ).arg( path );
+ break;
+ case svn_wc_notify_status_completed: //status_completed
+ if (SVN_IS_VALID_REVNUM (revision))
+ userstring = i18n( "Status against revision: %1.").arg( revision );
+ break;
+ case svn_wc_notify_status_external: //status_external
+ userstring = i18n("Performing status on external item at %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_modified: //commit_modified
+ userstring = i18n( "Sending %1").arg( path );
+ break;
+ case svn_wc_notify_commit_added: //commit_added
+ if (mime_type && svn_mime_type_is_binary (mime_type)) {
+ userstring = i18n( "Adding (bin) %1.").arg( path );
+ } else {
+ userstring = i18n( "Adding %1.").arg( path );
+ }
+ break;
+ case svn_wc_notify_commit_deleted: //commit_deleted
+ userstring = i18n( "Deleting %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_replaced: //commit_replaced
+ userstring = i18n( "Replacing %1.").arg( path );
+ break;
+ case svn_wc_notify_commit_postfix_txdelta: //commit_postfix_txdelta
+ if (! nb->sent_first_txdelta) {
+ nb->sent_first_txdelta = TRUE;
+ userstring=i18n("Transmitting file data ");
+ } else {
+ userstring=".";
+ }
+ break;
+
+ break;
+ case svn_wc_notify_blame_revision: //blame_revision
+ userstring = i18n("Blame %1.").arg(path);
+ break;
+ default:
+ break;
+ }
+ //// End convert
+ kio_svnProtocol *p = ( kio_svnProtocol* )nb->master;
+ if (!p) kdDebug(9036) << " Null Pointer at Line " << __LINE__ << endl;
+
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path" , QString::fromUtf8( path ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "action", QString::number( action ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "kind", QString::number( kind ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "mime_t", QString::fromUtf8( mime_type ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "content", QString::number( content_state ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( prop_state ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( revision ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "string", userstring );
+ kdDebug(9036) << " kio_svnProtocol::notify() userstring " << userstring << endl;
+ p->incCounter();
+}
+
+void kio_svnProtocol::status(void *baton, const char *path, svn_wc_status_t *status) {
+ kdDebug(9036) << "STATUS : " << path << ", wc text status : " << status->text_status
+ << ", wc prop status : " << status->prop_status
+ << ", repos text status : " << status->repos_text_status
+ << ", repos prop status : " << status->repos_prop_status
+ << endl;
+
+ QByteArray params;
+ kio_svnProtocol *p = ( kio_svnProtocol* )baton;
+
+ QDataStream stream(params, IO_WriteOnly);
+ long int rev = status->entry ? status->entry->revision : 0;
+ stream << QString::fromUtf8( path ) << status->text_status << status->prop_status << status->repos_text_status << status->repos_prop_status << rev;
+
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path", QString::fromUtf8( path ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "text", QString::number( status->text_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( status->prop_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "reptxt", QString::number( status->repos_text_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "repprop", QString::number( status->repos_prop_status ));
+ p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( rev ));
+ p->incCounter();
+}
+
+void kio_svnProtocol::progressCallback( apr_off_t processed, apr_off_t total, void *baton, apr_pool_t *pool)
+{
+ kio_svnProtocol *p = (kio_svnProtocol*)baton;
+ if( total > -1 )
+ p->totalSize( total );
+ if( processed > -1 )
+ p->processedSize( processed );
+}
+
+void kio_svnProtocol::wc_resolve( const KURL& wc, bool recurse ) {
+ kdDebug(9036) << "kio_svnProtocol::wc_resolve() : " << wc.url() << endl;
+
+ apr_pool_t *subpool = svn_pool_create (pool);
+
+ KURL nurl = wc;
+ nurl.setProtocol( "file" );
+ recordCurrentURL( nurl );
+
+ initNotifier(false, false, false, subpool);
+ svn_error_t *err = svn_client_resolved(svn_path_canonicalize( nurl.path().utf8(), subpool ), recurse,ctx,subpool);
+ if ( err )
+ error( KIO::ERR_SLAVE_DEFINED, err->message );
+
+ finished();
+ svn_pool_destroy (subpool);
+}
+
+extern "C"
+{
+ KDE_EXPORT int kdemain(int argc, char **argv) {
+ KInstance instance( "kio_kdevsvn" );
+
+ kdDebug(9036) << "*** Starting kio_kdevsvn " << endl;
+
+ if (argc != 4) {
+ kdDebug(9036) << "Usage: kio_kdevsvn protocol domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+
+ kio_svnProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug(9036) << "*** kio_kdevsvn Done" << endl;
+ return 0;
+ }
+}
+
diff --git a/vcs/subversion/svn_kio.h b/vcs/subversion/svn_kio.h
new file mode 100644
index 00000000..6164488a
--- /dev/null
+++ b/vcs/subversion/svn_kio.h
@@ -0,0 +1,163 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Mickael Marchand <marchand@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _svn_H_
+#define _svn_H_
+
+#include <qstring.h>
+#include <qcstring.h>
+
+#include <kurl.h>
+#include <kio/global.h>
+#include <kio/slavebase.h>
+#include <subversion-1/svn_pools.h>
+#include <subversion-1/svn_auth.h>
+#include <subversion-1/svn_client.h>
+#include <subversion-1/svn_config.h>
+#include <sys/stat.h>
+#include <qvaluelist.h>
+#include <subversion-1/svn_wc.h>
+#include "subversion_global.h"
+
+class QCString;
+class kio_svnProtocol;
+
+typedef struct kbaton {
+ svn_stream_t *target_stream;
+ svn_stringbuf_t *target_string;
+ svn_stream_t *string_stream;
+} kbaton;
+
+typedef struct kio_svn_callback_baton_t {
+ const char* base_dir;
+ apr_hash_t *config;
+ apr_pool_t *pool;
+} kio_svn_callback_baton_t;
+
+typedef struct notify_baton {
+ svn_boolean_t received_some_change;
+ svn_boolean_t is_checkout;
+ svn_boolean_t is_export;
+ svn_boolean_t suppress_final_line;
+ svn_boolean_t sent_first_txdelta;
+ svn_boolean_t in_external;
+ svn_boolean_t had_print_error; /* Used to not keep printing error messages
+ when we've already had one print error. */
+ apr_pool_t *pool; /* this pool is cleared after every notification,
+ so don't keep anything here! */
+ kio_svnProtocol *master;
+} notify_baton;
+
+
+class kio_svnProtocol : public KIO::SlaveBase
+{
+ public:
+ kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket);
+ virtual ~kio_svnProtocol();
+ virtual void special( const QByteArray& data );
+ virtual void get(const KURL& url);
+ virtual void listDir(const KURL& url);
+ virtual void stat(const KURL& url);
+ virtual void mkdir(const KURL& url, int permissions);
+ virtual void mkdir(const KURL::List& list, int permissions);
+ virtual void del( const KURL& url, bool isfile );
+// virtual void copy(const KURL & src, const KURL& dest, int permissions, bool overwrite);
+ virtual void rename(const KURL& src, const KURL& dest, bool overwrite);
+ void checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind );
+ void import( const KURL& repos, const KURL& wc );
+ void svn_switch( const KURL& wc, const KURL& url, int revnumber, const QString& revkind, bool recurse);
+ void svn_switch_relocate( const KURL &wc, const KURL &origUrl, const KURL &newUrl,
+ bool recurse );
+ void svn_diff( const KURL& url1, const KURL& url2, int rev1, int rev2, const QString& revkind1, const QString& revkind2, bool recurse, bool pegdiff);
+ //TODO fix with svn 1.2 : support a KURL::List -> svn_client_update2()
+ void update( const KURL::List &list, int revnumber, const QString& revkind );
+ void commit( const KURL::List& wc );
+ void commit2( bool recurse, bool keeplocks, const KURL::List& wc );
+ void blame( KURL url, SvnGlobal::UrlMode mode, /*int pegRev, QString pegRevKind,*/ int startRev, QString startRevKind, int endRev, QString endRevKind );
+ static svn_error_t* blameReceiver( void *baton, apr_int64_t line_no, svn_revnum_t rev, const char *author, const char *date, const char *line, apr_pool_t *pool );
+ void svn_log( int revstart, const QString &revkindstart, int revend, const QString &revkindend, bool discorverChangedPath, bool strictNodeHistory, const KURL::List& targets );
+ static svn_error_t* receiveLogMessage(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, const char *author, const char *date, const char *message, apr_pool_t *pool );
+ void add( const KURL::List& wcList );
+ //these work using the working copy
+ void wc_resolve( const KURL& wc, bool recurse = true );
+ void wc_delete( const KURL::List& wc );
+ void wc_revert( const KURL::List& wc );
+ void wc_status(const KURL& wc, bool checkRepos=false, bool fullRecurse=true, bool getAll=true, int revnumber=-1, const QString& revkind="HEAD");
+ void wc_status2(const KURL& wc, bool checkRepos=false, bool fullRecurse=true, bool getAll=true, bool noIgnore=false, int revnumber=-1, const QString& revkind="WORKING");
+ void svn_info( KURL pathOrUrl, int pegRev, QString pegRevKind, int rev, QString revKind, bool recurse );
+ static svn_error_t* infoReceiver( void *baton, const char *path, const svn_info_t *info, apr_pool_t *pool);
+ void svn_copy( const KURL &srcUrl, int srcRev, const QString &srcRevKind, const KURL &destUrl );
+ void svn_merge( const KURL &src1, int rev1, QString revKind1, const KURL &src2, int rev2, QString revKind2,
+ const KURL &target_wc,
+ bool recurse, bool ignore_ancestry, bool force, bool dry_run );
+
+ static svn_error_t* checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *, 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);
+ static svn_error_t *clientCertSSLPrompt(svn_auth_cred_ssl_client_cert_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *clientCertPasswdPrompt(svn_auth_cred_ssl_client_cert_pw_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool);
+ static svn_error_t *commitLogPrompt( const char **log_msg, const char **tmp_file, apr_array_header_t *commit_items, void *baton, apr_pool_t *pool );
+ static void notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision);
+ static void status(void *baton, const char *path, svn_wc_status_t *status);
+ static void progressCallback( apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool);
+
+ QString chooseProtocol ( const QString& kproto ) const;
+ QString makeSvnURL ( const KURL& url ) const;
+ void initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool);
+
+ void recordCurrentURL(const KURL& url);
+ void popupMessage( const QString& message );
+ int counter() { return m_counter; }
+ void incCounter() { m_counter++; }
+ svn_opt_revision_t createRevision( int revision, const QString& revkind, apr_pool_t *pool );
+
+ KURL myURL;
+ svn_client_ctx_t *ctx;
+ KIO::AuthInfo info;
+
+ enum SVN_METHOD {
+ SVN_CHECKOUT=1, //KURL repository, KURL workingcopy, int revnumber=-1, QString revkind(HEAD, ...) //revnumber==-1 => use of revkind
+ SVN_UPDATE=2, // KURL wc (svn:///tmp/test, int revnumber=-1, QString revkind(HEAD, ...) // revnumber==-1 => use of revkind
+ SVN_COMMIT=3,
+ SVN_LOG=4,
+ SVN_IMPORT=5,
+ SVN_ADD=6,
+ SVN_DEL=7,
+ SVN_REVERT=8,
+ SVN_STATUS=9,
+ SVN_MKDIR=10,
+ SVN_RESOLVE=11,
+ SVN_SWITCH=12,
+ SVN_DIFF=13,
+ SVN_BLAME=14,
+ SVN_INFO = 15,
+ SVN_SWITCH_RELOCATE = 16,
+ SVN_COPY = 17,
+ SVN_MERGE = 18,
+ SVN_COMMIT_2=103,
+ SVN_STATUS_2=109
+
+ };
+
+ private:
+ bool createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, KIO::UDSEntry& entry);
+ apr_pool_t *pool;
+ unsigned long int m_counter;
+};
+
+#endif
diff --git a/vcs/subversion/svn_logviewoptiondlgbase.ui b/vcs/subversion/svn_logviewoptiondlgbase.ui
new file mode 100644
index 00000000..149c82e1
--- /dev/null
+++ b/vcs/subversion/svn_logviewoptiondlgbase.ui
@@ -0,0 +1,156 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnLogViewOptionDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnLogViewOptionDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>449</width>
+ <height>288</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Log View</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="3" column="0">
+ <property name="name">
+ <cstring>pushButton1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>checkBox1</cstring>
+ </property>
+ <property name="text">
+ <string>Do not show logs before branching point</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>buttonGroup2_2</cstring>
+ </property>
+ <property name="title">
+ <string>End Revision</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radio5</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;By Revision Number</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radio6</cstring>
+ </property>
+ <property name="text">
+ <string>B&amp;y Revision Specifier</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>comboBox2</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>intInput2</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>pushButton2</cstring>
+ </property>
+ <property name="text">
+ <string>C&amp;ancel</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Start Revision</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>comboBox1</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>intInput1</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>radio3</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;By Revision Number</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>radio4</cstring>
+ </property>
+ <property name="text">
+ <string>B&amp;y Revision Specifier</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>pushButton1</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnLogViewOptionDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>pushButton2</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnLogViewOptionDlgBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_logviewwidget.cpp b/vcs/subversion/svn_logviewwidget.cpp
new file mode 100644
index 00000000..c6aae452
--- /dev/null
+++ b/vcs/subversion/svn_logviewwidget.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "svn_logviewwidget.h"
+#include "svn_blamewidget.h"
+#include "subversion_core.h"
+#include "subversion_global.h"
+#include <kdevproject.h>
+#include <ktextedit.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qradiobutton.h>
+#include <qcombobox.h>
+#include <knuminput.h>
+#include <qcheckbox.h>
+
+#include <qsplitter.h>
+#include <qheader.h>
+#include <qlistview.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+
+SvnLogViewWidget::SvnLogViewWidget(subversionPart *part, QWidget *parent)
+ :QWidget(parent), m_part(part)
+{
+ m_layout = new QGridLayout( this, 1, 1, 11, 6, "SvnLogViewWidgetBaseLayout");
+
+ splitter1 = new QSplitter( this, "splitter1" );
+ splitter1->setOrientation( QSplitter::Horizontal );
+ splitter1->setMargin(1);
+
+ listView1 = new QListView( splitter1, "listView1" );
+ listView1->addColumn( i18n( "Rev" ) );
+ listView1->addColumn( i18n( "Date" ) );
+ listView1->addColumn( i18n( "Author" ) );
+ listView1->addColumn( i18n( "Comment" ) );
+ listView1->resize( QSize(1, 1).expandedTo(minimumSizeHint()) );
+ QFont listView1_font( listView1->font() );
+ listView1_font.setPointSize( 9 );
+ listView1->setFont( listView1_font );
+ listView1->setAllColumnsShowFocus( TRUE );
+ listView1->setShowSortIndicator( TRUE );
+
+ textEdit1 = new KTextEdit( splitter1, "textEdit1" );
+ textEdit1->resize( QSize(1, 1).expandedTo(minimumSizeHint()) );
+ QFont textEdit1_font( textEdit1->font() );
+ textEdit1_font.setPointSize( 9 );
+ textEdit1->setFont( textEdit1_font );
+ textEdit1->setFocusPolicy( QTextEdit::WheelFocus );
+ textEdit1->setReadOnly( TRUE );
+
+ m_layout->addWidget( splitter1, 0, 0 );
+ m_layout->setMargin(1);
+
+ resize( QSize(692, 343).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+
+ connect( listView1, SIGNAL(clicked( QListViewItem *)), this, SLOT(slotClicked(QListViewItem*)) );
+ connect( listView1, SIGNAL(contextMenuRequested( QListViewItem*, const QPoint&, int )),
+ this, SLOT(contextMenuRequested(QListViewItem*, const QPoint&, int)) );
+}
+SvnLogViewWidget::~SvnLogViewWidget()
+{
+}
+
+void SvnLogViewWidget::setLogResult( QValueList<SvnLogHolder> *loglist )
+{
+ this->listView1->clear();
+ this->textEdit1->clear();
+ this->listView1->setSorting( 1, false );
+
+ for( QValueList<SvnLogHolder>::Iterator it=loglist->begin(); it!=loglist->end(); ++it ){
+
+ SvnLogHolder holder = *it;
+ SvnLogViewItem *item = new SvnLogViewItem(this->listView1);
+
+ QString prettyDate = holder.date.left(16).replace(10, 1, ' ');
+
+ item->setText(0, holder.rev );
+ item->setText(1, prettyDate );
+ item->setText(2, holder.author );
+ item->setText(3, holder.logMsg.simplifyWhiteSpace() );
+
+ item->m_pathList = holder.pathList;
+ item->m_message = holder.logMsg;
+ }
+// this->listView1->show();
+}
+
+void SvnLogViewWidget::setRequestedUrl( QString reqUrl )
+{
+ m_reqUrl = reqUrl;
+}
+
+void SvnLogViewWidget::slotClicked( QListViewItem *oneItem )
+{
+ if( !oneItem ) return;
+ SvnLogViewItem *item = dynamic_cast<SvnLogViewItem*>( oneItem );
+ if( !item ) return;
+ textEdit1->clear();
+ textEdit1->append( item->m_pathList );
+ textEdit1->append( "\n\n" );
+ textEdit1->append( item->m_message + "\n" );
+}
+void SvnLogViewWidget::contextMenuRequested( QListViewItem *item, const QPoint & pos, int col )
+{
+ if( !item || col == -1 )
+ return;
+ m_ctxLogItem = dynamic_cast<SvnLogViewItem*>(item);
+ if( !m_ctxLogItem )
+ return;
+ QPopupMenu *menu = new QPopupMenu(this);
+ menu->insertItem( i18n("Blame this revision"), this, SLOT(blameThis()) );
+ menu->insertItem( i18n("Difference to previous revision"), this, SLOT(diffToPrevious()) );
+ menu->exec( pos );
+}
+void SvnLogViewWidget::blameThis()
+{
+ if( !m_ctxLogItem ){
+ KMessageBox::error( this, i18n("No revision was clicked"), i18n("error") );
+ return;
+ }
+ // note that blame is done on single file.
+ QStringList modifies = QStringList::split( "\n", m_ctxLogItem->m_pathList, false );
+ QString selectedPath;
+ if( modifies.count() > 1 ){
+ SvnBlameFileSelectDlg dlg(this);
+ dlg.setCandidate( &modifies );
+ if( dlg.exec() == QDialog::Accepted ){
+ selectedPath = dlg.selected();
+ } else{
+ return;
+ }
+
+ } else if( modifies.count() == 1 ){
+ selectedPath = *( modifies.at(0) );
+ } else {
+ return;
+ }
+
+ QString relPath = selectedPath.section( '/', 1 );
+
+ QValueList< SvnGlobal::SvnInfoHolder > holderList = m_part->m_prjInfoMap.values();
+ SvnGlobal::SvnInfoHolder holder;
+ if( holderList.count() > 0 ){
+ // get full Url
+ holder = holderList.first();
+ QString absPath = holder.reposRootUrl.url(-1) + '/' + relPath;
+ kdDebug(9036) << " Blame requested on path " << absPath << endl;
+ // get revision
+ int revEnd = m_ctxLogItem->text(0).toInt();
+ // final request
+ m_part->svncore()->blame( KURL(absPath), SvnGlobal::dont_touch, 0, "", revEnd, "" );
+ }
+ else{
+ return;
+ }
+}
+
+void SvnLogViewWidget::diffToPrevious()
+{
+ if( !m_ctxLogItem ){
+ KMessageBox::error( this, i18n("No revision was clicked"), i18n("error") );
+ return;
+ }
+ int revThis = m_ctxLogItem->text(0).toInt();
+ int revPrev = revThis - 1;
+ kdDebug(9036) << " Diff to prev requested on " << m_reqUrl << endl;
+ m_part->svncore()->diffAsync( m_reqUrl, m_reqUrl, revPrev, "", revThis, "",
+ true/*recurse*/, true/*peg_diff*/ );
+}
+
+SvnLogViewOptionDlg::SvnLogViewOptionDlg( QWidget *parent, const char* name, bool modal, WFlags f )
+: SvnLogViewOptionDlgBase( parent, name, modal,f )
+{
+// radio1->setChecked(true); //repository log
+ radio4->setChecked(true); //start revistion by revision keyword
+ radio5->setChecked(true); //end revision by revision number
+ reinstallRevisionSpecifiers();
+ connect( intInput1, SIGNAL(valueChanged(int)), this, SLOT(setStartRevnumRadio()) );
+ connect( comboBox1, SIGNAL(activated(const QString&)), this, SLOT(setStartRevkindRadio()) );
+ connect( intInput2, SIGNAL(valueChanged(int)), this, SLOT(setEndRevnumRadio()) );
+ connect( comboBox2, SIGNAL(activated(const QString&)), this, SLOT(setEndRevkindRadio()) );
+}
+SvnLogViewOptionDlg::~SvnLogViewOptionDlg()
+{}
+void SvnLogViewOptionDlg::reinstallRevisionSpecifiers()
+{
+ comboBox1->clear();
+ comboBox2->clear();
+
+ QStringList items;
+ items << "HEAD" << "BASE" << "PREV" << "COMMITTED";
+ comboBox1->insertStringList( items );
+ comboBox2->insertStringList( items );
+}
+int SvnLogViewOptionDlg::revstart()
+{
+ if( !radio3->isChecked() ){
+ return -1;
+ } else{
+ return intInput1->value();
+ }
+}
+QString SvnLogViewOptionDlg::revKindStart()
+{
+ if( !radio4->isChecked() ){
+ return QString("");
+ } else{
+ return comboBox1->currentText();
+ }
+}
+int SvnLogViewOptionDlg::revend()
+{
+ if( !radio5->isChecked() ){
+ return -1;
+ } else{
+ return intInput2->value();
+ }
+}
+QString SvnLogViewOptionDlg::revKindEnd()
+{
+ if( !radio6->isChecked() ){
+ return QString("");
+ } else{
+ return comboBox2->currentText();
+ }
+}
+bool SvnLogViewOptionDlg::strictNode()
+{
+ if( checkBox1->isChecked() ){
+ return true;
+ } else{
+ return false;
+ }
+}
+void SvnLogViewOptionDlg::setStartRevnumRadio()
+{
+ radio3->setChecked(true);
+}
+void SvnLogViewOptionDlg::setStartRevkindRadio()
+{
+ radio4->setChecked(true);
+}
+void SvnLogViewOptionDlg::setEndRevnumRadio()
+{
+ radio5->setChecked(true);
+}
+void SvnLogViewOptionDlg::setEndRevkindRadio()
+{
+ radio6->setChecked(true);
+}
+
+#include "svn_logviewwidget.moc"
+
diff --git a/vcs/subversion/svn_logviewwidget.h b/vcs/subversion/svn_logviewwidget.h
new file mode 100644
index 00000000..40bf7e38
--- /dev/null
+++ b/vcs/subversion/svn_logviewwidget.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef SVNLOGVIEWWIDGET_H
+#define SVNLOGVIEWWIDGET_H
+
+#include "subversion_widget.h"
+#include "svn_logviewoptiondlgbase.h"
+// #include "subversion_part.h"
+#include <qvaluelist.h>
+#include <qlistview.h>
+class subversionPart;
+// class QWidget;
+#include <qwidget.h>
+class KTextEdit;
+class QSplitter;
+class QGridLayout;
+class SvnLogViewItem;
+
+class SvnLogHolder{
+ public:
+ SvnLogHolder(){};
+ ~SvnLogHolder(){};
+ QString author;
+ QString date;
+ QString logMsg;
+ QString pathList;
+ QString rev;
+};
+
+class SvnLogViewWidget : public /*SvnLogViewWidgetBase*/ QWidget {
+ Q_OBJECT
+public:
+ SvnLogViewWidget(subversionPart *part, QWidget *parent);
+ virtual ~SvnLogViewWidget();
+ void setLogResult( QValueList<SvnLogHolder> *loglist );
+ void setRequestedUrl( QString url );
+
+protected slots:
+ void slotClicked( QListViewItem* item );
+ void contextMenuRequested( QListViewItem *item, const QPoint & pos, int col );
+ void blameThis();
+ void diffToPrevious();
+
+private:
+ QString m_reqUrl;
+ subversionPart *m_part;
+ SvnLogViewItem* m_ctxLogItem;
+
+ QSplitter* splitter1;
+ QListView* listView1;
+ KTextEdit* textEdit1;
+ QGridLayout* m_layout;
+
+};
+
+class SvnLogViewOptionDlg : public SvnLogViewOptionDlgBase {
+ Q_OBJECT
+public:
+ SvnLogViewOptionDlg(QWidget *parent=0, const char* name=0, bool modal=TRUE, WFlags f=0);
+ ~SvnLogViewOptionDlg();
+ int revstart();
+ QString revKindStart();
+ int revend();
+ QString revKindEnd();
+ bool strictNode();
+public slots:
+ void reinstallRevisionSpecifiers();
+ void setStartRevnumRadio();
+ void setStartRevkindRadio();
+ void setEndRevnumRadio();
+ void setEndRevkindRadio();
+};
+
+#endif
+
diff --git a/vcs/subversion/svn_mergeoptiondlgbase.ui b/vcs/subversion/svn_mergeoptiondlgbase.ui
new file mode 100644
index 00000000..0ad25c83
--- /dev/null
+++ b/vcs/subversion/svn_mergeoptiondlgbase.ui
@@ -0,0 +1,374 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnMergeOptionDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnMergeOptionDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>473</width>
+ <height>590</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Merge</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Destination</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Destination working path</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="0">
+ <property name="name">
+ <cstring>dest</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>buttonGroup2</cstring>
+ </property>
+ <property name="title">
+ <string>Source 1</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput" row="3" column="1">
+ <property name="name">
+ <cstring>revnum1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>revnumbtn1</cstring>
+ </property>
+ <property name="text">
+ <string>Number:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="2">
+ <property name="name">
+ <cstring>revkindbtn1</cstring>
+ </property>
+ <property name="text">
+ <string>Keyword:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="3">
+ <item>
+ <property name="text">
+ <string>HEAD</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>BASE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>COMMITTED</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PREV</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>revkind1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="currentItem">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>src1</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Source URL or working path:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Specify revision as</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>buttonGroup2_2</cstring>
+ </property>
+ <property name="title">
+ <string>Source 2</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>revnumbtn2</cstring>
+ </property>
+ <property name="text">
+ <string>Number:</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="2">
+ <property name="name">
+ <cstring>revkindbtn2</cstring>
+ </property>
+ <property name="text">
+ <string>Keyword:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>src2</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Specify revision as</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="3">
+ <item>
+ <property name="text">
+ <string>HEAD</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>BASE</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>COMMITTED</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>PREV</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>revkind2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="currentItem">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="3" column="1">
+ <property name="name">
+ <cstring>revnum2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="text">
+ <string>Source URL or working path:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton" row="7" column="1">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ <spacer row="7" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>171</width>
+ <height>31</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="7" column="2">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>forceCheck</cstring>
+ </property>
+ <property name="text">
+ <string>--force (Force to delete locally modified or unversioned items.)</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>nonRecurse</cstring>
+ </property>
+ <property name="text">
+ <string>--non-recursive</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>ignoreAncestryCheck</cstring>
+ </property>
+ <property name="text">
+ <string>--ignore-ancestry</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>dryRunCheck</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>--dry-run (Only receive full result notification
+ without actually modifying working copy)</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnMergeOptionDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnMergeOptionDialogBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_mergewidget.cpp b/vcs/subversion/svn_mergewidget.cpp
new file mode 100644
index 00000000..6a8fc0b3
--- /dev/null
+++ b/vcs/subversion/svn_mergewidget.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "svn_mergewidget.h"
+#include "subversion_global.h"
+#include <kurlrequester.h>
+#include <qradiobutton.h>
+#include <knuminput.h>
+#include <qcheckbox.h>
+#include <kcombobox.h>
+
+using namespace SvnGlobal;
+
+SvnMergeDialog::SvnMergeDialog( const KURL &wcTarget, QWidget *parent )
+ : SvnMergeOptionDialogBase( parent )
+{
+ dest->setURL( wcTarget.prettyURL() );
+
+ connect( revnumbtn1, SIGNAL(toggled(bool)), revnum1, SLOT(setEnabled(bool)) );
+ connect( revnumbtn1, SIGNAL(toggled(bool)), revkind1, SLOT(setDisabled(bool)) );
+ connect( revnumbtn2, SIGNAL(toggled(bool)), revnum2, SLOT(setEnabled(bool)) );
+ connect( revnumbtn2, SIGNAL(toggled(bool)), revkind2, SLOT(setDisabled(bool)) );
+ revkind1->setDisabled(true);
+ revnum2->setDisabled(true);
+}
+
+SvnMergeDialog::~SvnMergeDialog()
+{
+}
+
+KURL SvnMergeDialog::source1()
+{
+ return KURL( src1->url() );
+}
+SvnRevision SvnMergeDialog::rev1()
+{
+ SvnRevision rev;
+
+ if( revkindbtn1->isChecked() ){
+ rev.revNum = -1;
+ rev.revKind = revkind1->currentText();
+ } else {
+ rev.revNum = revnum1->value();
+ rev.revKind = "UNSPECIFIED";
+ }
+ return rev;
+}
+KURL SvnMergeDialog::source2()
+{
+ return KURL( src2->url() );
+}
+SvnRevision SvnMergeDialog::rev2()
+{
+ SvnRevision rev;
+
+ if( revkindbtn2->isChecked() ){
+ rev.revNum = -1;
+ rev.revKind = revkind2->currentText();
+ } else {
+ rev.revNum = revnum2->value();
+ rev.revKind = "UNSPECIFIED";
+ }
+ return rev;
+}
+bool SvnMergeDialog::recurse()
+{
+ return !(nonRecurse->isChecked());
+}
+bool SvnMergeDialog::force()
+{
+ return forceCheck->isChecked();
+}
+bool SvnMergeDialog::ignoreAncestry()
+{
+ return ignoreAncestryCheck->isChecked();
+}
+bool SvnMergeDialog::dryRun()
+{
+ return dryRunCheck->isChecked();
+}
+
+#include "svn_mergewidget.moc"
diff --git a/vcs/subversion/svn_mergewidget.h b/vcs/subversion/svn_mergewidget.h
new file mode 100644
index 00000000..ff54a6da
--- /dev/null
+++ b/vcs/subversion/svn_mergewidget.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Dukju Ahn (dukjuahn@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 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef SVN_MERGEWIDGET_H
+#define SVN_MERGEWIDGET_H
+
+#include "svn_mergeoptiondlgbase.h"
+namespace SvnGlobal
+{
+ class SvnRevision;
+}
+
+class KURL;
+
+class SvnMergeDialog : public SvnMergeOptionDialogBase
+{
+ Q_OBJECT
+public:
+ SvnMergeDialog( const KURL &wcTarget, QWidget *parent = NULL );
+ virtual ~SvnMergeDialog();
+
+ KURL source1();
+ SvnGlobal::SvnRevision rev1();
+ KURL source2();
+ SvnGlobal::SvnRevision rev2();
+ bool recurse();
+ bool force();
+ bool ignoreAncestry();
+ bool dryRun();
+
+};
+
+#endif
diff --git a/vcs/subversion/svn_switchdlgbase.ui b/vcs/subversion/svn_switchdlgbase.ui
new file mode 100644
index 00000000..02257196
--- /dev/null
+++ b/vcs/subversion/svn_switchdlgbase.ui
@@ -0,0 +1,213 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnSwitchDlgBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnSwitchDlgBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>603</width>
+ <height>255</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subversion Switch</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>nonRecurseCheck</cstring>
+ </property>
+ <property name="text">
+ <string>Non-recursive. (Switch its immediate children only)</string>
+ </property>
+ </widget>
+ <widget class="Line" row="5" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="6" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton" row="0" column="2">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton" row="0" column="1">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Current Repository URL</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>currentUrlEdit</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Working copy to switch</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>wcUrlEdit</cstring>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Working Mode</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>switchOnlyRadio</cstring>
+ </property>
+ <property name="text">
+ <string>svn switch</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>relocationRadio</cstring>
+ </property>
+ <property name="text">
+ <string>svn switch --relocation</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>New destination URL</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>destUrlEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnSwitchDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnSwitchDlgBase</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>destUrlEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>SvnSwitchDlgBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">svn_switchdlgbase.ui.h</include>
+</includes>
+<slots>
+ <slot>Form1_destroyed( QObject * )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/vcs/subversion/svn_switchwidget.cpp b/vcs/subversion/svn_switchwidget.cpp
new file mode 100644
index 00000000..ec1b603c
--- /dev/null
+++ b/vcs/subversion/svn_switchwidget.cpp
@@ -0,0 +1,60 @@
+#include <kurl.h>
+#include <klineedit.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+
+#include "svn_switchwidget.h"
+#include "subversion_global.h"
+
+SvnSwitchDlg::SvnSwitchDlg( const SvnGlobal::SvnInfoHolder *holder,
+ const QString &wcPath, QWidget *parent )
+ : SvnSwitchDlgBase( parent )
+ , m_info( holder )
+{
+ connect( switchOnlyRadio, SIGNAL(clicked()), this, SLOT(resetCurrentRepositoryUrlEdit()) );
+ connect( relocationRadio , SIGNAL(clicked()), this, SLOT(resetCurrentRepositoryUrlEdit()) );
+ // set switch only
+ switchOnlyRadio->setChecked( true );
+ wcUrlEdit->setText( wcPath );
+ currentUrlEdit->setText( m_info->url.prettyURL() );
+}
+
+SvnSwitchDlg::~SvnSwitchDlg()
+{}
+
+const QString SvnSwitchDlg::currentUrl()
+{
+ return currentUrlEdit->text();
+}
+const QString SvnSwitchDlg::destUrl()
+{
+ return destUrlEdit->text();
+}
+
+bool SvnSwitchDlg::recursive()
+{
+ return (! nonRecurseCheck->isChecked() );
+}
+bool SvnSwitchDlg::switchOnly()
+{
+ return switchOnlyRadio->isChecked();
+}
+bool SvnSwitchDlg::relocation()
+{
+ return relocationRadio->isChecked();
+}
+
+void SvnSwitchDlg::resetCurrentRepositoryUrlEdit()
+{
+ if( relocation() ){
+ // only ROOT repository url should be given
+ currentUrlEdit->setText( m_info->reposRootUrl.prettyURL() );
+ } else if( switchOnly() ){
+ // the full URL of item should be given
+ currentUrlEdit->setText( m_info->url.prettyURL() );
+ } else{
+ // should not reach here!!
+ }
+}
+
+#include "svn_switchwidget.moc"
diff --git a/vcs/subversion/svn_switchwidget.h b/vcs/subversion/svn_switchwidget.h
new file mode 100644
index 00000000..643fb4b9
--- /dev/null
+++ b/vcs/subversion/svn_switchwidget.h
@@ -0,0 +1,31 @@
+#ifndef SVN_SWITCHWIDGET_H
+#define SVN_SWITCHWIDGET_H
+
+#include "svn_switchdlgbase.h"
+
+namespace SvnGlobal
+{
+ class SvnInfoHolder;
+}
+
+class SvnSwitchDlg : public SvnSwitchDlgBase
+{
+ Q_OBJECT
+public:
+ SvnSwitchDlg( const SvnGlobal::SvnInfoHolder *holder,
+ const QString &wcPath, QWidget *parent = NULL );
+ virtual ~SvnSwitchDlg();
+
+ const QString currentUrl();
+ const QString destUrl();
+ bool recursive();
+ bool switchOnly();
+ bool relocation();
+private slots:
+ void resetCurrentRepositoryUrlEdit();
+
+private:
+ const SvnGlobal::SvnInfoHolder *m_info;
+};
+
+#endif
diff --git a/vcs/subversion/svnssltrustpromptbase.ui b/vcs/subversion/svnssltrustpromptbase.ui
new file mode 100644
index 00000000..a94e345c
--- /dev/null
+++ b/vcs/subversion/svnssltrustpromptbase.ui
@@ -0,0 +1,116 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SvnSSLTrustPromptBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SvnSSLTrustPromptBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>504</width>
+ <height>281</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>SSL Certificate Trust</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="2" column="0">
+ <property name="name">
+ <cstring>btnPermanent</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QListView" row="1" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>listView1</cstring>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="2">
+ <property name="name">
+ <cstring>btnReject</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="1">
+ <property name="name">
+ <cstring>btnTemporary</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>errMsgLabel</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>btnPermanent</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnSSLTrustPromptBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>btnTemporary</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnSSLTrustPromptBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>btnReject</sender>
+ <signal>clicked()</signal>
+ <receiver>SvnSSLTrustPromptBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>