summaryrefslogtreecommitdiffstats
path: root/vcs/cvsservice
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch)
treeacaf47eb0fa12142d3896416a69e74cbf5a72242 /vcs/cvsservice
downloadtdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz
tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'vcs/cvsservice')
-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
76 files changed, 10763 insertions, 0 deletions
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>