diff options
Diffstat (limited to 'vcs/cvsservice')
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>&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>&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>&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>&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>&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>&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>&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>&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><b>Changelog filename path</b><br/>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>&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>&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 &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>&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>&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>&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>&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:<ul> +<li>/home/cvsroot or</li><li>:pserver:me@localhost:/home/cvs</li></ul></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_&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 &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>&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 &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 &new directories (if any)</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>pruneEmptyDirWhenUpdateCheck</cstring> + </property> + <property name="text"> + <string>&Prune empty directories</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>recursiveWhenUpdateCheck</cstring> + </property> + <property name="text"> + <string>&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>&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&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&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("<", "<"); + lineNew.replace(">", ">"); + lineNew.replace("&", "&"); + + 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 &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>&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&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&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>&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>&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>&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>&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>&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 &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>&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>&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>&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 &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&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>&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&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&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>&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 Binary files differnew file mode 100644 index 00000000..921b0674 --- /dev/null +++ b/vcs/cvsservice/kdev_cvs.png diff --git a/vcs/cvsservice/kdev_cvs.xcf b/vcs/cvsservice/kdev_cvs.xcf Binary files differnew file mode 100644 index 00000000..aafee609 --- /dev/null +++ b/vcs/cvsservice/kdev_cvs.xcf 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>&Version Control</Text> + <Merge /> + <Menu name="version_control_tools_cvsservice" group="tools_project_operations"> + <Text>&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>&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 &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. <i>make_it_cool, kdevelop_alpha5, ...</i>)</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 &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. <i>20030204</i>)</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>&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>&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>&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 &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 &branch</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>forceCheck</cstring> + </property> + <property name="text"> + <string>&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>&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>&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> |