diff options
Diffstat (limited to 'vcs')
170 files changed, 22461 insertions, 0 deletions
diff --git a/vcs/Makefile.am b/vcs/Makefile.am new file mode 100644 index 00000000..d1fcb5b0 --- /dev/null +++ b/vcs/Makefile.am @@ -0,0 +1,39 @@ +## +## Do NOT remove the comments that start with "kdevelop:" +## They are actually directives to the kdevelop plugin system +## +## The include_xxxx variables are controlled by configure.in.in +## + +#kdevelop: CERVISIA_SUBDIR = cervisia +#if include_cervisia +#CERVISIA_SUBDIR = cervisia +#endif + +#kdevelop: CLEARCASE_SUBDIR = clearcase +if include_clearcase +CLEARCASE_SUBDIR = clearcase +endif + +#kdevelop: CVSCLIENT_SUBDIR = cvsclient +#if include_cvsclient +#CVSCLIENT_SUBDIR = cvsclient +#endif + +#kdevelop: CVSSERVICE_SUBDIR = cvsservice +if include_cvsservice +CVSSERVICE_SUBDIR = cvsservice +endif + +#kdevelop: PERFORCE_SUBDIR = perforce +if include_perforce +PERFORCE_SUBDIR = perforce +endif + +#kdevelop: SUBVERSION_SUBDIR = subversion +if include_subversion +SUBVERSION_SUBDIR = subversion +endif + +#SUBDIRS = $(CERVISIA_SUBDIR) $(CLEARCASE_SUBDIR) $(CVSSERVICE_SUBDIR) $(PERFORCE_SUBDIR) $(SUBVERSION_SUBDIR) +SUBDIRS = $(CLEARCASE_SUBDIR) $(CVSSERVICE_SUBDIR) $(PERFORCE_SUBDIR) $(SUBVERSION_SUBDIR) diff --git a/vcs/clearcase/Makefile.am b/vcs/clearcase/Makefile.am new file mode 100644 index 00000000..64b70392 --- /dev/null +++ b/vcs/clearcase/Makefile.am @@ -0,0 +1,18 @@ +# Here resides the clearcase part + +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util $(all_includes) + +kde_module_LTLIBRARIES = libkdevclearcase.la +libkdevclearcase_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkdevclearcase_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la + +libkdevclearcase_la_SOURCES = clearcasepart.cpp commentdlg.cpp \ + clearcasefileinfoprovider.cpp clearcasemanipulator.cpp + +METASOURCES = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = kdevclearcase.desktop + +SUBDIRS = integrator diff --git a/vcs/clearcase/README b/vcs/clearcase/README new file mode 100644 index 00000000..731741e1 --- /dev/null +++ b/vcs/clearcase/README @@ -0,0 +1,3 @@ +Please read the on-line, automaticaly updated KDevelop API documentation at: +http://www.kdevelop.org +or read the README.dox file. diff --git a/vcs/clearcase/README.dox b/vcs/clearcase/README.dox new file mode 100644 index 00000000..74f2678b --- /dev/null +++ b/vcs/clearcase/README.dox @@ -0,0 +1,42 @@ +/** \class ClearcasePart +Integrates Clearcase configuration management system into KDevelop. +Based on Perforce (PerforcePart) implementation by Harald Fernengel <harry AT kdevelop.org> + +To use clearcase functions, you need to: + -# Create a view in which you will keep your project files + -# Start the view and open project as a view extended directory.<br> + <b>IMPORTANT:</b> If you have a view test_vu and your project is located + under /vobs/source/project1 you should open the project + from /view/test_vu/vobs/source/project1 rather than + inside the view from /vobs/source/project1. File open + dialog does not show any files if you do otherwise. Who + knows, maybe it will work for you. If so, let me know. + -# Clearcase functions appear in the popup menu for an open file just + like cvs or perforce. + -# Functions supported so far are: checkout, checkin, uncheckout, diff, + mkelem, rmname (not rmelem), lshistory, and lsco (list checkouts). + -# For mkelem or rmname, you need to make sure that current directory + is checked out or the operation will fail. + -# For lshistory, the history is printed to the Messages window. + -# For lsco, the checkouts are listed recursively from the directory + containing the selected file. + -# Snapshot views should work. + -# To checkout a directory, select directory in file selector part and use + popup-menu. + -# The Clearcase popup-menu will appear for any file, even if it is not in + a VOB. Attempts to perform Clearcase operations on these files will not + succeed, and the output can be viewed in the Messages window. + +\authors <a href="mailto:ajay_guleria AT yahoo dot com">Ajay Guleria</a> +\authors <a href="mailto:pnoffke AT bigpond dot com">Patrick Noffke</a> +\authors <a href="mailto:phil AT hetroy dot org">Philippe Hétroy</a> + +\feature Integrates Clearcase configuration management system into KDevelop and displays VCS file information +\feature Detects the clearcase environment and activates menus +\feature Provided a dialog for checkout and checkin comments. + + +\todo Update the tree view when a VCS action is done (checkout, checkin...) +\todo Add a clearcase logging window + +*/ diff --git a/vcs/clearcase/clearcasefileinfoprovider.cpp b/vcs/clearcase/clearcasefileinfoprovider.cpp new file mode 100644 index 00000000..66dec0c8 --- /dev/null +++ b/vcs/clearcase/clearcasefileinfoprovider.cpp @@ -0,0 +1,66 @@ +// +// C++ Implementation: clearcasefileinfoprovider +// +// Description: +// +// +// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "clearcasefileinfoprovider.h" +#include "clearcasepart.h" +#include "kdevversioncontrol.h" + +#include <kprocess.h> +#include <qapplication.h> + +ClearcaseFileinfoProvider::ClearcaseFileinfoProvider(ClearcasePart *parent) + : KDevVCSFileInfoProvider( (KDevVersionControl*) parent, "clearcasefileinfoprovider") +{ + vcsInfo_ = NULL; + + connect(parent, SIGNAL(statusReady(const VCSFileInfoMap&, void*)), SIGNAL(triggerUpdate(const VCSFileInfoMap&, void*))); + + kdevVCS_ = parent; +} + + +ClearcaseFileinfoProvider::~ClearcaseFileinfoProvider() +{ +} + + +const VCSFileInfoMap* ClearcaseFileinfoProvider::status( const QString &dirPath ) { + + if (curDirPath_ == dirPath) return vcsInfo_; + + curDirPath_ = dirPath; + + if (vcsInfo_ != NULL) delete vcsInfo_; + + vcsInfo_ = ccManipulator_.retreiveFilesInfos(dirPath); + + return vcsInfo_; +} + +bool ClearcaseFileinfoProvider::requestStatus( const QString &dirPath, void *callerData, bool recursive, bool checkRepos ) { + + VCSFileInfoMap* vcsDirInfos = ccManipulator_.retreiveFilesInfos(dirPath); + + // update the file tree view + emit statusReady(*vcsDirInfos, callerData); + + delete vcsDirInfos; + return true; +} + + + +QStringList ClearcaseFileinfoProvider::registeredEntryList() const +{ + QStringList l; + return l; +} + diff --git a/vcs/clearcase/clearcasefileinfoprovider.h b/vcs/clearcase/clearcasefileinfoprovider.h new file mode 100644 index 00000000..b716d01b --- /dev/null +++ b/vcs/clearcase/clearcasefileinfoprovider.h @@ -0,0 +1,50 @@ +// +// C++ Interface: clearcasefileinfoprovider +// +// Description: +// +// +// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef CLEARCASEFILEINFOPROVIDER_H +#define CLEARCASEFILEINFOPROVIDER_H + +#include "clearcasepart.h" +#include "clearcasemanipulator.h" + + +/** +@author KDevelop Authors +*/ +class ClearcaseFileinfoProvider : public KDevVCSFileInfoProvider +{ + Q_OBJECT +public: + ClearcaseFileinfoProvider(ClearcasePart *parent); + + virtual ~ClearcaseFileinfoProvider(); + + // -- Sync interface + const VCSFileInfoMap *status( const QString &dirPath ) ; + + // -- Async interface for requesting data + bool requestStatus( const QString &dirPath, void *callerData, bool recursive = true, bool checkRepos = true ); + + +private: + + QStringList registeredEntryList() const; + + +private: + ClearcaseManipulator ccManipulator_; + QString curDirPath_; + VCSFileInfoMap* vcsInfo_; + ClearcasePart* kdevVCS_; + +}; + +#endif diff --git a/vcs/clearcase/clearcasemanipulator.cpp b/vcs/clearcase/clearcasemanipulator.cpp new file mode 100644 index 00000000..c51436ba --- /dev/null +++ b/vcs/clearcase/clearcasemanipulator.cpp @@ -0,0 +1,133 @@ +// +// C++ Implementation: ClearcaseManipulator +// +// Description: +// +// +// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "clearcasemanipulator.h" + +#include <kprocess.h> + +#include <qregexp.h> +#include <qstring.h> + +#include <stdlib.h> +#include <libgen.h> +#include <errno.h> +#ifdef __NetBSD__ +#include <sys/param.h> +#endif + +#if defined(Q_OS_MACX) || defined(MACOSX) || defined(Q_OS_SOLARIS) || defined(Q_OS_FREEBSD) || (defined(__NetBSD__) && (__NetBSD_Version__ < 599001500)) || defined(__DragonFly__) +//this function is taken from GNU libc +//it does not exist on macos +int getline(char **lineptr, size_t *n, FILE *stream) +{ + static char line[256]; + char *ptr; + unsigned int len; + + if (lineptr == NULL || n == NULL) + { + errno = EINVAL; + return -1; + } + + if (ferror (stream)) + return -1; + + if (feof(stream)) + return -1; + + fgets(line,256,stream); + + ptr = strchr(line,'\n'); + if (ptr) + *ptr = '\0'; + + len = strlen(line); + + if ((len+1) < 256) + { + ptr = (char*)realloc(*lineptr, 256); + if (ptr == NULL) + return(-1); + *lineptr = ptr; + *n = 256; + } + + strcpy(*lineptr,line); + return(len); +} +#endif + +const char ClearcaseManipulator::CT_DESC_SEPARATOR = ';'; + + +ClearcaseManipulator::ClearcaseManipulator() +{ +} + + +ClearcaseManipulator::~ClearcaseManipulator() +{} + + +bool ClearcaseManipulator::isCCRepository( const QString & directory ) { + QString cmd; + cmd = "cd " + directory + " && cleartool pwv -root"; + if ( system(cmd.ascii()) == 0 ) return true; + + return false; +} + +VCSFileInfoMap* ClearcaseManipulator::retreiveFilesInfos(const QString& directory) { + + + VCSFileInfoMap* fileInfoMap = new VCSFileInfoMap(); + + char CCcommand[1024]; + sprintf(CCcommand, "cleartool desc -fmt \"%%m;%%En;%%Rf;%%Sn;%%PVn\\n\" %s/*", directory.ascii()); + FILE* outputFile = popen(CCcommand, "r"); + + char* line = NULL; + size_t numRead; + while (!feof(outputFile)) { + getline(&line,&numRead,outputFile); + + if (numRead > 0) { + int pos = 0; + int lastPos = -1; + + QStringList outputList; + outputList = outputList.split(CT_DESC_SEPARATOR, QString(line), true ); + outputList[Name] = QString(basename((char*)outputList[Name].ascii())); + + VCSFileInfo::FileState state; + if (outputList[ClearcaseManipulator::State] == "unreserved" || outputList[ClearcaseManipulator::State] == "reserved") { + state = VCSFileInfo::Modified; + } + else if (outputList[ClearcaseManipulator::State] == "") { + state = VCSFileInfo::Uptodate; + } + else { + state = VCSFileInfo::Unknown; + } + + + (*fileInfoMap)[outputList[ClearcaseManipulator::Name]] = VCSFileInfo(outputList[ClearcaseManipulator::Name], outputList[ClearcaseManipulator::Version], outputList[ClearcaseManipulator::RepositoryVersion], state); + } + } + + pclose(outputFile); + + return fileInfoMap; +} + + + diff --git a/vcs/clearcase/clearcasemanipulator.h b/vcs/clearcase/clearcasemanipulator.h new file mode 100644 index 00000000..baa7c17f --- /dev/null +++ b/vcs/clearcase/clearcasemanipulator.h @@ -0,0 +1,49 @@ +// +// C++ Interface: ClearcaseManipulator +// +// Description: +// +// +// Author: KDevelop Authors <kdevelop-devel@kdevelop.org>, (C) 2005 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#ifndef CLEARCASEMANIPULATOR_H +#define CLEARCASEMANIPULATOR_H + +#include "kdevversioncontrol.h" + +#include <kprocess.h> + +#include <qregexp.h> + +#include <string> + +/** + @author KDevelop Authors + */ +class ClearcaseManipulator { + public: + ClearcaseManipulator(); + + ~ClearcaseManipulator(); + + static bool isCCRepository(const QString& directory); + + VCSFileInfoMap* retreiveFilesInfos(const QString& directory); + + private: + enum FileInfosFields { + Type = 0, + Name, + State, + Version, + RepositoryVersion + }; + + static const char CT_DESC_SEPARATOR; + +}; + +#endif diff --git a/vcs/clearcase/clearcasepart.cpp b/vcs/clearcase/clearcasepart.cpp new file mode 100644 index 00000000..6c11a4a6 --- /dev/null +++ b/vcs/clearcase/clearcasepart.cpp @@ -0,0 +1,363 @@ +/*************************************************************************** + * Copyright (C) 2003 by Ajay Guleria * + * ajay_guleria at yahoo dot com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "clearcasepart.h" +#include "commentdlg.h" + +#include <qfileinfo.h> +#include <qpopupmenu.h> + +#include <kpopupmenu.h> +#include <kdebug.h> +#include <kdevgenericfactory.h> +#include <klocale.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <kapplication.h> + +#include "kdevcore.h" +#include "kdevmakefrontend.h" +#include "kdevdifffrontend.h" +#include "kdevappfrontend.h" +#include "execcommand.h" +#include "domutil.h" +#include "kdevmainwindow.h" +#include "kdevproject.h" +#include "kdevplugininfo.h" + +#include "clearcasefileinfoprovider.h" +#include "clearcasemanipulator.h" + + +static const KDevPluginInfo data("kdevclearcase"); + +typedef KDevGenericFactory<ClearcasePart> ClearcaseFactory; +K_EXPORT_COMPONENT_FACTORY( libkdevclearcase, ClearcaseFactory( data ) ) + +ClearcasePart::ClearcasePart( QObject *parent, const char *name, const QStringList & ) + : KDevVersionControl( &data, parent, name ? name : "ClearcasePart" ), + default_checkin(""), + default_checkout(""), + default_uncheckout("-rm"), + default_create("-ci"), + default_remove("-f"), + default_lshistory(""), + default_diff("-pred -diff"), + default_lscheckout("-recurse") +{ + + // check if project directory is valid and cache it + isValidCCDirectory_ = ClearcaseManipulator::isCCRepository( project()->projectDirectory() ); + + fileInfoProvider_ = new ClearcaseFileinfoProvider(this); + + setInstance(ClearcaseFactory::instance()); + connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), + this, SLOT(contextMenu(QPopupMenu *, const Context *)) ); +} + +ClearcasePart::~ClearcasePart() +{} + + + +bool ClearcasePart::isValidDirectory(const QString &dirPath) const { + return isValidCCDirectory_; +} + + +void ClearcasePart::contextMenu(QPopupMenu *popup, const Context *context) +{ + + if (context->hasType( Context::FileContext )) { + const FileContext *fcontext = static_cast<const FileContext*>(context); + popupfile_ = fcontext->urls().first().path(); + + QFileInfo fi(popupfile_); + popup->insertSeparator(); + + KPopupMenu *sub = new KPopupMenu(popup); + QString name = fi.fileName(); + sub->insertTitle( i18n("Actions for %1").arg(name) ); + sub->insertItem( i18n("Checkin"), + this, SLOT(slotCheckin()) ); + sub->insertItem( i18n("Checkout"), + this, SLOT(slotCheckout()) ); + sub->insertItem( i18n("Uncheckout"), + this, SLOT(slotUncheckout()) ); + sub->insertSeparator(); + sub->insertItem( i18n("Create Element"), + this, SLOT(slotCreate()) ); + sub->insertItem( i18n("Remove Element"), + this, SLOT(slotRemove()) ); + sub->insertSeparator(); + sub->insertItem( i18n("History"), + this, SLOT(slotListHistory()) ); + sub->insertSeparator(); + sub->insertItem( i18n("Diff"), + this, SLOT(slotDiff()) ); + + sub->insertSeparator(); + sub->insertItem( i18n("List Checkouts"), + this, SLOT(slotListCheckouts()) ); + + popup->insertItem(i18n("Clearcase"), sub); + + if (!project() || !isValidDirectory( project()->projectDirectory() )) { + sub->setEnabled( false ); + } + } +} + + +void ClearcasePart::slotCheckin() +{ + QString dir, name; + QFileInfo fi(popupfile_); + dir = fi.dirPath(); + name = fi.fileName(); + + CcaseCommentDlg dlg(FALSE); + if (dlg.exec() == QDialog::Rejected) + return; + + QDomDocument &dom = *this->projectDom(); + QString message = DomUtil::readEntry(dom,"/kdevclearcase/checkin_options",default_checkin); + if(dlg.logMessage().isEmpty()) + message += "-nc "; + else + message += "-c \"" + dlg.logMessage() + "\""; + + QString command("cd "); + command += KShellProcess::quote(dir); + command += " && "; + command += " cleartool checkin "; + command += message; // Already quoted, see above + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); +} + + +void ClearcasePart::slotCheckout() +{ + QString dir, name; + QFileInfo fi(popupfile_); + dir = fi.dirPath(); + name = fi.fileName(); + + CcaseCommentDlg dlg(TRUE); + if (dlg.exec() == QDialog::Rejected) + return; + + QDomDocument &dom = *this->projectDom(); + QString message = DomUtil::readEntry(dom,"/kdevclearcase/checkout_options",default_checkout); + if(!dlg.isReserved()) + message += "-unres "; + if(dlg.logMessage().isEmpty()) + message += "-nc "; + else + message += "-c \"" + dlg.logMessage() + "\""; + + QString command("cd "); + command += KShellProcess::quote(dir); + command += " && cleartool checkout "; + command += message; + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); + + emit finishedFetching(dir); +} + + +void ClearcasePart::slotUncheckout() +{ + QString dir, name; + QFileInfo fi(popupfile_); + dir = fi.dirPath(); + name = fi.fileName(); + + QDomDocument &dom = *this->projectDom(); + + QString command("cd "); + command += KShellProcess::quote(dir); + command += " && cleartool uncheckout "; + command += DomUtil::readEntry(dom,"/kdevclearcase/uncheckout_options",default_uncheckout); + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); + + emit finishedFetching(dir); +} + +void ClearcasePart::slotCreate() +{ + QFileInfo fi(popupfile_); + QString dir = fi.dirPath(); + QString name = fi.fileName(); + + QDomDocument &dom = *this->projectDom(); + + // Checking whether current directory is checked out or not is cumbersome so skip it for now + QString command("cd "); + command += KShellProcess::quote(dir); + QFileInfo di(dir); + if(!di.isWritable()) { // Work-around to check if directory is checked out + command += " && cleartool co -unres -nc "; + command += KShellProcess::quote(dir); + } + command += " && cleartool mkelem "; + if(fi.isDir()) + command += " -elt directory "; + command += DomUtil::readEntry(dom,"/kdevclearcase/create_options",default_create); + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); + + emit finishedFetching(dir); +} + + +void ClearcasePart::slotRemove() +{ + QFileInfo fi(popupfile_); + QString dir = fi.dirPath(); + QString name = fi.fileName(); + + QDomDocument &dom = *this->projectDom(); + + QString command("cd "); + command += KShellProcess::quote(dir); + QFileInfo di(dir); + if(!di.isWritable()) { // Work-around to check if directory is checked out + command += " && cleartool co -unres -nc "; + command += KShellProcess::quote(dir); + } + command += " && cleartool rmname "; // Don't use rm command + command += DomUtil::readEntry(dom,"/kdevclearcase/remove_options",default_remove); + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); + + emit finishedFetching(dir); +} + +void ClearcasePart::slotListHistory() +{ + QFileInfo fi(popupfile_); + QString dir = fi.dirPath(); + QString name = fi.fileName(); + QStringList args; + QStringList env; + QString str; + + QDomDocument &dom = *this->projectDom(); + + QString command("cd "); + command += KShellProcess::quote(dir); + command += " && cleartool lshistory "; + command += DomUtil::readEntry(dom, "/kdevclearcase/lshistory_options", default_lshistory); + command += " "; + command += KShellProcess::quote(name); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); +} + +void ClearcasePart::slotDiff() +{ + QFileInfo fi(popupfile_); + QString dir = fi.dirPath(); + QString name = fi.fileName(); + QStringList args; + QStringList env; + QString str; + + QDomDocument &dom = *this->projectDom(); + + args << "diff"; + str = DomUtil::readEntry(dom,"/kdevclearcase/diff_options",default_diff); + if (str.length()) { + QStringList list = QStringList::split(' ',str); + for(QStringList::Iterator it = list.begin(); it != list.end(); ++it) args << *it; + } + + args << name; + + ExecCommand* cmv = new ExecCommand( "cleartool", args, dir, env, this ); + connect( cmv, SIGNAL(finished( const QString&, const QString& )), + this, SLOT(slotDiffFinished( const QString&, const QString& )) ); +} + + +void ClearcasePart::slotDiffFinished( const QString& diff, const QString& err ) +{ + if ( diff.isNull() && err.isNull() ) { + kdDebug(9000) << "clearcase diff canceled" << endl; + return; // user pressed cancel or an error occured + } + + if ( diff.isEmpty() && !err.isEmpty() ) { + KMessageBox::detailedError( 0, i18n("Clearcase output errors during diff."), err, i18n("Errors During Diff") ); + return; + } + + if ( !err.isEmpty() ) { + int s = KMessageBox::warningContinueCancelList( 0, i18n("Clearcase outputted errors during diff. Do you still want to continue?"), + QStringList::split( "\n", err, false ), i18n("Errors During Diff") ); + if ( s != KMessageBox::Continue ) + return; + } + + if ( diff.isEmpty() ) { + KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Difference Found") ); + return; + } + + if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("KDevelop/DiffFrontend")) + diffFrontend->showDiff( diff ); +} + +void ClearcasePart::slotListCheckouts() +{ + QString dir; + QFileInfo fi(popupfile_); + if (fi.isDir()) { + dir = fi.absFilePath(); + } else { + dir = fi.dirPath(); + } + + QDomDocument &dom = *this->projectDom(); + + QString command("cd "); + command += KShellProcess::quote(dir); + command += " && cleartool lsco "; + command += DomUtil::readEntry(dom, "/kdevclearcase/lscheckout_options", default_lscheckout); + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); + +} + + +#include "clearcasepart.moc" diff --git a/vcs/clearcase/clearcasepart.h b/vcs/clearcase/clearcasepart.h new file mode 100644 index 00000000..2f82b61d --- /dev/null +++ b/vcs/clearcase/clearcasepart.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2003 by Ajay Guleria * + * ajay_guleria at yahoo dot com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _CLEARCASEPART_H_ +#define _CLEARCASEPART_H_ + +#include <kdevversioncontrol.h> + +class Context; +class QPopupMenu; + +class ClearcasePart : public KDevVersionControl { + Q_OBJECT + +public: + ClearcasePart( QObject *parent, const char *name, const QStringList & ); + ~ClearcasePart(); + + const QString default_checkin; + const QString default_checkout; + const QString default_uncheckout; + const QString default_create; + const QString default_remove; + const QString default_lshistory; + const QString default_lscheckout; + const QString default_diff; + + virtual void createNewProject(const QString& dir) {} + virtual bool fetchFromRepository() { return true; } + virtual KDevVCSFileInfoProvider *fileInfoProvider() const { return fileInfoProvider_; } + virtual bool isValidDirectory(const QString &dirPath) const; + +private slots: + void contextMenu(QPopupMenu *popup, const Context *context); + + void slotCheckin(); + void slotCheckout(); + void slotUncheckout(); + + void slotCreate(); + void slotRemove(); + void slotDiff(); + void slotDiffFinished( const QString& diff, const QString& err ); + void slotListHistory(); + void slotListCheckouts(); + + +private: + + bool isValidCCDirectory_; + QString popupfile_; + QString viewname; + + KDevVCSFileInfoProvider *fileInfoProvider_; +}; + +#endif diff --git a/vcs/clearcase/commentdlg.cpp b/vcs/clearcase/commentdlg.cpp new file mode 100644 index 00000000..36b3bc6f --- /dev/null +++ b/vcs/clearcase/commentdlg.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2003 by Ajay Guleria * + * ajay_guleria at yahoo dot com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "commentdlg.h" + +#include <qlayout.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <kapplication.h> +#include <kbuttonbox.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstdguiitem.h> + +CcaseCommentDlg::CcaseCommentDlg(bool bCheckin) + : QDialog(0, "", true) +{ + setCaption( i18n("Clearcase Comment") ); + + QBoxLayout *layout = new QVBoxLayout(this, 10); + + QLabel *messagelabel = new QLabel(i18n("Enter log message:"), this); + messagelabel->setMinimumSize(messagelabel->sizeHint()); + layout->addWidget(messagelabel, 0); + + _edit = new QMultiLineEdit(this); + QFontMetrics fm(_edit->fontMetrics()); + _edit->setMinimumSize(fm.width("0")*40, fm.lineSpacing()*3); + layout->addWidget(_edit, 10); + + QBoxLayout *layout2 = new QHBoxLayout(layout); + if(bCheckin) { + _check = new QCheckBox(i18n("Reserve"), this); + layout2->addWidget(_check); + } + + KButtonBox *buttonbox = new KButtonBox(this); + buttonbox->addStretch(); + QPushButton *ok = buttonbox->addButton(KStdGuiItem::ok()); + QPushButton *cancel = buttonbox->addButton(KStdGuiItem::cancel()); + connect(ok, SIGNAL(clicked()), SLOT(accept()) ); + connect(cancel, SIGNAL(clicked()), SLOT(reject()) ); + ok->setDefault(true); + buttonbox->layout(); + layout2->addWidget(buttonbox, 0); + + layout->activate(); + adjustSize(); +} + + + +#include "commentdlg.moc" diff --git a/vcs/clearcase/commentdlg.h b/vcs/clearcase/commentdlg.h new file mode 100644 index 00000000..8ac50a38 --- /dev/null +++ b/vcs/clearcase/commentdlg.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2003 by Ajay Guleria * + * ajay_guleria at yahoo dot com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _CLEARCASECOMMENTDLG_H_ +#define _CLEARCASECOMMENTDLG_H_ + +#include <qcheckbox.h> +#include <qdialog.h> +#include <qmultilineedit.h> + +class CcaseCommentDlg : public QDialog +{ +Q_OBJECT +public: + CcaseCommentDlg(bool = FALSE); + QString logMessage() { return _edit->text(); }; + bool isReserved() { return (_check) ? _check->isChecked() : FALSE; }; + +private: + QMultiLineEdit *_edit; + QCheckBox* _check; +}; + +#endif diff --git a/vcs/clearcase/integrator/Makefile.am b/vcs/clearcase/integrator/Makefile.am new file mode 100644 index 00000000..cd998856 --- /dev/null +++ b/vcs/clearcase/integrator/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \ + $(all_includes) +METASOURCES = AUTO +kde_module_LTLIBRARIES = libclearcaseintegrator.la +libclearcaseintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries) +libclearcaseintegrator_la_LIBADD =\ + $(top_builddir)/lib/interfaces/extras/libkdevextras.la\ + $(top_builddir)/lib/libkdevelop.la +kde_services_DATA = kdevclearcaseintegrator.desktop +noinst_HEADERS = clearcaseintegrator.h ccintegratordlg.h +libclearcaseintegrator_la_SOURCES = clearcaseintegrator.cpp \ + ccintegratordlgbase.ui ccintegratordlg.cpp diff --git a/vcs/clearcase/integrator/ccintegratordlg.cpp b/vcs/clearcase/integrator/ccintegratordlg.cpp new file mode 100644 index 00000000..3e58aada --- /dev/null +++ b/vcs/clearcase/integrator/ccintegratordlg.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "ccintegratordlg.h" + +CCIntegratorDlg::CCIntegratorDlg(QWidget *parent, const char *name) + :CCIntegratorDlgBase(parent, name) +{ +} + +void CCIntegratorDlg::accept() +{ +} + +void CCIntegratorDlg::init(const QString &/*projectName*/, const QString &/*projectLocation*/) +{ +} + +QWidget *CCIntegratorDlg::self() +{ + return const_cast<CCIntegratorDlg*>(this); +} + +#include "ccintegratordlg.moc" diff --git a/vcs/clearcase/integrator/ccintegratordlg.h b/vcs/clearcase/integrator/ccintegratordlg.h new file mode 100644 index 00000000..0b197437 --- /dev/null +++ b/vcs/clearcase/integrator/ccintegratordlg.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef CCINTEGRATORDLG_H +#define CCINTEGRATORDLG_H + +#include "ccintegratordlgbase.h" +#include <kdevvcsintegrator.h> + +class CCIntegratorDlg: public CCIntegratorDlgBase, public VCSDialog { +Q_OBJECT +public: + CCIntegratorDlg(QWidget *parent = 0, const char *name = 0); + + virtual void accept(); + virtual void init(const QString &projectName, const QString &projectLocation); + virtual QWidget *self(); +}; + +#endif diff --git a/vcs/clearcase/integrator/ccintegratordlgbase.ui b/vcs/clearcase/integrator/ccintegratordlgbase.ui new file mode 100644 index 00000000..ae961a9f --- /dev/null +++ b/vcs/clearcase/integrator/ccintegratordlgbase.ui @@ -0,0 +1,47 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>CCIntegratorDlgBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CCIntegratorDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>480</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>No options available for this VCS.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>437</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/vcs/clearcase/integrator/clearcaseintegrator.cpp b/vcs/clearcase/integrator/clearcaseintegrator.cpp new file mode 100644 index 00000000..3ea4295f --- /dev/null +++ b/vcs/clearcase/integrator/clearcaseintegrator.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "clearcaseintegrator.h" + +#include <kdevgenericfactory.h> +#include <kdevplugininfo.h> + +#include "ccintegratordlg.h" + +static const KDevPluginInfo data("kdevclearcaseintegrator"); +typedef KDevGenericFactory<ClearcaseIntegrator> ClearcaseIntegratorFactory; +K_EXPORT_COMPONENT_FACTORY( libclearcaseintegrator, ClearcaseIntegratorFactory(data) ) + +ClearcaseIntegrator::ClearcaseIntegrator(QObject* parent, const char* name, + const QStringList // args + ) + :KDevVCSIntegrator(parent, name) +{ +} + +ClearcaseIntegrator::~ClearcaseIntegrator() +{ +} + +VCSDialog* ClearcaseIntegrator::fetcher(QWidget* // parent + ) +{ + return 0; +} + +VCSDialog* ClearcaseIntegrator::integrator(QWidget* parent) +{ + CCIntegratorDlg *dlg = new CCIntegratorDlg(parent); + return dlg; +} + +#include "clearcaseintegrator.moc" diff --git a/vcs/clearcase/integrator/clearcaseintegrator.h b/vcs/clearcase/integrator/clearcaseintegrator.h new file mode 100644 index 00000000..a6aaf396 --- /dev/null +++ b/vcs/clearcase/integrator/clearcaseintegrator.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef CLEARCASEINTEGRATOR_H +#define CLEARCASEINTEGRATOR_H + +#include <kdevvcsintegrator.h> + +#include <qstringlist.h> + +class ClearcaseIntegrator : public KDevVCSIntegrator +{ +Q_OBJECT +public: + ClearcaseIntegrator(QObject* parent, const char* name, const QStringList args = QStringList()); + ~ClearcaseIntegrator(); + + virtual VCSDialog* fetcher(QWidget* parent); + virtual VCSDialog* integrator(QWidget* parent); + +}; + +#endif diff --git a/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop b/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop new file mode 100644 index 00000000..b9957370 --- /dev/null +++ b/vcs/clearcase/integrator/kdevclearcaseintegrator.desktop @@ -0,0 +1,44 @@ +[Desktop Entry] +Type=Service +Name=KDevClearcaseIntegrator +Name[da]=KDevelop Clearcase-integration +Name[nds]=KDevelop-Clearcase-Integreren +Name[sk]=KDev ClearCase integrácia +Name[sv]=KDevelop Clearcase-integration +Name[zh_TW]=KDevelop Clearcase æ•´åˆå™¨ +Comment=Clearcase Project Integration Facility +Comment[ca]=Faciliat per a la integració amb projectes Clearcase +Comment[da]=Clearcase projektintegration +Comment[de]=Clearcase-Integration +Comment[el]=ΛειτουÏγία ενσωμάτωσης Clearcase στο ÎÏγο +Comment[es]=Facilidad para integración con proyectos Clearcase +Comment[et]=Clearcase projekti põimimisvahend +Comment[eu]=Clearcase proiektu-integraziorako tresna +Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ Clearcase +Comment[fr]=Fonction d'intégration pour un projet utilisant Clearcase +Comment[gl]=Utilidade para a integración de proxectos ClearCase +Comment[hu]=Integrálás Clearcase-projektekkel +Comment[it]=Funzione di integrazione del progetto ClearCase +Comment[ja]=Clearcase プãƒã‚¸ã‚§ã‚¯ãƒˆçµ±åˆãƒ„ール +Comment[ms]=Kemudahan Integrasi Projek Clearcase +Comment[nds]=Projektintegreren för Clearcase +Comment[ne]=कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾ +Comment[nl]=Clearcase-projectintegratie +Comment[pl]=Integracja z Clearcase +Comment[pt]=Integração com Projectos Clearcase +Comment[pt_BR]=Facilidade de Integração ao Projeto de Clearcase +Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Clearcase +Comment[sk]=Integrácia ClearCase projektu +Comment[sr]=Интеграција Clearcase-а у пројекат +Comment[sr@Latn]=Integracija Clearcase-a u projekat +Comment[sv]=Funktion för integrering av Clearcase i projekt +Comment[tr]=Clearcase Proje BütünleÅŸtirilmesi Aracı +Comment[zh_CN]=Clearcase 工程集æˆåŠŸèƒ½ +Comment[zh_TW]=Clearcase 專案整åˆå·¥å…· +Exec=blubb +ServiceTypes=KDevelop/VCSIntegrator +X-KDE-Library=libclearcaseintegrator +X-KDevelop-Default=false +X-KDevelop-VCS=ClearCase +X-KDevelop-VCSPlugin=kdevclearcase +X-KDevelop-Version=5 diff --git a/vcs/clearcase/kdevclearcase.desktop b/vcs/clearcase/kdevclearcase.desktop new file mode 100644 index 00000000..5a691980 --- /dev/null +++ b/vcs/clearcase/kdevclearcase.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +Type=Service +Exec=blubb +Comment=A plugin that provides support for Rational ClearCase, a large version control and build management system. http://www.rational.com/products/clearcase/index.jsp +Comment[ca]=Un connector que proporciona suport per a ClearCase de Rational, un potent sistema de control de versions i gestió de compilacions. http://www.rational.com/products/clearcase/index.jsp +Comment[da]=Et plugin der sørger for støtte for Rational ClearCase, et stort versionskontrol og byggehÃ¥ndteringssystem. http://www.rational.com/products/clearcase/index.jsp +Comment[de]=Eine Komponente, die eine Schnittstelle zu Rational ClearCase zur Verfügung stellt, einem umfangreichen Werkzeug zur Verwaltung von Versionen und Erstellungsvorgängen. http://www.rational.com/products/clearcase/index.jsp +Comment[el]=Ένα Ï€Ïόσθετο που Ï€ÏοσφÎÏει υποστήÏιξη για το Rational ClearCase, Îνα μεγάλο σÏστημα διαχείÏισης ελÎγχου εκδόσεων και κατασκευής. http://www.rational.com/products/clearcase/index.jsp +Comment[es]=Un complemento que proporciona soporte para Rational ClearCase, un potente sistema de control de versiones y administración de compilaciones (http://www.rational.com/products/clearcase/index.jsp) +Comment[et]=See plugin pakub suure versioonikontrolli ja ehitamise haldamise süsteemi Rational ClearCase toetust. http://www.rational.com/products/clearcase/index.jsp +Comment[eu]=Rational ClearCase euskarri plugin bat. ClearCase bertsio kontrol eta eraikuntza kudeaketa sistema handi bat da. http://www.rational.com/products/clearcase/index.jsp +Comment[fa]=وصله‌ای Ú©Ù‡ پشتیبانی برای Rational ClearCaseØŒ یک کنترل نسخۀ بزرگ Ùˆ سیستم مدیریت ساختن Ùراهم ‌می‌کند. http://www.rational.com/products/clearcase/index.jsp +Comment[fr]=Un module externe qui offre une prise en charge pour Rational ClearCase, un puissant système de contrôle de versions et de gestion de compilation. http://www.rational.com/products/clearcase/index.jsp +Comment[gl]=Extensión que proporciona soporte para Rational ClearCase, un gran sistema de control de versións e xestión da compilación. http://www.rational.com/products/clearcase/index.jsp +Comment[hu]=BÅ‘vÃtÅ‘modul a Rational ClearCase komplex verziókövetÅ‘ rendszerhez. http://www.rational.com/products/clearcase/index.jsp +Comment[it]=Un plugin che offre il supporto per Rational ClearCase, un sistema molto vasto per il controllo di versione e la compilazione. http://www.rational.com/products/clearcase/index.jsp +Comment[ja]=大è¦æ¨¡ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚³ãƒ³ãƒˆãƒãƒ¼ãƒ«ã‚„ビルド管ç†ã‚·ã‚¹ãƒ†ãƒ ã®åˆç†çš„㪠ClearCase ã®æ”¯æ´ã‚’æä¾›ã™ã‚‹ãƒ—ラグイン。http://www.rational.com/products/clearcase/index.jsp +Comment[ms]=Plugin yang menyediakan sokongan untuk Rational ClearCase, sistem kawalan versi dan pengurus pembinaan yang besar. http://www.rational.com/products/clearcase/index.jsp +Comment[nds]=En Moduul, dat Ãœnnerstütten för "Rational ClearCase" praatstellt, en groot Verschoonkuntrull- un Opstellen-Pleegsysteem. http://www.rational.com/products/clearcase/index.jsp +Comment[ne]=à¤à¤‰à¤Ÿà¤¾ पà¥à¤²à¤—इन जसले रà¥à¤¯à¤¾à¤¸à¤¨à¤² कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸, à¤à¤‰à¤Ÿà¤¾ ठूलो संसà¥à¤•à¤°à¤£ नियनà¥à¤¤à¥à¤°à¤£ र निरà¥à¤®à¤¾à¤£ वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ पà¥à¤°à¤£à¤¾à¤²à¥€à¤•à¤¾ लागि समरà¥à¤¥à¤¨ पà¥à¤°à¤¦à¤¾à¤¨ गरà¥à¤¦à¤› । http://www.rational.com/products/clearcase/index.jsp +Comment[nl]=Een plugin die ondersteuning biedt voor Rational ClearCase, een omvangrijk versiebeheer en buildmanagement-systeem. Zie http://www.rational.com/products/clearcase/index.jsp +Comment[pl]=Wtyczka udostÄ™pniajÄ…ca obsÅ‚ugÄ™ Rational ClearCase, dużego systemu kontroli wersji i zarzÄ…dzania budowaniem. http://www.rational.com/products/clearcase/index.jsp +Comment[pt]=Um 'plugin' que oferece o suporte para o ClearCase da Rational, um sistema grande de controlo de versões e de gestão de compilações. http://www.rational.com/products/clearcase/index.jsp +Comment[pt_BR]=Um plug-in que fornece suporte para o Rational ClearCase, um grande sistema de controle de versão e gerenciamento de compilação. http://www.rational.com/products/clearcase/index.jsp +Comment[ru]=Модуль поддержки Rational ClearCase, мощной ÑиÑтемы ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð²ÐµÑ€Ñий и ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð¾Ð¼. http://www.rational.com/products/clearcase/index.jsp +Comment[sk]=Modul poskytuje podporu pre Rational ClearCase, riadenie verzià a projektový manažment. +Comment[sl]=Vstavek, ki omogoÄa podporo za Rational ClearCase, velik sistem za upravljanje z razliÄicami in grajenjem. http://www.rational.com/products/clearcase/index.jsp +Comment[sr]=Прикључак који обезбеђује подршку за Rational-ов ClearCase, велики ÑиÑтем за контролу верзија и управљање градњом. http://www.rational.com/products/clearcase/index.jsp +Comment[sr@Latn]=PrikljuÄak koji obezbeÄ‘uje podrÅ¡ku za Rational-ov ClearCase, veliki sistem za kontrolu verzija i upravljanje gradnjom. http://www.rational.com/products/clearcase/index.jsp +Comment[sv]=Ett insticksprogram som stöder Rational ClearCase, ett omfattande versions- och bygghanteringssystem. http://www.rational.com/products/clearcase/index.jsp +Comment[ta]=சொரà¯à®•à®¿ ரெஷியனல௠தெளிவான எழà¯à®¤à¯à®¤à¯ˆ ஆதரிகà¯à®•à¯à®®à¯,கடைசி பதிபà¯à®ªà¯ˆ இயகà¯à®• மறà¯à®±à¯à®®à¯ மேலாளர௠அமைபà¯à®ªà¯ˆ கடà¯à®Ÿ.http://www.rational.com/products/clearcase/index.jsp +Comment[tg]=Модули тарафдори Rational ClearCase, барномаи назораткунандаи калони тафÑир ва идоракунии лоиҳаҳо мебошад.http://www.rational.com/products/clearcase/index.jsp +Comment[tr]=Mantıksal ClearCase, büyük bir kontrol ve yapım yönetim sistemi, için destek saÄŸlayan bir eklenti. http://www.rational.com/products/clearcase/index.jsp +Comment[zh_CN]=æä¾› Rational ClearCase 支æŒï¼Œä¸€ä¸ªå¤§åž‹çš„版本控制和编译管ç†ç³»ç»Ÿã€‚http://www.rational.com/products/clearcase/index.jsp +Comment[zh_TW]=æä¾›æ”¯æ´ Rational ClearCase,大型的版本控制與建立管ç†ç³»çµ±çš„外掛程å¼ã€‚http://www.rational.com/products/clearcase/index.jsp +Name=KDevClearCase +Name[da]=KDevelop ClearCase +Name[de]=Unterstützung für ClearCase (KDevelop) +Name[hi]=के-डेव-कà¥à¤²à¥€à¤¯à¤°-केस +Name[nds]=ClearCase-Ãœnnerstütten för KDevelop +Name[sk]=KDev ClearCase +Name[sv]=KDevelop ClearCase +Name[ta]=KDevதெளிவானஎழà¯à®¤à¯à®¤à¯ +Name[zh_TW]=KDevelop ClearCase +GenericName=ClearCase Integration +GenericName[ca]=Integració amb ClearClase +GenericName[da]=ClearCase integration +GenericName[de]=ClearCase-Integration +GenericName[el]=Ενσωμάτωση ClearCase +GenericName[es]=Integración con ClearClase +GenericName[et]=ClearCase'i integratsioon +GenericName[eu]=ClearCase integrazioa +GenericName[fa]=مجتمع‌سازی ClearCase +GenericName[fr]=Intégration de « ClearCase » +GenericName[ga]=Comhtháthú ClearCase +GenericName[gl]=Integración de ClearCase +GenericName[hi]=कà¥à¤²à¥€à¤¯à¤°-केस इंटीगà¥à¤°à¥‡à¤¶à¤¨ +GenericName[hu]=ClearCase-integráció +GenericName[it]=Integrazione di ClearCase +GenericName[ja]=ClearCase çµ±åˆ +GenericName[ms]=Intergrasi ClearCase +GenericName[nds]=ClearCase-Integreren +GenericName[ne]=कà¥à¤²à¥‡à¤¯à¤°à¤•à¥‡à¤¸ à¤à¤•à¤¿à¤•à¤°à¤£ +GenericName[nl]=ClearCase-integratie +GenericName[pl]=Integracja z ClearCase +GenericName[pt]=Integração com o ClearCase +GenericName[pt_BR]=Integração com o ClearCase +GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ ClearCase +GenericName[sk]=Integrácia ClearCase +GenericName[sl]=Integracija ClearCase +GenericName[sr]=Интеграција ClearCase-а +GenericName[sr@Latn]=Integracija ClearCase-a +GenericName[sv]=Integrering av ClearCase +GenericName[ta]=தெளிவான எழà¯à®¤à¯à®¤à¯ à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®ªà¯à®ªà¯ +GenericName[tg]=ИнтегратÑиÑи ClearCase +GenericName[tr]=ClearCase BütünleÅŸtirmesi +GenericName[zh_CN]=ClearCaseé›†æˆ +GenericName[zh_TW]=ClearCase æ•´åˆ +ServiceTypes=KDevelop/VersionControl +X-KDE-Library=libkdevclearcase +X-KDevelop-Version=5 +X-KDevelop-Properties=VCS,ClearcaseVCS diff --git a/vcs/cvsservice/Makefile.am b/vcs/cvsservice/Makefile.am new file mode 100644 index 00000000..04802374 --- /dev/null +++ b/vcs/cvsservice/Makefile.am @@ -0,0 +1,40 @@ +# Here resides the cvs part + +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets $(all_includes) + +kde_module_LTLIBRARIES = libkdevcvsservice.la +libkdevcvsservice_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkdevcvsservice_la_LIBADD = $(top_builddir)/lib/libkdevelop.la \ + $(top_builddir)/lib/widgets/libkdevwidgets.la $(LIB_KHTML) -lcvsservice $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la + +libkdevcvsservice_la_SOURCES = cvspart.cpp cvspartimpl.cpp cvsformbase.ui \ + cvsform.cpp commitdialogbase.ui commitdlg.cpp cvsoptionswidgetbase.ui \ + cvsoptionswidget.cpp cvsprocesswidget.cpp cvsentry.cpp cvsdir.cpp changelog.cpp \ + cvsoptions.cpp checkoutdialogbase.ui checkoutdialog.cpp tagdialog.cpp tagdialogbase.ui \ + diffdialogbase.ui diffdialog.cpp releaseinputdialogbase.ui releaseinputdialog.cpp \ + cvslogdialog.cpp cvslogpage.cpp cvsdiffpage.cpp diffwidget.cpp jobscheduler.cpp \ + bufferedstringreader.cpp cvsfileinfoprovider.cpp cvsservicedcopIface.skel editorsdialogbase.ui \ + editorsdialog.cpp annotatedialog.cpp annotatepage.cpp annotateview.cpp + +noinst_HEADERS = changelog.h checkoutdialog.h checkoutdialogbase.h commitdlg.h \ + cvsentry.h cvsform.h cvsformbase.h cvsoptions.h cvsoptionswidget.h \ + cvsoptionswidgetbase.h cvspart.h cvspartimpl.h cvsprocesswidget.h tagdialog.h tagdialogbase.h \ + diffdialog.h cvsdir.h cvslogpage.h cvslogdialog.h jobscheduler.h diffwidget.h \ + cvsfileinfoprovider.h cvsservicedcopIface.h bufferedstringreader.h editorsdialog.h \ + editorsdialogbase.h annotatedialog.h annotatepage.h annotateview.h + +METASOURCES = AUTO + +ICONS = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = kdevcvsservice.desktop + +servicepicsdir = $(kde_datadir)/kdevcvsservice/pics +servicepics_DATA = kdev_cvs.png + +rcdir = $(kde_datadir)/kdevcvsservice +rc_DATA = buildcvs.sh + +SUBDIRS = integrator diff --git a/vcs/cvsservice/README b/vcs/cvsservice/README new file mode 100644 index 00000000..0146b60f --- /dev/null +++ b/vcs/cvsservice/README @@ -0,0 +1 @@ +Please read the README.dox file.
\ No newline at end of file diff --git a/vcs/cvsservice/README.dox b/vcs/cvsservice/README.dox new file mode 100644 index 00000000..c89e9422 --- /dev/null +++ b/vcs/cvsservice/README.dox @@ -0,0 +1,82 @@ +/** \class CvsServicePart +This plugin integrates Cervisia (version >= 2.1) cvsservice DCOP service into kdevelop (read FAQ at the bottom +of this document): so, this part _does_ require cvsservice installed on your system: the configure script +in the main source directory should automagically detect the presence of Cervisia and build this plugin. +If Cervisia wasn't installed in $KDEDIR than you need to specify paths for lib and include +files, for example: +<code> + --with-extra-libs=$HOME/kde/lib --with-extra-includes=$HOME/kde/include +</code> +(where $HOME/kde is where I install my own kde stuff so I don't mess with working kde installation) + +<b>WARNING:</b> So, if you have already compiled kdevelop *without* cvsservice and have now +installed cervisia to try this nice piece of software, you need to re-run configure so it +can detect cervisia installation and enable compilation for vcs/cvsservice. + +<b>WARNING:</b> This plugin will quite surely change when the upcoming modifications in Cervisia's own +architecture (separation of core and front-ends and user applications' library) are done (probably +starting from kde >= 3.3). If you want to partecipate please join discussions on the cervisia@kde.org +mailing list. Contributions are always welcome :-) + +<b>WARNING2:</b> If it doesn't compile try to update your cervisia installation. + +Implementation of this component is done by: + - class CvsServicePart, which does provide integration within kdevelop, set-up GUI + integration, forward cvs commands to the implementation (m_impl). It does also + intercepts signals like "new files added to project" and "... removed from ...". + - class CvsServicePartImpl implements the actual feature: more general speaking + functions (like checking for whether files are in repository, provide checks + on file lists, ...). + - class CvsProcessWidget provides output wrapping for commands (ok, it is useful + for debugging too ;-). It simply starts a DCOP job and awaits notification for + its termination. + - class CvsOptions* provide info about the user preferences when executing commands: + settings are stored in myprj.kdevses file, loaded when project is opened and + saved when project is closed. + - There is a bunch of dialog classes for collecting useful data about the operations + one wants to perform: exception to this are the cvslog* classes which do start + cvs jobs independently archiving parallelism with the CvsProcesssWidget. + - CVSDir and CVSEntry provide abstraction for accessing to local CVS information + - CVSFileInfoProvider is an implementation of KDevVCSFileInfoProvider interface + and collects data about files stats: for CVS, both synch (fetch data from local sandbox) + and asynch (fetch from repository server) are working with some minor bugs in the parsing + of 'cvs status' output for the latter. (Sync means that information are collected + from local CVS dirs which do not provide much information; async mean that a + "cvs status <dir-name>" request is launched, output parsed and information returned + to the client in _different_ times). Obviously this stuff requires the client + (actually only the FileTree viewer) to be aware of this feature (see parts/fileview for + additional info). + +\todo + - Fix the "cvs update" function which behave strangely for sub-directories of the main + project dir. + - (> 3.0) Replace the menu entries text with shorter ones + - Fix bugs on bugs.kde.org ;-) + + +\authors <a href="mailto:mario.scalas AT libero.it">Mario Scalas</a> + +\maintainer <a href="mailto:mario.scalas AT libero.it">Mario Scalas</a> + +\feature All that provided by parts/cvs +\feature it is possible to 'add as binary' files to repository +\feature checkout from remote repository ability added to the appwizard/importdlg +\feature should handle :ext: repositories thanks to cvsservice +\feature can tag / un-tag files +\feature can revert and diff between specific releases +\feature can do multiple diff from a common cvs log output text + +\bug bugs in <a href="http://bugs.kde.org/buglist.cgi?product=kdevelop&component=cvs%20part&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=Bug+Number">cvs part component at Bugzilla database</a> + +\requirement <a href="http://www.cvshome.org">CVS</a> >= 1.10.6 +\requirement Cervisia >= 2.1 (from kdesdk package included in <a href="http://www.kde.org">KDE</a> >= 3.2) + +\todo Test with SSH repositories! +\todo Share a common outputview between VCS: CvsProcessWidget should be reworked :-/ +\todo Additional slots for more complex stuff as status, revert, patch creation, ... + +\faq <b>Does cvsservicepart support login with :pserver: or :ext: ?</b> + Well, I dunno ;-) I have no ssh repositories to test so feel free to provide feedback on the subject :-) + Update: Ok, it seems at least one user has tried :ext: reporting it to work (with ssh-agent avoiding some + typing headache ;-)) +*/ diff --git a/vcs/cvsservice/annotatedialog.cpp b/vcs/cvsservice/annotatedialog.cpp new file mode 100644 index 00000000..08d0f24f --- /dev/null +++ b/vcs/cvsservice/annotatedialog.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qvbox.h> +#include <qdir.h> +#include <qstringlist.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +#include <cvsjob_stub.h> +#include <cvsservice_stub.h> + +#include "annotatedialog.h" +#include "annotatepage.h" + +AnnotateDialog::AnnotateDialog( CvsService_stub *cvsService, QWidget *parent, const char *name, int ) + : KDialogBase( Tabbed, i18n("CVS Annotate Dialog"), Close, Close, + parent, name? name : "annotateformdialog", false /*modal*/, true /*separator*/ ), + m_cvsService( cvsService ) +{ + setWFlags( getWFlags() | WDestructiveClose ); + + QVBox *vbox = addVBoxPage( i18n("Annotate") ); + m_cvsAnnotatePage = new AnnotatePage( m_cvsService, vbox ); + + connect( m_cvsAnnotatePage, SIGNAL(requestAnnotate(const QString)), + this, SLOT(slotAnnotate(const QString)) ); +} + +AnnotateDialog::~AnnotateDialog() +{ + kdDebug(9006) << "AnnotateDialog::~AnnotateDialog()" << endl; +} + +void AnnotateDialog::startFirstAnnotate( const QString pathName, const QString revision ) +{ + kdDebug(9006) << "AnnotateDialog::startFirstAnnotate() pathName = " << pathName << + "revision = " << revision << endl; + + //save the filename for any later use + m_pathName = pathName; + + m_cvsAnnotatePage->startAnnotate( pathName, revision ); +} + +void AnnotateDialog::slotAnnotate(const QString rev) +{ + kdDebug(9006) << "AnnotateDialog::slotAnnotate(QString) revision = " << rev << endl; + + QVBox *vbox = addVBoxPage( i18n("Annotate")+" "+rev ); + AnnotatePage * page = new AnnotatePage( m_cvsService, vbox ); + page->startAnnotate(m_pathName, rev); + + connect( page, SIGNAL(requestAnnotate(const QString)), + this, SLOT(slotAnnotate(const QString)) ); +} + +#include "annotatedialog.moc" diff --git a/vcs/cvsservice/annotatedialog.h b/vcs/cvsservice/annotatedialog.h new file mode 100644 index 00000000..7fea14f1 --- /dev/null +++ b/vcs/cvsservice/annotatedialog.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef ANNOTATEDIALOG_H +#define ANNOTATEDIALOG_H + +#include <kdialogbase.h> + +class CvsJob_stub; +class CvsService_stub; +class AnnotatePage; + +/** + * Implementation for the dialog displaying 'cvs annotate' output. + * + * This dialog hold a tab for each revision. The user just needs to + * click a line in the AnnotateView to get the annotate output for + * the selected revision. + * + * @author Robert Gruber <rgruber@users.sourceforge.net> + */ +class AnnotateDialog : public KDialogBase +{ + Q_OBJECT +public: + AnnotateDialog( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 ); + virtual ~AnnotateDialog(); + + /** + * Entrypoint from outside. + * By calling this method, an annotate job is execuded for the given + * file and the specifed a revision. + * The output gets showen in the page which has already been created by the constructor. + * + * You need to call this function in order to set the file which you want to annotate. + * Any further operation will be execucted on the file specified by @param pathName + * + * @param pathName The file for which to run cvs annotate + */ + void startFirstAnnotate( const QString pathName, const QString revision = "" ); + +private slots: + /** + * This slot runs cvs annotate for the given revision. + * The output gets shown in a new page. + * @param rev The revision which will be annotated + */ + void slotAnnotate(const QString rev); + +private: + QString m_pathName; + + AnnotatePage *m_cvsAnnotatePage; + CvsService_stub *m_cvsService; +}; + +#endif diff --git a/vcs/cvsservice/annotatepage.cpp b/vcs/cvsservice/annotatepage.cpp new file mode 100644 index 00000000..fea16ece --- /dev/null +++ b/vcs/cvsservice/annotatepage.cpp @@ -0,0 +1,257 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qlayout.h> +#include <qregexp.h> +#include <qstringlist.h> +#include <qdatetime.h> +#include <qlabel.h> + +#include <kmessagebox.h> +#include <kcursor.h> +#include <klocale.h> +#include <kdebug.h> +#include <krfcdate.h> +#include <klineedit.h> +#include <kpushbutton.h> +#include <kdialogbase.h> +#include <kmessagebox.h> + +#include <dcopref.h> +#include <cvsjob_stub.h> +#include <cvsservice_stub.h> + +#include "annotatepage.h" +#include "annotateview.h" + +AnnotatePage::AnnotatePage( CvsService_stub *cvsService, QWidget *parent, const char *name, int ) + : DCOPObject( "CvsAnnotatePageDCOPIface" ), + QWidget( parent, name? name : "annotateformpage" ), + m_cvsService( cvsService ), m_cvsAnnotateJob( 0 ) +{ + kdDebug(9006) << "AnnotatePage::AnnotatePage()" << endl; + + QLayout *dialogLayout = new QVBoxLayout( this ); + + //First create the top-line where user can choose a revision + QWidget * LayoutWidget = new QWidget( this ); + QHBoxLayout * AnnotateLayout = new QHBoxLayout( LayoutWidget ); + + QLabel * lblRevision = new QLabel( LayoutWidget ); + AnnotateLayout->addWidget( lblRevision ); + lblRevision->setText( tr( "Revision:" ) ); + + m_leRevision = new KLineEdit( LayoutWidget ); + AnnotateLayout->addWidget( m_leRevision ); + + m_btnAnnotate = new KPushButton( LayoutWidget ); + AnnotateLayout->addWidget( m_btnAnnotate ); + m_btnAnnotate->setText( tr( "&Annotate" ) ); + m_btnAnnotate->setAccel( QKeySequence( tr( "Alt+A" ) ) ); + + dialogLayout->add( LayoutWidget ); + + connect( m_btnAnnotate, SIGNAL(clicked()), + this, SLOT(slotNewAnnotate()) ); + connect( m_leRevision, SIGNAL( returnPressed() ), + m_btnAnnotate, SLOT( setFocus() ) ); + + //Nest create the AnnotateView; it will do the actual displaying + m_annotateView = new AnnotateView(this, "annotateview"); + dialogLayout->add( m_annotateView ); +} + +AnnotatePage::~AnnotatePage() +{ + kdDebug(9006) << "AnnotatePage::~Annotate()" << endl; + cancel(); + delete m_cvsAnnotateJob; +} + +void AnnotatePage::startAnnotate( const QString pathName, const QString revision ) +{ + kdDebug(9006) << "AnnotatePage::startAnnotate() pathName = " << pathName << + "revision = " << revision << endl; + + m_leRevision->setText(revision); + + m_pathName = pathName; + + DCOPRef job = m_cvsService->annotate( pathName, revision ); + m_cvsAnnotateJob = new CvsJob_stub( job.app(), job.obj() ); + + // establish connections to the signals of the cvs m_job + connectDCOPSignal( job.app(), job.obj(), "jobExited(bool, int)", "slotJobExited(bool, int)", true ); + connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "slotReceivedOutput(QString)", true ); + + //clear both the outputbuffer and the AnnotateView + m_output = ""; + ((KListView*)m_annotateView)->clear(); + + kdDebug(9006) << "Running: " << m_cvsAnnotateJob->cvsCommand() << endl; + m_cvsAnnotateJob->execute(); +} + +void AnnotatePage::slotJobExited( bool normalExit, int exitStatus ) +{ + kdDebug(9006) << "AnnotatePage::slotJobExited(bool, int)" << endl; + + if (!normalExit) + { + KMessageBox::sorry( this, i18n("Annotate failed with exitStatus == %1").arg( exitStatus), i18n("Annotate Failed") ); + return; + } + + //split the collected output and pass the lines to the parser function + QStringList lines = QStringList::split("\n", m_output); + parseAnnotateOutput(lines); +} + +void AnnotatePage::slotReceivedOutput( QString someOutput ) +{ + kdDebug(9006) << "AnnotatePage::slotReceivedOutput(QString)" << endl; + m_output += someOutput; +} + +void AnnotatePage::slotReceivedErrors( QString ) +{ + kdDebug(9006) << "AnnotatePage::slotReceivedErrors(QString)" << endl; +} + +void AnnotatePage::cancel() +{ + if (m_cvsAnnotateJob && m_cvsAnnotateJob->isRunning()) + m_cvsAnnotateJob->cancel(); +} + +void AnnotatePage::parseAnnotateOutput(QStringList& lines) +{ + kdDebug(9006) << "AnnotatePage::parseAnnotateOutput(QStringList)" << endl; + + /** + * First we need to parse the output of "cvs log" which the dcop-interface delivers + * everytime annotate is requested. + * The QMap m_comments stores the revisions together with the matching comments. + * The comments will be passed to the AnnotateView in order to display them as QToolTip + */ + QString line, comment, rev; + + enum { Begin, Tags, Admin, Revision, + Author, Branches, Comment, Finished } state; + + QStringList::Iterator it = lines.begin(); + state = Begin; + do + { + line = *it; + + switch( state ) + { + case Begin: + if( line == "symbolic names:" ) + state = Tags; + break; + case Tags: + if( line[0] != '\t' ) + state = Admin; + break; + case Admin: + if( line == "----------------------------" ) + state = Revision; + break; + case Revision: + rev = line.section(' ', 1, 1); + state = Author; + break; + case Author: + state = Branches; + break; + case Branches: + if( !line.startsWith("branches:") ) + { + state = Comment; + comment = line; + } + break; + case Comment: + if( line == "----------------------------" ) + state = Revision; + else if( line == "=============================================================================" ) + state = Finished; + if( state == Comment ) + comment += QString("\n") + line; + else + m_comments[rev] = comment; + break; + case Finished: + ; + } + + if (state == Finished) + break; + } while( ++it != lines.end()); + + // move forward until we get to the actual output of "cvs annotate" + bool notEof = true; + while( notEof && !(*it).startsWith("*****") ) { + notEof = (++it != lines.end()); + } + + //if the upper loop hit the ent of the list, this can only mean, that + //the selected revision is unknown to CVS + if (!notEof) { + KMessageBox::error(this, i18n("The selected revision does not exist.")); + ((KListView*)m_annotateView)->clear(); + return; + } + ++it; + + QString author, content; + QString oldRevision = ""; //we always store the last revision to recognice... + bool changeColor = false; //...when the AnnotateView needs to change the coloring + QDateTime logDate; + + do + { + line = *it; + + //the log date should be printed according to the user's global setting + //so we pass it as QDateTime to the AnnotateView below + QString dateString = line.mid(23, 9); + if( !dateString.isEmpty() ) + logDate.setTime_t(KRFCDate::parseDate(dateString), Qt::UTC); + + rev = line.left(13).stripWhiteSpace(); + author = line.mid(14, 8).stripWhiteSpace(); + content = line.mid(35, line.length()-35); + + comment = m_comments[rev]; + if( comment.isNull() ) + comment = ""; + + if( rev != oldRevision ) + { + oldRevision = rev; + changeColor = !changeColor; + } + + //finished parsing the annotate line + //We pass the needed data to the AnnotateView + m_annotateView->addLine(rev, author, logDate, content, m_comments[rev], changeColor); + } while (++it != lines.end()); +} + +void AnnotatePage::slotNewAnnotate() +{ + startAnnotate(m_pathName, m_leRevision->text()); +} + +#include "annotatepage.moc" diff --git a/vcs/cvsservice/annotatepage.h b/vcs/cvsservice/annotatepage.h new file mode 100644 index 00000000..2a062804 --- /dev/null +++ b/vcs/cvsservice/annotatepage.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef ANNOTATEPAGE_H +#define ANNOTATEPAGE_H + +#include "cvsservicedcopIface.h" +#include <qwidget.h> +#include <qmap.h> +#include <qlistview.h> + +class CvsJob_stub; +class CvsService_stub; +class QTextBrowser; +class AnnotateView; +class QStringList; +class KLineEdit; +class KPushButton; + +/** + * Implementation for the page displaying 'cvs annotate' output. + * To the top of the page the user can enter a revision and request + * a annotate run for it. + * The main widget of a page is the AnnotateView. It holds the output + * of the cvs annotate job. See there for further detail. + * + * @author Robert Gruber <rgruber@users.sourceforge.net> + */ +class AnnotatePage : public QWidget, virtual public CVSServiceDCOPIface +{ + Q_OBJECT + + friend class AnnotateDialog; + friend class AnnotateView; + +public: + AnnotatePage( CvsService_stub *cvsService, QWidget *parent=0, const char *name=0, int flags=0 ); + virtual ~AnnotatePage(); + + /** + * Call cvs annotate for the given file and revistion. + * @param pathName The filename to annotate + * @param revision The CVS revision number + */ + void startAnnotate( const QString pathName, const QString revision="" ); + + /** + * Cancels the current operation if any + */ + void cancel(); + +signals: + /** + * This signal is ment to be emitted by the nested AnnotateView. + * The dialog that holds this page catches it in order to create + * a new page with the annotate output for the given revision. + * @param rev The revision for which a new annotate run is requested + */ + void requestAnnotate(const QString rev); + +private slots: + // DCOP Iface + virtual void slotJobExited( bool normalExit, int exitStatus ); + virtual void slotReceivedOutput( QString someOutput ); + virtual void slotReceivedErrors( QString someErrors ); + + /** + * This slot is connected to the button next to m_leRevision. + * It clears the AnnotateView and reruns cvs annotate with the + * revision the user entered into m_leRevision + */ + void slotNewAnnotate(); + +private: + /** + * This method is executed after the cvs annotate job finished. + * It parses the output and passes it to the AnnotateView + */ + void parseAnnotateOutput(QStringList& lines); + + + /** + * This is the output buffer for the cvs annotate job. + * Everytime slotReceivedOutput() is called by dcop + * we append the gained data to this buffer. + */ + QString m_output; + /** + * This is the AnnotateView. It gets nested into this page. + */ + AnnotateView *m_annotateView; + /** + * The file for which this page holds the annotate output. + */ + QString m_pathName; + /** + * Maps the checkin comments to revision numbers + */ + QMap<QString, QString> m_comments; + + /** + * With this KLineEdit and the KPushButton next to it + * the user can rerun cvs annotate for any revision he + * enters into this KLineEdit. + */ + KLineEdit *m_leRevision; + /** + * With this KPushButton the user can rerun cvs annotate + * for the revision he entered into m_leRevision + */ + KPushButton *m_btnAnnotate; + + CvsService_stub *m_cvsService; + CvsJob_stub *m_cvsAnnotateJob; +}; + +#endif diff --git a/vcs/cvsservice/annotateview.cpp b/vcs/cvsservice/annotateview.cpp new file mode 100644 index 00000000..93a2a46d --- /dev/null +++ b/vcs/cvsservice/annotateview.cpp @@ -0,0 +1,221 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This file has been taken from cervisia an adapted to fit my needs: * + * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de> * + * Copyright (c) 2003-2005 André Wöbbeking <Woebbeking@web.de> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "annotateview.h" + +#include <qheader.h> +#include <qdatetime.h> +#include <qpainter.h> +#include <kglobalsettings.h> +#include <kglobal.h> +#include <klocale.h> +#include <kdebug.h> + +#include "annotatepage.h" + +class AnnotateViewItem : public QListViewItem +{ + friend class AnnotateView; + +public: + enum { LineNumberColumn, AuthorColumn, DateColumn,ContentColumn }; + + AnnotateViewItem(AnnotateView *parent, QString rev, QString author, + QDateTime date, QString content, QString comment, + bool odd, int linenumber); + + virtual int compare(QListViewItem *item, int col, bool ascending) const; + virtual int width(const QFontMetrics &, const QListView *, int col) const; + virtual QString text(int col) const; + virtual void paintCell(QPainter *, const QColorGroup &, int, int, int); + +private: + QString m_revision; + QString m_author; + QString m_content; + QString m_comment; + QDateTime m_logDate; + bool m_odd; + int m_lineNumber; + + static const int BORDER; +}; + + +const int AnnotateViewItem::BORDER = 4; + + +AnnotateViewItem::AnnotateViewItem(AnnotateView *parent, QString rev, + QString author, QDateTime date, QString content, QString comment, + bool odd, int linenumber) + : QListViewItem(parent) + , m_revision(rev) + , m_author(author) + , m_content(content) + , m_comment(comment) + , m_logDate(date) + , m_odd(odd) + , m_lineNumber(linenumber) +{} + + +int AnnotateViewItem::compare(QListViewItem *item, int, bool) const +{ + int linenum1 = m_lineNumber; + int linenum2 = static_cast<AnnotateViewItem*>(item)->m_lineNumber; + + return (linenum2 > linenum1)? -1 : (linenum2 < linenum1)? 1 : 0; +} + + +QString AnnotateViewItem::text(int col) const +{ + switch (col) + { + case LineNumberColumn: + return QString::number(m_lineNumber); + case AuthorColumn: + return (m_revision + QChar(' ') + m_author); + case DateColumn: + return KGlobal::locale()->formatDate(m_logDate.date(), true); + case ContentColumn: + return m_content; + default: + ; + }; + + return QString::null; +} + + +void AnnotateViewItem::paintCell(QPainter *p, const QColorGroup &, int col, int width, int align) +{ + QColor backgroundColor; + + switch (col) + { + case LineNumberColumn: + backgroundColor = KGlobalSettings::highlightColor(); + p->setPen(KGlobalSettings::highlightedTextColor()); + break; + default: + backgroundColor = m_odd ? KGlobalSettings::baseColor() + : KGlobalSettings::alternateBackgroundColor(); + p->setPen(KGlobalSettings::textColor()); + break; + }; + + p->fillRect(0, 0, width, height(), backgroundColor); + + QString str = text(col); + if (str.isEmpty()) + return; + + if (align & (AlignTop || AlignBottom) == 0) + align |= AlignVCenter; + + p->drawText(BORDER, 0, width - 2*BORDER, height(), align, str); +} + + +int AnnotateViewItem::width(const QFontMetrics &fm, const QListView *, int col) const +{ + return fm.width(text(col)) + 2*BORDER; +} + + +/******************************************************************************/ +/*****************Definition of class AnnotateView ****************************/ +/******************************************************************************/ + +AnnotateView::AnnotateView(AnnotatePage *parent, const char *name) + : KListView(parent, name), QToolTip( viewport() ), + m_page(parent) +{ + setFrameStyle(QFrame::WinPanel | QFrame::Sunken); + setAllColumnsShowFocus(true); + setShowToolTips(false); + header()->hide(); + + addColumn(QString::null); + addColumn(QString::null); + addColumn(QString::null); + addColumn(QString::null); + + setSorting(AnnotateViewItem::LineNumberColumn); + setColumnAlignment(AnnotateViewItem::LineNumberColumn, Qt::AlignRight); + + connect( this, SIGNAL(executed(QListViewItem*)), + this, SLOT(itemClicked(QListViewItem*)) ); +} + + +void AnnotateView::addLine(QString rev, QString author, QDateTime date, + QString content, QString comment, bool odd) +{ + new AnnotateViewItem(this, rev, author, date, content, comment, + odd, childCount()+1); +} + + +QSize AnnotateView::sizeHint() const +{ + QFontMetrics fm(fontMetrics()); + return QSize(100 * fm.width("0"), 20 * fm.lineSpacing()); +} + + +void AnnotateView::maybeTip( const QPoint & p ) +{ + AnnotateViewItem * item = dynamic_cast<AnnotateViewItem*>( itemAt( p ) ); + if (!item) + return; + + const int column(header()->sectionAt(p.x())); + if (column != AnnotateViewItem::AuthorColumn && + column != AnnotateViewItem::DateColumn) { + return; + } + + QRect r = itemRect( item ); + //get the dimension of the author + the date column + QRect headerRect = header()->sectionRect(AnnotateViewItem::AuthorColumn); + headerRect = headerRect.unite(header()->sectionRect(AnnotateViewItem::DateColumn)); + + r.setLeft(headerRect.left()); + r.setWidth(headerRect.width()); + + if (r.isValid()) + { + tip( r, "<nobr><b>"+item->text(AnnotateViewItem::AuthorColumn)+"</b></nobr><br>" + "<nobr>"+item->text(AnnotateViewItem::DateColumn)+"</nobr>" + "<pre>"+item->m_comment+"</pre>"); + } +} + +void AnnotateView::itemClicked(QListViewItem *item) +{ + kdDebug(9006) << "itemClicked()" << endl; + + AnnotateViewItem * line = dynamic_cast<AnnotateViewItem*>(item); + if (line) { + kdDebug(9006) << "requesting annotate for revision " << line->m_revision << endl; + emit m_page->requestAnnotate(line->m_revision); + } else { + kdDebug(9006) << "This is not an AnnotateViewItem" << endl; + } +} + +#include "annotateview.moc" diff --git a/vcs/cvsservice/annotateview.h b/vcs/cvsservice/annotateview.h new file mode 100644 index 00000000..6c9cded9 --- /dev/null +++ b/vcs/cvsservice/annotateview.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2005 by Robert Gruber * + * rgruber@users.sourceforge.net * + * * + * This file has been taken from cervisia an adapted to fit my needs: * + * Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de> * + * Copyright (c) 2003-2005 André Wöbbeking <Woebbeking@web.de> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef ANNOTATEVIEW_H +#define ANNOTATEVIEW_H + + +#include <klistview.h> +#include <qtooltip.h> + +class QDateTime; +class AnnotatePage; + +/** + * This is the main widget of each page. + * It shows the user the output of cvs annotate. + * The user can click any line of this view in order + * to get a new page which shows the annotate output + * of the clicked revision. + */ +class AnnotateView : public KListView, public QToolTip +{ + Q_OBJECT + +public: + + explicit AnnotateView(AnnotatePage *parent, const char *name=0 ); + + void addLine(QString rev, QString author, QDateTime date, QString content, + QString comment, bool odd); + + virtual QSize sizeHint() const; + void maybeTip( const QPoint & p ); + +private: + AnnotatePage * m_page; + +public slots: + void itemClicked(QListViewItem *item); +}; + + +#endif diff --git a/vcs/cvsservice/bufferedstringreader.cpp b/vcs/cvsservice/bufferedstringreader.cpp new file mode 100644 index 00000000..5c2151fc --- /dev/null +++ b/vcs/cvsservice/bufferedstringreader.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "bufferedstringreader.h" + +/////////////////////////////////////////////////////////////////////////////// +// class CvsOptions +/////////////////////////////////////////////////////////////////////////////// + +BufferedStringReader::BufferedStringReader() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +BufferedStringReader::~BufferedStringReader() +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +QStringList BufferedStringReader::process( const QString &otherChars ) +{ + // Add to previous buffered chars + m_stringBuffer += otherChars; + QStringList strings; + // Now find all the basic strings in the buffer + int pos; + while ( (pos = m_stringBuffer.find('\n')) != -1) + { + QString line = m_stringBuffer.left( pos ); + if (!line.isEmpty()) + { + strings.append( line ); + } + m_stringBuffer = m_stringBuffer.right( m_stringBuffer.length() - pos - 1 ); + } + return strings; +} diff --git a/vcs/cvsservice/bufferedstringreader.h b/vcs/cvsservice/bufferedstringreader.h new file mode 100644 index 00000000..1f96c0d1 --- /dev/null +++ b/vcs/cvsservice/bufferedstringreader.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef BUFFEREDSTRINGREADER_H +#define BUFFEREDSTRINGREADER_H + +#include <qstringlist.h> + +class CvsServicePart; +class KConfig; +class KDevProject; + +/* This class helps when we have to collect a string list from a text + * stream, just as many cvs commands do. The problem is that the these commands + * does not provide strings as we need: often a sent string is received + * broken in two pieces and so we need a way to rebuild it. This class provide an + * abstraction for avoiding this. + * @author Mario Scalas <mario.scalas@libero.it> +*/ +class BufferedStringReader +{ +public: + BufferedStringReader(); + virtual ~BufferedStringReader(); + + /** + * Add the specified characters to current buffered ones and grab + * as many '\n'-terminated strings as found. + * @param otherChars additional chars to be added to the buffer + */ + QStringList process( const QString &otherChars ); +private: + QString m_stringBuffer; +}; + +#endif // BUFFEREDSTRINGREADER_H diff --git a/vcs/cvsservice/buildcvs.sh b/vcs/cvsservice/buildcvs.sh new file mode 100644 index 00000000..9c7c95c4 --- /dev/null +++ b/vcs/cvsservice/buildcvs.sh @@ -0,0 +1,25 @@ +#! /bin/sh + +# 3 arguments : +# - relative path to the local directory (e.g. ".") +# - module name (e.g. "plop") +# - root repository (e.g. ":ext:me@host:/path/to/cvsroot") + +mkcvs() { + rm -rf $1/CVS + mkdir -p $1/CVS + + echo $2 > $1/CVS/Repository + echo $3 > $1/CVS/Root + + for i in $1/*; do + if [ -d $i -a $i != $1/CVS ]; then + echo "D/"`basename $i`"////" >> $1/CVS/Entries + mkcvs "$i" "$2/"`basename $i` $3 + elif [ -f $i ]; then + echo "/"`basename $i`"/1.1.1.1/"`date +"%a %b %d %T %Y//"` >> $1/CVS/Entries + fi + done +} + +mkcvs $1 $2 $3 diff --git a/vcs/cvsservice/changelog.cpp b/vcs/cvsservice/changelog.cpp new file mode 100644 index 00000000..a63a2b92 --- /dev/null +++ b/vcs/cvsservice/changelog.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qdatetime.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <kemailsettings.h> + +#include "changelog.h" + +ChangeLogEntry::ChangeLogEntry() +{ + KEMailSettings emailConfig; + emailConfig.setProfile( emailConfig.defaultProfileName() ); + authorEmail = emailConfig.getSetting( KEMailSettings::EmailAddress ); + authorName = emailConfig.getSetting( KEMailSettings::RealName ); + + QDate currDate = QDate::currentDate(); + date = currDate.toString( "yyyy-MM-dd" ); +} + +ChangeLogEntry::~ChangeLogEntry() +{ +} + +void ChangeLogEntry::addLine( const QString &aLine ) +{ + lines << aLine; +} + +void ChangeLogEntry::addLines( const QStringList &someLines ) +{ + lines += someLines; +} + +void streamCopy( QTextStream &is, QTextStream &os ) +{ + while (!is.eof()) + os << is.readLine() << "\n"; // readLine() eats '\n' !! +} + +void ChangeLogEntry::addToLog( const QString &logFilePath, const bool prepend, const QString &startLineString ) +{ + if (prepend) // add on head + { + QString fakeLogFilePath = logFilePath + ".fake"; + + QFile fakeFile( fakeLogFilePath ); + QFile changeLogFile( logFilePath ); + { + if (!fakeFile.open( IO_WriteOnly | IO_Append)) + return; + + if (changeLogFile.open( IO_ReadOnly )) // A Changelog already exist + { + QTextStream is( &changeLogFile ); + QTextStream os( &fakeFile ); + + // Put current entry + os << toString( startLineString ); + // Write the rest of the change log file + streamCopy( is, os ); + } + else // ChangeLog doesn't exist: just write our entry + { + QTextStream t( &fakeFile ); + t << toString( startLineString ); + } + fakeFile.close(); + changeLogFile.close(); + } + // Ok, now we have the change log we need in fakeLogFilePath: we should ask for a + // 'mv fakeLogFilePath logFilePath'-like command ... :-/ + if (!fakeFile.open( IO_ReadOnly )) + return; + + if (changeLogFile.open( IO_WriteOnly )) + { + QTextStream os( &changeLogFile ); + QTextStream is( &fakeFile ); + + // Write the rest of the change log file + streamCopy( is, os ); + } + fakeFile.close(); + fakeFile.remove(); // fake changelog is no more needed! + changeLogFile.close(); + } + else // add on tail + { + QFile f( logFilePath ); + if (!f.open( IO_WriteOnly | IO_Append)) + return; + + QTextStream t( &f ); + t << toString( startLineString ); + } +} + +QString ChangeLogEntry::toString( const QString &startLineString ) const +{ + QString header = date + " " + authorName + " <" + authorEmail + ">\n"; + + return header + startLineString + lines.join( "\n" + startLineString ) + "\n\n"; +} diff --git a/vcs/cvsservice/changelog.h b/vcs/cvsservice/changelog.h new file mode 100644 index 00000000..3d512f95 --- /dev/null +++ b/vcs/cvsservice/changelog.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef CHANGELOG_H +#define CHANGELOG_H + +#include <qstringlist.h> + +/** +A class which abstracts the building of an entry in the ChangeLog file (it formats name, e-mail and text). + +@author Mario Scalas +*/ +struct ChangeLogEntry +{ +public: + ChangeLogEntry(); + ~ChangeLogEntry(); + + //! Add a single line to the lines for this entry + void addLine( const QString &aLine ); + //! Add a bunch of lines for this entry + void addLines( const QStringList &someLines ); + //! Pretty format for this entry: you may insert a line tag (such as tab ("\t") or 4 spaces (" ") + //! or whatever you want (such as "\t * ") + QString toString( const QString &startLineString = QString::null ) const; + //! Once the entry is completed one would like to write on a file! (You may add on start of file + //! prepend == true, or append on tail (prepend == false) + void addToLog( const QString &logFilePath, const bool prepend = true, const QString &startLineString = "\t" ); + + QString authorName, + authorEmail, + date; + QStringList lines; +}; + +#endif diff --git a/vcs/cvsservice/checkoutdialog.cpp b/vcs/cvsservice/checkoutdialog.cpp new file mode 100644 index 00000000..7fb9455c --- /dev/null +++ b/vcs/cvsservice/checkoutdialog.cpp @@ -0,0 +1,276 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include <qcheckbox.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qfile.h> +#include <qtextstream.h> + +#include <klistview.h> +#include <kurlrequester.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <kcursor.h> +#include <kdebug.h> +#include <kapplication.h> +#include <klineedit.h> + +#include <dcopref.h> +#include <cvsjob_stub.h> +#include <repository_stub.h> +#include <cvsservice_stub.h> + +#include "checkoutdialogbase.h" + +#include "checkoutdialog.h" + +/////////////////////////////////////////////////////////////////////////////// +// Constants +/////////////////////////////////////////////////////////////////////////////// + +const QString SSS( ":" ); // Server String Separator :) + +/////////////////////////////////////////////////////////////////////////////// +// class ModuleListViewItem +/////////////////////////////////////////////////////////////////////////////// + +class ModuleListViewItem : public KListViewItem +{ +public: + ModuleListViewItem( KListView *listview, + const QString &moduleAlias, const QString &moduleRealPath ) + : KListViewItem( listview ) + { + setAlias( moduleAlias ); + setRealPath( moduleRealPath ); + } + + void setAlias( const QString &aName ) { setText( 0, aName); } + QString alias() const { return text(0); } + void setRealPath( const QString &aRealPath ) { setText(1, aRealPath); } + QString realPath() const { return text(1); } + +// virtual QString text() const { return name(); } +}; + +/////////////////////////////////////////////////////////////////////////////// +// class CheckoutDialog +/////////////////////////////////////////////////////////////////////////////// + +CheckoutDialog::CheckoutDialog( CvsService_stub *cvsService, + QWidget *parent, const char *name, WFlags ) : + DCOPObject( "CheckoutDialogDCOPIface" ), + KDialogBase( parent, name? name : "checkoutdialog", true, i18n("CVS Checkout"), + Ok | Cancel, Ok, true ), + m_service( cvsService ), m_job( 0 ) +{ + m_base = new CheckoutDialogBase( this, "checkoutdialogbase" ); + setMainWidget( m_base ); + + connect( m_base->fetchModulesButton, SIGNAL(clicked()), + this, SLOT(slotFetchModulesList()) ); + connect( m_base->modulesListView, SIGNAL(executed(QListViewItem*)), + this, SLOT(slotModuleSelected(QListViewItem*)) ); + + // Avoid displaying 'file:/' when displaying the file + m_base->workURLRequester->setShowLocalProtocol( false ); + m_base->workURLRequester->setMode( KFile::Directory ); + + // Grab the entries from $HOME/.cvspass + fetchUserCvsRepositories(); + // And suggest to use the default projects dir set in KDevelop's preferences + KConfig *config = kapp->config(); + config->setGroup("General Options"); + QString defaultProjectsDir = config->readPathEntry("DefaultProjectsDir", QDir::homeDirPath()+"/"); + setWorkDir( defaultProjectsDir ); +} + +/////////////////////////////////////////////////////////////////////////////// + +CheckoutDialog::~CheckoutDialog() +{ + delete m_job; +} + +/////////////////////////////////////////////////////////////////////////////// + +QString CheckoutDialog::serverPath() const +{ + return m_base->serverPaths->currentText(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::fillServerPaths( const QStringList &serverPaths ) +{ + m_base->serverPaths->insertStringList( serverPaths ); +} + +/////////////////////////////////////////////////////////////////////////////// + +QString CheckoutDialog::workDir() const +{ + return m_base->workURLRequester->url(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::setWorkDir( const QString &aDir ) +{ + m_base->workURLRequester->setURL( aDir ); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool CheckoutDialog::pruneDirs() const +{ + return m_base->pruneDirsCheck->isChecked(); +} + +/////////////////////////////////////////////////////////////////////////////// + +QString CheckoutDialog::tag() const +{ + return m_base->tagEdit->text(); +} + +/////////////////////////////////////////////////////////////////////////////// + +QString CheckoutDialog::module() const +{ + return m_base->moduleEdit->text(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::slotFetchModulesList() +{ + setCursor( KCursor::waitCursor() ); + + if (serverPath().isEmpty() || workDir().isEmpty()) + return; + + DCOPRef job = m_service->moduleList( serverPath() ); + if (!m_service->ok()) + return; + + m_job = new CvsJob_stub( job.app(), job.obj() ); + // We only need to know when it finishes and then will grab the output + // by using m_job->output() :-) + connectDCOPSignal( job.app(), job.obj(), "jobFinished(bool,int)", "slotJobExited(bool,int)", true ); + connectDCOPSignal( job.app(), job.obj(), "receivedStdout(QString)", "receivedOutput(QString)", true ); + + kdDebug() << "Running: " << m_job->cvsCommand() << endl; + m_job->execute(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::slotJobExited( bool /*normalExit*/, int /*exitStatus*/ ) +{ + kdDebug(9006) << "CheckoutDialog::slotModulesListFetched() here!" << endl; + + kdDebug(9006) << "Received: " << m_job->output().join( "\n" ) << endl; + +// m_base->modulesListView->insertStringList( m_job->output() ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::slotReceivedOutput( QString someOutput ) +{ + kdDebug( 9006 ) << " Received output: " << someOutput << endl; + + setCursor( KCursor::arrowCursor() ); + + // Fill the modules KListView if the list obtained is not empty + // QStringList modules = m_job->output(); + QStringList modules = QStringList::split( "\n", someOutput ); + if (modules.count() <= 0) + return; + + QStringList::iterator it = modules.begin(); + for ( ; it != modules.end(); ++it ) + { + QStringList l = QStringList::split( " ", (*it) ); + // Now, l[0] is the module name, l[1] is ... another string ;-) + new ModuleListViewItem( m_base->modulesListView, l[0], l[1] ); + } +} + +void CheckoutDialog::slotReceivedErrors( QString someErrors ) +{ + kdDebug( 9006 ) << " Received errors: " << someErrors << endl; +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::slotModuleSelected( QListViewItem * ) +{ + ModuleListViewItem *aModuleItem = static_cast<ModuleListViewItem*>( + m_base->modulesListView->selectedItem() + ); + if (!aModuleItem) + return; + + m_base->moduleEdit->setText( aModuleItem->alias() ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::fetchUserCvsRepositories() +{ + QStringList repositories; + + QFile cvspass( QDir::homeDirPath() + QDir::separator() + ".cvspass" ); + if (!cvspass.open( IO_ReadOnly )) + return; + QByteArray data = cvspass.readAll(); + cvspass.close(); + + QTextIStream istream( data ); + // Entries are like: + // /1 :pserver:marios@cvs.kde.org:2401/home/kde Ahz:UIK?=d ? + // /1 :pserver:mario@xamel:2401/home/cvsroot aJT_d'K?=d ? + while (!istream.eof()) { + QString line = istream.readLine(); + QStringList lineElements = QStringList::split( " ", line ); + if (lineElements.count() > 1) { + repositories << lineElements[ 1 ]; + } + } + + fillServerPaths( repositories ); +} + +/////////////////////////////////////////////////////////////////////////////// + +void CheckoutDialog::slotOk() +{ + QString errorMessage = QString::null; + + if (!(workDir().length() > 0) && QFile::exists( workDir() )) + errorMessage = i18n( "Please, choose a valid working directory" ); + else if (!(serverPath().length() > 0)) + errorMessage = i18n( "Please, choose a CVS server." ); + else if (!(module().length() > 0)) + errorMessage = i18n( "Please, fill the CVS module field." ); + + if (errorMessage.isNull()) + KDialogBase::slotOk(); + else + KMessageBox::error( this, errorMessage ); +} + + +#include "checkoutdialog.moc" diff --git a/vcs/cvsservice/checkoutdialog.h b/vcs/cvsservice/checkoutdialog.h new file mode 100644 index 00000000..597a806a --- /dev/null +++ b/vcs/cvsservice/checkoutdialog.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2003 by Mario Scalas * + * mario.scalas@libero.it * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef CHECKOUTDIALOG_H +#define CHECKOUTDIALOG_H + +#include <kdialogbase.h> +#include "cvsservicedcopIface.h" + +class CvsService_stub; +class CvsJob_stub; +class CheckoutDialogBase; +class QListViewItem; +//class QStringList; + +/** +* This dialog widget will collect all useful informazion about the module the +* user want to to check-out from a remote repository. +* +* @author Mario Scalas +*/ +class CheckoutDialog : public KDialogBase, virtual public CVSServiceDCOPIface +{ + Q_OBJECT +public: + CheckoutDialog( CvsService_stub *cvsService, QWidget *parent = 0, + const char *name = 0, WFlags f = 0 ); + virtual ~CheckoutDialog(); + + virtual void slotOk(); + + /** + * @return a server path string (i.e. :pserver:marios@cvs.kde.org:/home/kde) + */ + QString serverPath() const; + /** + * @param serverPaths a list of server location to use when filling the widget + */ + void fillServerPaths( const QStringList &serverPaths ); + /** + * @return the directory which the user has fetched the module in + */ + QString workDir() const; + /** + * @param aDir directory which fetched modules will be put in (ending with '/') + */ + void setWorkDir( const QString &aDir ); + /** + * @return the module the user has chosen to check-out from repository + */ + QString module() const; + /** + * @return + */ + bool pruneDirs() const; + /** + * @return + */ + QString tag() const; + +private slots: + void slotModuleSelected( QListViewItem *item ); + void slotFetchModulesList(); + // DCOP Iface + virtual void slotJobExited( bool normalExit, int exitStatus ); + virtual void slotReceivedOutput( QString someOutput ); + virtual void slotReceivedErrors( QString someErrors ); + +private: + /** + * Retrives the known servers from $HOME/.cvspass file + * @return a list of server locations (:pserver:user@server.somewhere:/cvsroot) + */ + void fetchUserCvsRepositories(); + + CvsService_stub *m_service; + CvsJob_stub *m_job; + + CheckoutDialogBase *m_base; +}; + +#endif diff --git a/vcs/cvsservice/checkoutdialogbase.ui b/vcs/cvsservice/checkoutdialogbase.ui new file mode 100644 index 00000000..f0ebdf8d --- /dev/null +++ b/vcs/cvsservice/checkoutdialogbase.ui @@ -0,0 +1,312 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CheckoutDialogBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>CheckoutDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>671</width> + <height>538</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>3</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>CVS Server Configuration</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Configuration</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>&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> diff --git a/vcs/perforce/Makefile.am b/vcs/perforce/Makefile.am new file mode 100644 index 00000000..e684e2f0 --- /dev/null +++ b/vcs/perforce/Makefile.am @@ -0,0 +1,19 @@ +# Here resides the cvs part + +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/util $(all_includes) + +kde_module_LTLIBRARIES = libkdevperforce.la +libkdevperforce_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkdevperforce_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la + +libkdevperforce_la_SOURCES = perforcepart.cpp commitdlg.cpp + +METASOURCES = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = kdevperforce.desktop + +rcdir = $(kde_datadir)/kdevperforce + +SUBDIRS = integrator diff --git a/vcs/perforce/README b/vcs/perforce/README new file mode 100644 index 00000000..731741e1 --- /dev/null +++ b/vcs/perforce/README @@ -0,0 +1,3 @@ +Please read the on-line, automaticaly updated KDevelop API documentation at: +http://www.kdevelop.org +or read the README.dox file. diff --git a/vcs/perforce/README.dox b/vcs/perforce/README.dox new file mode 100644 index 00000000..6a0ae647 --- /dev/null +++ b/vcs/perforce/README.dox @@ -0,0 +1,15 @@ +/** \class PerforcePart +Integrates the perforce version managment system into KDevelop. + +\authors <a href="mailto:bernd AT kdevelop.org">Bernd Gehrmann</a> Copyright (C) 1999-2001 +\authors <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a> Copyright (C) 2002-2003 + +\maintainer <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a> + +\feature edit, revert and submit +\feature use the diff frontend (also removes the crappy perforce diff headers) +\feature Uses KAction, so you can assign your favourite shortcuts to the commands. + +\requirement Perforce 2003.1 http://www.perforce.com/perforce/products.html + +*/ diff --git a/vcs/perforce/commitdlg.cpp b/vcs/perforce/commitdlg.cpp new file mode 100644 index 00000000..8a9be561 --- /dev/null +++ b/vcs/perforce/commitdlg.cpp @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (C) 1999, 2000 by Bernd Gehrmann * + * bernd@kdevelop.org * + * Modified for perforce 2002 by Harald Fernengel <harry@kdevelop.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "commitdlg.h" + +#include <qlayout.h> +#include <qlabel.h> +#include <qtextedit.h> +#include <qpushbutton.h> +#include <qregexp.h> +#include <kprocess.h> +#include <kapplication.h> +#include <klocale.h> +#include <klineedit.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include <stdlib.h> + +#include "execcommand.h" + +CommitDialog::CommitDialog( QWidget *parent, const char *name ) + : KDialogBase( parent, name, true, i18n("Perforce Submit"), Ok|Cancel|Details ) +{ + QWidget *w = new QWidget( this, "main widget" ); + setMainWidget( w ); + + edit = new QTextEdit( w ); + QFontMetrics fm(edit->fontMetrics()); + edit->setMinimumSize(fm.width("0")*40, fm.lineSpacing()*3); + + QVBoxLayout *layout = new QVBoxLayout( w, 0, spacingHint() ); + QLabel *editLabel = new QLabel(i18n("&Enter description:"), w); + editLabel->setBuddy(edit); + layout->addWidget(editLabel); + layout->addWidget(edit); + + w = new QWidget( this, "details widget" ); + + clientEdit = new KLineEdit( w ); + userEdit = new KLineEdit( w ); + filesBox = new KListBox( w ); + + layout = new QVBoxLayout( w, 0, spacingHint() ); + QLabel *clientLabel = new QLabel(i18n("C&lient:"), w); + clientLabel->setBuddy(clientEdit); + layout->addWidget(clientLabel); + layout->addWidget( clientEdit ); + QLabel *userLabel = new QLabel(i18n("&User:"), w); + userLabel->setBuddy(userEdit); + layout->addWidget( userLabel ); + layout->addWidget( userEdit ); + QLabel *filesLabel = new QLabel(i18n("&File(s):"), w); + filesLabel->setBuddy(filesBox); + layout->addWidget( filesLabel ); + layout->addWidget( filesBox ); + + setDetailsWidget( w ); + autoGuess(); + edit->setFocus(); +} + +CommitDialog::~CommitDialog() +{ +} + +void CommitDialog::autoGuess() +{ + char *cenv; + + cenv = getenv( "P4USER" ); + if ( cenv ) { + setUser( QString::fromLocal8Bit( cenv ) ); + } + + cenv = getenv( "P4CLIENT" ); + if ( cenv ) { + setClient( QString::fromLocal8Bit( cenv ) ); + } +} + +void CommitDialog::setFiles( const QStringList& lst ) +{ + filesBox->clear(); + setDepotFiles( lst ); +} + +void CommitDialog::setDepotFiles( const QStringList& lst ) +{ + QStringList args; + + args << "files"; + for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + args << (*it); + } + + ExecCommand* cmd = new ExecCommand( "p4", args, QString::null, QStringList(), this ); + connect( cmd, SIGNAL(finished( const QString&, const QString& )), + this, SLOT(getFilesFinished( const QString&, const QString& )) ); +} + +void CommitDialog::getFilesFinished( const QString& out, const QString& /* err */ ) +{ + QStringList lst = QStringList::split( QChar('\n'), out ); + for ( QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it ) { + int pos = (*it).find( QChar('#') ); + if ( pos > 1 && (*it).startsWith( "//" ) ) { + filesBox->insertItem( (*it).left( pos ) ); + } + } +} + +QString CommitDialog::changeList() const +{ + QString lst; + + lst += "Change: new\n" + "Client: " + client() + "\n" + "User: " + user() + "\n" + "Status: new\n" + "Description:\n "; + + lst += logMessage().replace(QRegExp("\n"), "\n ") + "\n\n"; + + lst += "Files:\n"; + + for ( uint i = 0; i < filesBox->count(); ++i ) { + lst += " " + filesBox->text( i ) + "\n"; + } + + return lst; +} + +void CommitDialog::accept() +{ + if ( client().isEmpty() ) { + setDetails( true ); + KMessageBox::error( this, i18n("Please enter the P4 client name.") ); + clientEdit->setFocus(); + } else if ( user().isEmpty() ) { + setDetails( true ); + KMessageBox::error( this, i18n("Please enter the P4 user.") ); + userEdit->setFocus(); + } else if ( filesBox->count() == 0 ) { + setDetails( true ); + KMessageBox::error( this, i18n("The changelist does not contain any files.") ); + } else { + KDialogBase::accept(); + } +} + +#include "commitdlg.moc" diff --git a/vcs/perforce/commitdlg.h b/vcs/perforce/commitdlg.h new file mode 100644 index 00000000..390681fd --- /dev/null +++ b/vcs/perforce/commitdlg.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 1999, 2000 by Bernd Gehrmann * + * bernd@kdevelop.org * + * Modified for perforce 2002 by Harald Fernengel <harry@kdevelop.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _COMMITDIALOG_H_ +#define _COMMITDIALOG_H_ + +#include <qstringlist.h> +#include <qtextedit.h> +#include <klineedit.h> +#include <klistbox.h> +#include <kdialogbase.h> + +class KProcess; + +class CommitDialog : public KDialogBase +{ + Q_OBJECT +public: + CommitDialog( QWidget *parent = 0, const char *name = 0 ); + ~CommitDialog(); + + QString logMessage() const { return edit->text(); } + QString user() const { return userEdit->text(); } + QString client() const { return clientEdit->text(); } + QString changeList() const; + + void setUser( const QString& usr ) { userEdit->setText( usr ); } + void setClient( const QString& clnt ) { clientEdit->setText( clnt ); } + void setFiles( const QStringList& lst ); + + /** tries to fill out user and client */ + void autoGuess(); + +protected slots: + void accept(); + +private slots: + void getFilesFinished( const QString& out, const QString& err ); + +private: + void setDepotFiles( const QStringList& lst ); + QTextEdit *edit; + KLineEdit *clientEdit, *userEdit; + KListBox *filesBox; +}; + +#endif + diff --git a/vcs/perforce/integrator/Makefile.am b/vcs/perforce/integrator/Makefile.am new file mode 100644 index 00000000..0df84d8e --- /dev/null +++ b/vcs/perforce/integrator/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \ + $(all_includes) +METASOURCES = AUTO +kde_module_LTLIBRARIES = libperforceintegrator.la +libperforceintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries) +libperforceintegrator_la_LIBADD =\ + $(top_builddir)/lib/interfaces/extras/libkdevextras.la\ + $(top_builddir)/lib/libkdevelop.la +kde_services_DATA = kdevperforceintegrator.desktop +noinst_HEADERS = perforceintegrator.h pfintegratordlg.h +libperforceintegrator_la_SOURCES = perforceintegrator.cpp \ + pfintegratordlgbase.ui pfintegratordlg.cpp diff --git a/vcs/perforce/integrator/kdevperforceintegrator.desktop b/vcs/perforce/integrator/kdevperforceintegrator.desktop new file mode 100644 index 00000000..d70c7f67 --- /dev/null +++ b/vcs/perforce/integrator/kdevperforceintegrator.desktop @@ -0,0 +1,44 @@ +[Desktop Entry] +Type=Service +Name=KDevPerforceIntegrator +Name[da]=KDevelop Perforce-integration +Name[nds]=KDevelop-Perforce-Integreren +Name[sk]=KDev Perforce integrácia +Name[sv]=KDevelop Perforce-integration +Name[zh_TW]=KDevelop Perforce æ•´åˆå™¨ +Comment=Perforce Project Integration Facility +Comment[ca]=Facilitat per a la integració amb projectes Perforce +Comment[da]=Perforce projektintegration +Comment[de]=Perforce-Projektintegration +Comment[el]=ΛειτουÏγία ενσωμάτωσης Perforce στο ÎÏγο +Comment[es]=Entorno para integración con proyectos Perforce +Comment[et]=Perforce projekti põimimisvahend +Comment[eu]=Perforce proiektuen integrazio-tresna +Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ Perforce +Comment[fr]=Fonction d'intégration pour un projet utilisant Perforce +Comment[gl]=Utilidade para a integración de proxectos Perforce +Comment[hu]=Integrálás a Perforce-szal +Comment[it]=Funzione di integrazione del progetto Perforce +Comment[ja]=Perforce プãƒã‚¸ã‚§ã‚¯ãƒˆçµ±åˆãƒ„ール +Comment[ms]=Kemudahan Integrasi Projek Perforce +Comment[nds]=Perforce-Projektintegreren +Comment[ne]=परफोरà¥à¤¸ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾ +Comment[nl]=Perforce project-integratie +Comment[pl]=Integracja z Perforce +Comment[pt]=Integração com Projectos Perforce +Comment[pt_BR]=Facilidade de Integração ao Projeto de Perforce +Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Perforce +Comment[sk]=Perforce projektová integrácia +Comment[sr]=Интеграција Perforce-а у пројекат +Comment[sr@Latn]=Integracija Perforce-a u projekat +Comment[sv]=Funktion för integrering av Perforce i projekt +Comment[tr]=Perforce Proje BütünleÅŸtirme Aracı +Comment[zh_CN]=Perforce 工程集æˆåŠŸèƒ½ +Comment[zh_TW]=Perforce 專案整åˆå·¥å…· +Exec=blubb +ServiceTypes=KDevelop/VCSIntegrator +X-KDE-Library=libperforceintegrator +X-KDevelop-Default=false +X-KDevelop-VCS=Perforce +X-KDevelop-VCSPlugin=kdevperforce +X-KDevelop-Version=5 diff --git a/vcs/perforce/integrator/perforceintegrator.cpp b/vcs/perforce/integrator/perforceintegrator.cpp new file mode 100644 index 00000000..a5e40a36 --- /dev/null +++ b/vcs/perforce/integrator/perforceintegrator.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "perforceintegrator.h" + +#include <kdevgenericfactory.h> +#include <kdevplugininfo.h> + +#include "pfintegratordlg.h" + +static const KDevPluginInfo data("kdevperforceintegrator"); +typedef KDevGenericFactory<PerforceIntegrator> PerforceIntegratorFactory; +K_EXPORT_COMPONENT_FACTORY( libperforceintegrator, PerforceIntegratorFactory(data) ) + +PerforceIntegrator::PerforceIntegrator(QObject* parent, const char* name, + const QStringList // args + ) + :KDevVCSIntegrator(parent, name) +{ +} + +PerforceIntegrator::~PerforceIntegrator() +{ +} + +VCSDialog* PerforceIntegrator::fetcher(QWidget* // parent + ) +{ + return 0; +} + +VCSDialog* PerforceIntegrator::integrator(QWidget* parent) +{ + PFIntegratorDlg *dlg = new PFIntegratorDlg(parent); + return dlg; +} + +#include "perforceintegrator.moc" diff --git a/vcs/perforce/integrator/perforceintegrator.h b/vcs/perforce/integrator/perforceintegrator.h new file mode 100644 index 00000000..3bb82a2d --- /dev/null +++ b/vcs/perforce/integrator/perforceintegrator.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PERFORCEINTEGRATOR_H +#define PERFORCEINTEGRATOR_H + +#include <kdevvcsintegrator.h> + +#include <qstringlist.h> + +class PerforceIntegrator : public KDevVCSIntegrator +{ +Q_OBJECT +public: + PerforceIntegrator(QObject* parent, const char* name, const QStringList args = QStringList()); + ~PerforceIntegrator(); + + virtual VCSDialog* fetcher(QWidget* parent); + virtual VCSDialog* integrator(QWidget* parent); + +}; + +#endif diff --git a/vcs/perforce/integrator/pfintegratordlg.cpp b/vcs/perforce/integrator/pfintegratordlg.cpp new file mode 100644 index 00000000..917f2a20 --- /dev/null +++ b/vcs/perforce/integrator/pfintegratordlg.cpp @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "pfintegratordlg.h" + +PFIntegratorDlg::PFIntegratorDlg(QWidget *parent, const char *name) + :PFIntegratorDlgBase(parent, name) +{ +} + +void PFIntegratorDlg::accept() +{ +} + +void PFIntegratorDlg::init(const QString &/*projectName*/, const QString &/*projectLocation*/) +{ +} + +QWidget *PFIntegratorDlg::self() +{ + return const_cast<PFIntegratorDlg*>(this); +} + +#include "pfintegratordlg.moc" diff --git a/vcs/perforce/integrator/pfintegratordlg.h b/vcs/perforce/integrator/pfintegratordlg.h new file mode 100644 index 00000000..a74b6749 --- /dev/null +++ b/vcs/perforce/integrator/pfintegratordlg.h @@ -0,0 +1,36 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PFINTEGRATORDLG_H +#define PFINTEGRATORDLG_H + +#include "pfintegratordlgbase.h" +#include <kdevvcsintegrator.h> + +class PFIntegratorDlg: public PFIntegratorDlgBase, public VCSDialog { +Q_OBJECT +public: + PFIntegratorDlg(QWidget *parent = 0, const char *name = 0); + + virtual void accept(); + virtual void init(const QString &projectName, const QString &projectLocation); + virtual QWidget *self(); +}; + +#endif diff --git a/vcs/perforce/integrator/pfintegratordlgbase.ui b/vcs/perforce/integrator/pfintegratordlgbase.ui new file mode 100644 index 00000000..5b12a70f --- /dev/null +++ b/vcs/perforce/integrator/pfintegratordlgbase.ui @@ -0,0 +1,47 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>PFIntegratorDlgBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>PFIntegratorDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>480</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>No options available for this VCS.</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>435</height> + </size> + </property> + </spacer> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/vcs/perforce/kdevperforce.desktop b/vcs/perforce/kdevperforce.desktop new file mode 100644 index 00000000..678eab7e --- /dev/null +++ b/vcs/perforce/kdevperforce.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +Type=Service +Exec=blubb +Comment=Integrates Perforce, a software configuration management system. http://www.perforce.com/ +Comment[ca]=Integra Perforce, un sistema de gestió de la configuració del programari. http://www.perforce.com/ +Comment[da]=Integrerer Perforce, et software-indstilling hÃ¥ndteringssystem. http://www.perforce.com/ +Comment[de]=Integration von Perforce, einem System zur Verwaltung von Software-Konfigurationen. http://www.perforce.com/ +Comment[el]=Ενσωματώνει το Perforce, Îνα σÏστημα διαχείÏισης και ÏÏθμισης λογισμικοÏ.http://www.perforce.com/ +Comment[es]=Integra Perforce, un sistema de adminsitración de la configuración del software. http://www.perforce.com/ +Comment[et]=Integreerib tarkvaraseadistuste haldamise süsteemi Perforce. http://www.perforce.com/ +Comment[eu]=Perforce integratzen du, software konfiguazio kudeaketa sistema bat. http://www.perforce.com/ +Comment[fa]=Perforce را مجتمع‌سازی می‌کند. یک سیستم مدیریت پیکربندی نرم‌اÙزار. http://www.perforce.com/ +Comment[fr]=Intègre « PerForce », un système de gestion de configuration de logiciels. http:/www.perforce.com/ +Comment[gl]=Integra Perforce, un sistema de xestións de configuracións. http://www.perforce.com/ +Comment[hi]=परफ़ोरà¥à¤¸ को इंटीगà¥à¤°à¥‡à¤Ÿ करता है, जो कि सॉफà¥à¤Ÿà¤µà¥‡à¤¯à¤° कॉनà¥à¤«à¤¼à¤¿à¤—रेशन पà¥à¤°à¤¬à¤‚धन तंतà¥à¤° है. http://www.perforce.com/ +Comment[hu]=Integrációt biztosÃt a Perforce szoftverkonfigurációs rendszerrel - http://www.perforce.com/ +Comment[it]=Integra Perforce, un sistema per la configurazione software. http://www.perforce.com/ +Comment[ja]=ソフトウェアè¨å®šç®¡ç†ã‚·ã‚¹ãƒ†ãƒ Perforce ã‚’çµ±åˆã—ã¾ã™ã€‚ +Comment[ms]=Menggabungkan Perforce, sebuah sistem pengurusan tetapan perisian. http://www.perforce.com/ +Comment[nds]=Integreren vun Perforce, en Systeem för't Plegen vun Programminstellen. http://www.perforce.com/ +Comment[ne]=परफोरà¥à¤¸ à¤à¤•à¤¿à¤•à¤°à¤£ गरà¥à¤¦à¤›, सफà¥à¤Ÿà¤µà¥‡à¤¯à¤° कनà¥à¤«à¤¿à¤—रेसन वà¥à¤¯à¤µà¤¸à¥à¤¥à¤¾à¤ªà¤¨ पà¥à¤°à¤£à¤¾à¤²à¥€ http://www.perforce.com/ +Comment[nl]=Integreert Perforce, een systeem voor softwareconfiguratie. Zie http://www.perforce.com/ +Comment[pl]=Integracja z Perforce, systemem zarzÄ…dzania konfiguracjÄ… oprogramowania. http://www.perforce.com/ +Comment[pt]=Integra o Perforce, um sistema de gestão de configurações de 'software'. http://www.perforce.com/ +Comment[pt_BR]=Integra o Perforce, um software de configuração e gerenciamento do sistema. http://www.perforce.com/ +Comment[ru]=Интегрирует Perforce, ÑиÑтему ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñми программного обеÑпечениÑ. http://www.perforce.com/ +Comment[sk]=Integrácia Perforce, konfiguraÄný projektový manažment. http://www.perforce.com/ +Comment[sl]=Integrira Perforce, upravljalni sistem programja. http://www.perforce.com/ +Comment[sr]=Интегрише Perforce, ÑиÑтем за управљање подешавањем Ñофтвера. http://www.perforce.com/ +Comment[sr@Latn]=IntegriÅ¡e Perforce, sistem za upravljanje podeÅ¡avanjem softvera. http://www.perforce.com/ +Comment[sv]=Integrerar Perforce, ett konfigurationshanteringsverktyg för programvara. http://www.perforce.com/ +Comment[ta]=à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®•à¯à®•à¯à®®à¯ Perforce, ஒர௠மெனà¯à®ªà¯Šà®°à¯à®³à¯ மேலாளர௠அமைபà¯à®ªà¯. http://www.perforce.com/ +Comment[tg]=Интеграл намудани Perforce, барномаи идоракунандаро шарҳи барномаҳои таъмин нигоҳ медорад.http://www.perforce.com/ +Comment[tr]=Bir yazılım ayar yönetimi sistemi olan Perforce'u bütünleÅŸtirir. http://www.perforce.com/ +Comment[zh_CN]=é›†æˆ Perforce,系统é…置管ç†è½¯ä»¶ http://www.perforce.com/ +Comment[zh_TW]=æ•´åˆ Perforce,一套軟體è¨å®šç®¡ç†ç³»çµ±ã€‚http://www.perforce.com/ +Name=KDevPerforce +Name[da]=KDevelop Perforce +Name[de]=Unterstützung für Perforce (KDevelop) +Name[hi]=के-डेव-परफ़ोरà¥à¤¸ +Name[nds]=Perforce-Ãœnnerstütten för KDevelop +Name[sk]=KDev Perforce +Name[sv]=KDevelop Perforce +Name[ta]=Kdev Perforce +Name[zh_TW]=KDevelop Perforce +GenericName=Perforce Integration +GenericName[ca]=Integració amb Perforce +GenericName[da]=Perforce integration +GenericName[de]=Perforce-Integration +GenericName[el]=Ενσωμάτωση Perforce +GenericName[es]=Integración de Perforce +GenericName[et]=Perforce'i põimimine +GenericName[eu]=Perforce integrazioa +GenericName[fa]=مجتمع‌سازی Perforce +GenericName[fr]=Intégration de « Perforce » +GenericName[ga]=Comhtháthú Perforce +GenericName[gl]=Integración de Perforce +GenericName[hi]=परफ़ोरà¥à¤¸ इंटीगà¥à¤°à¥‡à¤¶à¤¨ +GenericName[hu]=Perforce-integráció +GenericName[it]=Integrazione di Perforce +GenericName[ms]=Intergrasi Perforce +GenericName[nds]=Perforce-Integreren +GenericName[ne]=परफोरà¥à¤¸ इनà¥à¤Ÿà¤¿à¤—à¥à¤°à¥‡à¤¸à¤¨ +GenericName[nl]=Perforce-integratie +GenericName[pl]=Integracja z Perforce +GenericName[pt]=Integração com o Perforce +GenericName[pt_BR]=Integração com o Perforce +GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Perforce +GenericName[sk]=Perforce integrácia +GenericName[sl]=Integracija Perforce +GenericName[sr]=Интеграција perforce-а +GenericName[sr@Latn]=Integracija perforce-a +GenericName[sv]=Integrering av Perforce +GenericName[ta]=Perforce à®’à®°à¯à®™à¯à®•à®¿à®£à¯ˆà®ªà¯à®ªà¯ +GenericName[tg]=ИнтегратÑÐ¸Ñ Perforce +GenericName[tr]=Perforce BütünleÅŸtirmesi +GenericName[zh_CN]=Perforce é›†æˆ +GenericName[zh_TW]=Perforce æ•´åˆ +ServiceTypes=KDevelop/VersionControl +X-KDE-Library=libkdevperforce +X-KDevelop-Version=5 +X-KDevelop-Properties=VCS,PerforceVCS diff --git a/vcs/perforce/kdevperforcepart.rc b/vcs/perforce/kdevperforcepart.rc new file mode 100644 index 00000000..27b5fe08 --- /dev/null +++ b/vcs/perforce/kdevperforcepart.rc @@ -0,0 +1,23 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="KDevPerforcePart" version="1"> +<MenuBar> + <Menu name="tools"> + <Menu name="version_control" group="tools_project_operations"> + <Text>&Version Control</Text> + <Merge /> + <Menu name="version_control_tools_perforce"> + <Text>&Perforce</Text> + <Action name="perforce_submit" /> + <Action name="perforce_diff" /> + <Action name="perforce_edit" /> + <Action name="perforce_revert" /> + <Action name="perforce_sync" /> + <Action name="perforce_add" /> + <Action name="perforce_remove" /> + </Menu> + </Menu> + </Menu> +</MenuBar> + +</kpartgui> + diff --git a/vcs/perforce/perforcepart.cpp b/vcs/perforce/perforcepart.cpp new file mode 100644 index 00000000..9aeadc6f --- /dev/null +++ b/vcs/perforce/perforcepart.cpp @@ -0,0 +1,364 @@ +/*************************************************************************** + * Copyright (C) 1999-2001 by Bernd Gehrmann * + * bernd@kdevelop.org * + * Extended 2002 by Harald Fernengel <harry@kdevelop.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "perforcepart.h" + +#include <qfileinfo.h> +#include <qpopupmenu.h> +#include <qregexp.h> +#include <kpopupmenu.h> +#include <kdebug.h> +#include <kdevgenericfactory.h> +#include <kprocess.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kaction.h> +#include <kurl.h> +#include <kparts/part.h> + +#include "kdevpartcontroller.h" +#include "kdevcore.h" +#include "kdevmakefrontend.h" +#include "kdevdifffrontend.h" +#include "kdevplugininfo.h" +#include "commitdlg.h" +#include "execcommand.h" + +static const KDevPluginInfo data("kdevperforce"); + +typedef KDevGenericFactory<PerforcePart> PerforceFactory; +K_EXPORT_COMPONENT_FACTORY( libkdevperforce, PerforceFactory( data ) ) + +PerforcePart::PerforcePart( QObject *parent, const char *name, const QStringList & ) + : KDevVersionControl( &data, parent, name ? name : "PerforcePart" ) +{ + setInstance(PerforceFactory::instance()); + setupActions(); + + connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), + this, SLOT(contextMenu(QPopupMenu *, const Context *)) ); +} + + +PerforcePart::~PerforcePart() +{} + +void PerforcePart::setupActions() +{ + actionEdit = new KAction( i18n("Edit"), 0, this, SLOT(slotActionEdit()), + actionCollection(), "perforce_edit" ); + actionEdit->setToolTip(i18n("Edit")); + actionEdit->setWhatsThis(i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit.")); + actionRevert = new KAction( i18n("Revert"), 0, this, SLOT(slotActionRevert()), + actionCollection(), "perforce_revert" ); + actionRevert->setToolTip(i18n("Revert")); + actionRevert->setWhatsThis(i18n("<b>Revert</b><p>Discards changes made to open files.")); + actionSubmit = new KAction( i18n("Submit"), 0, this, SLOT(slotActionCommit()), + actionCollection(), "perforce_submit" ); + actionSubmit->setToolTip(i18n("Submit")); + actionSubmit->setWhatsThis(i18n("<b>Submit</b><p>Sends changes made to open files to the depot.")); + actionSync = new KAction( i18n("Sync"), 0, this, SLOT(slotActionUpdate()), + actionCollection(), "perforce_sync" ); + actionSync->setToolTip(i18n("Sync")); + actionSync->setWhatsThis(i18n("<b>Sync</b><p>Copies files from the depot into the workspace.")); + actionDiff = new KAction( i18n("Diff Against Repository"), 0, this, SLOT(slotActionDiff()), + actionCollection(), "perforce_diff" ); + actionDiff->setToolTip(i18n("Diff against repository")); + actionDiff->setWhatsThis(i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot.")); + actionAdd = new KAction( i18n("Add to Repository"), 0, this, SLOT(slotActionAdd()), + actionCollection(), "perforce_add" ); + actionAdd->setToolTip(i18n("Add to repository")); + actionAdd->setWhatsThis(i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot.")); + actionRemove = new KAction( i18n("Remove From Repository"), 0, this, SLOT(slotActionRemove()), + actionCollection(), "perforce_remove" ); + actionRemove->setToolTip(i18n("Remove from repository")); + actionRemove->setWhatsThis(i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot.")); +} + +void PerforcePart::contextMenu(QPopupMenu *popup, const Context *context) +{ + if (context->hasType( Context::FileContext )) { + const FileContext *fcontext = static_cast<const FileContext*>(context); + popupfile = fcontext->urls().first().path(); + QFileInfo fi( popupfile ); + popup->insertSeparator(); + + KPopupMenu *sub = new KPopupMenu(popup); + QString name = fi.fileName(); + sub->insertTitle( i18n("Actions for %1").arg(name) ); + + int id = sub->insertItem( i18n("Edit"), + this, SLOT(slotEdit()) ); + sub->setWhatsThis(id, i18n("<b>Edit</b><p>Opens file(s) in a client workspace for edit.")); + id = sub->insertItem( i18n("Revert"), + this, SLOT(slotRevert()) ); + sub->setWhatsThis(id, i18n("<b>Revert</b><p>Discards changes made to open files.")); + id = sub->insertItem( i18n("Submit"), + this, SLOT(slotCommit()) ); + sub->setWhatsThis(id, i18n("<b>Submit</b><p>Sends changes made to open files to the depot.")); + id = sub->insertItem( i18n("Sync"), + this, SLOT(slotUpdate()) ); + sub->setWhatsThis(id, i18n("<b>Sync</b><p>Copies files from the depot into the workspace.")); + sub->insertSeparator(); + id = sub->insertItem( i18n("Diff Against Repository"), + this, SLOT(slotDiff()) ); + sub->setWhatsThis(id, i18n("<b>Diff against repository</b><p>Compares a client workspace file to a revision in the depot.")); + id = sub->insertItem( i18n("Add to Repository"), + this, SLOT(slotAdd()) ); + sub->setWhatsThis(id, i18n("<b>Add to repository</b><p>Open file(s) in a client workspace for addition to the depot.")); + id = sub->insertItem( i18n("Remove From Repository"), + this, SLOT(slotRemove()) ); + sub->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Open file(s) in a client workspace for deletion from the depot.")); + id = popup->insertItem(i18n("Perforce"), sub); + } +} + +void PerforcePart::execCommand( const QString& cmd, const QString& filename ) +{ + if ( filename.isEmpty() ) + return; + + QFileInfo fi( filename ); + if (fi.isDir()) { + KMessageBox::error( 0, i18n("Cannot handle directories, please select single files") ); + return; + } + QString dir = fi.dirPath(); + QString name = fi.fileName(); + + QString command("cd "); + command += KProcess::quote(dir); + command += " && p4 " + cmd + " "; + command += name; + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); +} + +void PerforcePart::edit( const QString& filename ) +{ + execCommand( "edit", filename ); +} + +void PerforcePart::revert( const QString& filename ) +{ + if ( KMessageBox::questionYesNo( 0, + i18n("Do you really want to revert " + "the file %1 and lose all your changes?").arg( filename ), QString::null, i18n("Revert"), i18n("Do Not Revert") ) == KMessageBox::Yes ) { + execCommand( "revert", filename ); + } +} + +void PerforcePart::commit( const QString& filename ) +{ + if ( filename.isEmpty() ) + return; + + QFileInfo fi( filename ); + if ( fi.isDir() ) { + KMessageBox::error( 0, i18n("Submitting of subdirectories is not supported") ); + return; + } + + CommitDialog d; + QStringList lst; + lst << filename; + d.setFiles( lst ); + if (d.exec() == QDialog::Rejected) + return; + + QString message = d.changeList(); + if (!message.isEmpty()) + message = KShellProcess::quote(message); + + QString command("echo " + message); + command += " | p4 submit -i"; + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand("", command); +} + + +void PerforcePart::update( const QString& filename ) +{ + if ( filename.isEmpty() ) + return; + + QString dir, name; + QFileInfo fi( filename ); + if (fi.isDir()) { + dir = fi.absFilePath(); + name = "..."; // three dots means "recoursive" + } else { + dir = fi.dirPath(); + name = fi.fileName(); + } + + QString command("cd "); + command += KProcess::quote(dir); + command += " && p4 sync "; + command += name; + + if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("KDevelop/MakeFrontend")) + makeFrontend->queueCommand(dir, command); +} + + +void PerforcePart::add( const QString& filename ) +{ + execCommand( "add", filename ); +} + + +void PerforcePart::remove( const QString& filename ) +{ + execCommand( "delete", filename ); +} + +void PerforcePart::diff( const QString& filename ) +{ + if ( filename.isEmpty() ) + return; + + QString name; + QFileInfo fi( filename ); + + if ( fi.isDir() ) { + name = fi.absFilePath() + "..."; + } else { + name = filename; + } + QStringList args; + + args << "diff"; + args << "-du"; + args << name; + ExecCommand* cmv = new ExecCommand( "p4", args, QString::null, QStringList(), this ); + connect( cmv, SIGNAL(finished( const QString&, const QString& )), + this, SLOT(slotDiffFinished( const QString&, const QString& )) ); +} + +void PerforcePart::slotDiffFinished( const QString& diff, const QString& err ) +{ + if ( diff.isNull() && err.isNull() ) { + kdDebug(9000) << "p4 diff cancelled" << endl; + return; // user pressed cancel or an error occured + } + + if ( diff.isEmpty() && !err.isEmpty() ) { + KMessageBox::detailedError( 0, i18n("P4 output errors during diff."), err, i18n("Errors During Diff") ); + return; + } + + if ( !err.isEmpty() ) { + int s = KMessageBox::warningContinueCancelList( 0, i18n("P4 output errors during diff. Do you still want to continue?"), + QStringList::split( "\n", err, false ), i18n("Errors During Diff") ); + if ( s != KMessageBox::Continue ) + return; + } + + if ( diff.isEmpty() ) { + KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Differences Found") ); + return; + } + + // strip the ==== headers + static QRegExp rx( "(^|\\n)==== ([^ ]+) -.*====\\n" ); + rx.setMinimal( true ); + QString strippedDiff = diff; + strippedDiff.replace( rx, "--- \\2\n+++ \\2\n" ); + + if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("KDevelop/DiffFrontend")) + diffFrontend->showDiff( strippedDiff ); +} + +QString PerforcePart::currentFile() +{ + KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() ); + if ( part ) { + KURL url = part->url(); + if ( url.isLocalFile() ) + return url.path(); + } + return QString::null; +} + +void PerforcePart::slotActionCommit() +{ + commit( currentFile() ); +} + +void PerforcePart::slotActionUpdate() +{ + update( currentFile() ); +} +void PerforcePart::slotActionAdd() +{ + add( currentFile() ); +} + +void PerforcePart::slotActionRemove() +{ + remove( currentFile() ); +} + +void PerforcePart::slotActionEdit() +{ + edit( currentFile() ); +} + +void PerforcePart::slotActionRevert() +{ + revert( currentFile() ); +} + +void PerforcePart::slotActionDiff() +{ + diff( currentFile() ); +} + +void PerforcePart::slotCommit() +{ + commit( popupfile ); +} + +void PerforcePart::slotUpdate() +{ + update( popupfile ); +} + +void PerforcePart::slotAdd() +{ + add( popupfile ); +} + +void PerforcePart::slotRemove() +{ + remove( popupfile ); +} + +void PerforcePart::slotEdit() +{ + edit( popupfile ); +} + +void PerforcePart::slotRevert() +{ + revert( popupfile ); +} + +void PerforcePart::slotDiff() +{ + diff( popupfile ); +} + +#include "perforcepart.moc" diff --git a/vcs/perforce/perforcepart.h b/vcs/perforce/perforcepart.h new file mode 100644 index 00000000..5a50871c --- /dev/null +++ b/vcs/perforce/perforcepart.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 1999-2001 by Bernd Gehrmann * + * bernd@kdevelop.org * + * Extended to use perforce 2002 by Harald Fernengel <harry@kdevelop.org>* + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _PERFORCEPART_H_ +#define _PERFORCEPART_H_ + +#include <kdevversioncontrol.h> +#include <klocale.h> + +class Context; +class QPopupMenu; +class KAction; + +class PerforcePart : public KDevVersionControl +{ + Q_OBJECT + +public: + PerforcePart( QObject *parent, const char *name, const QStringList & ); + ~PerforcePart(); + + virtual QString shortDescription() const + { return i18n( "Perforce is a version control system" ); } + + virtual void createNewProject(const QString& /* dir */) {} + virtual bool fetchFromRepository() { return true; } + virtual KDevVCSFileInfoProvider *fileInfoProvider() const { return 0; } + virtual bool isValidDirectory(const QString& /* dirPath*/) const + { return true; } + +private slots: + void contextMenu(QPopupMenu *popup, const Context *context); + void slotCommit(); + void slotUpdate(); + void slotAdd(); + void slotRemove(); + void slotEdit(); + void slotRevert(); + void slotDiff(); + + void slotActionCommit(); + void slotActionUpdate(); + void slotActionAdd(); + void slotActionRemove(); + void slotActionEdit(); + void slotActionRevert(); + void slotActionDiff(); + + void slotDiffFinished( const QString&, const QString& ); + +private: + void commit( const QString& filename ); + void update( const QString& filename ); + void add( const QString& filename ); + void remove( const QString& filename ); + void edit( const QString& filename ); + void revert( const QString& filename ); + void diff( const QString& filename ); + QString currentFile(); + + /** calls p4 with the command cmd and appends the filename */ + void execCommand( const QString& cmd, const QString& filename ); + void setupActions(); + QString popupfile; + KAction *actionEdit, *actionRevert, + *actionSubmit, *actionSync, + *actionDiff, *actionAdd, *actionRemove; +}; + +#endif diff --git a/vcs/subversion/Makefile.am b/vcs/subversion/Makefile.am new file mode 100644 index 00000000..449d3889 --- /dev/null +++ b/vcs/subversion/Makefile.am @@ -0,0 +1,38 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/interfaces/extensions $(SVN_INCLUDE) $(all_includes) + +METASOURCES = AUTO + +kde_module_LTLIBRARIES = libkdevsubversion.la kio_kdevsvn.la kded_kdevsvnd.la + +libkdevsubversion_la_SOURCES = subversion_core.cpp subversion_fileinfo.cpp \ + subversion_fileinfo.skel subversion_part.cpp subversion_widget.cpp subversiondiff.ui \ + subversionprojectwidget.ui svn_blamewidget.cpp svn_co.ui svn_commitdlgbase.ui svn_copydlgwidget.ui \ + svn_copywidget.cpp svn_fileselectdlg_commit.cpp svn_logviewoptiondlgbase.ui \ + svn_logviewwidget.cpp svn_mergeoptiondlgbase.ui svn_mergewidget.cpp svn_switchdlgbase.ui \ + svn_switchwidget.cpp +libkdevsubversion_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la +libkdevsubversion_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) + + +kio_kdevsvn_la_SOURCES = svn_kio.cpp +kio_kdevsvn_la_LIBADD = $(LIB_KIO) +kio_kdevsvn_la_LDFLAGS = -module $(all_libraries) $(KDE_PLUGIN) $(SVN_LIB) + +kded_kdevsvnd_la_SOURCES = commitdlg.cpp commitdlgbase.ui kdevsvnd.cpp \ + kdevsvnd.skel kdevsvnd_widgets.cpp svnssltrustpromptbase.ui +kded_kdevsvnd_la_LIBADD = $(LIB_KIO) -lkdeinit_kded +kded_kdevsvnd_la_LDFLAGS = -module $(all_libraries) $(KDE_PLUGIN) + +kdeddir = $(kde_servicesdir)/kded +kded_DATA = kdevsvnd.desktop + +servicedir = $(kde_servicesdir) +service_DATA = kdevsubversion.desktop + +protocoldir = $(kde_servicesdir) +protocol_DATA = kdevsvn+file.protocol kdevsvn+http.protocol kdevsvn+https.protocol kdevsvn+ssh.protocol kdevsvn+svn.protocol + + +SUBDIRS = integrator +noinst_HEADERS = commitdlg.h kdevsvnd.h svn_blamewidget.h svn_copywidget.h \ + svn_fileselectdlg_commit.h svn_logviewwidget.h svn_mergewidget.h svn_switchwidget.h diff --git a/vcs/subversion/README.dox b/vcs/subversion/README.dox new file mode 100644 index 00000000..df3badcc --- /dev/null +++ b/vcs/subversion/README.dox @@ -0,0 +1,13 @@ +/** \class subversionPart +Integrates the SVN (Subversion) version management system into KDevelop. + +\authors <a href="mailto:marchand AT kde.org">Mickael Marchand</a> + +\maintainer <a href="mailto:marchand AT kde.org">Mickael Marchand</a> + +\feature Integrates the SVN (Subversion) version management system into KDevelop. + +\requirement You need to compile and install kdesdk/kioslave/svn + +*/ + diff --git a/vcs/subversion/commitdlg.cpp b/vcs/subversion/commitdlg.cpp new file mode 100644 index 00000000..e227dd67 --- /dev/null +++ b/vcs/subversion/commitdlg.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * This file is part of KDevelop * + * Copyright (C) 2007 The KDevelop Authors <kdevelop-devel@kdevelop.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "commitdlg.h" +#include <qevent.h> +#include <ktextedit.h> + +CommitDlg::CommitDlg( QWidget* parent ) + : CommitDlgBase( parent ) +{ + textMessage->installEventFilter(this); +} + +bool CommitDlg::eventFilter( QObject* obj, QEvent* ev ) +{ + if( ev->type() == QEvent::KeyPress ) + { + QKeyEvent* k = static_cast<QKeyEvent*>(ev); + if( ( k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter ) && k->state() == Qt::ControlButton ) + { + accept(); + return true; + } + } + return false; +} + +#include "commitdlg.moc" + +//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle; diff --git a/vcs/subversion/commitdlg.h b/vcs/subversion/commitdlg.h new file mode 100644 index 00000000..4ac54054 --- /dev/null +++ b/vcs/subversion/commitdlg.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * This file is part of KDevelop * + * Copyright (C) 2007 The KDevelop Authors <kdevelop-devel@kdevelop.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef COMMITDLG_H +#define COMMITDLG_H + +#include "commitdlgbase.h" + +class CommitDlg : public CommitDlgBase +{ + Q_OBJECT +public: + CommitDlg( QWidget* = 0 ); +protected: + bool eventFilter( QObject* o, QEvent* e ); +}; + +#endif + +//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle; diff --git a/vcs/subversion/commitdlgbase.ui b/vcs/subversion/commitdlgbase.ui new file mode 100644 index 00000000..76499a60 --- /dev/null +++ b/vcs/subversion/commitdlgbase.ui @@ -0,0 +1,111 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>CommitDlgBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>CommitDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>451</width> + <height>337</height> + </rect> + </property> + <property name="caption"> + <string>Log Message</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KTextEdit"> + <property name="name"> + <cstring>textMessage</cstring> + </property> + </widget> + <widget class="KTextEdit"> + <property name="name"> + <cstring>listMessage</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>220</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton1</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton2</cstring> + </property> + <property name="text"> + <string>Ca&ncel</string> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>pushButton1</sender> + <signal>clicked()</signal> + <receiver>CommitDlgBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>pushButton2</sender> + <signal>clicked()</signal> + <receiver>CommitDlgBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>ktextedit.h</includehint> + <includehint>ktextedit.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/configure.in.bot b/vcs/subversion/configure.in.bot new file mode 100644 index 00000000..ccab94db --- /dev/null +++ b/vcs/subversion/configure.in.bot @@ -0,0 +1,9 @@ +if test "x$with_subversion" = xcheck && test -z "$SVN_SUBDIR"; then + echo "" + echo "You're missing Subversion libraries (1.x)" + echo "KDE will not be able to browse Subversion repositories without it," + echo "consider installing it." + echo "Look at kioslave/svn/README for more information" + echo "" + all_tests=bad +fi diff --git a/vcs/subversion/configure.in.in b/vcs/subversion/configure.in.in new file mode 100644 index 00000000..9bccba66 --- /dev/null +++ b/vcs/subversion/configure.in.in @@ -0,0 +1,134 @@ +SVN_SUBDIR="" + +AC_ARG_ENABLE(subversion, AC_HELP_STRING([--disable-subversion], [disable vcs support for subversion]), [with_subversion=${enableval}], [with_subversion=check]) + + + +if test "x$with_subversion" != xno; then + + APR_CONFIGS="/usr/bin/apr-config /usr/bin/apr-1-config /usr/local/bin/apr-config /usr/local/apr/bin/apr-config" + SVN_SUBDIR="svn" + AC_ARG_WITH(apr-config, + [[ --with-apr-config=FILE Use the given path to apr-config when determining + APR configuration; defaults to "apr-config"]], + [ + if test "$withval" != "yes" -a "$withval" != ""; then + APR_CONFIGS=$withval + fi + ]) + AC_MSG_CHECKING([for APR]) + APR_CONFIG="" + for VALUE in $APR_CONFIGS ; do + if test -x "$VALUE"; then + if $VALUE --cflags > /dev/null; then + APR_CONFIG="$VALUE" + break + fi + fi + done + if test -n "$APR_CONFIG" ; then + AC_MSG_RESULT([$APR_CONFIG]) + APR_CPPFLAGS="`$APR_CONFIG --cppflags`" + APR_INCLUDE="`$APR_CONFIG --includes`" + APR_LIBS="`$APR_CONFIG --link-ld --libs`" + else + AC_MSG_RESULT([not found]) + SVN_SUBDIR= + fi + + dnl + dnl APR util + dnl + + APU_CONFIGS="/usr/bin/apu-config /usr/bin/apu-1-config /usr/local/bin/apu-config /usr/local/apu/bin/apu-config" + AC_ARG_WITH(apu-config, + [[ --with-apu-config=FILE Use the given path to apu-config when determining + APR util configuration; defaults to "apu-config"]], + [ + if test "$withval" != "yes" -a "$withval" != ""; then + APU_CONFIGS=$withval + fi + ]) + AC_MSG_CHECKING([for APR util]) + APU_CONFIG="" + for VALUE in $APU_CONFIGS ; do + if test -x $VALUE + then + if $VALUE --includes > /dev/null; then + APU_CONFIG=$VALUE + break + fi + fi + done + if test -n "$APU_CONFIG"; then + AC_MSG_RESULT([found]) + APR_INCLUDE="$APR_INCLUDE `$APU_CONFIG --includes`" + APR_LIBS="$APR_LIBS `$APU_CONFIG --link-ld --libs`" + else + AC_MSG_RESULT([not found]) + SVN_SUBDIR= + fi + + dnl Search for subversion libraries + dnl svn-config was removed at current subversion release. + + + SVN_INCLUDES="/usr/local/include /usr/include /usr/include/subversion-1 /usr/local/include/subversion-1" + AC_ARG_WITH(svn-include, + [[ --with-svn-include=DIR Use the given path to the subversion headers.]], + [ + if test "$withval" != "yes" -a "$withval" != ""; then + SVN_INCLUDES=$withval + fi + ]) + AC_MSG_CHECKING([for Subversion headers]) + SVN_INCLUDE="" + for VALUE in $SVN_INCLUDES ; do + if test -f $VALUE/svn_types.h ; then + SVN_INCLUDE="-I$VALUE" + break + fi + done + if test $SVN_INCLUDE ; then + AC_MSG_RESULT([found]) + else + AC_MSG_RESULT([not found]) + SVN_SUBDIR= + fi + SVN_LIBS="/usr/local/lib /usr/lib /usr/lib64" + AC_ARG_WITH(svn-lib, + [[ --with-svn-lib=DIR Use the given path to the subversion libraries.]], + [ + if test "$withval" != "yes" -a "$withval" != ""; then + SVN_LIBS=$withval + fi + ]) + AC_MSG_CHECKING([for Subversion libraries]) + SVN_LIB="" + for VALUE in $SVN_LIBS ; do + if ls $VALUE/libsvn_client-1.* 1>/dev/null 2>&1; then + SVN_LIB="-L$VALUE" + break + fi + done + if test $SVN_LIB ; then + AC_MSG_RESULT([found]) + else + AC_MSG_RESULT([not found]) + SVN_SUBDIR= + fi + SVN_LIB="$SVN_LIB $APR_LIBS -lsvn_client-1 -lsvn_subr-1 -lsvn_ra-1" + SVN_INCLUDE="$SVN_INCLUDE $APR_INCLUDE" + SVN_CPPFLAGS="$APR_CPPFLAGS $SVN_CPPFLAGS" + + if test "x$with_subversion" != xcheck && test -z "$SVN_SUBDIR"; then + AC_MSG_ERROR([--enable-subversion was given, but test for subversion failed. Please install subversion headers and libraries and its dependencies (APR and APU utils)]) + fi +fi + +AM_CONDITIONAL(include_subversion, test -n "$SVN_SUBDIR") + +AC_SUBST(SVN_INCLUDE) +AC_SUBST(SVN_LIB) +AC_SUBST(SVN_CPPFLAGS) +AM_CONDITIONAL(include_kioslave_svn, test -n "$SVN_SUBDIR") diff --git a/vcs/subversion/integrator/Makefile.am b/vcs/subversion/integrator/Makefile.am new file mode 100644 index 00000000..a0fe82cd --- /dev/null +++ b/vcs/subversion/integrator/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = -I$(top_srcdir)/lib/interfaces \ + -I$(top_srcdir)/lib/interfaces/extensions -I$(top_srcdir)/lib/interfaces/extras -I$(top_srcdir)/lib/util \ + $(all_includes) +METASOURCES = AUTO + +kde_module_LTLIBRARIES = libsubversionintegrator.la +libsubversionintegrator_la_LDFLAGS = -avoid-version -no-undefined $(all_libraries) +libsubversionintegrator_la_LIBADD =\ + $(top_builddir)/lib/interfaces/extras/libkdevextras.la\ + $(top_builddir)/lib/libkdevelop.la +kde_services_DATA = kdevsubversionintegrator.desktop +noinst_HEADERS = subversionintegrator.h svnintegratordlg.h +libsubversionintegrator_la_SOURCES = subversionintegrator.cpp \ + svnintegratordlgbase.ui svnintegratordlg.cpp diff --git a/vcs/subversion/integrator/kdevsubversionintegrator.desktop b/vcs/subversion/integrator/kdevsubversionintegrator.desktop new file mode 100644 index 00000000..4b3a1c1c --- /dev/null +++ b/vcs/subversion/integrator/kdevsubversionintegrator.desktop @@ -0,0 +1,45 @@ +[Desktop Entry] +Type=Service +Name=KDevSubversionIntegrator +Name[da]=KDevelop Subversion-integration +Name[nds]=KDevelop-Subversion-Integreren +Name[sk]=KDev Subversion integrácia +Name[sv]=KDevelop Subversion-integration +Name[zh_TW]=KDevelop Subversion æ•´åˆå™¨ +Comment=Subversion Project Integration Facility +Comment[ca]=Facilitat per a la integració amb Subversion +Comment[da]=Subversion projektintegration +Comment[de]=Subversion-Projektintegration +Comment[el]=ΛειτουÏγία ενσωμάτωσης Subversion στο ÎÏγο +Comment[es]=Facilidad para integración con proyectos que utilicen Subversion +Comment[et]=Subversion projekti põimimisvahend +Comment[eu]=Subversion proiektuen integrazio-tesna +Comment[fa]=تسهیلات مجتمع‌سازی پروژۀ زیرنسخه +Comment[fr]=Fonction d'intégration pour un projet utilisant Subversion +Comment[gl]=Utilidade para a integración de proxectos Subversión +Comment[hu]=Projektintegrálást tesz lehetÅ‘vé a Subversion-nel +Comment[it]=Funzione di integrazione del progetto Subversion +Comment[ja]=Subversion プãƒã‚¸ã‚§ã‚¯ãƒˆçµ±åˆãƒ„ール +Comment[ms]=Kemudahan Integrasi Projek Subversion +Comment[nds]=Subversion-Projektintegreren +Comment[ne]=सबà¤à¤°à¥à¤¸à¤¨ परियोजना à¤à¤•à¤¿à¤•à¤°à¤£ सà¥à¤µà¤¿à¤§à¤¾ +Comment[nl]=Subversion project-integratie +Comment[pl]=Integracja z Subversion +Comment[pt]=Integração com Projectos Subversion +Comment[pt_BR]=Facilidade de Integração ao Projeto de Subversão +Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion +Comment[sk]=Subversion projektová integrácia +Comment[sr]=Интеграција Subversion-а у пројекат +Comment[sr@Latn]=Integracija Subversion-a u projekat +Comment[sv]=Funktion för integrering av Subversion i projekt +Comment[tr]=Subversion Proje BütünleÅŸtirme Aracı +Comment[zh_CN]=Subversion 工程集æˆåŠŸèƒ½ +Comment[zh_TW]=Subversion 專案整åˆå·¥å…· +Icon=misc +Exec=blubb +ServiceTypes=KDevelop/VCSIntegrator +X-KDE-Library=libsubversionintegrator +X-KDevelop-Default=false +X-KDevelop-VCS=Subversion +X-KDevelop-VCSPlugin=kdevsubversion +X-KDevelop-Version=5 diff --git a/vcs/subversion/integrator/subversionintegrator.cpp b/vcs/subversion/integrator/subversionintegrator.cpp new file mode 100644 index 00000000..65bf1a78 --- /dev/null +++ b/vcs/subversion/integrator/subversionintegrator.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "subversionintegrator.h" + +#include <kdevgenericfactory.h> +#include <kdevplugininfo.h> + +#include "svnintegratordlg.h" + +static const KDevPluginInfo data("kdevsubversionintegrator"); +typedef KDevGenericFactory<SubversionIntegrator> SubversionIntegratorFactory; +K_EXPORT_COMPONENT_FACTORY( libsubversionintegrator, SubversionIntegratorFactory(data) ) + +SubversionIntegrator::SubversionIntegrator(QObject* parent, const char* name, + const QStringList // args + ) + :KDevVCSIntegrator(parent, name) +{ +} + +SubversionIntegrator::~SubversionIntegrator() +{ +} + +VCSDialog* SubversionIntegrator::fetcher(QWidget* // parent + ) +{ + return 0; +} + +VCSDialog* SubversionIntegrator::integrator(QWidget* parent) +{ + SvnIntegratorDlg *dlg = new SvnIntegratorDlg(parent); + return dlg; +} + +#include "subversionintegrator.moc" diff --git a/vcs/subversion/integrator/subversionintegrator.h b/vcs/subversion/integrator/subversionintegrator.h new file mode 100644 index 00000000..e58c7786 --- /dev/null +++ b/vcs/subversion/integrator/subversionintegrator.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SUBVERSIONINTEGRATOR_H +#define SUBVERSIONINTEGRATOR_H + +#include <kdevvcsintegrator.h> + +#include <qstringlist.h> + +class SubversionIntegrator : public KDevVCSIntegrator +{ +Q_OBJECT +public: + SubversionIntegrator(QObject* parent, const char* name, const QStringList args = QStringList()); + ~SubversionIntegrator(); + + virtual VCSDialog* fetcher(QWidget* parent); + virtual VCSDialog* integrator(QWidget* parent); + +}; + +#endif diff --git a/vcs/subversion/integrator/svnintegratordlg.cpp b/vcs/subversion/integrator/svnintegratordlg.cpp new file mode 100644 index 00000000..9d271a90 --- /dev/null +++ b/vcs/subversion/integrator/svnintegratordlg.cpp @@ -0,0 +1,122 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * Copyright (C) 2004 * + * Mickael Marchand <marchand@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "svnintegratordlg.h" +#include "blockingkprocess.h" +#include <kurl.h> +#include <kio/jobclasses.h> +#include <kio/job.h> +#include <kurlrequester.h> +#include <kdebug.h> +#include <qradiobutton.h> +#include <kio/scheduler.h> +#include <kprocess.h> +#include <kdeversion.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kdebug.h> + +#include <kio/netaccess.h> + +using namespace KIO; + +SvnIntegratorDlg::SvnIntegratorDlg( QWidget *parent, const char *name ) + : SvnIntegratorDlgBase( parent, name ) +{ + repos1->setMode( KFile::Directory ); +} + +void SvnIntegratorDlg::accept() +{ + // to let ioslave know which protocol it should start. + KURL protocolUrl = KURL("kdevsvn+svn://blah/"); + KURL servURL( repos1->url() ); + if ( servURL.isEmpty() ) return; + + kdDebug( 9036 ) << "servURL : " << servURL.prettyURL() << endl; + if ( createProject->isChecked() ) + { + KURL::List list; + list << servURL; // project root directory + KURL miscURL = servURL.url(); + miscURL.setPath( servURL.path() + "/tags/" ); + list << miscURL; + miscURL.setPath( servURL.path() + "/branches/" ); + list << miscURL; + miscURL.setPath( servURL.path() + "/trunk/" ); + list << miscURL; + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 10; // MKDIR(list) + s << cmd << list; + KIO::SimpleJob* job = KIO::special( protocolUrl, parms, true ); + if( !NetAccess::synchronousRun( job, 0 ) ){ + KMessageBox::error( this, i18n("Unable to create project directories on repository") ); + return; + } + + QByteArray parms2; + QDataStream s2( parms2, IO_WriteOnly ); + cmd = 5; //IMPORT + servURL.setPath( servURL.path() + "/trunk/" ); + s2 << cmd << servURL << KURL::fromPathOrURL( m_projectLocation ); + KIO::SimpleJob* importJob = KIO::special( protocolUrl, parms2, true ); + if( !NetAccess::synchronousRun( importJob, 0 ) ){ + KMessageBox::error( this, i18n("Unable to import into repository.") ); + return; + } + } + //delete the template directory and checkout a fresh one from the server + BlockingKProcess *rmproc = new BlockingKProcess(); + *rmproc << "rm"; + *rmproc << "-f" << "-r" << m_projectLocation; + rmproc->start(); + + delete rmproc; + rmproc = NULL; + + QByteArray parms3; + QDataStream s3( parms3, IO_WriteOnly ); + int cmd2 = 1; //CHECKOUT + int rev = -1; + + s3 << cmd2 << servURL << KURL::fromPathOrURL( m_projectLocation ) << rev << QString( "HEAD" ); + SimpleJob *job2 = KIO::special( protocolUrl, parms3, true ); + if( ! NetAccess::synchronousRun( job2, 0 ) ){ + // Checkout failed + KMessageBox::error(this, i18n("Unable to checkout from repository.") ); + return; + } +} + +void SvnIntegratorDlg::init( const QString &projectName, const QString &projectLocation ) +{ + m_name = projectName; + m_projectLocation = projectLocation; +} + +QWidget *SvnIntegratorDlg::self() +{ + return const_cast<SvnIntegratorDlg*>( this ); +} + +#include "svnintegratordlg.moc" diff --git a/vcs/subversion/integrator/svnintegratordlg.h b/vcs/subversion/integrator/svnintegratordlg.h new file mode 100644 index 00000000..c68ee256 --- /dev/null +++ b/vcs/subversion/integrator/svnintegratordlg.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * adymo@kdevelop.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SVNINTEGRATORDLG_H +#define SVNINTEGRATORDLG_H + +#include "svnintegratordlgbase.h" +#include <kdevvcsintegrator.h> + +class SvnIntegratorDlg: public SvnIntegratorDlgBase, public VCSDialog { +Q_OBJECT +public: + SvnIntegratorDlg(QWidget *parent = 0, const char *name = 0); + + virtual void accept(); + virtual void init(const QString &projectName, const QString &projectLocation); + virtual QWidget *self(); +private: + QString m_name; + QString m_projectLocation; +}; + +#endif diff --git a/vcs/subversion/integrator/svnintegratordlgbase.ui b/vcs/subversion/integrator/svnintegratordlgbase.ui new file mode 100644 index 00000000..a2ec9982 --- /dev/null +++ b/vcs/subversion/integrator/svnintegratordlgbase.ui @@ -0,0 +1,190 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnIntegratorDlgBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SvnIntegratorDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>648</width> + <height>429</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QButtonGroup" row="0" column="0"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string></string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>doNothing</cstring> + </property> + <property name="text"> + <string>&Do not do anything</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Adds subversion menus to project. + +NOTE: Unless you import the project +out of kdevelop, you will not be able +to perform any subversion operations.</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Adds subversion menus to project. + +NOTE: Unless you import the project +out of kdevelop, you will not be able +to perform any subversion operations.</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>createProject</cstring> + </property> + <property name="text"> + <string>&Create a project tree and import new project into trunk, then checkout from the repository</string> + </property> + <property name="toolTip" stdset="0"> + <string>Creates project, imports it into the subversion +repository and checks it out as a working copy. + +NOTE: The repository has to exist. +e.g. has been created with 'svnadmin'</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Creates project, imports it into the subversion +repository and checks it out as a working copy. + +NOTE: The repository has to exist. +e.g. has been created with 'svnadmin'</string> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Example for the url (if /home/user/subversion is the subversion repository): +file:///home/user/subversion/mynewproject</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>repositoryLabel1</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Repository:</string> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>repos1</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip" stdset="0"> + <string>Subversion repository location. +The repository has to exist - +e.g. has been created with 'svnadmin'</string> + </property> + <property name="whatsThis" stdset="0"> + <string>Subversion repository location. This should include the subdirectory for the project in the repository. The project subdirectory and further subdirectories will be created. + +So for example if you give http://localhost/svn/projectname the following directories will be created and the project imported into the trunk subdirectory: +http://localhost/svn/projectname +http://localhost/svn/projectname/tags +http://localhost/svn/projectname/branches +http://localhost/svn/projectname/trunk</string> + </property> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>131</height> + </size> + </property> + </spacer> + </vbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>createProject</sender> + <signal>toggled(bool)</signal> + <receiver>repositoryLabel1</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>createProject</sender> + <signal>toggled(bool)</signal> + <receiver>repos1</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/kdevpart_subversion.rc b/vcs/subversion/kdevpart_subversion.rc new file mode 100644 index 00000000..ad957e99 --- /dev/null +++ b/vcs/subversion/kdevpart_subversion.rc @@ -0,0 +1,31 @@ +<!DOCTYPE kpartgui> +<kpartplugin name="subversion" library="libsubversionplugin" version="2"> +<MenuBar> + <Menu name="tools"><Text>&Tools</Text> + <Menu name="version_control"><Text>&Version Control</Text> + <Merge/> + <Menu name="version_control_tools_subversion" group="tools_project_operations"> + <Text>&Subversion</Text> + <Action name="subversion_commit" /> + <Action name="subversion_diff" /> + <Action name="subversion_log" /> + <Action name="subversion_add" /> + <Action name="subversion_add_bin" /> + <Action name="subversion_remove" /> + <Separator /> + <Action name="subversion_tag" /> + <Action name="subversion_untag" /> + <Action name="subversion_update" /> + <Action name="subversion_removesticky" /> + <Action name="subversion_revert" /> + <Separator /> + <Action name="subversion_ignore" /> + <Action name="subversion_donot_ignore" /> +<!-- <Separator /> + <Action name="subversion_login" /> + <Action name="subversion_logout" /> --> + </Menu> + </Menu> + </Menu> +</MenuBar> +</kpartplugin> diff --git a/vcs/subversion/kdevsubversion.desktop b/vcs/subversion/kdevsubversion.desktop new file mode 100644 index 00000000..500b5fb0 --- /dev/null +++ b/vcs/subversion/kdevsubversion.desktop @@ -0,0 +1,34 @@ +[Desktop Entry] +Type=Service +Exec=blubb +Comment=Subversion +Comment[fa]=زیرنسخه +Comment[hi]=सबवरà¥à¤¸à¤¨ +Comment[ne]=सबà¤à¤°à¥à¤¸à¤¨ +Comment[pt_BR]=Subversão +Comment[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion +Comment[ta]=உப பதிபà¯à®ªà¯ +Comment[tg]=ИнтегратÑÐ¸Ñ Subversion +Name=KDevsubversion +Name[da]=KDevelop Subversion +Name[de]=Unterstützung für Subversion (KDevelop) +Name[hi]=के-डेव-सबवरà¥à¤¸à¤¨ +Name[nds]=Subversion-Ãœnnerstütten för KDevelop +Name[sk]=KDev Subversion +Name[sv]=KDevelop Subversion +Name[ta]=kdev உப பதிபà¯à®ªà¯ +Name[tg]=KDevзер-ривоÑÑ‚ +Name[zh_TW]=KDevelop Subversion +GenericName=Subversion +GenericName[fa]=زیرنسخه +GenericName[hi]=सबवरà¥à¤¸à¤¨ +GenericName[ne]=सबà¤à¤°à¥à¤¸à¤¨ +GenericName[pt_BR]=Subversão +GenericName[ru]=Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Subversion +GenericName[ta]=தà¯à®£à¯ˆ பதிபà¯à®ªà¯ +GenericName[tg]=Зер-ривоÑÑ‚ +Icon=misc +ServiceTypes=KDevelop/VersionControl +X-KDE-Library=libkdevsubversion +X-KDevelop-Version=5 +X-KDevelop-Properties=VCS,SubversionVCS diff --git a/vcs/subversion/kdevsvn+file.protocol b/vcs/subversion/kdevsvn+file.protocol new file mode 100644 index 00000000..decc1cc4 --- /dev/null +++ b/vcs/subversion/kdevsvn+file.protocol @@ -0,0 +1,39 @@ +[Protocol] +exec=kio_kdevsvn +protocol=kdevsvn+file +input=none +output=filesystem +reading=true +writing=true +deleting=true +makedir=true +linking=false +moving=true +deleteRecursive=true +listing=Name,Size,Date,Owner +defaultMimetype=application/octet-stream +Icon=remote +Description=Subversion ioslave for KDevelop +Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop +Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop) +Description[el]=Subversion ioslave για το KDevelop +Description[es]=El ioslave de Subversion para KDevelop +Description[et]=KDevelopi Subversioni IO-moodul +Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop +Description[hu]=Subversion KDE-protokoll a KDevelophoz +Description[it]=ioslave di subversion per KDevelop +Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave +Description[ms]=IOslave Subversion untuk KDevelop +Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion +Description[nl]=Subversion-ioslave voor KDevelop +Description[pl]=Wtyczka protokoÅ‚u Subversion dla KDevelopa +Description[pt]='Ioslave' do Subversion para o KDevelop +Description[pt_BR]='Ioslave' do Subversion para o KDevelop +Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop +Description[sk]=Subversion ioslave pre KDevelop +Description[sr]=KIOSlave Subversion-а за KDevelop +Description[sr@Latn]=KIOSlave Subversion-a za KDevelop +Description[sv]=Subversion I/O-slav för KDevelop +Description[zh_TW]=KDevelop çš„ Subversion ioslave +maxInstances=5 +class=:internet diff --git a/vcs/subversion/kdevsvn+http.protocol b/vcs/subversion/kdevsvn+http.protocol new file mode 100644 index 00000000..5e836c02 --- /dev/null +++ b/vcs/subversion/kdevsvn+http.protocol @@ -0,0 +1,39 @@ +[Protocol] +exec=kio_kdevsvn +protocol=kdevsvn+http +input=none +output=filesystem +reading=true +writing=true +deleting=true +makedir=true +linking=false +moving=true +deleteRecursive=true +listing=Name,Size,Date,Owner +defaultMimetype=application/octet-stream +Icon=remote +Description=Subversion ioslave for KDevelop +Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop +Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop) +Description[el]=Subversion ioslave για το KDevelop +Description[es]=El ioslave de Subversion para KDevelop +Description[et]=KDevelopi Subversioni IO-moodul +Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop +Description[hu]=Subversion KDE-protokoll a KDevelophoz +Description[it]=ioslave di subversion per KDevelop +Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave +Description[ms]=IOslave Subversion untuk KDevelop +Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion +Description[nl]=Subversion-ioslave voor KDevelop +Description[pl]=Wtyczka protokoÅ‚u Subversion dla KDevelopa +Description[pt]='Ioslave' do Subversion para o KDevelop +Description[pt_BR]='Ioslave' do Subversion para o KDevelop +Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop +Description[sk]=Subversion ioslave pre KDevelop +Description[sr]=KIOSlave Subversion-а за KDevelop +Description[sr@Latn]=KIOSlave Subversion-a za KDevelop +Description[sv]=Subversion I/O-slav för KDevelop +Description[zh_TW]=KDevelop çš„ Subversion ioslave +maxInstances=5 +class=:internet diff --git a/vcs/subversion/kdevsvn+https.protocol b/vcs/subversion/kdevsvn+https.protocol new file mode 100644 index 00000000..af9301af --- /dev/null +++ b/vcs/subversion/kdevsvn+https.protocol @@ -0,0 +1,39 @@ +[Protocol] +exec=kio_kdevsvn +protocol=kdevsvn+https +input=none +output=filesystem +reading=true +writing=true +deleting=true +makedir=true +linking=false +moving=true +deleteRecursive=true +listing=Name,Size,Date,Owner +defaultMimetype=application/octet-stream +Icon=remote +Description=Subversion ioslave for KDevelop +Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop +Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop) +Description[el]=Subversion ioslave για το KDevelop +Description[es]=El ioslave de Subversion para KDevelop +Description[et]=KDevelopi Subversioni IO-moodul +Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop +Description[hu]=Subversion KDE-protokoll a KDevelophoz +Description[it]=ioslave di subversion per KDevelop +Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave +Description[ms]=IOslave Subversion untuk KDevelop +Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion +Description[nl]=Subversion-ioslave voor KDevelop +Description[pl]=Wtyczka protokoÅ‚u Subversion dla KDevelopa +Description[pt]='Ioslave' do Subversion para o KDevelop +Description[pt_BR]='Ioslave' do Subversion para o KDevelop +Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop +Description[sk]=Subversion ioslave pre KDevelop +Description[sr]=KIOSlave Subversion-а за KDevelop +Description[sr@Latn]=KIOSlave Subversion-a za KDevelop +Description[sv]=Subversion I/O-slav för KDevelop +Description[zh_TW]=KDevelop çš„ Subversion ioslave +maxInstances=5 +class=:internet diff --git a/vcs/subversion/kdevsvn+ssh.protocol b/vcs/subversion/kdevsvn+ssh.protocol new file mode 100644 index 00000000..33a644f0 --- /dev/null +++ b/vcs/subversion/kdevsvn+ssh.protocol @@ -0,0 +1,39 @@ +[Protocol] +exec=kio_kdevsvn +protocol=kdevsvn+ssh +input=none +output=filesystem +reading=true +writing=true +deleting=true +makedir=true +linking=false +moving=true +deleteRecursive=true +listing=Name,Size,Date,Owner +defaultMimetype=application/octet-stream +Icon=remote +Description=Subversion ioslave for KDevelop +Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop +Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop) +Description[el]=Subversion ioslave για το KDevelop +Description[es]=El ioslave de Subversion para KDevelop +Description[et]=KDevelopi Subversioni IO-moodul +Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop +Description[hu]=Subversion KDE-protokoll a KDevelophoz +Description[it]=ioslave di subversion per KDevelop +Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave +Description[ms]=IOslave Subversion untuk KDevelop +Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion +Description[nl]=Subversion-ioslave voor KDevelop +Description[pl]=Wtyczka protokoÅ‚u Subversion dla KDevelopa +Description[pt]='Ioslave' do Subversion para o KDevelop +Description[pt_BR]='Ioslave' do Subversion para o KDevelop +Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop +Description[sk]=Subversion ioslave pre KDevelop +Description[sr]=KIOSlave Subversion-а за KDevelop +Description[sr@Latn]=KIOSlave Subversion-a za KDevelop +Description[sv]=Subversion I/O-slav för KDevelop +Description[zh_TW]=KDevelop çš„ Subversion ioslave +maxInstances=5 +class=:internet diff --git a/vcs/subversion/kdevsvn+svn.protocol b/vcs/subversion/kdevsvn+svn.protocol new file mode 100644 index 00000000..0f9ab069 --- /dev/null +++ b/vcs/subversion/kdevsvn+svn.protocol @@ -0,0 +1,39 @@ +[Protocol] +exec=kio_kdevsvn +protocol=kdevsvn+svn +input=none +output=filesystem +reading=true +writing=true +deleting=true +makedir=true +linking=false +moving=true +deleteRecursive=true +listing=Name,Size,Date,Owner +defaultMimetype=application/octet-stream +Icon=remote +Description=Subversion ioslave for KDevelop +Description[ca]=L'esclau io (ioslave) Subversion per a KDevelop +Description[de]=Ein-/Ausgabemodul für Subversion (KDevelop) +Description[el]=Subversion ioslave για το KDevelop +Description[es]=El ioslave de Subversion para KDevelop +Description[et]=KDevelopi Subversioni IO-moodul +Description[fr]=Esclave d'E/S (ioslave) Subversion pour KDevelop +Description[hu]=Subversion KDE-protokoll a KDevelophoz +Description[it]=ioslave di subversion per KDevelop +Description[ja]=KDevelop ã®ãŸã‚ã® Subversion ioslave +Description[ms]=IOslave Subversion untuk KDevelop +Description[nds]=KDevelop-In-/Utgaavmoduul för Subversion +Description[nl]=Subversion-ioslave voor KDevelop +Description[pl]=Wtyczka protokoÅ‚u Subversion dla KDevelopa +Description[pt]='Ioslave' do Subversion para o KDevelop +Description[pt_BR]='Ioslave' do Subversion para o KDevelop +Description[ru]=Поддержка протокола Subversion Ð´Ð»Ñ KDevelop +Description[sk]=Subversion ioslave pre KDevelop +Description[sr]=KIOSlave Subversion-а за KDevelop +Description[sr@Latn]=KIOSlave Subversion-a za KDevelop +Description[sv]=Subversion I/O-slav för KDevelop +Description[zh_TW]=KDevelop çš„ Subversion ioslave +maxInstances=5 +class=:internet diff --git a/vcs/subversion/kdevsvnd.cpp b/vcs/subversion/kdevsvnd.cpp new file mode 100644 index 00000000..9963cddd --- /dev/null +++ b/vcs/subversion/kdevsvnd.cpp @@ -0,0 +1,394 @@ +/* + This file is part of the KDE Project + + Copyright (C) 2003, 2004 Mickael Marchand <marchand@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kfiledialog.h> +#include <ktextedit.h> +#include <kpassdlg.h> +#include <qdir.h> +#include <qfile.h> + +#include "config.h" + +#include "kdevsvnd.h" + +#include "kdevsvnd_widgets.h" +#include "commitdlg.h" + +extern "C" { + KDE_EXPORT KDEDModule *create_kdevsvnd(const QCString &name) { + return new KDevSvnd(name); + } +} + +KDevSvnd::KDevSvnd(const QCString &name) + : KDEDModule(name) { +} +KDevSvnd::~KDevSvnd() +{} + +QString KDevSvnd::commitDialog(QString modifiedFiles) { + CommitDlg commitDlg; + commitDlg.setCaption(i18n("Enter Commit Log Message:")); + commitDlg.listMessage->setText( modifiedFiles ); + int result = commitDlg.exec(); + if ( result == QDialog::Accepted ) { + return commitDlg.textMessage->text(); + } else + return QString::null; +} +int KDevSvnd::sslServerTrustPrompt( QString errmsg, QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert ) +{ + SvnSSLTrustPrompt dlg; + dlg.setupCertInfo( hostname, fingerPrint, validfrom, validuntil, issuerName, ascii_cert ); + dlg.setupFailedReasonMsg( errmsg ); + int result = dlg.exec(); + if ( result == QDialog::Accepted ){ + return dlg.code(); + } else{ + return -1; + } +} +QString KDevSvnd::sslCertFile() +{ + QString fileName = KFileDialog::getOpenFileName(QString::null,QString::null,0, i18n("Open SSL certificate file")); + return fileName; +} +QCString KDevSvnd::sslPasswdDlg(QString promptMsg) +{ + QCString passwd; + int ret = KPasswordDialog::getPassword( passwd,promptMsg ); + if( ret == KPasswordDialog::Accepted ){ + QCString retstr; + retstr.setNum(1); + return retstr + passwd; + } else{ + QCString nullstr; + nullstr.setNum(-1); + return nullstr; + } +} + + +// void KDevSvnd::registerMe(const QCString &app) +// { +// insert(app, "test", new TestObject(app)); +// // When 'app' unregisters with DCOP, the TestObject will get deleted. +// } + +// bool KSvnd::AreAnyFilesInSvn( const KURL::List& wclist ) { +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl; +// QDir bdir ( ( *it ).path() ); +// if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) { +// return true; +// } else if ( !bdir.exists() ) { +// if ( isFileInSvnEntries( ( *it ).fileName(), ( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) ) +// return true; +// } +// } +// return false; +// } +// +// bool KSvnd::AreAnyFilesNotInSvn( const KURL::List& wclist ) { +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl; +// QDir bdir ( ( *it ).path() ); +// if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) { +// return true; +// } else if ( !bdir.exists() ) { +// if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) ) +// return true; +// } +// } +// return false; +// } +// +// bool KSvnd::AreAllFilesInSvn( const KURL::List& wclist ) { +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl; +// QDir bdir ( ( *it ).path() ); +// if ( bdir.exists() && !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) { +// return false; +// } else if ( !bdir.exists() ) { +// if ( !isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) && !isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) ) +// return false; +// } +// } +// return true; +// } +// +// bool KSvnd::AreAllFilesNotInSvn( const KURL::List& wclist ) { +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// kdDebug( 9036 ) << "Checking file " << ( *it ) << endl; +// QDir bdir ( ( *it ).path() ); +// if ( bdir.exists() && QFile::exists( ( *it ).path() + "/.svn/entries" ) ) { +// return false; +// } else if ( !bdir.exists() ) { +// if ( isFileInSvnEntries( ( *it ).fileName(),( *it ).directory() + "/.svn/entries" ) || isFileInExternals ( ( *it ).fileName(), ( *it ).directory()+"/.svn/dir-props" ) ) +// return false; +// } +// } +// return true; +// } +// +// bool KSvnd::isFileInSvnEntries ( const QString filename, const QString entfile ) { +// QFile file( entfile ); +// if ( file.open( IO_ReadOnly ) ) { +// QTextStream stream( &file ); +// QString line; +// while ( !stream.atEnd() ) { +// line = stream.readLine().simplifyWhiteSpace(); +// if ( line == "name=\""+ filename + "\"" ) { +// file.close(); +// return true; +// } +// } +// file.close(); +// } +// return false; +// } +// +// bool KSvnd::isFileInExternals ( const QString filename, const QString propfile ) { +// QFile file( propfile ); +// if ( file.open( IO_ReadOnly ) ) { +// QTextStream stream( &file ); +// QStringList line; +// while ( !stream.atEnd() ) +// line << stream.readLine().simplifyWhiteSpace(); +// for ( uint i = 0 ; i < line.count(); i++ ) { +// if ( line[ i ] == "K 13" && line[ i+1 ] == "svn:externals" ) { //Key 13 : svn:externals +// //next line should be "V xx" +// if ( line [ i+2 ].startsWith( "V " ) ) { +// //ok browse the values now +// i+=2; +// while ( i < line.count() ) { +// if ( line[ i ].startsWith( filename+" " ) ) { //found it ! +// file.close( ); +// return true; +// } else if ( line[ i ].isEmpty() ) { +// file.close( ); +// return false; //we are out of svn:externals now... +// } +// i++; +// } +// } +// } +// } +// file.close(); +// } +// return false; +// } +// +// bool KSvnd::anyNotValidWorkingCopy( const KURL::List& wclist ) { +// bool result = true; //one negative match is enough +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// //exception for .svn dirs +// if ( ( *it ).path(-1).endsWith( "/.svn" ) ) +// return true; +// //if is a directory check whether it contains a .svn/entries file +// QDir dir( ( *it ).path() ); +// if ( dir.exists() ) { //it's a dir +// if ( !QFile::exists( ( *it ).path() + "/.svn/entries" ) ) +// result = false; +// } +// +// //else check if ./.svn/entries exists +// if ( !QFile::exists( ( *it ).directory() + "/.svn/entries" ) ) +// result = false; +// } +// return result; +// } +// +// bool KSvnd::anyValidWorkingCopy( const KURL::List& wclist ) { +// for ( QValueListConstIterator<KURL> it = wclist.begin(); it != wclist.end() ; ++it ) { +// //skip .svn dirs +// if ( ( *it ).path(-1).endsWith( "/.svn" ) ) +// continue; +// //if is a directory check whether it contains a .svn/entries file +// QDir dir( ( *it ).path() ); +// if ( dir.exists() ) { //it's a dir +// if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) ) +// return true; +// } +// +// //else check if ./.svn/entries exists +// if ( QFile::exists( ( *it ).directory() + "/.svn/entries" ) ) +// return true; +// } +// return false; +// } +// +// int KSvnd::getStatus( const KURL::List& list ) { +// int result = 0; +// uint files = 0, folders = 0, parentsentries = 0, parentshavesvn = 0, subdirhavesvn = 0, external = 0; +// for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) { +// if ( isFolder ( ( *it ) ) ) { +// folders++; +// } else { +// files++; +// } +// if ( isFileInSvnEntries ( (*it).filename(),( *it ).directory() + "/.svn/entries" ) ) { // normal subdir known in the working copy +// parentsentries++; +// } else if ( isFolder( *it ) ) { // other subfolders (either another module checkouted or an external, or something not known at all) +// if ( QFile::exists( ( *it ).path() + "/.svn/entries" ) ) +// subdirhavesvn++; +// if ( isFileInExternals( (*it).filename(), ( *it ).directory() + "/.svn/dir-props" ) ) { +// external++; +// } +// } +// if ( ( isFolder( ( *it ) ) && QFile::exists( ( *it ).directory() + "../.svn/entries" ) ) || QFile::exists( ( *it ).directory() + "/.svn/entries" ) ) //parent has a .svn ? +// parentshavesvn++; +// } +// if ( files > 0 ) +// result |= SomeAreFiles; +// if ( folders == list.count() ) { +// result |= AllAreFolders; +// result |= SomeAreFolders; +// } +// if ( folders > 0 ) +// result |= SomeAreFolders; +// if ( parentsentries == list.count() ) { +// result |= AllAreInParentsEntries; +// result |= SomeAreInParentsEntries; +// } else if ( parentsentries != 0 ) +// result |= SomeAreInParentsEntries; +// if ( parentshavesvn == list.count() ) { +// result |= AllParentsHaveSvn; +// result |= SomeParentsHaveSvn; +// } else if ( parentshavesvn > 0 ) +// result |= SomeParentsHaveSvn; +// if ( subdirhavesvn == list.count() ) { +// result |= AllHaveSvn; +// result |= SomeHaveSvn; +// } else if ( subdirhavesvn > 0 ) +// result |= SomeHaveSvn; +// if ( external == list.count() ) { +// result |= AllAreExternalToParent; +// result |= SomeAreExternalToParent; +// } else if ( external > 0 ) +// result |= SomeAreExternalToParent; +// +// return result; +// } +// +// bool KSvnd::isFolder( const KURL& url ) { +// QDir d( url.path() ); +// return d.exists(); +// } +// +// QStringList KSvnd::getActionMenu ( const KURL::List &list ) { +// QStringList result; +// int listStatus = getStatus( list ); +// +// if ( !(listStatus & SomeAreInParentsEntries) && +// !(listStatus & SomeAreExternalToParent) && +// !(listStatus & SomeHaveSvn)) { +// if( list.size() == 1 && listStatus & SomeAreFolders) { +// result << "Checkout"; +// result << "Export"; +// // result << "CreateRepository"; +// result << "Import"; +// } +// } else if ( (listStatus & AllAreInParentsEntries) ) { +// result << "Diff"; +// //In SVN +// // result << "ShowLog"; +// // result << "CheckForModifications"; +// // result << "RevisionGraph"; +// // result << "_SEPARATOR_"; +// // result << "Update to revision..." +// result << "Rename"; +// result << "Delete"; +// if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) { +// result << "Revert"; +// // result << "Cleanup"; +// } +// result << "_SEPARATOR_"; +// // result << "BranchTag"; +// result << "Switch"; +// result << "Merge"; +// if( listStatus & SomeAreFolders && !(listStatus & SomeAreFiles)) { +// // result << "Export"; +// // result << "Relocate"; +// result << "_SEPARATOR_"; +// result << "Add"; +// } +// result << "_SEPARATOR_"; +// if( listStatus & SomeAreFiles && !(listStatus & SomeAreFolders)) { +// result << "Blame"; +// } +// result << "CreatePatch"; +// +// if( list.size() == 1 && listStatus & SomeAreFolders) { +// // result << "ApplyPatchToFolder"; +// } +// } +// return result; +// } +// +// QStringList KSvnd::getTopLevelActionMenu ( const KURL::List &list ) { +// QStringList result; +// int listStatus = getStatus( list ); +// +// +// if ( ( listStatus & AllParentsHaveSvn && +// ( ( listStatus & SomeAreExternalToParent ) || ( listStatus & SomeAreInParentsEntries ) ) +// || ( listStatus & SomeHaveSvn ) ) +// ) { +// result << "Update"; +// result << "Commit"; +// } +// +// return result; +// } +// +// #if 0 +// void KSvnd::notify(const QString& path, int action, int kind, const QString& mime_type, int content_state, int prop_state, long int revision, const QString& userstring) { +// kdDebug(9036) << "KDED/Subversion : notify " << path << " action : " << action << " mime_type : " << mime_type << " content_state : " << content_state << " prop_state : " << prop_state << " revision : " << revision << " userstring : " << userstring << endl; +// QByteArray params; +// +// QDataStream stream(params, IO_WriteOnly); +// stream << path << action << kind << mime_type << content_state << prop_state << revision << userstring; +// +// emitDCOPSignal( "subversionNotify(QString,int,int,QString,int,int,long int,QString)", params ); +// } +// +// void KSvnd::status(const QString& path, int text_status, int prop_status, int repos_text_status, int repos_prop_status, long int rev ) { +// kdDebug(9036) << "KDED/Subversion : status " << path << " " << text_status << " " << prop_status << " " +// << repos_text_status << " " << repos_prop_status << " " << rev << endl; +// QByteArray params; +// +// QDataStream stream(params, IO_WriteOnly); +// stream << path << text_status << prop_status << repos_text_status << repos_prop_status << rev; +// +// emitDCOPSignal( "subversionStatus(QString,int,int,int,int,long int)", params ); +// } +// +// void KSvnd::popupMessage( const QString& message ) { +// kdDebug(9036) << "KDED/Subversion : popupMessage" << message << endl; +// KMessageBox::information(0, message, i18n( "Subversion" ) ); +// } +// #endif + +#include "kdevsvnd.moc" diff --git a/vcs/subversion/kdevsvnd.desktop b/vcs/subversion/kdevsvnd.desktop new file mode 100644 index 00000000..139350f5 --- /dev/null +++ b/vcs/subversion/kdevsvnd.desktop @@ -0,0 +1,31 @@ +[Desktop Entry] +Type=Service +Name=KDevelop subversion module +Name[ca]=Mòdul de Subversion per a KDevelop +Name[da]=KDevelop Subversion-modul +Name[de]=Subversion-Komponente (KDevelop) +Name[el]=ΆÏθÏωμα subversion του KDevelop +Name[es]=Módulo de Subversion de KDevelop +Name[et]=KDevelopi Subversioni moodul +Name[fr]=Module Subversion pour KDevelop +Name[hu]=KDevelop-modul a Subversion kezeléséhez +Name[it]=Modulo subversion di KDevelop +Name[ja]=KDevelop Subversion モジュール +Name[ms]=Modul Subversion KDevelop +Name[nds]=KDevelop-Moduul för Subversion +Name[nl]=KDevelop subversion-module +Name[pl]=Modul Subversion dla KDevelopa +Name[pt]=Módulo de Subversion do KDevelop +Name[pt_BR]=Módulo de Subversion do KDevelop +Name[ru]=Модуль Subversion Ð´Ð»Ñ KDevelop +Name[sk]=KDevelop subversion modul +Name[sr]=KDevelop-ов модул за Subversion +Name[sr@Latn]=KDevelop-ov modul za Subversion +Name[sv]=KDevelop Subversion-modul +Name[zh_TW]=KDevelop Subversion 模組 +ServiceTypes=KDEDModule +X-KDE-ModuleType=Library +X-KDE-Library=kdevsvnd +X-KDE-FactoryName=kdevsvnd +X-KDE-Kded-autoload=true +X-KDE-Kded-load-on-demand=true diff --git a/vcs/subversion/kdevsvnd.h b/vcs/subversion/kdevsvnd.h new file mode 100644 index 00000000..ad718f0c --- /dev/null +++ b/vcs/subversion/kdevsvnd.h @@ -0,0 +1,50 @@ +/* + This file is part of the KDE Project + + Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef KSVND_H +#define KSVND_H + +#include <dcopclient.h> +#include <kdedmodule.h> +#include <kurl.h> +#include <qstringlist.h> + +class KDevSvnd : public KDEDModule +{ +Q_OBJECT + +K_DCOP + + //note: InSVN means parent is added. InRepos means itself is added + enum { SomeAreFiles = 1, SomeAreFolders = 2, SomeAreInParentsEntries = 4, SomeParentsHaveSvn = 8, SomeHaveSvn = 16, SomeAreExternalToParent = 32, AllAreInParentsEntries = 64, AllParentsHaveSvn = 128, AllHaveSvn = 256, AllAreExternalToParent = 512, AllAreFolders = 1024 }; +public: + KDevSvnd(const QCString &); + ~KDevSvnd(); + +k_dcop: +// void addAuthInfo(KIO::AuthInfo, long); + QString commitDialog(QString); + int sslServerTrustPrompt(QString certFailMsg, QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert ); + QString sslCertFile(); + QCString sslPasswdDlg(QString promptMsg); + +}; + +#endif diff --git a/vcs/subversion/kdevsvnd_widgets.cpp b/vcs/subversion/kdevsvnd_widgets.cpp new file mode 100644 index 00000000..16e35ce3 --- /dev/null +++ b/vcs/subversion/kdevsvnd_widgets.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include "kdevsvnd_widgets.h" +#include <qpushbutton.h> +#include <qlistview.h> +#include <qlabel.h> +#include <klocale.h> + +SvnSSLTrustPrompt::SvnSSLTrustPrompt( QWidget* parent, const char* name, bool modal, WFlags f ) + :SvnSSLTrustPromptBase( parent, name, modal, f ) + , m_code(-1) +{ + listView1->setColumnText( 0, "Items" ); + listView1->setColumnText( 1, "Values" ); + btnPermanent->setText(i18n("Accept Permanently")); + btnTemporary->setText(i18n("Accept Temporarily")); + btnReject->setText(i18n("Reject")); + connect( btnPermanent, SIGNAL(clicked()), this, SLOT(setPermanent()) ); + connect( btnTemporary, SIGNAL(clicked()), this, SLOT(setTemporary()) ); + connect( btnReject, SIGNAL(clicked()), this, SLOT(setRejected ()) ); +} +SvnSSLTrustPrompt::~SvnSSLTrustPrompt() +{} + +void SvnSSLTrustPrompt::setupCertInfo( QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert ) +{ + // setup texts + QListViewItem *host= new QListViewItem(listView1, i18n("Hostname"), hostname ); + QListViewItem *finger = new QListViewItem(listView1, i18n("FingerPrint"), fingerPrint ); + QListViewItem *validFrom = new QListViewItem(listView1, i18n("Valid From"), validfrom ); + QListViewItem *validUntil = new QListViewItem(listView1, i18n("Valid Until"), validuntil ); + QListViewItem *issName = new QListViewItem(listView1, i18n("Issuer"), issuerName ); + QListViewItem *cert = new QListViewItem(listView1, i18n("Cert"), ascii_cert ); +} +void SvnSSLTrustPrompt::setupFailedReasonMsg( QString msg ) +{ + errMsgLabel->setText( msg ); +} +int SvnSSLTrustPrompt::code() +{ + return m_code; +} + +void SvnSSLTrustPrompt::setPermanent() +{ + m_code = 1; +} + +void SvnSSLTrustPrompt::setTemporary() +{ + m_code = 0; +} + +void SvnSSLTrustPrompt::setRejected() +{ + m_code = -1; +} +#include "kdevsvnd_widgets.moc" diff --git a/vcs/subversion/kdevsvnd_widgets.h b/vcs/subversion/kdevsvnd_widgets.h new file mode 100644 index 00000000..c69fdb14 --- /dev/null +++ b/vcs/subversion/kdevsvnd_widgets.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#ifndef KDEVSVND_WIDGETS_H +#define KDEVSVND_WIDGETS_H + +#include "svnssltrustpromptbase.h" + +class SvnSSLTrustPrompt : public SvnSSLTrustPromptBase{ +Q_OBJECT +public: + SvnSSLTrustPrompt( QWidget* parent=0, const char* name=0, bool modal=true, WFlags f=0 ); + ~SvnSSLTrustPrompt(); + void setupCertInfo( QString hostname, QString fingerPrint, QString validfrom, QString validuntil, QString issuerName, QString ascii_cert ); + void setupFailedReasonMsg( QString msg ); + int code(); + +public slots: + void setPermanent(); + void setTemporary(); + void setRejected(); + +protected: + // -1 for reject + // 0 for accept temporarily + // 1 for accept permanently + int m_code; +}; + +#endif diff --git a/vcs/subversion/subversion_core.cpp b/vcs/subversion/subversion_core.cpp new file mode 100644 index 00000000..0a91d349 --- /dev/null +++ b/vcs/subversion/subversion_core.cpp @@ -0,0 +1,738 @@ +/** + Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#include <kparts/part.h> +#include <kdevcore.h> +#include <kdevproject.h> +#include "subversion_part.h" +#include "subversion_core.h" +#include "subversion_widget.h" +#include "svn_blamewidget.h" +#include "svn_logviewwidget.h" +#include "subversiondiff.h" +#include <kdevmainwindow.h> +#include "svn_co.h" +#include <kurlrequester.h> +#include <klineedit.h> +#include <kio/job.h> +#include <kio/jobclasses.h> +#include <kio/netaccess.h> +#include <kdebug.h> +#include <kmainwindow.h> +#include <kapplication.h> +#include <dcopclient.h> +#include <ktempfile.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <qtextcodec.h> +#include <qtextstream.h> +#include <qtextbrowser.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <qregexp.h> + +#include <kapplication.h> +#include <kinstance.h> +#include <kaboutdata.h> + +using namespace KIO; +using namespace SvnGlobal; + +subversionCore::subversionCore(subversionPart *part) +// : QObject(NULL, "subversion core"), DCOPObject("subversion") { + : QObject(NULL, "subversion core") { + m_part = part; + m_widget = new subversionWidget(part, 0 , "subversionprocesswidget"); +// m_logViewWidget = new SvnLogViewWidget( part, 0 ); +// m_part->mainWindow()->embedOutputView( m_logViewWidget, i18n( "Subversion Log" ), i18n( "Subversion Log" ) ); +// if ( ! connectDCOPSignal("kded", "ksvnd", "subversionNotify(QString,int,int,QString,int,int,long int,QString)", "notification(QString,int,int,QString,int,int,long int,QString)", false ) ) +// kdWarning() << "Failed to connect to kded dcop signal ! Notifications won't work..." << endl; + + m_fileInfoProvider = new SVNFileInfoProvider( part ); + diffTmpDir = new KTempDir(); + diffTmpDir->setAutoDelete(true); +} + +subversionCore::~subversionCore() { + if ( processWidget() ) { + m_part->mainWindow()->removeView( processWidget() ); + delete processWidget(); + } +// if( m_logViewWidget ){ +// m_part->mainWindow()->removeView( m_logViewWidget ); +// delete m_logViewWidget; +// } + delete diffTmpDir; + //FIXME delete m_fileInfoProvider here? +} + +KDevVCSFileInfoProvider *subversionCore::fileInfoProvider() const { + return m_fileInfoProvider; +} + +//not used anymore +// void subversionCore::notification( const QString& path, int action, int kind, const QString& mime_type, int content_state ,int prop_state ,long int revision, const QString& userstring ) { +// kdDebug(9036) << "Subversion Notification : " +// << "path : " << path +// << "action: " << action +// << "kind : " << kind +// << "mime_type : " << mime_type +// << "content_state : " << content_state +// << "prop_state : " << prop_state +// << "revision : " << revision +// << "userstring : " << userstring +// << endl; +// if ( !userstring.isEmpty() ) { +// m_part->mainWindow()->raiseView(processWidget()); +// processWidget()->append( userstring ); +// } +// } + +subversionWidget *subversionCore::processWidget() const { +// SvnLogViewWidget* subversionCore::processWidget() const { +// return processWidget(); +// return m_logViewWidget; + return m_widget; +} + +void subversionCore::resolve( const KURL::List& list ) { + KURL servURL = m_part->baseURL(); + if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/"; + if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) { + servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn" + } + kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl; + for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) { + kdDebug(9036) << "resolving: " << (*it).prettyURL() << endl; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 11; + bool recurse = true; + s << cmd << *it << recurse; + SimpleJob * job = KIO::special(servURL, parms, true); + job->setWindow( m_part->mainWindow()->main() ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + } +} + +void subversionCore::update( const KURL::List& list ) { + KURL servURL = "kdevsvn+svn://blah/"; + kdDebug(9036) << "Updating. servURL : " << servURL.prettyURL() << endl; + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 2; + int rev = -1; + s << cmd << list << rev << QString( "HEAD" ); + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, i18n("Subversion Update") , i18n("Subversion Update") ); +} + +void subversionCore::diff( const KURL::List& list, const QString& where){ + kdDebug(9036) << "diff " << list << endl; + KURL servURL = "kdevsvn+svn://this_is_a_fake_URL_and_this_is_normal/"; + for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) { + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 13; + kdDebug(9036) << "diffing : " << (*it).prettyURL() << endl; + int rev1=-1; + int rev2=-1; + QString revkind1 = where; + QString revkind2 = "WORKING"; + s << cmd << *it << *it << rev1 << revkind1 << rev2 << revkind2 << true ; + KIO::SimpleJob * job = KIO::special(servURL, parms, true); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + KIO::NetAccess::synchronousRun( job, 0 ); + if ( diffresult.count() > 0 ) { + //check kompare is available + if ( !KStandardDirs::findExe( "kompare" ).isNull() ) { + if (!KStandardDirs::findExe("patch").isNull()){ + // we have patch - so can merge + KTempDir tmpDir = KTempDir(diffTmpDir->name()); + KTempFile tmpPatch = KTempFile(tmpDir.name()); + + // write the patch + QTextStream *stream = tmpPatch.textStream(); + stream->setCodec( QTextCodec::codecForName( "utf8" ) ); + for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) { + ( *stream ) << ( *it2 ) << "\n"; + } + tmpPatch.close(); + + QString ourCopy = tmpDir.name()+(*it).fileName(); + + KProcess copy; + copy << "cp" << (*it).prettyURL(0,KURL::StripFileProtocol) << tmpDir.name(); + copy.start(KProcess::Block); + + KProcess patch; + patch.setWorkingDirectory(tmpDir.name()); + patch << "patch" << "-R" << ourCopy << tmpPatch.name(); + patch.start(KProcess::Block, KProcess::All); + + KProcess *p = new KProcess; + *p << "kompare" << ourCopy << (*it).prettyURL(); + p->start(); + } + else{ + // only diff + KTempFile *tmp = new KTempFile; + tmp->setAutoDelete(true); + QTextStream *stream = tmp->textStream(); + stream->setCodec( QTextCodec::codecForName( "utf8" ) ); + for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) { + ( *stream ) << ( *it2 ) << "\n"; + } + tmp->close(); + KProcess *p = new KProcess; + *p << "kompare" << "-n" << "-o" << tmp->name(); + p->start(); + } + } else { //else do it with message box + Subversion_Diff df; + for ( QStringList::Iterator it2 = diffresult.begin();it2 != diffresult.end() ; ++it2 ) { + df.text->append( *it2 ); + } + QFont f = df.font(); + f.setFixedPitch( true ); + df.text->setFont( f ); + df.exec(); + } + } + else{ + QString diffTo = i18n("the local disk checked out copy."); + if ( where=="HEAD"){ + diffTo=i18n("the current svn HEAD version."); + } + KMessageBox::information( 0, i18n("No differences between the file and %1").arg(diffTo), i18n("No difference") ); + } + diffresult.clear(); + } +} + +void subversionCore::diffAsync( const KURL &pathOrUrl1, const KURL &pathOrUrl2, + int rev1, QString revKind1, int rev2, QString revKind2, + bool recurse, bool pegdiff ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 13; + kdDebug(9036) << "diffing async : " << pathOrUrl1 << " and " << pathOrUrl2 << endl; + s << cmd << pathOrUrl1 << pathOrUrl2 << rev1 << revKind1 << rev2 << revKind2 << recurse; + s << pegdiff; + KIO::SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotDiffResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, pathOrUrl1.prettyURL(), pathOrUrl2.prettyURL() ); +} + +void subversionCore::commit( const KURL::List& list, bool recurse, bool keeplocks ) { + KURL servURL = m_part->baseURL(); + if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/"; + if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) { + servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn" + } + kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 103; + s << cmd << recurse << keeplocks; + for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) { + kdDebug(9036) << "adding to list: " << (*it).prettyURL() << endl; + s << *it; + } + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + if( list.count() == 1 ) + initProcessDlg( (KIO::Job*)job, (*(list.begin())).prettyURL() , i18n("Commit to remote repository") ); + else if( list.count() > 1 ) + initProcessDlg( (KIO::Job*)job, i18n("From working copy") , i18n("Commit to remote repository") ); +} +// Right now, only one item for each action. +void subversionCore::svnLog( const KURL::List& list, + int revstart, QString revKindStart, int revend, QString revKindEnd, + bool discorverChangedPath, bool strictNodeHistory ) +{ + // ensure that part has repository information. This info is used to retrieve root repository URL + if( m_part->m_prjInfoMap.count() < 1 ) + clientInfo( KURL(m_part->project()->projectDirectory()), false, m_part->m_prjInfoMap ); + KURL servURL = m_part->baseURL(); + if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/"; + if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) { + servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn" + } + kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 4; +// int revstart = -1, revend = 0; +// QString revKindStart = "HEAD", revKindEnd = ""; +// bool repositLog = true, discorverChangedPath = true, strictNodeHistory = true; + s << cmd << revstart << revKindStart << revend << revKindEnd; + s << discorverChangedPath << strictNodeHistory; + for ( QValueListConstIterator<KURL> it = list.begin(); it != list.end() ; ++it ) { + kdDebug(9036) << "svnCore: adding to list: " << (*it).prettyURL() << endl; + s << *it; + } + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotLogResult( KIO::Job * ) ) ); + // progress info. LogView is allowed and meaninful only for one url in KDev3.4 + initProcessDlg( (KIO::Job*)job, (*(list.begin())).prettyURL() , i18n("Subversion Log View") ); +} + +void subversionCore::blame( const KURL &url, UrlMode mode, int revstart, QString revKindStart, int revend, QString revKindEnd ) +{ + KURL servURL = m_part->baseURL(); + if ( servURL.isEmpty() ) servURL="kdevsvn+svn://blah/"; + if ( ! servURL.protocol().startsWith( "kdevsvn+" ) ) { + servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn" + } + kdDebug(9036) << "servURL : " << servURL.prettyURL() << endl; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 14; + s << cmd << url << (int)mode ; + s << revstart << revKindStart << revend << revKindEnd ; + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotBlameResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, url.prettyURL() , i18n("Subversion Blame") ); +} + +void subversionCore::add( const KURL::List& list ) { + + KURL servURL = "kdevsvn+svn://blah/"; + kdDebug(9036) << "Deleting servURL : " << servURL.prettyURL() << endl; + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 6; + s << cmd << list; + // add/delete/revert works on local copy. Don't need to show progress dialog + SimpleJob * job = KIO::special(servURL, parms, false); + job->setWindow( m_part->mainWindow()->main() ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); +} + +void subversionCore::del( const KURL::List& list ) { + KURL servURL = "kdevsvn+svn://blah/"; + kdDebug(9036) << "Deleting servURL : " << servURL.prettyURL() << endl; + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 7; + s << cmd << list; + // add/delete/revert works on local copy. Don't need to show progress dialog + SimpleJob * job = KIO::special(servURL, parms, false); + job->setWindow( m_part->mainWindow()->main() ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); +} + +void subversionCore::revert( const KURL::List& list ) { + KURL servURL = "kdevsvn+svn://blah/"; + kdDebug(9036) << "Reverting servURL : " << servURL.prettyURL() << endl; + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 8; + s << cmd << list; + SimpleJob * job = KIO::special(servURL, parms, false); + job->setWindow( m_part->mainWindow()->main() ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); +} + +void subversionCore::checkout() { + svn_co checkoutDlg; + + if ( checkoutDlg.exec() == QDialog::Accepted ) { + //checkout :) + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + KURL servURL ( checkoutDlg.serverURL->url() ); + wcPath = checkoutDlg.localDir->url() + "/" + checkoutDlg.newDir->text(); + int cmd = 1; + int rev = -1; + s << cmd << servURL << KURL( wcPath ) << rev << QString( "HEAD" ); + servURL.setProtocol( "kdevsvn+" + servURL.protocol() ); //make sure it starts with "svn" + SimpleJob * job = KIO::special(servURL,parms, true); + job->setWindow( m_part->mainWindow()->main() ); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotEndCheckout( KIO::Job * ) ) ); + } +} + +void subversionCore::switchTree( const KURL &path, const KURL &repositUrl, + int revNum, const QString &revKind, bool recurse ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 12; + s << cmd << path << repositUrl ; + s << recurse << revNum << revKind; + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, repositUrl.prettyURL() , path.prettyURL() ); +} + +void subversionCore::switchRelocate( const KURL &path, + const KURL ¤tUrl, const KURL &newUrl, bool recurse ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 16; + s << cmd << path << currentUrl << newUrl << recurse; + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + // this doesn't contact repository +} + +void subversionCore::svnCopy( const KURL &src, int srcRev, const QString &srcRevKind, + const KURL &dest ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 17; + s << cmd << src << srcRev << srcRevKind << dest; + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, src.prettyURL(), dest.prettyURL() ); +} + +void subversionCore::merge( const KURL &src1, int rev1, QString revKind1, + const KURL &src2, int rev2, QString revKind2, const KURL &wc_path, + bool recurse, bool ignore_ancestry, bool force, bool dry_run ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + // prepare arguments + int cmd = 18; + s << cmd << src1 << rev1 << revKind1 << src2 << rev2 << revKind2 << wc_path; + s << recurse << ignore_ancestry << force << dry_run; + + SimpleJob * job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + initProcessDlg( (KIO::Job*)job, src1.prettyURL() + "\n" + src2.prettyURL() , + wc_path.prettyURL() ); +} + +bool subversionCore::clientInfo( KURL path_or_url, bool recurse, QMap< KURL, SvnInfoHolder> &holderMap ) +{ + KURL servURL = "kdevsvn+svn://blah/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 15; + s << cmd << path_or_url << -1 << QString("UNSPECIFIED") << -1 << QString("UNSPECIFIED") << recurse; + SimpleJob *job = KIO::special( servURL, parms, false ); + + QMap<QString,QString> ma; + KIO::NetAccess::synchronousRun(job, 0, 0, 0, &ma ); // synchronize + + QValueList<QString> keys = ma.keys(); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + int curIdx, lastIdx; + QRegExp rx( "([0-9]*)(.*)" ); + + for ( it = begin; it != end; /*++it*/) { + kdDebug(9036) << "METADATA key: " << *it << " value: " << ma[ *it ] << endl; + if ( rx.search( *it ) == -1 ) return false; // something is wrong ! :) + curIdx = lastIdx = rx.cap( 1 ).toInt(); + SvnInfoHolder holder; + + while ( curIdx == lastIdx ) { + if ( rx.cap( 2 ) == "PATH" ) + holder.path = KURL( ma[ *it ] ); + else if ( rx.cap( 2 ) == "URL" ) + holder.url = KURL( ma[*it] ); + else if ( rx.cap( 2 ) == "REV" ) + holder.rev= ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "KIND" ) + holder.kind = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "REPOS_ROOT_URL" ) + holder.reposRootUrl = KURL( ma[*it] ); + else if ( rx.cap( 2 ) == "REPOS_UUID" ) + holder.reposUuid = ma[ *it ]; + + ++it; + if ( it == end ) + break; + if ( rx.search( *it ) == -1 ) return false; // something is wrong ! :) + curIdx = rx.cap( 1 ).toInt(); + } + holderMap.insert( holder.path, holder ); + } + return true;; +} + +void subversionCore::slotEndCheckout( KIO::Job * job ) { + if ( job->error() ) { + job->showErrorDialog( m_part->mainWindow()->main() ); + emit checkoutFinished( QString::null ); + } else + emit checkoutFinished(wcPath); +} + +void subversionCore::slotResult( KIO::Job * job ) { + if ( job->error() ){ + job->showErrorDialog( m_part->mainWindow()->main() ); + if( job->error() == ERR_CANNOT_LAUNCH_PROCESS ) + KMessageBox::error( m_part->mainWindow()->main(), + i18n("If you have just have installed a new version of KDevelop," + " and the error message was 'unknown protocol kdevsvn+*'," + " try restarting KDE." + ) ); + return; + } + KIO::MetaData ma = job->metaData(); + QValueList<QString> keys = ma.keys(); + qHeapSort( keys ); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + + for ( it = begin; it != end; ++it ) { +// kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; + if ( ( *it ).endsWith( "string" ) ) { + m_part->mainWindow()->raiseView(processWidget()); + processWidget()->append( ma[ *it ] ); + } + //extra check to retrieve the diff output in case with run a diff command + if ( ( *it ).endsWith( "diffresult" ) ) { + diffresult << ma[ *it ]; + } + } +} +void subversionCore::slotLogResult( KIO::Job * job ) +{ + if ( job->error() ){ + job->showErrorDialog( m_part->mainWindow()->main() ); + if( job->error() == ERR_CANNOT_LAUNCH_PROCESS ) + KMessageBox::error( m_part->mainWindow()->main(), + i18n("If you have just have installed a new version of KDevelop," + " and the error message was 'unknown protocol kdevsvn+*'," + " try restarting KDE." + ) ); + return; + } + + QValueList<SvnLogHolder> holderList; + + KIO::MetaData ma = job->metaData(); + QValueList<QString> keys = ma.keys(); + QRegExp rx( "([0-9]*)(.*)" ); + int curIdx, lastIdx; + QString requestedUrl; + + for (QValueList<QString>::Iterator it = keys.begin(); it != keys.end(); /*++it*/ ){ + if ( rx.search( *it ) == -1 ){ + kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl; + return; // something is wrong ! :) + } + curIdx = lastIdx = rx.cap( 1 ).toInt(); + SvnLogHolder logHolder; + while ( curIdx == lastIdx ) { + kdDebug(9036) << "svn log MetaData: " << *it << ":" << ma[ *it ] << endl; + + if ( rx.cap( 2 ) == "author" ) + logHolder.author = ma[*it]; + else if ( rx.cap( 2 ) == "date" ) + logHolder.date = ma[*it]; + else if ( rx.cap( 2 ) == "logmsg" ) + logHolder.logMsg = ma[*it]; + else if ( rx.cap( 2 ) == "pathlist" ) + logHolder.pathList = ma[*it]; + else if ( rx.cap( 2 ) == "rev" ) + logHolder.rev = ma[*it]; + else if ( rx.cap( 2 ) == "requrl" ) + requestedUrl = ma[*it]; + + ++it; + if ( it == keys.end() ) + break; + if ( rx.search( *it ) == -1 ){ + kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl; + break; // something is wrong ! :) + } + curIdx = rx.cap( 1 ).toInt(); + }//end of while + holderList.append( logHolder ); + } + processWidget()->showLogResult( &holderList, requestedUrl ); + m_part->mainWindow()->raiseView(processWidget()); + +} + +void subversionCore::slotBlameResult( KIO::Job * job ) +{ + if ( job->error() ){ + job->showErrorDialog( m_part->mainWindow()->main() ); + if( job->error() == ERR_CANNOT_LAUNCH_PROCESS ) + KMessageBox::error( m_part->mainWindow()->main(), + i18n("If you have just have installed a new version of KDevelop," + " and the error message was 'unknown protocol kdevsvn+*'," + " try restarting KDE." + ) ); + return; + } + QValueList<SvnBlameHolder> blameList; + + KIO::MetaData ma = job->metaData(); + QValueList<QString> keys = ma.keys(); + QRegExp rx( "([0-9]*)(.*)" ); + int curIdx, lastIdx; + + for (QValueList<QString>::Iterator it = keys.begin(); it != keys.end(); /*++it*/ ){ + if ( rx.search( *it ) == -1 ){ + kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl; + return; // something is wrong ! :) + } + + // if metadata has action key, that means a notification for svn_wc_notify_blame_completed + // Thus, consume this notification + if ( rx.cap( 2 ) == "action" ){ + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ){ + ++it; + if ( it == keys.end() ) break; + if ( rx.search( *it ) == -1 ) continue; // something is wrong + curIdx = rx.cap( 1 ).toInt(); + } + continue; + } + // get actual blame data + curIdx = lastIdx = rx.cap( 1 ).toInt(); + SvnBlameHolder blameHolder; + while ( curIdx == lastIdx ) { + kdDebug(9036) << "svn blame MetaData: " << *it << ":" << ma[ *it ] << endl; + + if ( rx.cap( 2 ) == "LINE" ) + blameHolder.line= (ma[*it]).toInt(); + else if ( rx.cap( 2 ) == "REV" ) + blameHolder.rev = (ma[*it]).toLongLong(); + else if ( rx.cap( 2 ) == "AUTHOR" ) + blameHolder.author= ma[*it]; + else if ( rx.cap( 2 ) == "DATE" ) + blameHolder.date= ma[*it]; + else if ( rx.cap( 2 ) == "CONTENT" ) + blameHolder.content = ma[*it]; + + ++it; + if ( it == keys.end() ) + break; + if ( rx.search( *it ) == -1 ){ + kdDebug(9036) << " Exiting loop at line " << __LINE__ <<endl; + break; // something is wrong ! :) + } + curIdx = rx.cap( 1 ).toInt(); + }//end of while + blameList.append( blameHolder ); +// blameList.insert( blameHolder.line, blameHolder ); + } + processWidget()->showBlameResult( &blameList ); + m_part->mainWindow()->raiseView(processWidget()); +} + +void subversionCore::slotDiffResult( KIO::Job * job ) +{ + if ( job->error() ){ + job->showErrorDialog( m_part->mainWindow()->main() ); + if( job->error() == ERR_CANNOT_LAUNCH_PROCESS ) + KMessageBox::error( m_part->mainWindow()->main(), + i18n("If you have just have installed a new version of KDevelop," + " and the error message was 'unknown protocol kdevsvn+*'," + " try restarting KDE." + ) ); + return; + } + KIO::MetaData ma = job->metaData(); + QValueList<QString> keys = ma.keys(); + qHeapSort( keys ); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + QStringList diffList; + + for ( it = begin; it != end; ++it ) { +// kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; + if ( ( *it ).endsWith( "diffresult" ) ) { + diffList << ma[ *it ]; + } + } + + if ( diffList.count() > 0 ) { + //check kompare is available + if ( !KStandardDirs::findExe( "kompare" ).isNull() ) { + KTempFile *tmp = new KTempFile; + tmp->setAutoDelete(true); + QTextStream *stream = tmp->textStream(); + stream->setCodec( QTextCodec::codecForName( "utf8" ) ); + for ( QStringList::Iterator it2 = diffList.begin();it2 != diffList.end() ; ++it2 ) { + ( *stream ) << ( *it2 ) << "\n"; + } + tmp->close(); + KProcess *p = new KProcess; + *p << "kompare" << "-n" << "-o" << tmp->name(); + p->start(); + + } else { //else do it with message box + KMessageBox::information( NULL, i18n("You do not have kompare installed. We recommend you install kompare to view differences graphically.") + "\nhttp://www.caffeinated.me.uk/kompare/" , QString::null , "userDoesNotWantKompare" ); + Subversion_Diff df; + for ( QStringList::Iterator it2 = diffList.begin();it2 != diffList.end() ; ++it2 ) { + df.text->append( *it2 ); + } + QFont f = df.font(); + f.setFixedPitch( true ); + df.text->setFont( f ); + df.exec(); + } + } + else{ + KMessageBox::information( 0, i18n("No subversion differences") ); + } +} + +void subversionCore::initProcessDlg( KIO::Job *job, const QString &src, const QString &dest ) +{ + SvnProgressDlg *progress = new SvnProgressDlg( true ); + progress->setSourceUrl( src ); + progress->setDestUrl( dest ); + progress->setJob( job ); + connect( job, SIGNAL( totalSize(KIO::Job*, KIO::filesize_t) ), + progress, SLOT( slotTotalSize (KIO::Job*, KIO::filesize_t) ) ); + connect( job, SIGNAL( processedSize(KIO::Job*, KIO::filesize_t) ), + progress, SLOT( slotProcessedSize(KIO::Job*, KIO::filesize_t) ) ); +} + +void subversionCore::createNewProject( const QString& // dirName + , const KURL& // importURL + , bool // init + ) { + +} + +#include "subversion_core.moc" diff --git a/vcs/subversion/subversion_core.h b/vcs/subversion/subversion_core.h new file mode 100644 index 00000000..c879fce6 --- /dev/null +++ b/vcs/subversion/subversion_core.h @@ -0,0 +1,105 @@ +/** + + Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#ifndef __SUBVERSION_CORE_H__ +#define __SUBVERSION_CORE_H__ + +#include <qobject.h> +#include <qwidget.h> +#include <kio/job.h> +#include <kurl.h> +#include <ktempdir.h> +#include "subversion_fileinfo.h" +#include "subversion_global.h" + +class KDevProject; +class subversionPart; +class subversionWidget; +class KApplication; +class SvnBlameHolder; +class SvnLogHolder; +class SvnLogViewWidget; + +// class subversionCore : public QObject, public DCOPObject +class subversionCore : public QObject { + Q_OBJECT +// K_DCOP + +public: + + subversionCore(subversionPart *part); + ~subversionCore(); + subversionWidget *processWidget() const; +// SvnLogViewWidget *processWidget() const; + void update( const KURL::List&); + void commit( const KURL::List&, bool recurse, bool keeplocks ); + void svnLog( const KURL::List& list, + int revstart, QString revKindStart, int revend, QString revKindEnd, + bool discorverChangedPath, bool strictNodeHistory ); + void blame( const KURL &url, SvnGlobal::UrlMode mode, int revstart, QString revKindStart, int revend, QString revKindEnd ); + void add( const KURL::List&); + void del( const KURL::List&); + void diff( const KURL::List&, const QString& where); + void diffAsync( const KURL &pathOrUrl1, const KURL &pathOrUrl2, + int rev1, QString revKind1, int rev2, QString revKind2, + bool recurse, bool pegdiff = false ); + void revert( const KURL::List&); + void resolve( const KURL::List&); + void checkout(); + void switchTree( const KURL &path, const KURL &repositUrl, + int revNum, const QString &revKind, bool recurse ); + void switchRelocate( const KURL &path, const KURL ¤tUrl, const KURL &newUrl, bool recurse ); + void svnCopy( const KURL &src, int srcRev, const QString &srcRevKind, const KURL &dest ); + void merge( const KURL &src1, int rev1, QString revKind1, const KURL &src2, int rev2, QString revKind2, const KURL &wc_path, + bool recurse, bool ignore_ancestry, bool force, bool dry_run ); + // This is blocking function. But the GUI is not blocked. + // Information will be pulled solely from the working copy.Thus no network connections will be made. + // Parameter holderMap is the map to be filled out by this method. Callers should preallocate this object. + // Return true on success. Otherwise return false. + bool clientInfo( KURL path_or_url, bool recurse, QMap< KURL, SvnGlobal::SvnInfoHolder> &holderMap ); + void createNewProject( const QString& dirName, const KURL& importURL, bool init ); + KDevVCSFileInfoProvider *fileInfoProvider() const; + + void initProcessDlg( KIO::Job *job, const QString &src, const QString &dest ); +// k_dcop: +// void notification( const QString&, int,int, const QString&, int,int ,long int, const QString& ); + +private slots: + void slotEndCheckout( KIO::Job * job ); + void slotResult( KIO::Job * job ); + void slotLogResult( KIO::Job * job ); + void slotBlameResult( KIO::Job * job ); + void slotDiffResult( KIO::Job * job ); + +signals: + void checkoutFinished( QString dir ); + +private: + QGuardedPtr<subversionWidget> m_widget; + subversionPart *m_part; + QString wcPath; + SVNFileInfoProvider *m_fileInfoProvider; + QStringList diffresult; //for diff commands ;) + // be nice about tmp diff files: delete all of them when exiting. + KTempDir* diffTmpDir; + +}; + +#endif diff --git a/vcs/subversion/subversion_fileinfo.cpp b/vcs/subversion/subversion_fileinfo.cpp new file mode 100644 index 00000000..c9fb9ee6 --- /dev/null +++ b/vcs/subversion/subversion_fileinfo.cpp @@ -0,0 +1,507 @@ +/** + Copyright (C) 2004-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#include "subversion_fileinfo.h" +#include "subversion_core.h" +#include <kdebug.h> +#include <qfileinfo.h> +#include <qdir.h> +#include <kdevproject.h> +#include <unistd.h> +#include <kapplication.h> +#include <kdevmainwindow.h> +#include <kmainwindow.h> +#include <qregexp.h> + +#include <kio/netaccess.h> +#include <klocale.h> + +SVNFileInfoProvider::SVNFileInfoProvider(subversionPart *parent, const char *name) + : KDevVCSFileInfoProvider( parent, "svnfileinfoprovider" ), + m_cachedDirEntries( 0 ), m_recursiveDirEntries(0) { + Q_UNUSED(name); + m_part = parent; +} + +SVNFileInfoProvider::~SVNFileInfoProvider() { + delete m_cachedDirEntries; + m_cachedDirEntries = 0; + delete m_recursiveDirEntries; + m_recursiveDirEntries = 0; +} + +//synchronous +const VCSFileInfoMap *SVNFileInfoProvider::status( const QString &dirPath ) { + if ( !m_cachedDirEntries ) + m_cachedDirEntries = new VCSFileInfoMap; +// return m_cachedDirEntries; + + kdDebug(9036) << "svn provider : status " << dirPath << endl; + + if ( dirPath != m_previousDirPath ) { + m_previousDirPath = dirPath; + KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 9; + QString rPath = projectDirectory( ); + rPath += QDir::separator() + dirPath; + kdDebug(9036) << "DIR : " << rPath << " " << KURL( QFileInfo( rPath ).absFilePath() ) << endl; + +// s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << true << true; //original line + + // Dukju Ahn: if checkRepos is set, status() accesses remote repository, + // which causes significant delaym_owner especially when network speed is not fast enough. + // Of course, the user cannot get information about the out-of-dateness of his local copy. + s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << false/*checkRepos*/ << false /*fullRecurse*/; + + KIO::SimpleJob *job2 = KIO::special(servURL, parms, false); + job2->setWindow( m_part->mainWindow()->main() ); + + + QMap<QString,QString> ma; + + KIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma ); + + QValueList<QString> keys = ma.keys(); + qHeapSort( keys ); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + + QString path; + int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; + long int rev = 0; + int curIdx, lastIdx; + + QRegExp rx( "([0-9]*)(.*)" ); + for ( it = begin; it != end; ) { + kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; + if ( rx.search( *it ) == -1 ) return m_cachedDirEntries; // something is wrong ! :) + /* if some notification comes here, consume these notification metadatas */ + if ( rx.cap( 2 ) == "action" ){ + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ){ + ++it; + if ( it == end ) break; + if ( rx.search( *it ) == -1 ) continue; // something is wrong + curIdx = rx.cap( 1 ).toInt(); + } + continue; + } + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ) { + if ( rx.cap( 2 ) == "path" ) + path = ma[ *it ]; + else if ( rx.cap( 2 ) == "text" ) + text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "prop" ) + prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "reptxt" ) + repos_text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "repprop" ) + repos_prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "rev" ) + rev = ma[ *it ].toLong(); + ++it; + if ( it == end ) + break; + if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) + curIdx = rx.cap( 1 ).toInt(); + } + slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev); + } + } + kdDebug(9036) << " Returning VcsFileInfoMap. provider::status() finished " << endl; + return m_cachedDirEntries; +} + +bool SVNFileInfoProvider::requestStatus( const QString &dirPath, void *callerData, bool recursive, bool checkRepos ) { + kdDebug(9036) << "##################################################################################### svn provider : request status" << endl; + m_savedCallerData = callerData; + // Flush old cache + if (m_cachedDirEntries) + { + delete m_cachedDirEntries; + m_cachedDirEntries = 0; + m_previousDirPath = dirPath; + } + + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 9; + QString rPath = projectDirectory( ); + rPath += QDir::separator() + dirPath; + + if( ! m_part->isValidDirectory( rPath ) ){ + return false; + } + + kdDebug(9036) << "DIR : " << rPath << " " << QFileInfo( rPath ).absFilePath() << endl; + s << cmd << KURL( QFileInfo( rPath ).absFilePath() ) << checkRepos << recursive; + KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; + job = KIO::special(servURL, parms, false); + connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotResult( KIO::Job * ) ) ); + if( checkRepos ) + m_part->svncore()->initProcessDlg( job, dirPath, i18n("Subversion File/Directory Status") ); + return true; +} + +void SVNFileInfoProvider::slotResult( KIO::Job *j ) { + if ( j->error() ) + j->showErrorDialog( m_part->mainWindow()->main() ); + + KIO::MetaData ma = j->metaData(); + QValueList<QString> keys = ma.keys(); + qHeapSort( keys ); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + + QString path; + int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; + long int rev = 0; + int curIdx, lastIdx; + + QRegExp rx( "([0-9]*)(.*)" ); + for ( it = begin; it != end; ) { + kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; + if ( rx.search( *it ) == -1 ) return; // something is wrong ! :) + /* if some notification comes here, consume these notification metadatas */ + if ( rx.cap( 2 ) == "action" ){ + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ){ + ++it; + if ( it == end ) break; + if ( rx.search( *it ) == -1 ) continue; // something is wrong + curIdx = rx.cap( 1 ).toInt(); + } + continue; + } + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ) { + if ( rx.cap( 2 ) == "path" ) + path = ma[ *it ]; + else if ( rx.cap( 2 ) == "text" ) + text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "prop" ) + prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "reptxt" ) + repos_text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "repprop" ) + repos_prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "rev" ) + rev = ma[ *it ].toLong(); + ++it; + if ( it == end ) + break; + if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) + curIdx = rx.cap( 1 ).toInt(); + } + slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev); + } + + if ( m_cachedDirEntries ) + emit statusReady(*m_cachedDirEntries, m_savedCallerData); +} + +void SVNFileInfoProvider::slotStatus( const QString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) { +// kdDebug(9036) << "##################################################################################### svn provider : slotstatus" +// << " path " << path << " text_status " << text_status << " prop_status " << prop_status << " repos_text_status " << repos_text_status +// << " repos_prop_status " << repos_prop_status << " rev " << rev +// << endl; + + if ( !m_cachedDirEntries ) + m_cachedDirEntries = new VCSFileInfoMap; + + QString wRev = QString::number( rev ); //work rev + QString rRev = QString::number( rev );// repo rev + VCSFileInfo::FileState state = VCSFileInfo::Unknown; + + switch ( text_status ) { + case 1: + break; + case 2: + break; + case 3: + state = VCSFileInfo::Uptodate; + break; + case 4: + state = VCSFileInfo::Added; + break; + case 5: + break; + case 6: //deleted + state = VCSFileInfo::Deleted; + break; + case 7: //replaced + state = VCSFileInfo::Replaced; + break; + case 8: //modified + state = VCSFileInfo::Modified; + break; + case 9: //merged + break; + case 10: //conflicted + state = VCSFileInfo::Conflict; + break; + case 11: //ignored + break; + case 12: //obstructed + break; + case 13: //external + break; + case 14: //incomplete + break; + } + switch( prop_status ) { + case 8: + state = VCSFileInfo::Modified; + break; + } + switch ( repos_text_status ) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: //deleted + break; + case 7: //replaced + break; + case 8: //modified + state = VCSFileInfo::NeedsPatch; + break; + case 9: //merged + break; + case 10: //conflicted + break; + case 11: //ignored + break; + case 12: //obstructed + break; + case 13: //external + break; + case 14: //incomplete + break; + } + + VCSFileInfo info(QFileInfo( path ).fileName(),wRev,rRev,state); + kdDebug(9036) << "Inserting " << info.toString() << endl; + m_cachedDirEntries->insert( QFileInfo( path ).fileName(), info); +} + +QString SVNFileInfoProvider::projectDirectory() const { + return owner()->project()->projectDirectory(); +} + +const VCSFileInfoMap *SVNFileInfoProvider::statusExt( const QString &dirPath, + bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore ) +{ + if ( !m_recursiveDirEntries ) + m_recursiveDirEntries = new VCSFileInfoMap; + +// if ( dirPath != m_recursivePreviousDirPath ) { + m_recursiveDirEntries->clear(); + m_recursivePreviousDirPath = dirPath; + KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; + QByteArray parms; + QDataStream s( parms, IO_WriteOnly ); + int cmd = 109; + QString rPath = projectDirectory( ); + rPath += QDir::separator() + dirPath; + kdDebug(9036) << "DIR : " << rPath << " " << KURL( QFileInfo( rPath ).absFilePath() ) << endl; + s << cmd << checkRepos << fullRecurse << getAll << noIgnore << -1 << "WORKING" << KURL( QFileInfo( rPath ).absFilePath() ); + KIO::SimpleJob *job2 = KIO::special(servURL, parms, false); + job2->setWindow( m_part->mainWindow()->main() ); + + + QMap<QString,QString> ma; + KIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma ); + + QValueList<QString> keys = ma.keys(); + qHeapSort( keys ); + QValueList<QString>::Iterator begin = keys.begin(), end = keys.end(), it; + + QString path; + int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; + long int rev = 0; + int curIdx, lastIdx; + + QRegExp rx( "([0-9]*)(.*)" ); + for ( it = begin; it != end; ) { + kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; + if ( rx.search( *it ) == -1 ) return m_recursiveDirEntries; // something is wrong ! :) + /* if some notification comes here, consume these notification metadatas */ + if ( rx.cap( 2 ) == "action" ){ + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ){ + ++it; + if ( it == end ) break; + if ( rx.search( *it ) == -1 ) continue; // something is wrong + curIdx = rx.cap( 1 ).toInt(); + } + continue; + } + /* get properties */ + curIdx = lastIdx = rx.cap( 1 ).toInt(); + while ( curIdx == lastIdx ) { + if ( rx.cap( 2 ) == "path" ) + path = ma[ *it ]; + else if ( rx.cap( 2 ) == "text" ) + text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "prop" ) + prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "reptxt" ) + repos_text_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "repprop" ) + repos_prop_status = ma[ *it ].toInt(); + else if ( rx.cap( 2 ) == "rev" ) + rev = ma[ *it ].toLong(); + ++it; + if ( it == end ) + break; + if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) + curIdx = rx.cap( 1 ).toInt(); + } + slotStatusExt(dirPath, path, text_status, prop_status, repos_text_status, repos_prop_status, rev); + } +// } + + return m_recursiveDirEntries; +} + +void SVNFileInfoProvider::slotStatusExt( + const QString& reqPath, const QString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) +{ + + if ( !m_recursiveDirEntries ) + m_recursiveDirEntries = new VCSFileInfoMap; + + QString wRev = QString::number( rev ); //work rev + QString rRev = QString::number( rev );// repo rev + VCSFileInfo::FileState state = VCSFileInfo::Unknown; + + switch ( text_status ) { + case 1: // does not exist + break; + case 2: // unversioned + break; + case 3: + state = VCSFileInfo::Uptodate; + break; + case 4: + state = VCSFileInfo::Added; + break; + case 5: // missing + break; + case 6: //deleted + state = VCSFileInfo::Deleted; + break; + case 7: //replaced + state = VCSFileInfo::Replaced; + break; + case 8: //modified + state = VCSFileInfo::Modified; + break; + case 9: //merged + break; + case 10: //conflicted + state = VCSFileInfo::Conflict; + break; + case 11: //ignored + break; + case 12: //obstructed + break; + case 13: //external + break; + case 14: //incomplete + break; + } + switch( prop_status ) { + case 8: + state = VCSFileInfo::Modified; + break; + } + switch ( repos_text_status ) { + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: //deleted + break; + case 7: //replaced + break; + case 8: //modified + state = VCSFileInfo::NeedsPatch; + break; + case 9: //merged + break; + case 10: //conflicted + break; + case 11: //ignored + break; + case 12: //obstructed + break; + case 13: //external + break; + case 14: //incomplete + break; + } + + QString relativeReqPath; + if (reqPath == "./"){ + // case of project top directory + QString reqAbsPath = projectDirectory(); + + if( path == reqAbsPath ){ + //key of VCSInfo is project directory itself. So it is set to . + relativeReqPath = "."; + } + else{ + relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 ); + } + } + else { + QString reqAbsPath = projectDirectory() + QDir::separator() + reqPath; + relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 ); + + if (relativeReqPath == reqAbsPath){ + // case of requested directory itself. + relativeReqPath = "."; + } + } + + VCSFileInfo info(relativeReqPath, wRev, rRev, state); + m_recursiveDirEntries->insert( relativeReqPath, info ); + +// VCSFileInfo info(QFileInfo( path ).fileName(),wRev,rRev,state); + kdDebug(9036) << "Inserting " << info.toString() << endl; +// m_recursiveDirEntries->insert( QFileInfo( path ).fileName(), info); +} + +#include "subversion_fileinfo.moc" + diff --git a/vcs/subversion/subversion_fileinfo.h b/vcs/subversion/subversion_fileinfo.h new file mode 100644 index 00000000..e2ab1b70 --- /dev/null +++ b/vcs/subversion/subversion_fileinfo.h @@ -0,0 +1,73 @@ +/** + + Copyright (C) 2004-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#ifndef SVNFILEINFOPROVIDER_H +#define SVNFILEINFOPROVIDER_H + +#include <qmap.h> + +#include <kdevversioncontrol.h> +#include <kio/job.h> +#include <dcopclient.h> +#include <dcopobject.h> +#include <subversion_part.h> + +/** +Provider for SVN file information + +@author Mickael Marchand +*/ +class SVNFileInfoProvider : public KDevVCSFileInfoProvider, public DCOPObject/*, virtual public DCOPClient*/ +{ + Q_OBJECT + K_DCOP + +public: + SVNFileInfoProvider( subversionPart *parent, const char *name = 0); + virtual ~SVNFileInfoProvider(); + +// -- Sync interface + virtual const VCSFileInfoMap *status( const QString &dirPath ); +// -- These two are used for subversionPart and subversionCore. Of couruse, others can use it. + const VCSFileInfoMap* statusExt( const QString &dirPath, bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore ); + void slotStatusExt( const QString&, const QString& , int, int, int, int, long int ) ; + +// -- Async interface for requesting data + virtual bool requestStatus( const QString &dirPath, void *callerData, bool recursive = true, bool checkRepos = true ); + + QString projectDirectory() const; + +k_dcop: + void slotStatus( const QString& , int, int, int, int, long int ) ; + +public slots: + void slotResult( KIO::Job * ); + +private: + mutable void *m_savedCallerData; + mutable QString m_previousDirPath; + mutable QString m_recursivePreviousDirPath; + mutable VCSFileInfoMap *m_cachedDirEntries; + mutable VCSFileInfoMap *m_recursiveDirEntries; + KIO::SimpleJob *job; + subversionPart *m_part; +}; + +#endif diff --git a/vcs/subversion/subversion_global.h b/vcs/subversion/subversion_global.h new file mode 100644 index 00000000..062d7fe9 --- /dev/null +++ b/vcs/subversion/subversion_global.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#ifndef SUBVERSION_GLOBAL_H +#define SUBVERSION_GLOBAL_H + +#include <kurl.h> +#include <qdatetime.h> + +namespace SvnGlobal +{ + +typedef enum { + path_to_reposit = 0, + path_to_path = 1, + dont_touch = 2 +} UrlMode; + +/// A structure which describes various system-generated metadata about +/// a working-copy path or URL. +class SvnInfoHolder { +public: + // the requested path + KURL path; + /* Where the item lives in the repository. */ + KURL url; + // The revision of the object. If path_or_url is a working-copy + // path, then this is its current working revnum. If path_or_url + // is a URL, then this is the repos revision that path_or_url lives in. */ + int rev; + int kind; + /* The root URL of the repository. */ + KURL reposRootUrl; + QString reposUuid; +}; + +class SvnRevision{ +public: + int revNum; + QString revKind; + QDateTime revDate; +}; + +} // end of namespace SvnGlobal +#endif diff --git a/vcs/subversion/subversion_part.cpp b/vcs/subversion/subversion_part.cpp new file mode 100644 index 00000000..f918ea44 --- /dev/null +++ b/vcs/subversion/subversion_part.cpp @@ -0,0 +1,569 @@ +/** + Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ +#include "subversion_part.h" + +#include <qwhatsthis.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kdevgenericfactory.h> +#include <kaction.h> +#include <kpopupmenu.h> + +#include "kdevcore.h" +#include "kdevmainwindow.h" +#include "subversion_core.h" +#include "subversion_widget.h" +#include "subversionprojectwidget.h" +#include "subversion_fileinfo.h" +#include "subversion_global.h" +#include "kdevversioncontrol.h" +#include "svn_fileselectdlg_commit.h" +#include "svn_logviewwidget.h" +#include "svn_switchwidget.h" +#include "svn_copywidget.h" +#include "svn_mergewidget.h" + +#include "urlutil.h" +#include <qvbox.h> +#include <kdialogbase.h> +#include <kparts/part.h> +#include <kdevpartcontroller.h> +#include <kdevproject.h> +#include <domutil.h> +#include <kurlrequester.h> +#include <qradiobutton.h> +#include <kdebug.h> +#include <qwidget.h> +#include <kdevplugininfo.h> + +#include <kmessagebox.h> + +using namespace SvnGlobal; + +static const KDevPluginInfo data("kdevsubversion"); + +typedef KDevGenericFactory<subversionPart> subversionFactory; +K_EXPORT_COMPONENT_FACTORY( libkdevsubversion, subversionFactory( data ) ) + +//bool g_projectWasJustCreated = false; + +subversionPart::subversionPart(QObject *parent, const char *name, const QStringList& ) + : KDevVersionControl(&data, parent, name ? name : "Subversion" ) { + setInstance(subversionFactory::instance()); + m_projWidget = 0; + + m_impl = new subversionCore( this ); + + //m_impl->processWidget()->setIcon( SmallIcon("db") ); + + setupActions(); + + connect( m_impl, SIGNAL(checkoutFinished(QString)), SIGNAL(finishedFetching(QString)) ); + + // Context menu + connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), this, SLOT(contextMenu(QPopupMenu *, const Context *)) ); + connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), this, SLOT(projectConfigWidget(KDialogBase*)) ); + connect( core(), SIGNAL(stopButtonClicked(KDevPlugin*)), this, SLOT(slotStopButtonClicked(KDevPlugin*)) ); + connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) ); + connect( core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) ); + + m_impl->processWidget()->setCaption(i18n( "Subversion Output" )); + mainWindow()->embedOutputView( (QWidget*)m_impl->processWidget(), i18n( "Subversion" ), i18n( "Subversion messages" ) ); + QWhatsThis::add((QWidget*)m_impl->processWidget(), i18n("<b>Subversion</b><p>Subversion operations window.")); + +} + +subversionPart::~subversionPart() { + if ( m_projWidget ){ + delete (subversionProjectWidget*) m_projWidget; + m_projWidget = 0; + } + delete m_impl; +} + +void subversionPart::setupActions() { + actionCommit = new KAction( i18n("&Commit to Repository..."), 0, this, SLOT(slotActionCommit()), actionCollection(), "subversion_commit" ); + actionCommit->setToolTip( i18n("Commit file(s)") ); + actionCommit->setWhatsThis( i18n("<b>Commit file(s)</b><p>Commits file to repository if modified.") ); + + /* actionDiff = new KAction( i18n("&Difference Between Revisions"), 0, this, SLOT(slotActionDiff()), + actionCollection(), "subversion_diff" ); + actionDiff->setToolTip( i18n("Build difference") ); + actionDiff->setWhatsThis( i18n("<b>Build difference</b><p>Builds difference between releases.") ); + */ + actionAdd = new KAction( i18n("&Add to Repository"), 0, this, SLOT(slotActionAdd()), actionCollection(), "subversion_add" ); + actionAdd->setToolTip( i18n("Add file to repository") ); + actionAdd->setWhatsThis( i18n("<b>Add file to repository</b><p>Adds file to repository.") ); + + actionLog = new KAction( i18n("Show logs..."), 0, this, SLOT(slotLog()), actionCollection(), "subversion_log" ); + actionBlame = new KAction( i18n("Blame..."), 0, this, SLOT(slotBlame()), actionCollection(), "subversion_blame"); + + actionRemove = new KAction( i18n("&Remove From Repository"), 0, this, SLOT(slotActionDel()), actionCollection(), "subversion_remove" ); + actionRemove->setToolTip( i18n("Remove from repository") ); + actionRemove->setWhatsThis( i18n("<b>Remove from repository</b><p>Removes file(s) from repository.") ); + + actionUpdate = new KAction( i18n("&Update"), 0, this, SLOT(slotActionUpdate()), actionCollection(), "subversion_update" ); + actionUpdate->setToolTip( i18n("Update") ); + actionUpdate->setWhatsThis( i18n("<b>Update</b><p>Updates file(s) from repository.") ); + + actionDiffLocal = new KAction( i18n("&Diff to BASE"), 0, this, SLOT(slotActionDiffLocal()), actionCollection(), "subversion_diff_local" ); + actionDiffLocal->setToolTip( i18n("Diff to BASE") ); + actionDiffLocal->setWhatsThis( i18n("<b>Diff to disk</b><p>Diff current file to the BASE checked out copy.") ); + + actionDiffHead = new KAction( i18n("&Diff to HEAD"), 0, this, SLOT(slotActionDiffLocal()), actionCollection(), "subversion_diff_head" ); + actionDiffHead->setToolTip( i18n("Diff to HEAD") ); + actionDiffHead->setWhatsThis( i18n("<b>Diff HEAD</b><p>Diff the current file to HEAD in svn.") ); + + + actionRevert = new KAction( i18n("&Revert"), 0, this, SLOT(slotActionRevert()), actionCollection(), "subversion_revert" ); + actionRevert->setToolTip( i18n("Revert") ); + actionRevert->setWhatsThis( i18n("<b>Revert</b><p>Undo local changes.") ); + + /* + actionAddToIgnoreList = new KAction( i18n("&Ignore in Subversion Operations"), 0, + this, SLOT(slotActionAddToIgnoreList()), actionCollection(), "subversion_ignore" ); + actionAddToIgnoreList->setToolTip( i18n("Ignore in Subversion operations") ); + actionAddToIgnoreList->setWhatsThis( i18n("<b>Ignore in Subversion operations</b><p>Ignores file(s).") ); + + actionRemoveFromIgnoreList = new KAction( i18n("Do &Not Ignore in Subversion Operations"), 0, + this, SLOT(slotActionRemoveFromIgnoreList()), actionCollection(), "subversion_donot_ignore" ); + actionRemoveFromIgnoreList->setToolTip( i18n("Do not ignore in Subversion operations") ); + actionRemoveFromIgnoreList->setWhatsThis( i18n("<b>Do not ignore in Subversion operations</b><p>Do not ignore file(s).") ); + */ + actionResolve = new KAction( i18n("Re&solve Conflicting State"), 0, + this, SLOT(slotActionResolve()), actionCollection(), "subversion_resolve" ); + actionResolve->setToolTip( i18n("Resolve the conflicting state of a file after a merge") ); + actionResolve->setWhatsThis( i18n("<b>Resolve the conflicting state</b><p>Remove the conflict state that can be set on a file after a merge failed.") ); + actionSwitch = new KAction( i18n("Switch this working copy to URL.."), 0, + this, SLOT(slotSwitch()), actionCollection(), "subversion_switch" ); + // warn slogCopy(), slotMerge only works on context menu. There is no main-menu action + actionCopy = new KAction( i18n("Copy this working copy to URL.."), 0, + this, SLOT(slotCopy()), actionCollection(), "subversion_copy" ); + actionMerge = new KAction( i18n("Merge difference to working copy"), 0, + this, SLOT(slotMerge()), actionCollection(), "subversion_merge" ); +} + +QWidget* subversionPart::newProjectWidget( QWidget* parent ) { + if ( !m_projWidget ) + m_projWidget = new subversionProjectWidget(parent,"projectwidget"); + return m_projWidget; +} + +void subversionPart::createNewProject( const QString& dirname ) { + if ( !m_projWidget ) return; + + m_impl->createNewProject( dirname, KURL( m_projWidget->importURL->url() ), m_projWidget->yes->isChecked() ); + +} + +bool subversionPart::fetchFromRepository() { + m_impl->checkout(); + return true; +} + +KDevVCSFileInfoProvider * subversionPart::fileInfoProvider() const { + return m_impl->fileInfoProvider(); +} + +void subversionPart::contextMenu( QPopupMenu *popup, const Context *context ) { + //no project, no subversion. Don't test on projectDirectory() here. If the user wants this project to have subversion support + //give it to him. e.g. for out of root subprojects like with qmake +if(!project()) + return; + + kdDebug(9036) << "contextMenu()" << endl; + if (context->hasType( Context::FileContext ) || + context->hasType( Context::EditorContext )) + { + + if (context->hasType( Context::FileContext )) + { + kdDebug(9036) << "Requested for a FileContext" << endl; + const FileContext *fcontext = static_cast<const FileContext*>( context ); + m_urls = fcontext->urls(); + } + else + { + kdDebug(9036) << "Requested for an EditorContext" << endl; + const EditorContext *editorContext = static_cast<const EditorContext*>( context ); + m_urls = editorContext->url(); + } + // THis stuff should end up into prepareOperation() + URLUtil::dump( m_urls ); + if (m_urls.count() <= 0) + return; + + KPopupMenu *subMenu = new KPopupMenu( popup ); + if (context->hasType( Context::FileContext )) + popup->insertSeparator(); + + int id = subMenu->insertItem( actionCommit->text(), this, SLOT(slotCommit()) ); + // CvsService let to do log and diff operations only on one file (or directory) at time + /* if (m_urls.count() == 1) + { + subMenu->insertItem( actionDiff->text(), this, SLOT(slotDiff()) ); + subMenu->insertItem( actionLog->text(), this, SLOT(slotLog()) ); + }*/ + subMenu->setWhatsThis(id, i18n("<b>Commit file(s)</b><p>Commits file to repository if modified.")); + id = subMenu->insertItem( actionAdd->text(), this, SLOT(slotAdd()) ); + subMenu->setWhatsThis(id, i18n("<b>Add file to repository</b><p>Adds file to repository.")); + id = subMenu->insertItem( actionRemove->text(), this, SLOT(slotDel()) ); + subMenu->setWhatsThis(id, i18n("<b>Remove from repository</b><p>Removes file(s) from repository.")); + id = subMenu->insertItem( actionLog->text(), this, SLOT(slotLog()) ); + subMenu->setWhatsThis(id, i18n("<b>Show logs..</b><p>View Logs")); + id = subMenu->insertItem( actionBlame->text(), this, SLOT(slotBlame()) ); + subMenu->setWhatsThis(id, i18n("<b>Blame 0:HEAD </b><p>Show Annotate")); + + subMenu->insertSeparator(); + id = subMenu->insertItem( actionDiffLocal->text(), this, SLOT(slotDiffLocal()) ); + subMenu->setWhatsThis(id, i18n("<b>Diff</b><p>Diff file to local disk.")); + + id = subMenu->insertItem( actionDiffHead->text(), this, SLOT(slotDiffHead()) ); + subMenu->setWhatsThis(id, i18n("<b>Diff</b><p>Diff file to repository.")); + + id = subMenu->insertItem( actionUpdate->text(), this, SLOT(slotUpdate()) ); + subMenu->setWhatsThis(id, i18n("<b>Update</b><p>Updates file(s) from repository.")); + id = subMenu->insertItem( actionRevert->text(), this, SLOT(slotRevert()) ); + subMenu->setWhatsThis(id, i18n("<b>Revert</b><p>Undo local changes.") ); + id = subMenu->insertItem( actionResolve->text(), this, SLOT(slotResolve()) ); + subMenu->setWhatsThis(id, i18n("<b>Resolve</b><p>Resolve conflicting state.") ); + id = subMenu->insertItem( actionSwitch->text(), this, SLOT(slotSwitch()) ); + subMenu->setWhatsThis(id, i18n("<b>Switch</b><p>Switch working tree.") ); + id = subMenu->insertItem( actionCopy->text(), this, SLOT(slotCopy()) ); + subMenu->setWhatsThis(id, i18n("<b>Copy</b><p>Copy from/between path/URLs") ); + id = subMenu->insertItem( actionMerge->text(), this, SLOT(slotMerge()) ); + subMenu->setWhatsThis(id, i18n("<b>Merge</b><p>Merge difference to working copy") ); + + /* + subMenu->insertSeparator(); + id = subMenu->insertItem( actionAddToIgnoreList->text(), this, SLOT(slotAddToIgnoreList()) ); + subMenu->setWhatsThis(id, i18n("<b>Ignore in Subversion operations</b><p>Ignores file(s).")); + id = subMenu->insertItem( actionRemoveFromIgnoreList->text(), this, SLOT(slotRemoveFromIgnoreList()) ); + subMenu->setWhatsThis(id, i18n("<b>Do not ignore in Subversion operations</b><p>Do not ignore file(s).")); +*/ + // Now insert in parent menu + popup->insertItem( i18n("Subversion"), subMenu ); + } +} + +bool subversionPart::urlFocusedDocument( KURL &url ) { + KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart*>( partController()->activePart() ); + if ( part ) { + if (part->url().isLocalFile() ) { + url = part->url(); + return true; + } + } + return false; +} + +void subversionPart::slotActionUpdate() { + kdDebug(9036) << "subversion: slotActionUpdate()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->update( doc ); + } +} + +void subversionPart::slotUpdate() { + m_impl->update (m_urls); +} + +void subversionPart::slotActionResolve() { + kdDebug(9036) << "subversion: slotActionResolve()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->resolve( doc ); + } +} + +void subversionPart::slotResolve() { + m_impl->resolve (m_urls); +} + +void subversionPart::slotSwitch() +{ + if( m_urls.count() > 1 ){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Please select only one item for subversion switch") ); + return; + } + if( m_urls.count() < 1 ) return; + + // retrieve repository info from local-copy metadata which will be displayed in dialog box + KURL wcPath = m_urls.first(); + QMap< KURL, SvnGlobal::SvnInfoHolder> holderMap; + SvnGlobal::SvnInfoHolder holder; + + m_impl->clientInfo( wcPath, false, holderMap ); + QValueList< SvnGlobal::SvnInfoHolder > holderList = holderMap.values(); + holder = holderList.first(); + // invoke dialog box + SvnSwitchDlg dlg( &holder, wcPath.path(), (QWidget*)project()->mainWindow()->main() ); + + if( dlg.exec() != QDialog::Accepted ){ + return; + } + // check target url's validity + KURL repositUrl = KURL( dlg.destUrl() ); + if( !repositUrl.isValid() ){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("The destination URL is invalid") ); + return; + } + // call core + if( dlg.switchOnly() ) + m_impl->switchTree( wcPath, repositUrl, -1, "HEAD", dlg.recursive() ); + else if( dlg.relocation() ) + m_impl->switchRelocate( wcPath, dlg.currentUrl(), repositUrl, dlg.recursive() ); + else + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Fail to conduct subversion switch. No action was selected") ); +} + +void subversionPart::slotCopy() +{ + // error check + if( m_urls.count() > 1 ){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Please select only one item for subversion switch") ); + return; + } + if( m_urls.count() < 1 ) return; + + // retrieve repository info from local-copy metadata which will be displayed in dialog box + KURL wcPath = m_urls.first(); + QMap< KURL, SvnGlobal::SvnInfoHolder> holderMap; + SvnGlobal::SvnInfoHolder holder; + m_impl->clientInfo( wcPath, false, holderMap ); + QValueList< SvnGlobal::SvnInfoHolder > holderList = holderMap.values(); + holder = holderList.first(); + // start input dialog + SvnCopyDialog dlg( wcPath.prettyURL(), + &holder, + (QWidget*)project()->mainWindow()->main()); + + if( dlg.exec() != QDialog::Accepted ) + return; + // retrieve user input + KURL srcUrl = dlg.sourceUrl(); + int rev = dlg.revision(); + QString revKind = dlg.revKind(); + KURL dest = dlg.destUrl(); + + kdDebug(9036) << " SRC: " << srcUrl << " DEST: " << dest << " Revnum: " << rev << " RevKind: " << revKind << endl; + + m_impl->svnCopy( srcUrl, rev, revKind, dest ); +} + +void subversionPart::slotMerge() +{ + // error check + if( m_urls.count() > 1 ){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Please select only one item for subversion merge") ); + return; + } + if( m_urls.count() < 1 ) return; + + KURL wcTarget= m_urls.first(); + SvnMergeDialog dlg( wcTarget, (QWidget*)project()->mainWindow()->main() ); + if( dlg.exec() != QDialog::Accepted ) return; + + KURL src1 = dlg.source1(); + SvnRevision rev1 = dlg.rev1(); + KURL src2 = dlg.source2(); + SvnRevision rev2 = dlg.rev2(); + + m_impl->merge( src1, rev1.revNum, rev1.revKind, src2, rev2.revNum, rev2.revKind, wcTarget, + dlg.recurse(), dlg.ignoreAncestry(), dlg.force(), dlg.dryRun() ); +} + +void subversionPart::slotActionCommit() { + kdDebug(9036) << "subversion: slotActionCommit()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->commit( doc, true, true ); + } +} + +void subversionPart::slotActionAdd() { + kdDebug(9036) << "subversion: slotActionAdd()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->add( doc ); + } +} + +void subversionPart::slotActionDel() { + kdDebug(9036) << "subversion: slotActionDel()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->del( doc ); + } +} + +void subversionPart::slotActionRevert() { + kdDebug(9036) << "subversion: slotActionRevert()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->revert( doc ); + } +} + +void subversionPart::slotActionDiffLocal() { + kdDebug(9036) << "subversion: slotActionDiffLocal()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->diff( doc, "BASE" ); + } +} +void subversionPart::slotActionDiffHead() { + kdDebug(9036) << "subversion: slotActionDiffHead()" << endl; + KURL doc; + if (urlFocusedDocument( doc )) { + m_impl->diff( doc, "HEAD" ); + } +} +void subversionPart::slotCommit() +{ + SVNFileSelectDlgCommit dialog( m_urls, this, 0 ); + if( dialog.exec() == QDialog::Accepted ){ + KURL::List tobeCommittedUrls = dialog.checkedUrls(); + bool recursive = dialog.recursive(); + bool keepLocks = dialog.keepLocks(); + m_impl->commit(tobeCommittedUrls, recursive, keepLocks ); + } +} +void subversionPart::slotAdd() { + m_impl->add( m_urls ); +} + +void subversionPart::slotLog() +{ + if (m_urls.count() > 1){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Please select only one item for subversion log") ); + return; + } + SvnLogViewOptionDlg dlg; + if( dlg.exec() ){ + int revstart = dlg.revstart(); + QString revkindstart = dlg.revKindStart(); + int revend = dlg.revend(); + QString revkindend = dlg.revKindEnd(); + bool strictNode = dlg.strictNode(); + m_impl->svnLog (m_urls, revstart, revkindstart, revend, revkindend, true/*changedPath*/, strictNode); + } else{ + return; + } +} +void subversionPart::slotBlame() +{ + if (m_urls.count() > 1){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Please select only one item to see annotate") ); + return; + } + if (m_urls.count() < 1){ + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Select file to see blame") ); + return; + } + KURL url = m_urls.first(); + m_impl->blame(url, SvnGlobal::path_to_reposit, 0, "", -1, "BASE"); +} + +void subversionPart::slotDel() { + m_impl->del (m_urls); +} + +// note: currently diffAsync does not support merging. But svncore::diff() +// cannot be invoked on directory, while diffAsync can. +void subversionPart::slotDiffLocal() { +// m_impl->diff (m_urls, "BASE"); + if( m_urls.count() < 1 ){ + // Impossible to reach here but.. + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Select file or directory to see diff") ); + return; + } + m_impl->diffAsync( *(m_urls.begin()), *(m_urls.begin()), -1, "BASE", -1, "WORKING", true ); +} +void subversionPart::slotDiffHead() { +// m_impl->diff (m_urls, "HEAD"); + if( m_urls.count() < 1 ){ + // Impossible to reach here but.. + KMessageBox::error( (QWidget*)project()->mainWindow()->main(), + i18n("Select file or directory to see diff") ); + return; + } + m_impl->diffAsync( *(m_urls.begin()), *(m_urls.begin()), -1, "WORKING", -1, "HEAD", true ); +} + +void subversionPart::slotRevert() { + m_impl->revert (m_urls); +} + +void subversionPart::slotProjectOpened() { + kdDebug(9036) << "subversion :projectOpened" << endl; +/* if ( g_projectWasJustCreated ) { + //saveOptions(); + g_projectWasJustCreated = false; + } */ + //loadOptions(); + /// \FIXME slots + //connect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) ); + //connect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) ); +} + +void subversionPart::slotProjectClosed() { + kdDebug(9036) << "subversion :projectClosed" << endl; + //saveOptions(); + /// \FIXME slots + //disconnect( project(), SIGNAL(addedFilesToProject(const QStringList&)), this, SLOT(slotAddFilesToProject(const QStringList &)) ); + //disconnect( project(), SIGNAL(removedFilesFromProject(const QStringList&)), this, SLOT(slotRemovedFilesFromProject(const QStringList &)) ); +} + +void subversionPart::savePartialProjectSession(QDomElement* dom) { + kdDebug(9036) << "subversion : savePartialProjectSession" << endl; + QDomDocument doc = dom->ownerDocument(); + QDomElement svn = doc.createElement( "subversion" ); + svn.setAttribute( "base", base.url() ); + dom->appendChild( svn ); +} + +void subversionPart::restorePartialProjectSession(const QDomElement* dom) { + kdDebug(9036) << "subversion : restorePartialProjectSession" << endl; + QDomElement svn = dom->namedItem("subversion").toElement(); + base = svn.attribute( "base", "" ); +} + +bool subversionPart::isValidDirectory( const QString &dirPath) const { + QString svn = "/.svn/"; + QDir svndir( dirPath + svn ); + QString entriesFileName = dirPath + svn + "entries"; + + kdDebug(9036) << "dirpath " << dirPath+"/.svn/" << " exists:" << svndir.exists() << endl; + kdDebug(9036) << "entries " << entriesFileName << " exists:" << QFile::exists( entriesFileName ) << endl; + return svndir.exists() && + QFile::exists( entriesFileName ); +} + +#include "subversion_part.moc" diff --git a/vcs/subversion/subversion_part.h b/vcs/subversion/subversion_part.h new file mode 100644 index 00000000..911f8f7e --- /dev/null +++ b/vcs/subversion/subversion_part.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2003 + Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ +#ifndef __KDEVPART_SUBVERSION_H__ +#define __KDEVPART_SUBVERSION_H__ + + +#include <qguardedptr.h> +#include <kdevplugin.h> +#include <kurl.h> +#include <qpopupmenu.h> +#include <kdialogbase.h> +#include "kdevversioncontrol.h" + +class subversionCore; +class subversionOptionsWidget; +class subversionProjectWidget; +class Context; +namespace SvnGlobal +{ +class SvnInfoHolder; +}; + +class subversionPart : public KDevVersionControl +{ + Q_OBJECT + +public: + subversionPart(QObject *parent, const char *name, const QStringList &); + virtual ~subversionPart(); + + void setupActions(); + QWidget* newProjectWidget( QWidget* parent ); + void createNewProject( const QString& dirname ); + bool fetchFromRepository(); + KDevVCSFileInfoProvider * fileInfoProvider() const; + bool urlFocusedDocument( KURL &url ); + void restorePartialProjectSession(const QDomElement* ); + void savePartialProjectSession(QDomElement* ); + void setBaseURL(const KURL& url ) { base = url; } + KURL baseURL() { return base; } + virtual bool isValidDirectory( const QString &dirPath ) const; + KURL::List urls() { return m_urls; } + subversionCore* svncore() { return m_impl; } + +signals: +// void finishedFetching( QString destinationDir ); + +private slots: + void contextMenu( QPopupMenu *popup, const Context *context ); + void slotActionUpdate(); + void slotActionRevert(); + void slotActionCommit(); + void slotActionAdd(); + void slotActionDel(); + void slotActionDiffHead(); + void slotActionDiffLocal(); + void slotActionResolve(); + void slotUpdate(); + void slotRevert(); + void slotCommit(); + void slotAdd(); + void slotDel(); + void slotLog(); + void slotBlame(); + void slotDiffLocal(); + void slotDiffHead(); + void slotResolve(); + void slotSwitch(); + void slotCopy(); + void slotMerge(); + void slotProjectClosed(); + void slotProjectOpened(); + +private: + QGuardedPtr<subversionCore> m_impl; + KURL::List m_urls; + + KAction *actionCommit, + *actionDiffHead, + *actionDiffLocal, + *actionAdd, + *actionLog, + *actionBlame, + *actionRemove, + *actionUpdate, + //*actionAddToIgnoreList, + //*actionRemoveFromIgnoreList, + *actionRevert, + *actionResolve, + *actionSwitch, + *actionCopy, + *actionMerge; + + QGuardedPtr<subversionProjectWidget> m_projWidget; + KURL base; + +public: + QMap< KURL, SvnGlobal::SvnInfoHolder > m_prjInfoMap; + +}; + + +#endif diff --git a/vcs/subversion/subversion_widget.cpp b/vcs/subversion/subversion_widget.cpp new file mode 100644 index 00000000..af1ca14f --- /dev/null +++ b/vcs/subversion/subversion_widget.cpp @@ -0,0 +1,136 @@ +/** + Copyright (C) 2003-2005 Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#include <kparts/part.h> +#include <kdevcore.h> +#include <kdebug.h> +#include <klineedit.h> + +#include "subversion_part.h" +#include "subversion_widget.h" +#include <ktextedit.h> +#include <klocale.h> +#include <qtoolbutton.h> +#include <qpushbutton.h> + +subversionWidget::subversionWidget( subversionPart *part, QWidget *parent, const char* name ) + : KTabWidget(parent) +{ + m_part = part; + m_edit = new KTextEdit( this ); + m_edit->setReadOnly( TRUE ); + tab()->addTab( m_edit, i18n("Notification") ); + m_closeButton = new QPushButton( tab() ); + m_closeButton->setText( i18n("Close") ); + tab()->setCornerWidget(m_closeButton); + connect( m_closeButton, SIGNAL(clicked()), this, SLOT(closeCurrentTab()) ); +} + +subversionWidget::~subversionWidget() +{} + +void subversionWidget::append( QString notifications ) +{ + if( !m_edit ){ + // should not happen + m_edit = new KTextEdit(this); + } + m_edit->append( notifications ); + showPage( m_edit ); +} + +void subversionWidget::showLogResult( QValueList<SvnLogHolder> *holderList, QString reqUrl ) +{ + SvnLogViewWidget *widget = new SvnLogViewWidget( m_part, this ); + widget->setLogResult( holderList ); + widget->setRequestedUrl( reqUrl ); + tab()->addTab( widget, i18n("Log History") ); + tab()->setTabEnabled( widget, true ); + tab()->showPage( widget ); +} + +void subversionWidget::showBlameResult( QValueList<SvnBlameHolder> *blamelist ) +{ + SvnBlameWidget *widget = new SvnBlameWidget( this ); + widget->copyBlameData( blamelist ); + tab()->addTab( widget, i18n("Blame") ); + tab()->setTabEnabled( widget, true ); + tab()->showPage( widget ); +} +void subversionWidget::closeCurrentTab() +{ + QWidget *current = tab()->currentPage(); + KTextEdit *edit = static_cast<KTextEdit*>(current); + if( edit ){ + if( edit == m_edit ) // main notification output should not be deleted + return; + } + tab()->removePage( current ); + delete current; +} + +//////////////////////////////////////////////////////////////////////// + +SvnIntSortListItem::SvnIntSortListItem( QListView* parent ) + :QListViewItem(parent) +{} +SvnIntSortListItem::~SvnIntSortListItem() +{} + +int SvnIntSortListItem::compare( QListViewItem *item, int col, bool ascending ) const +{ + + unsigned int myVal = this->text(col).toUInt(); + unsigned int yourVal = item->text(col).toUInt(); + if( myVal < yourVal ) return -1; + if( myVal > yourVal ) return 1; + return 0; +} + +SvnLogViewItem::SvnLogViewItem( QListView * parent ) + :SvnIntSortListItem( parent ) +{ + m_pathList = ""; + m_message = ""; +} +SvnLogViewItem ::~SvnLogViewItem () +{} + +//////////////////////////////////////////////////////////////////////// + +SvnProgressDlg::SvnProgressDlg( bool showNow ) + : KIO::DefaultProgress( showNow ) +{ + setStopOnClose( true ); + setCaption( i18n("Subversion Job Progress") ); +} + +SvnProgressDlg::~SvnProgressDlg() +{} + +void SvnProgressDlg::setSourceUrl( const QString &src ) +{ + sourceEdit->setText( src ); +} +void SvnProgressDlg::setDestUrl( const QString &dest ) +{ + destEdit->setText( dest ); +} + +#include "subversion_widget.moc" diff --git a/vcs/subversion/subversion_widget.h b/vcs/subversion/subversion_widget.h new file mode 100644 index 00000000..4a21b636 --- /dev/null +++ b/vcs/subversion/subversion_widget.h @@ -0,0 +1,95 @@ +/* Copyright (C) 2003 + Mickael Marchand <marchand@kde.org> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ + +#ifndef __SUBVERSION_WIDGET_H__ +#define __SUBVERSION_WIDGET_H__ + +#include <qlistview.h> +#include "svn_blamewidget.h" +#include "svn_logviewwidget.h" +#include <qvaluelist.h> + +class subversionPart; +#include <ktabwidget.h> +#include <kio/defaultprogress.h> +#include <qguardedptr.h> +class KTextEdit; +class SvnLogHolder; +class SvnBlameHolder; +class SvnLogViewWidget; +class QToolButton; +class QPushButton; + +/** The main Subversion DockWidget. Contains logview-output, blame-output, status and etc */ +// class subversionWidget : public SvnOutputWidgetBase +class subversionWidget : public KTabWidget +{ + Q_OBJECT +public: + subversionWidget(subversionPart *part, QWidget *parent, const char* name); + ~subversionWidget(); + + // append what?. Append any text status outputs + void append( QString notifications ); + void showLogResult( QValueList<SvnLogHolder> *holderList, QString reqUrl ); + void showBlameResult( QValueList<SvnBlameHolder> *blamelist ); + +protected slots: + void closeCurrentTab(); + +private: + KTabWidget* tab(){ return this; } + subversionPart *m_part; + + QGuardedPtr<KTextEdit> m_edit; + QPushButton *m_closeButton; + +}; +/** + * reimplement compare(), to be able to sort any item by integer + */ +class SvnIntSortListItem : public QListViewItem { +public: + SvnIntSortListItem ( QListView* parent=0 ); + ~SvnIntSortListItem (); + /** Returns < 0 if this item is less than i, 0 if they are equal and > 0 if this item is greater than i. + */ + virtual int compare( QListViewItem* i, int col, bool ascending ) const; +}; + +class SvnLogViewItem : public SvnIntSortListItem { + public: + SvnLogViewItem( QListView* parent ); + ~SvnLogViewItem(); + + QString m_pathList; + QString m_message; +}; + +///////////////////////////////////////////////////////////// +/// Subversion Progress Display Widget +class SvnProgressDlg : public KIO::DefaultProgress { +public: + SvnProgressDlg( bool showNow = true ); + ~SvnProgressDlg(); + void setSourceUrl( const QString & ); + void setDestUrl( const QString & ); +}; + +#endif diff --git a/vcs/subversion/subversiondiff.ui b/vcs/subversion/subversiondiff.ui new file mode 100644 index 00000000..dab4ca0e --- /dev/null +++ b/vcs/subversion/subversiondiff.ui @@ -0,0 +1,100 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>Subversion_Diff</class> +<widget class="QDialog"> + <property name="name"> + <cstring>Subversion_Diff</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>511</width> + <height>282</height> + </rect> + </property> + <property name="caption"> + <string>Subversion Diff</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTextBrowser"> + <property name="name"> + <cstring>text</cstring> + </property> + <property name="textFormat"> + <enum>PlainText</enum> + </property> + <property name="wordWrap"> + <enum>NoWrap</enum> + </property> + <property name="autoFormatting"> + <set>AutoAll</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>Layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>6</number> + </property> + <spacer> + <property name="name"> + <cstring>Horizontal Spacing2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="accel"> + <string></string> + </property> + <property name="autoDefault"> + <bool>true</bool> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>buttonOk</sender> + <signal>clicked()</signal> + <receiver>Subversion_Diff</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/vcs/subversion/subversionprojectwidget.ui b/vcs/subversion/subversionprojectwidget.ui new file mode 100644 index 00000000..3977ce4c --- /dev/null +++ b/vcs/subversion/subversionprojectwidget.ui @@ -0,0 +1,89 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>subversionProjectWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>subversionProjectWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>438</width> + <height>149</height> + </rect> + </property> + <property name="caption"> + <string>New Subversion Project</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>&Import address:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>importURL</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>importURL</cstring> + </property> + </widget> + </hbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>init</cstring> + </property> + <property name="title"> + <string>Create &Standard Directories (tags/trunk/branches/)?</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>yes</cstring> + </property> + <property name="text"> + <string>Yes</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>no</cstring> + </property> + <property name="text"> + <string>No</string> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_blamewidget.cpp b/vcs/subversion/svn_blamewidget.cpp new file mode 100644 index 00000000..5d186177 --- /dev/null +++ b/vcs/subversion/svn_blamewidget.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + +#include "svn_blamewidget.h" +#include "subversion_widget.h" +#include <qmap.h> +#include <qlistview.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qstringlist.h> +#include <qfont.h> + +#include <klocale.h> +#include <kmessagebox.h> + +SvnBlameWidget::SvnBlameWidget( QWidget *parent, const char* name, bool modal, WFlags f ) + :QWidget( parent ) +{ + m_layout = new QVBoxLayout( this, 1, 1 ); + m_layout->setMargin(1); + + m_listView = new QListView( this ); + outView()->setAllColumnsShowFocus( TRUE ); + outView()->addColumn( i18n("Line") ); + outView()->addColumn( i18n("Rev") ); + outView()->addColumn( i18n("Date") ); + outView()->addColumn( i18n("Author") ); + outView()->addColumn( i18n("Content") ); + + m_layout->addWidget( m_listView ); +} +SvnBlameWidget::~SvnBlameWidget() +{} + +void SvnBlameWidget::copyBlameData( QValueList<SvnBlameHolder> *blamelist ) +{ + m_blamelist = *blamelist; +} + +void SvnBlameWidget::show() +{ + outView()->clear(); + outView()->setSortColumn(0); + + QFont f = outView()->font(); + f.setFixedPitch( true ); + outView()->setFont( f ); + + QValueList<SvnBlameHolder>::Iterator it; + + for( it = m_blamelist.begin(); it != m_blamelist.end(); ++it ){ + + SvnBlameHolder holder = *it; + SvnIntSortListItem *item = new SvnIntSortListItem(outView()); + + QString prettyDate = holder.date.left(16).replace(10, 1, ' '); + + item->setText(0, QString::number( holder.line+1 ) ); + item->setText(1, QString::number(holder.rev) ); + item->setText(2, prettyDate ); + item->setText(3, holder.author ); + item->setText(4, holder.content ); + + } + outView()->sort(); + QWidget::show(); +} + +QListView* SvnBlameWidget::outView() +{ + return m_listView; +} + +///////////////////////////////////////////////////////////// + +SvnBlameFileSelectDlg::SvnBlameFileSelectDlg( QWidget *parent ) + : QDialog( parent ) +{ + m_selected = ""; + setCaption( i18n("Select one file to view annotation") ); + + m_layout = new QGridLayout( this, 2, 2 ); + m_view = new QListView( this ); + m_view->addColumn( i18n("files") ); + m_okBtn = new QPushButton( i18n("OK"), this ); + m_cancelBtn = new QPushButton( i18n("Cancel"), this ); + m_layout->addMultiCellWidget( m_view, 0, 0, 0, 1 ); + m_layout->addWidget( m_okBtn, 1, 0 ); + m_layout->addWidget( m_cancelBtn, 1, 1 ); + + connect( m_okBtn, SIGNAL(clicked()), this, SLOT(accept()) ); + connect( m_cancelBtn, SIGNAL(clicked()), this, SLOT(reject()) ); +} +SvnBlameFileSelectDlg::~SvnBlameFileSelectDlg() +{} + +void SvnBlameFileSelectDlg::setCandidate( QStringList *list ) +{ + for( QValueList<QString>::iterator it = list->begin(); it != list->end(); ++it ){ + QListViewItem *item = new QListViewItem( m_view, *it ); + } +} + +QString SvnBlameFileSelectDlg::selected() +{ + return m_selected; +} + +void SvnBlameFileSelectDlg::accept() +{ + while( true ){ + QListViewItem *item = m_view->currentItem(); + if( item ){ + m_selected = item->text(0); + break; + } + else{ + KMessageBox::error( this, i18n("Select file from list to view annotation") ); + } + } + QDialog::accept(); +} + +#include "svn_blamewidget.moc" diff --git a/vcs/subversion/svn_blamewidget.h b/vcs/subversion/svn_blamewidget.h new file mode 100644 index 00000000..26bd0fa2 --- /dev/null +++ b/vcs/subversion/svn_blamewidget.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ + + +#ifndef SVN_BLAMEWIDGET_H +#define SVN_BLAMEWIDGET_H + +#include <qwidget.h> +#include <qdialog.h> +#include <qvaluelist.h> +class QVBoxLayout; +class QListView; +class QGridLayout; +class QPushButton; +class QStringList; + +class SvnBlameHolder { +public: +// SvnBlameHolder(){}; +// ~SvnBlameHolder(){}; + unsigned int line; + long int rev; + QString date; + QString author; + QString content; +}; + +class QListView; + +class SvnBlameWidget : public QWidget { + Q_OBJECT +public: + SvnBlameWidget( QWidget * parent = 0, const char * name = 0, bool modal = FALSE, WFlags f = 0 ); + virtual ~SvnBlameWidget(); + void copyBlameData( QValueList<SvnBlameHolder> *blamelist ); + void show(); + QListView* outView(); +protected: + QValueList <SvnBlameHolder> m_blamelist; + + QVBoxLayout *m_layout; + QListView *m_listView; +}; + +class SvnBlameFileSelectDlg : public QDialog { + Q_OBJECT +public: + SvnBlameFileSelectDlg( QWidget *parent = 0L ); + virtual ~SvnBlameFileSelectDlg(); + void setCandidate( QStringList *modifies ); + QString selected(); + +protected: + virtual void accept(); + +private: + QGridLayout *m_layout; + QListView *m_view; + QPushButton *m_okBtn; + QPushButton *m_cancelBtn; + + QStringList *m_candidates; + QString m_selected; +}; + +#endif diff --git a/vcs/subversion/svn_co.ui b/vcs/subversion/svn_co.ui new file mode 100644 index 00000000..4ea22290 --- /dev/null +++ b/vcs/subversion/svn_co.ui @@ -0,0 +1,335 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>svn_co</class> +<widget class="QDialog"> + <property name="name"> + <cstring>svn_co</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>509</width> + <height>360</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="caption"> + <string>Subversion Module Checkout</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox"> + <property name="name"> + <cstring>server</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Server Settings</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Checkout &from:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>serverURL</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>serverURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>&Revision:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>revision</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>revision</cstring> + </property> + <property name="text"> + <string>HEAD</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>WinPanel</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="title"> + <string>This Project has Standard &Trunk/Branches/Tags/Directories</string> + </property> + <property name="exclusive"> + <bool>true</bool> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>isStandard</cstring> + </property> + <property name="text"> + <string>Yes</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>radioButton1_2</cstring> + </property> + <property name="text"> + <string>No</string> + </property> + </widget> + </vbox> + </widget> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QGroupBox"> + <property name="name"> + <cstring>local</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Local Directory</string> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>C&heckout in:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>localDir</cstring> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>localDir</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>&Name of the newly created directory:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>newDir</cstring> + </property> + </widget> + <widget class="KLineEdit"> + <property name="name"> + <cstring>newDir</cstring> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>191</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>ok</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>cancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + </hbox> + </widget> + </hbox> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>ok</sender> + <signal>clicked()</signal> + <receiver>svn_co</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancel</sender> + <signal>clicked()</signal> + <receiver>svn_co</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_commitdlgbase.ui b/vcs/subversion/svn_commitdlgbase.ui new file mode 100644 index 00000000..9151d566 --- /dev/null +++ b/vcs/subversion/svn_commitdlgbase.ui @@ -0,0 +1,131 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnCommitDlgBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnCommitDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>514</width> + <height>305</height> + </rect> + </property> + <property name="caption"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QListView" row="0" column="0" rowspan="1" colspan="3"> + <column> + <property name="text"> + <string>Column 1</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <item> + <property name="text"> + <string>New Item</string> + </property> + <property name="pixmap"> + <pixmap></pixmap> + </property> + </item> + <property name="name"> + <cstring>listView1</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + </widget> + <spacer row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>335</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>keepLocksChk</cstring> + </property> + <property name="text"> + <string>Keep Locks</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QLayoutWidget" row="2" column="2"> + <property name="name"> + <cstring>layout8</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton3</cstring> + </property> + <property name="text"> + <string>O&K</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>pushButton3_2</cstring> + </property> + <property name="text"> + <string>C&ancel</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QCheckBox" row="1" column="1"> + <property name="name"> + <cstring>recursiveChk</cstring> + </property> + <property name="text"> + <string>Recursive</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>pushButton3</sender> + <signal>clicked()</signal> + <receiver>SvnCommitDlgBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>pushButton3_2</sender> + <signal>clicked()</signal> + <receiver>SvnCommitDlgBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/vcs/subversion/svn_copydlgwidget.ui b/vcs/subversion/svn_copydlgwidget.ui new file mode 100644 index 00000000..00a4d5c7 --- /dev/null +++ b/vcs/subversion/svn_copydlgwidget.ui @@ -0,0 +1,238 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnCopyDialogBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnCopyDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>439</width> + <height>433</height> + </rect> + </property> + <property name="caption"> + <string>Subversion Copy</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>reqEdit</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QPushButton" row="5" column="1"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <spacer row="5" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>110</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="5" column="2"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + <widget class="QButtonGroup" row="4" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup3</cstring> + </property> + <property name="title"> + <string>Destination</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KURLRequester" row="1" column="0"> + <property name="name"> + <cstring>destRequester</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Specify either the full repository URL or local working path</string> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Requested Local Path</string> + </property> + </widget> + <widget class="QButtonGroup" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string>Source Revision</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput" row="0" column="1"> + <property name="name"> + <cstring>revnumInput</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minValue"> + <number>-1</number> + </property> + </widget> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>revnumRadio</cstring> + </property> + <property name="text"> + <string>Specify by number:</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>revkindRadio</cstring> + </property> + <property name="text"> + <string>Specify by keyword:</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>HEAD</string> + </property> + </item> + <item> + <property name="text"> + <string>BASE</string> + </property> + </item> + <item> + <property name="text"> + <string>WORKING</string> + </property> + </item> + <property name="name"> + <cstring>revkindCombo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </grid> + </widget> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Source</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KLineEdit" row="2" column="0"> + <property name="name"> + <cstring>srcEdit</cstring> + </property> + <property name="readOnly"> + <bool>false</bool> + </property> + </widget> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>urlRadio</cstring> + </property> + <property name="text"> + <string>Specify by the repository URL of this item</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>pathRadio</cstring> + </property> + <property name="text"> + <string>Specify by local path of this item</string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>SvnCopyDialogBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>SvnCopyDialogBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_copywidget.cpp b/vcs/subversion/svn_copywidget.cpp new file mode 100644 index 00000000..a5d74bcb --- /dev/null +++ b/vcs/subversion/svn_copywidget.cpp @@ -0,0 +1,75 @@ +#include "svn_copywidget.h" +#include <klineedit.h> +#include <kurl.h> +#include "subversion_global.h" +#include <kurlrequester.h> +#include <knuminput.h> +#include <kcombobox.h> +#include <qradiobutton.h> + +SvnCopyDialog::SvnCopyDialog( const QString &reqPath, SvnGlobal::SvnInfoHolder *holder, QWidget *parent ) + : SvnCopyDialogBase( parent ) + , m_holder(holder) +{ + reqEdit->setText( reqPath ); + + connect( urlRadio, SIGNAL(clicked()), this, SLOT(setSourceAsUrl()) ); + connect( pathRadio, SIGNAL(clicked()), this, SLOT(setSourceAsLocalPath()) ); + connect( revnumRadio, SIGNAL(toggled(bool)), revnumInput, SLOT(setEnabled(bool)) ); + connect( revnumRadio, SIGNAL(toggled(bool)), revkindCombo, SLOT(setDisabled(bool)) ); + + // In many cases, users copy from reository to repository. This is for making tag/branche. + // The case where copying from local path to repository may be lesser than the above one. + // Thus, by default retrieve the repository URL of the given local path + urlRadio->setChecked( true ); + srcEdit->setText( m_holder->url.prettyURL() ); + // Also, revision is set to HEAD by default + revkindRadio->setChecked( true ); + revkindCombo->insertItem( "HEAD" ); +} + +SvnCopyDialog::~SvnCopyDialog() +{ +} + +KURL SvnCopyDialog::sourceUrl() +{ + return KURL( srcEdit->text() ); +} + +int SvnCopyDialog::revision() +{ + if( revnumRadio->isChecked() ) + return revnumInput->value(); + else + return -1; +} + +QString SvnCopyDialog::revKind() +{ + if( revkindRadio->isChecked() ) + return revkindCombo->currentText(); + else + return QString(""); +} + +KURL SvnCopyDialog::destUrl() +{ + return KURL( destRequester->url() ); +} + +void SvnCopyDialog::setSourceAsUrl() +{ + srcEdit->setText( m_holder->url.prettyURL() ); + revkindCombo->clear(); + revkindCombo->insertItem( "HEAD" ); +} + +void SvnCopyDialog::setSourceAsLocalPath() +{ + srcEdit->setText( reqEdit->text() ); + revkindCombo->clear(); + revkindCombo->insertItem( "WORKING" ); +} + +#include "svn_copywidget.moc" diff --git a/vcs/subversion/svn_copywidget.h b/vcs/subversion/svn_copywidget.h new file mode 100644 index 00000000..cc00636d --- /dev/null +++ b/vcs/subversion/svn_copywidget.h @@ -0,0 +1,32 @@ +#ifndef SVN_COPYWIDGET_H +#define SVN_COPYWIDGET_H + +#include "svn_copydlgwidget.h" + +namespace SvnGlobal +{ + class SvnInfoHolder; +} +class KURL; + +class SvnCopyDialog : public SvnCopyDialogBase +{ + Q_OBJECT +public: + SvnCopyDialog( const QString &reqPath, SvnGlobal::SvnInfoHolder *holder, QWidget *parent ); + ~SvnCopyDialog(); + + KURL sourceUrl(); + int revision(); + QString revKind(); + KURL destUrl(); + +public slots: + void setSourceAsUrl(); + void setSourceAsLocalPath(); + +private: + SvnGlobal::SvnInfoHolder *m_holder; +}; + +#endif diff --git a/vcs/subversion/svn_fileselectdlg_commit.cpp b/vcs/subversion/svn_fileselectdlg_commit.cpp new file mode 100644 index 00000000..4f4cdceb --- /dev/null +++ b/vcs/subversion/svn_fileselectdlg_commit.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + + +#include "svn_fileselectdlg_commit.h" +#include "subversion_fileinfo.h" +#include "subversion_part.h" +#include <kurl.h> +#include <qstring.h> +#include <qlistview.h> +#include <qfileinfo.h> +#include <qcheckbox.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include "kdevmainwindow.h" +#include <klocale.h> + +#include <kdevproject.h> + +SVNFileSelectDlgCommit::SVNFileSelectDlgCommit( KURL::List &urls, subversionPart *part, QWidget* parent) + :SvnCommitDlgBase( parent, "svnfileselectcommitdlg", true ) + ,m_part(part) +{ + this->setCaption(i18n("Select Files to Commit")); + listView()->clear(); + listView()->setColumnText(0, i18n("select") ); //col 0 + listView()->addColumn( i18n("status") ); //col 1 + listView()->addColumn( i18n("URL to commit") ); //col 2 + listView()->setColumnWidthMode( 2, QListView::Maximum ); + listView()->setSorting( 2, true ); + recursiveChk->setChecked(false); + keepLocksChk->setChecked(false); + + + const VCSFileInfoMap *vcsMap; + VCSFileInfo vcsInfo; + KURL::List tobeCommittedUrls; + + for( QValueListConstIterator<KURL> it = urls.begin(); it != urls.end(); ++it ){ + KURL oneUrl(*it); + QFileInfo fileInfo(oneUrl.path()); + //fileInfo.convertToAbs(); + + if (fileInfo.isFile()){ + KURL base_url( part->project()->projectDirectory()+"/" ); + QString dirPath = KURL::relativeURL( base_url, fileInfo.dirPath(TRUE) ); + vcsMap = ((SVNFileInfoProvider*)part->fileInfoProvider()) -> + statusExt(dirPath, false/*repository access*/, true/*recurse*/, false/*getall*/, true/*noIgnore*/); + vcsInfo = (*vcsMap)[fileInfo.fileName()]; + if( vcsInfo.state == VCSFileInfo::Added || vcsInfo.state == VCSFileInfo::Modified || + vcsInfo.state == VCSFileInfo::Deleted || vcsInfo.state == VCSFileInfo::Replaced ){ + + this->insertItem( VCSFileInfo::state2String( vcsInfo.state ), oneUrl ); +// tobeCommittedUrls.push_back(oneUrl); +// kdDebug(9036) << "slotCommit() : added AS FILE: " << oneUrl.prettyURL() << endl; + + } + else{ + kdDebug(9036) << "slotCommit() @ FileCase ignoring " << oneUrl.prettyURL() << endl; + } + } + else if (fileInfo.isDir()){ + KURL base_url( part->project()->projectDirectory()+"/" ); + QString dirPath = KURL::relativeURL( base_url, fileInfo.absFilePath() ); + vcsMap = ((SVNFileInfoProvider*)part->fileInfoProvider()) -> + statusExt(dirPath, false/*repository access*/, true/*recurse*/, false/*getall*/, true/*noIgnore*/); + for (VCSFileInfoMap::ConstIterator it=vcsMap->begin(); it!=vcsMap->end(); ++it){ + + vcsInfo = it.data(); +// QString absPathStr( fileInfo.absFilePath() + "/" + it.key() ); + QString absPathStr( fileInfo.filePath() + "/" + it.key() ); + KURL urlFromStatus( absPathStr ); + if( vcsInfo.state == VCSFileInfo::Added || vcsInfo.state == VCSFileInfo::Modified || + vcsInfo.state == VCSFileInfo::Deleted || vcsInfo.state == VCSFileInfo::Replaced){ + + this->insertItem( VCSFileInfo::state2String( vcsInfo.state ), urlFromStatus ); + +// tobeCommittedUrls.push_back( urlFromStatus ); +// kdDebug(9036) << "slotCommit() @ DirCase adding " << urlFromStatus.prettyURL() << endl; + } + else{ + kdDebug(9036) << "slotCommit() @ DirCase ignoring " << urlFromStatus.prettyURL() << endl; + } + + } + } + else if ( !fileInfo.exists() ){ + // maybe deleted files + this->insertItem( VCSFileInfo::state2String( VCSFileInfo::Deleted ), oneUrl ); + } + } + +} +SVNFileSelectDlgCommit::~SVNFileSelectDlgCommit() +{ +} + +int SVNFileSelectDlgCommit::exec() +{ + if (listView()->childCount() <= 0){ + //TODO if klauncher fails, this spot is also reached. We should show correct error message to user + KMessageBox::information( (QWidget*)m_part->project()->mainWindow()->main(), i18n("No added/modified/deleted file(s) to commit") ); + return QDialog::Rejected; + } + else{ + return SvnCommitDlgBase::exec(); + } +} +void SVNFileSelectDlgCommit::insertItem( QString status, KURL url ) +{ + QCheckListItem *item = new QCheckListItem( listView(), "", QCheckListItem::CheckBox ); + item->setText( 1, status ); + item->setText( 2, url.path() ); + item->setOn(true); +} +KURL::List SVNFileSelectDlgCommit::checkedUrls() +{ + QPtrList<QListViewItem> lst; + QListViewItemIterator it( listView() ); + KURL::List tobeCommittedUrls; + + for ( ; it.current() ; ++it ) { + if ( ((QCheckListItem*)(it.current()))->isOn() ){ + KURL tmpurl( it.current()->text(2) ); + tobeCommittedUrls.push_back( tmpurl ); + } + } + return tobeCommittedUrls; + +} +QListView* SVNFileSelectDlgCommit::listView() +{ + return listView1; +} + +bool SVNFileSelectDlgCommit::recursive() +{ + return recursiveChk->isChecked(); +} +bool SVNFileSelectDlgCommit::keepLocks() +{ + return keepLocksChk->isChecked(); +} + +#include "svn_fileselectdlg_commit.moc" + diff --git a/vcs/subversion/svn_fileselectdlg_commit.h b/vcs/subversion/svn_fileselectdlg_commit.h new file mode 100644 index 00000000..acd95ebb --- /dev/null +++ b/vcs/subversion/svn_fileselectdlg_commit.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _svnfileselectdlgcommit_ +#define _svnfileselectdlgcommit_ + +#include "svn_commitdlgbase.h" +#include <qdialog.h> +#include <kurl.h> + +class QString; +class KURL; +class QListView; +class subversionPart; + +class SVNFileSelectDlgCommit : public SvnCommitDlgBase{ + +Q_OBJECT + +public: + SVNFileSelectDlgCommit( KURL::List&, subversionPart* part, QWidget* parent = 0 ); + ~SVNFileSelectDlgCommit(); + void insertItem( QString status, KURL url ); + KURL::List checkedUrls(); + bool recursive(); + bool keepLocks(); + +public slots: + int exec(); +protected: + QListView* listView(); + subversionPart *m_part; +}; + +#endif diff --git a/vcs/subversion/svn_kio.cpp b/vcs/subversion/svn_kio.cpp new file mode 100644 index 00000000..c5c8dfe6 --- /dev/null +++ b/vcs/subversion/svn_kio.cpp @@ -0,0 +1,2155 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Mickael Marchand <marchand@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <qcstring.h> +#include <qsocket.h> +#include <qdatetime.h> +#include <qbitarray.h> + +#include <stdlib.h> +#include <math.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +#include <kapplication.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <kinstance.h> +#include <kglobal.h> +#include <kstandarddirs.h> +#include <klocale.h> +#include <kurl.h> +#include <ksock.h> +#include <dcopclient.h> +#include <qcstring.h> + +#include <subversion-1/svn_sorts.h> +#include <subversion-1/svn_path.h> +#include <subversion-1/svn_utf.h> +#include <subversion-1/svn_ra.h> +#include <subversion-1/svn_time.h> +#include <subversion-1/svn_cmdline.h> + +#include <kmimetype.h> +#include <qfile.h> + +#include "svn_kio.h" +#include <apr_portable.h> +// #include "commitdlg.h" +#include <ktextedit.h> + +using namespace KIO; +using namespace SvnGlobal; + +typedef struct +{ + /* Holds the directory that corresponds to the REPOS_URL at RA->open() + * time. When callbacks specify a relative path, they are joined with + * this base directory. */ + const char *base_dir; + svn_wc_adm_access_t *base_access; + + /* An array of svn_client_commit_item_t * structures, present only + * during working copy commits. */ + apr_array_header_t *commit_items; + + /* A hash of svn_config_t's, keyed off file name (i.e. the contents of + * ~/.subversion/config end up keyed off of 'config'). */ + apr_hash_t *config; + + /* The pool to use for session-related items. */ + apr_pool_t *pool; + +} svn_client__callback_baton_t; + +static svn_error_t * +open_tmp_file (apr_file_t **fp, + void *callback_baton, + apr_pool_t *pool) +{ + svn_client__callback_baton_t *cb = (svn_client__callback_baton_t *) callback_baton; + const char *truepath; + const char *ignored_filename; + + if (cb->base_dir) + truepath = apr_pstrdup (pool, cb->base_dir); + else + truepath = ""; + + /* Tack on a made-up filename. */ + truepath = svn_path_join (truepath, "tempfile", pool); + + /* Open a unique file; use APR_DELONCLOSE. */ + SVN_ERR (svn_io_open_unique_file (fp, &ignored_filename, + truepath, ".tmp", TRUE, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t *write_to_string(void *baton, const char *data, apr_size_t *len) { + kbaton *tb = ( kbaton* )baton; + svn_stringbuf_appendbytes(tb->target_string, data, *len); + return SVN_NO_ERROR; +} + +static int +compare_items_as_paths (const svn_sort__item_t*a, const svn_sort__item_t*b) { + return svn_path_compare_paths ((const char *)a->key, (const char *)b->key); +} + +kio_svnProtocol::kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket) + : SlaveBase("kio_svn", pool_socket, app_socket) { + kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol()" << endl; + + m_counter = 0; + + apr_initialize(); + // Make sure to properly initialize svn client, besides other things, this sets up + // NLS support for environments that don't use UTF-8 + svn_cmdline_init("kdevsvnd",NULL); + // CleanUP ctx preventing crash in svn_client_update and other + memset(&ctx, 0, sizeof(ctx)); + pool = svn_pool_create (NULL); + + svn_error_t *err = svn_client_create_context(&ctx, pool); + if ( err ) { + kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol() create_context ERROR" << endl; + error( KIO::ERR_SLAVE_DEFINED, err->message ); + return; + } + + err = svn_config_ensure (NULL,pool); + if ( err ) { + kdDebug(9036) << "kio_svnProtocol::kio_svnProtocol() configensure ERROR" << endl; + error( KIO::ERR_SLAVE_DEFINED, err->message ); + return; + } + svn_config_get_config (&ctx->config, NULL, pool); + + ctx->log_msg_func = kio_svnProtocol::commitLogPrompt; + ctx->log_msg_baton = this; //pass this so that we can get a dcopClient from it + //TODO + ctx->cancel_func = NULL; + // progress notifications + ctx->progress_func = kio_svnProtocol::progressCallback; + ctx->progress_baton = this; + + apr_array_header_t *providers = apr_array_make(pool, 15, sizeof(svn_auth_provider_object_t *)); + + svn_auth_provider_object_t *provider; + + //disk cache + svn_client_get_simple_provider(&provider,pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider; + svn_client_get_username_provider(&provider,pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider; + + //interactive prompt + svn_client_get_simple_prompt_provider (&provider,kio_svnProtocol::checkAuth,this,2,pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider; + //we always ask user+pass, no need for a user only question +/* svn_client_get_username_prompt_provider + * (&provider,kio_svnProtocol::checkAuth,this,2,pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t*) = provider;*/ + + //SSL disk cache, keep that one, because it does nothing bad :) + svn_client_get_ssl_server_trust_file_provider (&provider, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + svn_client_get_ssl_client_cert_file_provider (&provider, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + svn_client_get_ssl_client_cert_pw_file_provider (&provider, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + + //SSL interactive prompt, where things get hard + svn_client_get_ssl_server_trust_prompt_provider (&provider, kio_svnProtocol::trustSSLPrompt, (void*)this, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + svn_client_get_ssl_client_cert_prompt_provider (&provider, kio_svnProtocol::clientCertSSLPrompt, (void*)this, 2, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + svn_client_get_ssl_client_cert_pw_prompt_provider (&provider, kio_svnProtocol::clientCertPasswdPrompt, (void*)this, 2, pool); + APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; + + svn_auth_open(&ctx->auth_baton, providers, pool); +} + +kio_svnProtocol::~kio_svnProtocol(){ + kdDebug(9036) << "kio_svnProtocol::~kio_svnProtocol()" << endl; + svn_pool_destroy(pool); + apr_terminate(); +} + +void kio_svnProtocol::initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool) { + m_counter=0;//reset counter + ctx->notify_func = kio_svnProtocol::notify; + struct notify_baton *nb = ( struct notify_baton* )apr_palloc(spool, sizeof( struct notify_baton ) ); + nb->master = this; + nb->received_some_change = FALSE; + nb->sent_first_txdelta = FALSE; + nb->is_checkout = is_checkout; + nb->is_export = is_export; + nb->suppress_final_line = suppress_final_line; + nb->in_external = FALSE; + nb->had_print_error = FALSE; + nb->pool = svn_pool_create (spool); + + ctx->notify_baton = nb; +} + +svn_error_t* kio_svnProtocol::checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool) { + kdDebug(9036) << "kio_svnProtocol::checkAuth() " << endl; + kio_svnProtocol *p = ( kio_svnProtocol* )baton; + svn_auth_cred_simple_t *ret = (svn_auth_cred_simple_t*)apr_pcalloc (pool, sizeof (*ret)); + + p->info.keepPassword = true; + p->info.verifyPath=true; + kdDebug(9036 ) << "auth current URL : " << p->myURL.url() << endl; + p->info.url = p->myURL; + p->info.username = username; //( const char* )svn_auth_get_parameter( p->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_USERNAME ); + if (realm) { + p->info.prompt = i18n("Username and Password for %1.").arg(realm); + } + +// if ( !p->checkCachedAuthentication( p->info ) ){ + p->openPassDlg( p->info ); +// } + ret->username = apr_pstrdup(pool, p->info.username.utf8()); + ret->password = apr_pstrdup(pool, p->info.password.utf8()); + if (may_save) ret->may_save = p->info.keepPassword; + *cred = ret; + return SVN_NO_ERROR; +} + +void kio_svnProtocol::recordCurrentURL(const KURL& url) { + myURL = url; +} + +//don't implement mimeType() until we don't need to download the whole file + +void kio_svnProtocol::get(const KURL& url ){ + kdDebug(9036) << "kio_svn::get(const KURL& url)" << endl ; + + QString remoteServer = url.host(); + infoMessage(i18n("Looking for %1...").arg( remoteServer ) ); + + apr_pool_t *subpool = svn_pool_create (pool); + kbaton *bt = (kbaton*)apr_pcalloc(subpool, sizeof(*bt)); + bt->target_string = svn_stringbuf_create("", subpool); + bt->string_stream = svn_stream_create(bt,subpool); + svn_stream_set_write(bt->string_stream,write_to_string); + + QString target = makeSvnURL( url ); + kdDebug(9036) << "SvnURL: " << target << endl; + recordCurrentURL( KURL( target ) ); + + //find the requested revision + svn_opt_revision_t rev; + svn_opt_revision_t endrev; + int idx = target.findRev( "?rev=" ); + if ( idx != -1 ) { + QString revstr = target.mid( idx+5 ); +#if 0 + kdDebug(9036) << "revision string found " << revstr << endl; + if ( revstr == "HEAD" ) { + rev.kind = svn_opt_revision_head; + kdDebug(9036) << "revision searched : HEAD" << endl; + } else { + rev.kind = svn_opt_revision_number; + rev.value.number = revstr.toLong(); + kdDebug(9036) << "revision searched : " << rev.value.number << endl; + } +#endif + svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool ); + target = target.left( idx ); + kdDebug(9036) << "new target : " << target << endl; + } else { + kdDebug(9036) << "no revision given. searching HEAD " << endl; + rev.kind = svn_opt_revision_head; + } + initNotifier(false, false, false, subpool); + + svn_error_t *err = svn_client_cat (bt->string_stream, svn_path_canonicalize( target.utf8(),subpool ),&rev,ctx, subpool); + if ( err ) { + error( KIO::ERR_SLAVE_DEFINED, err->message ); + svn_pool_destroy( subpool ); + return; + } + + // Send the mimeType as soon as it is known + QByteArray *cp = new QByteArray(); + cp->setRawData( bt->target_string->data, bt->target_string->len ); + KMimeType::Ptr mt = KMimeType::findByContent(*cp); + kdDebug(9036) << "KMimeType returned : " << mt->name() << endl; + mimeType( mt->name() ); + + totalSize(bt->target_string->len); + + //send data + data(*cp); + + data(QByteArray()); // empty array means we're done sending the data + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::stat(const KURL & url){ + kdDebug(9036) << "kio_svn::stat(const KURL& url) : " << url.url() << endl ; + + void *ra_baton, *session; + svn_ra_plugin_t *ra_lib; + svn_node_kind_t kind; + apr_pool_t *subpool = svn_pool_create (pool); + + QString target = makeSvnURL( url); + kdDebug(9036) << "SvnURL: " << target << endl; + recordCurrentURL( KURL( target ) ); + + //find the requested revision + svn_opt_revision_t rev; + svn_opt_revision_t endrev; + int idx = target.findRev( "?rev=" ); + if ( idx != -1 ) { + QString revstr = target.mid( idx+5 ); +#if 0 + kdDebug(9036) << "revision string found " << revstr << endl; + if ( revstr == "HEAD" ) { + rev.kind = svn_opt_revision_head; + kdDebug(9036) << "revision searched : HEAD" << endl; + } else { + rev.kind = svn_opt_revision_number; + rev.value.number = revstr.toLong(); + kdDebug(9036) << "revision searched : " << rev.value.number << endl; + } +#endif + svn_opt_parse_revision( &rev, &endrev, revstr.utf8( ), subpool ); + target = target.left( idx ); + kdDebug(9036) << "new target : " << target << endl; + } else { + kdDebug(9036) << "no revision given. searching HEAD " << endl; + rev.kind = svn_opt_revision_head; + } + + //init + svn_error_t *err = svn_ra_init_ra_libs(&ra_baton,subpool); + if ( err ) { + kdDebug(9036) << "init RA libs failed : " << err->message << endl; + return; + } + //find RA libs + err = svn_ra_get_ra_library(&ra_lib,ra_baton,svn_path_canonicalize( target.utf8(), subpool ),subpool); + if ( err ) { + kdDebug(9036) << "RA get libs failed : " << err->message << endl; + return; + } + kdDebug(9036) << "RA init completed" << endl; + + //start session + svn_ra_callbacks_t *cbtable = (svn_ra_callbacks_t*)apr_pcalloc(subpool, sizeof(*cbtable)); + kio_svn_callback_baton_t *callbackbt = (kio_svn_callback_baton_t*)apr_pcalloc(subpool, sizeof( *callbackbt )); + + cbtable->open_tmp_file = open_tmp_file; + cbtable->get_wc_prop = NULL; + cbtable->set_wc_prop = NULL; + cbtable->push_wc_prop = NULL; + cbtable->auth_baton = ctx->auth_baton; + + callbackbt->base_dir = target.utf8(); + callbackbt->pool = subpool; + callbackbt->config = ctx->config; + + err = ra_lib->open(&session,svn_path_canonicalize( target.utf8(), subpool ),cbtable,callbackbt,ctx->config,subpool); + if ( err ) { + kdDebug(9036)<< "Open session " << err->message << endl; + return; + } + kdDebug(9036) << "Session opened to " << target << endl; + //find number for HEAD + if (rev.kind == svn_opt_revision_head) { + err = ra_lib->get_latest_revnum(session,&rev.value.number,subpool); + if ( err ) { + kdDebug(9036)<< "Latest RevNum " << err->message << endl; + return; + } + kdDebug(9036) << "Got rev " << rev.value.number << endl; + } + + //get it + ra_lib->check_path(session,"",rev.value.number,&kind,subpool); + kdDebug(9036) << "Checked Path" << endl; + UDSEntry entry; + switch ( kind ) { + case svn_node_file: + kdDebug(9036) << "::stat result : file" << endl; + createUDSEntry(url.filename(),"",0,false,0,entry); + statEntry( entry ); + break; + case svn_node_dir: + kdDebug(9036) << "::stat result : directory" << endl; + createUDSEntry(url.filename(),"",0,true,0,entry); + statEntry( entry ); + break; + case svn_node_unknown: + case svn_node_none: + //error XXX + default: + kdDebug(9036) << "::stat result : UNKNOWN ==> WOW :)" << endl; + ; + } + finished(); + svn_pool_destroy( subpool ); +} + +void kio_svnProtocol::listDir(const KURL& url){ + kdDebug(9036) << "kio_svn::listDir(const KURL& url) : " << url.url() << endl ; + + apr_pool_t *subpool = svn_pool_create (pool); + apr_hash_t *dirents; + + QString target = makeSvnURL( url); + kdDebug(9036) << "SvnURL: " << target << endl; + recordCurrentURL( KURL( target ) ); + + //find the requested revision + svn_opt_revision_t rev; + svn_opt_revision_t endrev; + int idx = target.findRev( "?rev=" ); + if ( idx != -1 ) { + QString revstr = target.mid( idx+5 ); + svn_opt_parse_revision( &rev, &endrev, revstr.utf8(), subpool ); +#if 0 + kdDebug(9036) << "revision string found " << revstr << endl; + if ( revstr == "HEAD" ) { + rev.kind = svn_opt_revision_head; + kdDebug(9036) << "revision searched : HEAD" << endl; + } else { + rev.kind = svn_opt_revision_number; + rev.value.number = revstr.toLong(); + kdDebug(9036) << "revision searched : " << rev.value.number << endl; + } +#endif + target = target.left( idx ); + kdDebug(9036) << "new target : " << target << endl; + } else { + kdDebug(9036) << "no revision given. searching HEAD " << endl; + rev.kind = svn_opt_revision_head; + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_ls (&dirents, svn_path_canonicalize( target.utf8(), subpool ), &rev, false, ctx, subpool); + if ( err ) { + error( KIO::ERR_SLAVE_DEFINED, err->message ); + svn_pool_destroy( subpool ); + return; + } + + apr_array_header_t *array; + int i; + + array = svn_sort__hash (dirents, compare_items_as_paths, subpool); + + UDSEntry entry; + for (i = 0; i < array->nelts; ++i) { + entry.clear(); + const char *utf8_entryname, *native_entryname; + svn_dirent_t *dirent; + svn_sort__item_t *item; + + item = &APR_ARRAY_IDX (array, i, svn_sort__item_t); + + utf8_entryname = (const char*)item->key; + + dirent = (svn_dirent_t*)apr_hash_get (dirents, utf8_entryname, item->klen); + + svn_utf_cstring_from_utf8 (&native_entryname, utf8_entryname, subpool); + const char *native_author = NULL; + + //XXX BUGGY +/* apr_time_exp_t timexp; + apr_time_exp_lt(&timexp, dirent->time); + apr_os_exp_time_t *ostime; + apr_os_exp_time_get( &ostime, &timexp); + + time_t mtime = mktime( ostime );*/ + + if (dirent->last_author) + svn_utf_cstring_from_utf8 (&native_author, dirent->last_author, subpool); + + if ( createUDSEntry(QString( native_entryname ), QString( native_author ), dirent->size, + dirent->kind==svn_node_dir ? true : false, 0, entry) ) + listEntry( entry, false ); + } + listEntry( entry, true ); + + finished(); + svn_pool_destroy (subpool); +} + +bool kio_svnProtocol::createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, UDSEntry& entry) { + kdDebug(9036) << "MTime : " << ( long )mtime << endl; + kdDebug(9036) << "UDS filename : " << filename << endl; + UDSAtom atom; + atom.m_uds = KIO::UDS_NAME; + atom.m_str = filename; + entry.append( atom ); + + atom.m_uds = KIO::UDS_FILE_TYPE; + atom.m_long = isdir ? S_IFDIR : S_IFREG; + entry.append( atom ); + + atom.m_uds = KIO::UDS_SIZE; + atom.m_long = size; + entry.append( atom ); + + atom.m_uds = KIO::UDS_MODIFICATION_TIME; + atom.m_long = mtime; + entry.append( atom ); + + atom.m_uds = KIO::UDS_USER; + atom.m_str = user; + entry.append( atom ); + + return true; +} + +// not used, at least for KDevelop +// void kio_svnProtocol::copy(const KURL & src, const KURL& dest, int /*permissions*/, bool /*overwrite*/) { +// kdDebug(9036) << "kio_svnProtocol::copy() Source : " << src.url() << " Dest : " << dest.url() << endl; +// +// apr_pool_t *subpool = svn_pool_create (pool); +// svn_client_commit_info_t *commit_info = NULL; +// +// KURL nsrc = src; +// KURL ndest = dest; +// nsrc.setProtocol( chooseProtocol( src.protocol() ) ); +// ndest.setProtocol( chooseProtocol( dest.protocol() ) ); +// QString srcsvn = nsrc.url(); +// QString destsvn = ndest.url(); +// +// recordCurrentURL( nsrc ); +// +// //find the requested revision +// svn_opt_revision_t rev; +// int idx = srcsvn.findRev( "?rev=" ); +// if ( idx != -1 ) { +// QString revstr = srcsvn.mid( idx+5 ); +// kdDebug(9036) << "revision string found " << revstr << endl; +// if ( revstr == "HEAD" ) { +// rev.kind = svn_opt_revision_head; +// kdDebug(9036) << "revision searched : HEAD" << endl; +// } else { +// rev.kind = svn_opt_revision_number; +// rev.value.number = revstr.toLong(); +// kdDebug(9036) << "revision searched : " << rev.value.number << endl; +// } +// srcsvn = srcsvn.left( idx ); +// kdDebug(9036) << "new src : " << srcsvn << endl; +// } else { +// kdDebug(9036) << "no revision given. searching HEAD " << endl; +// rev.kind = svn_opt_revision_head; +// } +// +// initNotifier(false, false, false, subpool); +// svn_error_t *err = svn_client_copy(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), ctx, subpool); +// if ( err ) { +// error( KIO::ERR_SLAVE_DEFINED, err->message ); +// svn_pool_destroy (subpool); +// } +// +// finished(); +// svn_pool_destroy (subpool); +// } + +void kio_svnProtocol::mkdir( const KURL::List& list, int /*permissions*/ ) { + kdDebug(9036) << "kio_svnProtocol::mkdir(LIST) : " << list << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + + recordCurrentURL( list[ 0 ] ); + + apr_array_header_t *targets = apr_array_make(subpool, list.count()+1, sizeof(const char *)); + + KURL::List::const_iterator it = list.begin(), end = list.end(); + for ( ; it != end; ++it ) { + QString cur = makeSvnURL( *it ); + kdDebug( 9036 ) << "kio_svnProtocol::mkdir raw url for subversion : " << cur << endl; + const char *_target = apr_pstrdup( subpool, svn_path_canonicalize( apr_pstrdup( subpool, cur.utf8() ), subpool ) ); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = _target; + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool); + if ( err ) { + error( KIO::ERR_COULD_NOT_MKDIR, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::mkdir( const KURL& url, int /*permissions*/ ) { + kdDebug(9036) << "kio_svnProtocol::mkdir() : " << url.url() << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + + QString target = makeSvnURL( url); + kdDebug(9036) << "SvnURL: " << target << endl; + recordCurrentURL( KURL( target ) ); + + apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *)); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() ); + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_mkdir(&commit_info,targets,ctx,subpool); + if ( err ) { + error( KIO::ERR_COULD_NOT_MKDIR, err->message ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::del( const KURL& url, bool /*isfile*/ ) { + kdDebug(9036) << "kio_svnProtocol::del() : " << url.url() << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + + QString target = makeSvnURL(url); + kdDebug(9036) << "SvnURL: " << target << endl; + recordCurrentURL( KURL( target ) ); + + apr_array_header_t *targets = apr_array_make(subpool, 2, sizeof(const char *)); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = apr_pstrdup( subpool, target.utf8() ); + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_delete(&commit_info,targets,false/*force remove locally modified files in wc*/,ctx,subpool); + if ( err ) { + error( KIO::ERR_CANNOT_DELETE, err->message ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::rename(const KURL& src, const KURL& dest, bool /*overwrite*/) { + kdDebug(9036) << "kio_svnProtocol::rename() Source : " << src.url() << " Dest : " << dest.url() << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + + KURL nsrc = src; + KURL ndest = dest; + nsrc.setProtocol( chooseProtocol( src.protocol() ) ); + ndest.setProtocol( chooseProtocol( dest.protocol() ) ); + QString srcsvn = nsrc.url(); + QString destsvn = ndest.url(); + + recordCurrentURL( nsrc ); + + //find the requested revision + svn_opt_revision_t rev; + int idx = srcsvn.findRev( "?rev=" ); + if ( idx != -1 ) { + QString revstr = srcsvn.mid( idx+5 ); + kdDebug(9036) << "revision string found " << revstr << endl; + if ( revstr == "HEAD" ) { + rev.kind = svn_opt_revision_head; + kdDebug(9036) << "revision searched : HEAD" << endl; + } else { + rev.kind = svn_opt_revision_number; + rev.value.number = revstr.toLong(); + kdDebug(9036) << "revision searched : " << rev.value.number << endl; + } + srcsvn = srcsvn.left( idx ); + kdDebug(9036) << "new src : " << srcsvn << endl; + } else { + kdDebug(9036) << "no revision given. searching HEAD " << endl; + rev.kind = svn_opt_revision_head; + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_move(&commit_info, srcsvn.utf8(), &rev, destsvn.utf8(), false/*force remove locally modified files in wc*/, ctx, subpool); + if ( err ) { + error( KIO::ERR_CANNOT_RENAME, err->message ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::special( const QByteArray& data ) { +// kdDebug(9036) << "kio_svnProtocol::special" << endl; + + QDataStream stream(data, IO_ReadOnly); + int tmp; + + stream >> tmp; + kdDebug(9036) << "kio_svnProtocol::special " << tmp << endl; + + switch ( tmp ) { + case SVN_CHECKOUT: + { + KURL repository, wc; + int revnumber; + QString revkind; + stream >> repository; + stream >> wc; + stream >> revnumber; + stream >> revkind; + kdDebug(9036) << "kio_svnProtocol CHECKOUT from " << repository.url() << " to " << wc.url() << " at " << revnumber << " or " << revkind << endl; + checkout( repository, wc, revnumber, revkind ); + break; + } + case SVN_UPDATE: + { + KURL::List list; + int revnumber; + QString revkind; + stream >> list; + stream >> revnumber; + stream >> revkind; + kdDebug(9036) << "kio_svnProtocol UPDATE " << endl; + update( list, revnumber, revkind ); + break; + } + case SVN_COMMIT: + { + KURL::List wclist; + while ( !stream.atEnd() ) { + KURL tmp; + stream >> tmp; + wclist << tmp; + } + kdDebug(9036) << "kio_svnProtocol COMMIT" << endl; + commit( wclist ); + break; + } + case SVN_COMMIT_2: + { + bool recurse, keeplocks; + KURL::List wclist; + stream >> recurse; + stream >> keeplocks; + while ( !stream.atEnd() ) { + KURL tmp; + stream >> tmp; + wclist << tmp; + } + kdDebug(9036) << "kio_svnProtocol COMMIT2" << endl; + commit2( recurse, keeplocks, wclist ); + break; + } + case SVN_LOG: + { + kdDebug(9036) << "kio_svnProtocol LOG" << endl; + int revstart, revend; + QString revkindstart, revkindend; + bool discorverChangedPath, strictNodeHistory; + KURL::List targets; + + stream >> revstart; + stream >> revkindstart; + stream >> revend; + stream >> revkindend; + stream >> discorverChangedPath; + stream >> strictNodeHistory; + while ( !stream.atEnd() ) { + KURL tmp; + stream >> tmp; + targets << tmp; + } + svn_log( revstart, revkindstart, revend, revkindend, + discorverChangedPath, strictNodeHistory, targets ); + break; + } + case SVN_IMPORT: + { + KURL wc,repos; + stream >> repos; + stream >> wc; + kdDebug(9036) << "kio_svnProtocol IMPORT" << endl; + import(repos,wc); + break; + } + case SVN_ADD: + { + KURL::List wcList; + stream >> wcList; + kdDebug(9036) << "kio_svnProtocol ADD" << endl; + add(wcList); + break; + } + case SVN_DEL: + { + KURL::List wclist; + stream >> wclist; + kdDebug(9036) << "kio_svnProtocol DEL" << endl; + wc_delete(wclist); + break; + } + case SVN_REVERT: + { + KURL::List wclist; + stream >> wclist; + kdDebug(9036) << "kio_svnProtocol REVERT" << endl; + wc_revert(wclist); + break; + } + case SVN_STATUS: + { + KURL wc; + bool checkRepos=false; + bool fullRecurse=false; + stream >> wc; + stream >> checkRepos; + stream >> fullRecurse; + wc_status(wc,checkRepos,fullRecurse); + break; + } + case SVN_STATUS_2: + { + KURL wc; + QString revkind; + int revnumber; + bool checkRepos, fullRecurse, getAll, noIgnore; + stream >> checkRepos; + stream >> fullRecurse; + stream >> getAll; + stream >> noIgnore; + stream >> revnumber; + stream >> revkind; + stream >> wc; + wc_status2(wc,checkRepos,fullRecurse, getAll, noIgnore, revnumber, revkind); + break; + } + case SVN_MKDIR: + { + KURL::List list; + stream >> list; + kdDebug(9036) << "kio_svnProtocol MKDIR" << endl; + mkdir(list,0); + break; + } + case SVN_RESOLVE: + { + KURL url; + bool recurse; + stream >> url; + stream >> recurse; + kdDebug(9036) << "kio_svnProtocol RESOLVE" << endl; + wc_resolve(url,recurse); + break; + } + case SVN_SWITCH: + { + KURL wc,url; + bool recurse; + int revnumber; + QString revkind; + stream >> wc; + stream >> url; + stream >> recurse; + stream >> revnumber; + stream >> revkind; + kdDebug(9036) << "kio_svnProtocol SWITCH" << endl; + svn_switch(wc,url,revnumber,revkind,recurse); + break; + } + case SVN_SWITCH_RELOCATE: + { + KURL wc, origUrl, newUrl; + bool recurse; + stream >> wc; + stream >> origUrl; + stream >> newUrl; + stream >> recurse; + svn_switch_relocate( wc, origUrl, newUrl, recurse ); + break; + } + case SVN_DIFF: + { + KURL url1,url2; + int rev1, rev2; + bool recurse, pegdiff; + QString revkind1, revkind2; + stream >> url1; + stream >> url2; + stream >> rev1; + stream >> revkind1; + stream >> rev2; + stream >> revkind2; + stream >> recurse >> pegdiff; + kdDebug(9036) << "kio_svnProtocol DIFF" << endl; + svn_diff(url1,url2,rev1,rev2,revkind1,revkind2,recurse,pegdiff); + break; + } + case SVN_BLAME: + { + KURL url; + int urlMode; + int pegRev, startRev, endRev; + QString pegRevKind, startRevKind, endRevKind; + stream >> url; + stream >> urlMode; +// stream >> pegRev; +// stream >> pegRevKind; + stream >> startRev; + stream >> startRevKind; + stream >> endRev; + stream >> endRevKind; + + blame(url, (UrlMode)urlMode, startRev, startRevKind, endRev, endRevKind); + break; + } + case SVN_INFO: + { + KURL pathOrUrl; + int pegRev, rev; + QString pegRevKind, revKind; + bool recurse = false; + stream >> pathOrUrl; + stream >> pegRev; + stream >> pegRevKind; + stream >> rev; + stream >> revKind; + stream >> recurse; + svn_info( pathOrUrl, pegRev, pegRevKind, rev, revKind, recurse ); + break; + } + case SVN_COPY: + { + KURL src, dest; + int srcRev; + QString srcRevKind; + stream >> src; + stream >> srcRev; + stream >> srcRevKind; + stream >> dest; + svn_copy( src, srcRev, srcRevKind, dest ); + break; + } + case SVN_MERGE: + { + KURL src1, src2, wc_target; + int rev1, rev2; + QString revKind1, revKind2; + bool recurse, ignore_ancestry, force, dry_run; + stream >> src1 >> rev1 >> revKind1; + stream >> src2 >> rev2 >> revKind2; + stream >> wc_target; + stream >> recurse >> ignore_ancestry >> force >> dry_run; + svn_merge( src1, rev1, revKind1, src2, rev2, revKind2, wc_target, + recurse, ignore_ancestry, force, dry_run ); + break; + } + default: + { + kdDebug(9036) << "kio_svnProtocol DEFAULT" << endl; + break; + } + } +} +/** + * not used anywhere, anymore +*/ +void kio_svnProtocol::popupMessage( const QString& message ) { +// QByteArray params; +// QDataStream stream(params, IO_WriteOnly); +// stream << message; +// +// if ( !dcopClient()->send( "kded","ksvnd","popupMessage(QString)", params ) ) +// kdWarning() << "Communication with KDED:KSvnd failed" << endl; +} + +void kio_svnProtocol::blame( KURL url, UrlMode /*mode*/,/* int pegRev, QString pegRevKind,*/ int startRev, QString startRevKind, int endRev, QString endRevKind ) +{ + kdDebug(9036) << " __TIME__ " << __TIME__ << endl; +// kdDebug(9036) << " PegRev " << pegRev << pegRevKind << endl; + kdDebug(9036) << " StartRev" << startRev << startRevKind << endl; + kdDebug(9036) << " EndRev" << endRev << endRevKind << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + const char* path_or_url = apr_pstrdup( subpool, url.pathOrURL().utf8() );; + + svn_opt_revision_t rev1 = createRevision( startRev, startRevKind, subpool ); + svn_opt_revision_t rev2 = createRevision( endRev, endRevKind, subpool ); +// svn_opt_revision_t revPeg = createRevision( pegRev, pegRevKind, subpool ); + + //initNotifier(false, false, false, subpool); + svn_client_blame_receiver_t receiver = kio_svnProtocol::blameReceiver; + svn_error_t *err = svn_client_blame( path_or_url, &rev1, &rev2, receiver, (void*)this, ctx, subpool ); + if ( err ) + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + finished(); + svn_pool_destroy (subpool); + +} + +svn_error_t* kio_svnProtocol::blameReceiver( void *baton, apr_int64_t line_no, svn_revnum_t rev, const char *author, const char *date, const char *line, apr_pool_t *pool ) +{ + kio_svnProtocol *p = (kio_svnProtocol*)baton; + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "LINE", QString::number(line_no) ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REV", QString::number(rev) ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "AUTHOR", author ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "DATE", date ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "CONTENT", QString::fromLocal8Bit(line) ); + + p->incCounter(); + return SVN_NO_ERROR; +} + +/** + KDevelop has no way to retrieve URL of working copy. + Thus retreiving URL from WC should be done here, using subversion native API. + Thus, svn_log should get another flag (bool repositHistory )specifying between file:/// or URL +*/ +void kio_svnProtocol::svn_log( int revstart, const QString& revkindstart, int revend, const QString& revkindend, + bool discorverChangedPaths, bool strictNodeHistory, + const KURL::List& urls ) +{ +// kdDebug(9036) << " from revision " << revstart << " or " << revkindstart << " to " << " revision " << revend << " or " << revkindend << endl; + kdDebug(9036) << " __TIME__ " << __TIME__ << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + + // TODO HEAD:1 was removed from SVN API 1.2, instead callers should specify HEAD:0 + svn_opt_revision_t rev1 = createRevision( revstart, revkindstart, subpool ); + svn_opt_revision_t rev2 = createRevision( revend, revkindend, subpool ); + + m_counter = 0; + apr_array_header_t *targets = apr_array_make(subpool, 1+urls.count(), sizeof(const char *)); + + for ( QValueListConstIterator<KURL> it = urls.begin(); it != urls.end() ; ++it ) { + KURL nurl = *it; + const char *path = + apr_pstrdup( subpool, svn_path_canonicalize( nurl.pathOrURL().utf8(), subpool ) ); + kdDebug(9036) << path << endl; + *(( const char ** )apr_array_push(( apr_array_header_t* )targets)) = path; + + setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "requrl", nurl.pathOrURL() ); + incCounter(); + } + + svn_log_message_receiver_t receiver = kio_svnProtocol::receiveLogMessage; + svn_error_t *err = svn_client_log2(targets, &rev1, &rev2, 0, discorverChangedPaths, strictNodeHistory, receiver, this, ctx, subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +// save for one revision +svn_error_t* kio_svnProtocol::receiveLogMessage(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, + const char *author, const char *date, const char *message, apr_pool_t *pool ) +{ + kio_svnProtocol *p = (kio_svnProtocol*)baton; + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number(revision) ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "author", author ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "date", date ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "logmsg", QString::fromLocal8Bit(message) ); + if( changed_paths != NULL ){ + QString pathlist; + void *onePath; + const char *pathkey; + apr_hash_index_t *hi; + for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi)) { + apr_hash_this(hi, (const void**) &pathkey, NULL, &onePath); + svn_log_changed_path_t *cp = (svn_log_changed_path_t*)onePath; + kdDebug(9036) << "OnePath: " << cp->copyfrom_path << " and key: " << pathkey << endl; + pathlist += cp->action; + pathlist += " "; +// pathlist += cp->copyfrom_path; + pathlist += pathkey; + pathlist += "\n"; + } + kdDebug(9036) << "pathlist: " << pathlist <<endl; + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "pathlist", pathlist ); + } + p->incCounter(); + return SVN_NO_ERROR; +} + +svn_opt_revision_t kio_svnProtocol::createRevision( int revision, const QString& revkind, apr_pool_t *pool ) { + svn_opt_revision_t result;//,endrev; + // TODO support svn_opt_revision_date + if ( revision != -1 ) { + result.value.number = revision; + result.kind = svn_opt_revision_number; + } else if ( revkind == "WORKING" ) { + result.kind = svn_opt_revision_working; + } else if ( revkind == "BASE" ) { + result.kind = svn_opt_revision_base; + } else if ( revkind == "HEAD" ) { + result.kind = svn_opt_revision_head; + } else if ( revkind == "COMMITTED" ) { + result.kind = svn_opt_revision_committed; + } else if ( revkind == "PREV" ) { + result.kind = svn_opt_revision_previous; + } +// } else if ( !revkind.isNull() ) { +// svn_opt_parse_revision(&result,&endrev,revkind.utf8(),pool); + else if ( revkind == "UNSPECIFIED" ){ + result.kind = svn_opt_revision_unspecified; + } + else { + result.kind = svn_opt_revision_unspecified; + } + return result; +} + +void kio_svnProtocol::svn_diff(const KURL & url1, const KURL& url2,int rev1, int rev2,const QString& revkind1,const QString& revkind2,bool recurse, bool pegdiff ) +{ + kdDebug(9036) << "kio_svn::diff : " << url1.path() << " at revision " << rev1 << " or " << revkind1 << " with " + << url2.path() << " at revision " << rev2 << " or " << revkind2 + << endl ; + + apr_pool_t *subpool = svn_pool_create (pool); + apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", TRUE, subpool ); + +// KURL nurl1 = url1; +// KURL nurl2 = url2; +// nurl1.setProtocol( chooseProtocol( url1.protocol() ) ); //svn+https -> https for eg +// nurl2.setProtocol( chooseProtocol( url2.protocol() ) ); +// recordCurrentURL( nurl1 ); +// QString source = makeSvnURL( nurl1 ); +// QString target = makeSvnURL( nurl2 ); + +// const char *path1 = svn_path_canonicalize( apr_pstrdup( subpool, source.utf8() ), subpool ); +// const char *path2 = svn_path_canonicalize( apr_pstrdup( subpool, target.utf8() ), subpool ); + + //remove file:/// so we can diff for working copies, needs a better check (so we support URL for file:/// _repositories_ ) +// if ( nurl1.protocol() == "file" ) { +// path1 = svn_path_canonicalize( apr_pstrdup( subpool, nurl1.path().utf8() ), subpool ); +// } +// if ( nurl2.protocol() == "file" ) { +// path2 = svn_path_canonicalize( apr_pstrdup( subpool, nurl2.path().utf8() ), subpool ); +// } + + // all the commentted codes above are redundancy. url1/url2 is only file:// , svn:// or https:// + // svn+https etc. are not handed out here. + const char *path1 = apr_pstrdup( subpool, url1.pathOrURL().utf8() ); + const char *path2 = apr_pstrdup( subpool, url2.pathOrURL().utf8() );; + + kdDebug( 9036 ) << "1 : " << path1 << " 2: " << path2 << endl; + + svn_opt_revision_t revision1,revision2; + revision1 = createRevision(rev1, revkind1, subpool); + revision2 = createRevision(rev2, revkind2, subpool); + + char *templ; + templ = apr_pstrdup ( subpool, "/tmp/tmpfile_XXXXXX" ); + apr_file_t *outfile = NULL; + apr_file_mktemp( &outfile, templ , APR_READ|APR_WRITE|APR_CREATE|APR_TRUNCATE, subpool ); + + initNotifier(false, false, false, subpool); + svn_error_t *err = 0; + if( pegdiff ){ + svn_opt_revision_t peg_rev = createRevision(-1, "BASE", subpool ); + err = svn_client_diff_peg( options, path1, &peg_rev, &revision1, &revision2, + recurse, false, false, outfile, NULL, ctx, subpool ); + } else{ + err = svn_client_diff( options, path1, &revision1, path2, &revision2, recurse, + false, false, outfile, NULL, ctx, subpool ); + } + + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + //read the content of the outfile now + QStringList tmp; + apr_file_close(outfile); + QFile file(templ); + if ( file.open( IO_ReadOnly ) ) { + QTextStream stream( &file ); + QString line; + while ( !stream.atEnd() ) { + line = stream.readLine(); + tmp << line; + } + file.close(); + } + for ( QStringList::Iterator itt = tmp.begin(); itt != tmp.end(); itt++ ) { + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "diffresult", ( *itt ) ); + m_counter++; + } + //delete temp file + file.remove(); + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::svn_switch( const KURL& wc, const KURL& repos, int revnumber, const QString& revkind, bool recurse) { + kdDebug(9036) << "kio_svn::switch : " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ; + + apr_pool_t *subpool = svn_pool_create (pool); + + KURL nurl = repos; + KURL dest = wc; + nurl.setProtocol( chooseProtocol( repos.protocol() ) ); + dest.setProtocol( "file" ); +// recordCurrentURL( nurl ); +// QString source = dest.path(); +// QString target = makeSvnURL( repos ); + + const char *path = svn_path_canonicalize( apr_pstrdup( subpool, dest.path().utf8() ), subpool ); + const char *url = svn_path_canonicalize( apr_pstrdup( subpool, nurl.url().utf8() ), subpool ); + kdDebug(9036) << " WC path: " << path << " Repository URL: " << url << endl; + + svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool ); + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_switch (NULL/*result revision*/, path, url, &rev, recurse, ctx, subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::svn_switch_relocate( const KURL &wc, const KURL &origUrl, const KURL &newUrl, + bool recurse ) +{ + apr_pool_t *subpool = svn_pool_create( pool ); + + const char *wcPath = svn_path_canonicalize( apr_pstrdup( subpool, wc.path().utf8() ), subpool ); + const char *fromUrl = apr_pstrdup( subpool, origUrl.url().utf8() ); + const char *toUrl = apr_pstrdup( subpool, newUrl.url().utf8() ); + kdDebug(9036) << " WC path: " << wcPath << " from: " << fromUrl << " to: " << toUrl << endl; + + svn_error_t *err = svn_client_relocate( wcPath, fromUrl, toUrl, recurse, ctx, pool ); + + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) ); + svn_pool_destroy (subpool); + return; + } + m_counter = 0L; + setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string", + QString("switched to %1").arg( toUrl ) ); + finished(); + svn_pool_destroy( subpool ); +} + +void kio_svnProtocol::update( const KURL::List &list, int revnumber, const QString& revkind ) { + kdDebug(9036) << "kio_svn::update : __TIME__" << __TIME__ << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + + apr_array_header_t *targets = apr_array_make(subpool, 1+list.count(), sizeof(const char *)); + svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool ); + + for( QValueList<KURL>::ConstIterator it = list.begin(); it != list.end(); ++it ){ + KURL nurl = *it; + *( const char ** )apr_array_push(targets) = svn_path_canonicalize( nurl.path().utf8(), subpool ); + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_update2( NULL, targets, &rev, + true/*recurse*/, false/*ignore_external*/, + ctx, subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::import( const KURL& repos, const KURL& wc ) { + kdDebug(9036) << "kio_svnProtocol::import() : " << wc.url() << " into " << repos.url() << endl; + + apr_pool_t *subpool = svn_pool_create (pool); +// svn_client_commit_info_t *commit_info = +// (svn_client_commit_info_t*) apr_palloc( subpool, sizeof(svn_client_commit_info_t) ); + svn_commit_info_t *commit_info = svn_create_commit_info( subpool ); + bool nonrecursive = false; + + const char *path = apr_pstrdup( subpool, svn_path_canonicalize( wc.path().utf8(), subpool ) ); + const char *url = apr_pstrdup( subpool, svn_path_canonicalize( repos.url().utf8(), subpool ) ); + + initNotifier(false, false, false, subpool); + kdDebug(9036) << " Executing import: " << path << " to " << url << endl; + + svn_error_t *err = svn_client_import2(&commit_info, path, url, nonrecursive, false, ctx, subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + svn_pool_destroy (subpool); + finished(); +} + +void kio_svnProtocol::checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind ) { + kdDebug(9036) << "kio_svn::checkout : " << repos.url() << " into " << wc.path() << " at revision " << revnumber << " or " << revkind << endl ; + + apr_pool_t *subpool = svn_pool_create (pool); + KURL nurl = repos; + KURL dest = wc; + nurl.setProtocol( chooseProtocol( repos.protocol() ) ); + dest.setProtocol( "file" ); + QString target = makeSvnURL( repos ); + recordCurrentURL( nurl ); + QString dpath = dest.path(); + + //find the requested revision + svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool ); + + initNotifier(true, false, false, subpool); + svn_error_t *err = svn_client_checkout (NULL/* rev actually checkedout */, svn_path_canonicalize( target.utf8(), subpool ), svn_path_canonicalize ( dpath.utf8(), subpool ), &rev, true, ctx, subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, err->message ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::commit(const KURL::List& wc) +{ + commit2(true, true, wc); +} + +void kio_svnProtocol::commit2(bool recurse, bool keeplocks, const KURL::List& wc) { + kdDebug(9036) << "kio_svnProtocol::commit2() : " << wc << endl; + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + + apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *)); + + for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) { + KURL nurl = *it; + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool ); + } + + initNotifier(false, false, false, subpool); + kdDebug(9036) << "recurse: " << recurse << " keeplocks: " << keeplocks <<endl; + svn_error_t *err = svn_client_commit2(&commit_info,targets,recurse,keeplocks,ctx,subpool); + + if ( err ){ + char errbuf[512]; + svn_strerror(err->apr_err, errbuf, 512); + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) + "\n: " + QString::fromLocal8Bit(errbuf) ); + svn_pool_destroy (subpool); + return; + } + + if ( commit_info ) { + for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) { + KURL nurl = *it; + nurl.setProtocol( "file" ); + + QString userstring = i18n ( "Nothing to commit." ); + if ( SVN_IS_VALID_REVNUM( commit_info->revision ) ) + userstring = i18n( "Committed revision %1." ).arg(commit_info->revision); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "path", nurl.path() ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "action", "0" ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "kind", "0" ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "mime_t", "" ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "content", "0" ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "prop", "0" ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "rev" , QString::number( commit_info->revision ) ); + setMetaData(QString::number( m_counter ).rightJustify( 10,'0' )+ "string", userstring ); + m_counter++; + } + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::add(const KURL::List& list) { + kdDebug(9036) << "kio_svnProtocol::add() __TIME__" << __TIME__ << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + bool nonrecursive = false; + initNotifier(false, false, false, subpool); + + svn_error_t *err = NULL; + for( QValueList<KURL>::ConstIterator it = list.begin(); it != list.end(); ++it ){ + + KURL nurl = (*it); + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + kdDebug(9036) << " Schedule to Add: " << nurl.path().utf8() << endl; + err = svn_client_add( svn_path_canonicalize( nurl.path().utf8(), subpool ), + nonrecursive, ctx, subpool); + if( err ) break; + } + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::wc_delete(const KURL::List& wc) { + kdDebug(9036) << "kio_svnProtocol::wc_delete() : " << wc << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_client_commit_info_t *commit_info = NULL; + bool force = false; + + apr_array_header_t *targets = apr_array_make(subpool, 1+wc.count(), sizeof(const char *)); + + for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) { + KURL nurl = *it; + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool ); + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_delete(&commit_info,targets,force,ctx,subpool); + + if ( err ) + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::wc_revert(const KURL::List& wc) { + kdDebug(9036) << "kio_svnProtocol::revert() : " << wc << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + bool nonrecursive = false; + + apr_array_header_t *targets = apr_array_make(subpool, 1 + wc.count(), sizeof(const char *)); + + for ( QValueListConstIterator<KURL> it = wc.begin(); it != wc.end() ; ++it ) { + KURL nurl = *it; + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + (*(( const char ** )apr_array_push(( apr_array_header_t* )targets)) ) = svn_path_canonicalize( nurl.path().utf8(), subpool ); + } + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_revert(targets,nonrecursive,ctx,subpool); + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit( err->message ) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::wc_status(const KURL& wc, bool checkRepos, bool fullRecurse, bool getAll, int revnumber, const QString& revkind) { + kdDebug(9036) << "kio_svnProtocol::wc_status() : " << wc.url() << " checkRepos " << checkRepos << " fullRecurse " << fullRecurse << " getAll " << getAll << endl; + + wc_status2( wc, checkRepos, fullRecurse, getAll, false, revnumber, revkind ); +} + +void kio_svnProtocol::wc_status2(const KURL& wc, bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore, int revnumber, const QString& revkind) { + kdDebug(9036) << "kio_svnProtocol::wc_status2() : " << wc.url() << " checkRepos " << checkRepos << " fullRecurse " << fullRecurse << " getAll " << getAll << " noIgnore " << noIgnore << " revnumber " << revnumber << " revkind " << revkind << endl; + kdDebug(9036) << " __TIME__ " << __TIME__ << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_revnum_t result_rev; + + KURL nurl = wc; + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + + svn_opt_revision_t rev = createRevision( revnumber, revkind, subpool ); + + initNotifier(false, false, false, subpool); + + svn_error_t *err = svn_client_status(&result_rev, svn_path_canonicalize( nurl.path().utf8(), subpool ), &rev, kio_svnProtocol::status, this, fullRecurse, getAll, checkRepos, noIgnore, ctx, subpool); + + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::svn_info( KURL pathOrUrl, int pegRev, QString pegRevKind, int rev, QString revKind, bool recurse ) +{ + kdDebug(9036) << " kio_svnProtocol::svn_info(): pegRev " << pegRev << " pegKind " << pegRevKind << " rev " << rev << " revKind " << revKind << " recurse " << recurse << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + svn_opt_revision_t peg_rev = createRevision( pegRev, pegRevKind, subpool ); + svn_opt_revision_t revision = createRevision( rev, revKind, subpool ); + + svn_error_t *err = svn_client_info( pathOrUrl.pathOrURL().utf8(), + &peg_rev, &revision, + kio_svnProtocol::infoReceiver, + this, + recurse, + ctx, pool ); + + if ( err ){ + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(err->message) ); + svn_pool_destroy (subpool); + return; + } + svn_pool_destroy( subpool ); + finished(); +} + +svn_error_t* kio_svnProtocol::infoReceiver( void *baton, const char *path, + const svn_info_t *info, apr_pool_t *pool) +{ + kio_svnProtocol *p= (kio_svnProtocol*)baton ; + if( !p ) + return SVN_NO_ERROR; + + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "PATH", QString::fromUtf8( path )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "URL", QString( info->URL ) ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REV", QString::number( info->rev )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "KIND", QString::number( info->kind )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REPOS_ROOT_URL", QString( info->repos_root_URL ) ); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "REPOS_UUID", QString(info->repos_UUID) ); + p->incCounter(); + + return SVN_NO_ERROR; +} + +void kio_svnProtocol::svn_copy( const KURL &srcUrl, int srcRev, const QString &srcRevKind, + const KURL &destUrl ) +{ + kdDebug(9036) << " kio: svn_copy src: " << srcUrl << " Dest Url: " << destUrl << " revnum: " << srcRev << " revKind: " << srcRevKind << endl; + apr_pool_t *subpool = svn_pool_create (pool); + svn_commit_info_t *commit_info = svn_create_commit_info( subpool ); + + svn_opt_revision_t rev = createRevision( srcRev, srcRevKind, subpool ); + + // TODO more elegant notification mechanism + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_copy2( &commit_info, + srcUrl.pathOrURL().utf8(), &rev, + destUrl.pathOrURL().utf8(), + ctx, subpool); + + if ( err ) { + apr_status_t errcode = err->apr_err; + char buf[512]; + svn_strerror(errcode, buf, 512); + error( KIO::ERR_SLAVE_DEFINED, QString::fromLocal8Bit(buf) ); + svn_pool_destroy (subpool); + return; + } + + if( commit_info ){ + setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string", + i18n("Copied Revision %1").arg( commit_info->revision) ); + } else { + setMetaData(QString::number( counter() ).rightJustify( 10,'0' )+ "string", + i18n("Copied") ); + } + + finished(); + svn_pool_destroy (subpool); +} + +void kio_svnProtocol::svn_merge(const KURL &src1, int revNum1, QString revKind1, + const KURL &src2, int revNum2, QString revKind2, + const KURL &target_wc, + bool recurse, bool ignore_ancestry, bool force, bool dry_run ) +{ + kdDebug(9036) << " KIO::svn_merge src1 " << src1.pathOrURL().utf8() << " src2 " << src2.pathOrURL().utf8() << " target " << target_wc.pathOrURL().utf8() << endl; + apr_pool_t *subpool = svn_pool_create( pool ); + + svn_opt_revision_t rev1 = createRevision( revNum1, revKind1, subpool ); + svn_opt_revision_t rev2 = createRevision( revNum2, revKind2, subpool ); + + initNotifier( false, false, false, subpool ); + svn_error_t *err = svn_client_merge( src1.pathOrURL().utf8(), &rev1, + src2.pathOrURL().utf8(), &rev2, + target_wc.pathOrURL().utf8(), + recurse, ignore_ancestry, force, dry_run, + ctx, pool ); + if ( err ) { + apr_status_t errcode = err->apr_err; + char buf[512]; + svn_strerror(errcode, buf, 512); + error( KIO::ERR_SLAVE_DEFINED, + QString::fromLocal8Bit(err->message) + "\n "+ QString::fromLocal8Bit(buf) ); + svn_pool_destroy (subpool); + return; + } + + finished(); + svn_pool_destroy( subpool ); +} + +//change the proto and remove trailing / +//remove double / also +QString kio_svnProtocol::makeSvnURL ( const KURL& url ) const { + QString kproto = url.protocol(); + KURL tpURL = url; + tpURL.cleanPath( true ); + QString svnUrl; + if ( kproto == "kdevsvn+http" ) { + kdDebug(9036) << "http:/ " << url.url() << endl; + tpURL.setProtocol("http"); + svnUrl = tpURL.url(-1); + return svnUrl; + } + else if ( kproto == "kdevsvn+https" ) { + kdDebug(9036) << "https:/ " << url.url() << endl; + tpURL.setProtocol("https"); + svnUrl = tpURL.url(-1); + return svnUrl; + } + else if ( kproto == "kdevsvn+ssh" ) { + kdDebug(9036) << "svn+ssh:/ " << url.url() << endl; + tpURL.setProtocol("svn+ssh"); + svnUrl = tpURL.url(-1); + return svnUrl; + } + else if ( kproto == "kdevsvn+svn" ) { + kdDebug(9036) << "svn:/ " << url.url() << endl; + tpURL.setProtocol("svn"); + svnUrl = tpURL.url(-1); + return svnUrl; + } + else if ( kproto == "kdevsvn+file" ) { + kdDebug(9036) << "file:/ " << url.url() << endl; + tpURL.setProtocol("file"); + svnUrl = tpURL.url(-1); + //hack : add one more / after file:/ + int idx = svnUrl.find("/"); + svnUrl.insert( idx, "//" ); + return svnUrl; + } + return tpURL.url(-1); +} + +QString kio_svnProtocol::chooseProtocol ( const QString& kproto ) const { + if ( kproto == "svn+http" ) return QString( "http" ); + else if ( kproto == "svn+https" ) return QString( "https" ); + else if ( kproto == "svn+ssh" ) return QString( "svn+ssh" ); + else if ( kproto == "svn" ) return QString( "svn" ); + else if ( kproto == "svn+file" ) return QString( "file" ); + return kproto; +} +/** Certificate is not yet valid. */ +#define SVN_AUTH_SSL_NOTYETVALID 0x00000001 +/** Certificate has expired. */ +#define SVN_AUTH_SSL_EXPIRED 0x00000002 +/** Certificate's CN (hostname) does not match the remote hostname. */ +#define SVN_AUTH_SSL_CNMISMATCH 0x00000004 +/** @brief Certificate authority is unknown (i.e. not trusted) */ +#define SVN_AUTH_SSL_UNKNOWNCA 0x00000008 +/** @brief Other failure. This can happen if neon has introduced a new + * failure bit that we do not handle yet. */ +#define SVN_AUTH_SSL_OTHER 0x40000000 +svn_error_t *kio_svnProtocol::trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *baton, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *ci, svn_boolean_t may_save, apr_pool_t *pool) +{ + kio_svnProtocol *p = (kio_svnProtocol*)baton; + // prepare params. + QByteArray params, replyData; + QCString replyType; + QDataStream arg(params, IO_WriteOnly); + + arg << i18n( "The certificate from the server could not be trusted automatically. Do you want to trust this certificate? " ); + arg << QString::fromLocal8Bit(ci->hostname); + arg << QString::fromLocal8Bit(ci->fingerprint); + arg << QString::fromLocal8Bit(ci->valid_from) << QString::fromLocal8Bit(ci->valid_until); + arg << QString::fromLocal8Bit(ci->issuer_dname) << QString::fromLocal8Bit(ci->ascii_cert) ; + // call dcop + int ret = p->dcopClient()->call( "kded", "kdevsvnd", + "sslServerTrustPrompt(QString, QString, QString, QString, QString, QString, QString)", + params, replyType, replyData ); + if (!ret){ + kdWarning() << " failed to prompt SSL_Server_Trust_Prompt " << endl; + return SVN_NO_ERROR; + } + if (replyType != "int"){ + kdWarning() << " abnormal reply type " << endl; + return SVN_NO_ERROR; + } + int resultCode; + QDataStream replyStream( replyData, IO_ReadOnly ); + replyStream >> resultCode; + + if( resultCode == -1 ){ + kdWarning() << " SSL server trust rejected " << endl; + *cred_p = 0L; //FIXME when rejected, maybe more elegant methods.. + } else if( resultCode == 0 ){ //accept once + *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (svn_auth_cred_ssl_server_trust_t)); + kdDebug(9036) << " accept once " << endl; + (*cred_p)->may_save = false; + (*cred_p)->accepted_failures = 0; + } else if( resultCode == 1 ){ //accept permanently + *cred_p = (svn_auth_cred_ssl_server_trust_t*)apr_pcalloc (pool, sizeof (svn_auth_cred_ssl_server_trust_t)); + kdDebug(9036) << " accept permanently " << endl; + (*cred_p)->may_save = true; + (*cred_p)->accepted_failures = failures; + } else{ + kdWarning() << " SSL server trust failed for some reason" << endl; + *cred_p = 0L; + } + + return SVN_NO_ERROR; +} +/** TODO fully implemented, but there is no way to test this yet.*/ +svn_error_t *kio_svnProtocol::clientCertSSLPrompt( + svn_auth_cred_ssl_client_cert_t **cred_p, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool) +{ + kdDebug(9036) << " clientCertSSLPrompt " << endl; +// kio_svnProtocol *p = (kio_svnProtocol*)baton; +// QByteArray reply; +// QByteArray params; +// QCString replyType; +// call dcop +// if (!p->dcopClient()->call("kded","kdevsvnd", "sslCertFile()",params,replyType,reply)) { +// kdWarning()<<" Communication with dcop failed - fail to get certfile "<<endl; +// return SVN_NO_ERROR; +// } +// if (replyType != "QString") { +// kdWarning()<<" unexpected reply type "<<endl; +// return SVN_NO_ERROR; +// } +// save reply data +// QString fileName; +// QDataStream replyStream( reply, IO_ReadOnly ); +// replyStream >> fileName; +// allocate memory +// *cred_p = (svn_auth_cred_ssl_client_cert_t*) apr_palloc (pool, sizeof(svn_auth_cred_ssl_client_cert_t)); +// (*cred_p)->cert_file = apr_pstrdup( pool, fileName.utf8() ); +// (*cred_p)->may_save = may_save; + return SVN_NO_ERROR; +} + +/** TODO fully implemented, but there is no way to test this yet.*/ +svn_error_t *kio_svnProtocol::clientCertPasswdPrompt( + svn_auth_cred_ssl_client_cert_pw_t **cred_p, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool) +{ + kdDebug(9036) << " Password Prompt Callback " << endl; + kdDebug(9036) << " realm " << realm << " <--realm " << endl; +// kio_svnProtocol *p = ( kio_svnProtocol* )baton; +// // prepare dcop +// QByteArray reply; +// QByteArray params; +// QCString replyType; +// QDataStream arg( params, IO_WriteOnly ); +// arg << i18n( "Enter password for subversion repository access" ) + "\n" + QString(realm); +// // call dcop +// if (!p->dcopClient()->call("kded","kdevsvnd", "sslPasswdDlg(QString)",params,replyType,reply)) { +// kdWarning()<<" Communication with dcop failed - fail to show passwd dlg"<<endl; +// return SVN_NO_ERROR; +// } +// if (replyType != "QCString") { +// kdWarning()<<" unexpected reply type "<<endl; +// return SVN_NO_ERROR; +// } +// // save reply data +// QCString retstr, passwd; +// QDataStream replyStream( reply, IO_ReadOnly ); +// replyStream >> retstr; +// +// if( retstr.left(1) == "-1" ){ +// kdDebug(9036) << " Null string received for passwd " << endl; +// } else{ +// passwd = retstr.right( retstr.length() - 1 ); +// kdDebug(9036) << " PassWD : " << passwd << endl; +// } +// +// svn_auth_cred_ssl_client_cert_pw_t *newcred = (svn_auth_cred_ssl_client_cert_pw_t*) apr_palloc (pool, sizeof (svn_auth_cred_ssl_client_cert_pw_t ) ); +// +// newcred->password = apr_pstrdup(pool, (const char*) passwd ); +// newcred->may_save = false; +// *cred_p = newcred; + + return SVN_NO_ERROR; +} + + +svn_error_t *kio_svnProtocol::commitLogPrompt( const char **log_msg, const char **file, + apr_array_header_t *commit_items, void *baton, apr_pool_t *pool ) +{ + *file = NULL; // if omitting this, it will segfault at import operation. + QCString replyType; + QByteArray params; + QByteArray reply; + QString result;// slist; + QStringList slist; + kio_svnProtocol *p = ( kio_svnProtocol* )baton; + svn_stringbuf_t *message = NULL; + + for (int i = 0; i < commit_items->nelts; i++) { + QString list; + svn_client_commit_item_t *item = ((svn_client_commit_item_t **) commit_items->elts)[i]; + const char *path = item->path; + char text_mod = '_', prop_mod = ' '; + + if (! path) + path = item->url; + else if (! *path) + path = "."; + + if (! path) + path = "."; + + if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)) + text_mod = 'R'; + else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD) + text_mod = 'A'; + else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE) + text_mod = 'D'; + else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS) + text_mod = 'M'; + if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS) + prop_mod = 'M'; + + list += text_mod; + list += " "; + list += prop_mod; + list += " "; + list += path; + kdDebug(9036) << " Commiting items : " << list << endl; + slist << list; +// slist += list; + } + + QDataStream stream(params, IO_WriteOnly); + stream << slist.join("\n"); + + kdDebug(9036) << " __TIME__ " << __TIME__ << endl; + if ( !p->dcopClient()->call( "kded","kdevsvnd","commitDialog(QString)", params, replyType, reply ) ) { + kdWarning() << "Communication with KDED:KDevSvnd failed" << endl; + svn_error_t *err = svn_error_create( SVN_ERR_EXTERNAL_PROGRAM, NULL, + apr_pstrdup( pool, "Fail to call kded_kdevsvnd via DCOP. If this is your first problem, try to restart KDE" ) ); + return err; + } + + if ( replyType != "QString" ) { + kdWarning() << "Unexpected reply type" << endl; + svn_error_t *err = svn_error_create( SVN_ERR_EXTERNAL_PROGRAM, NULL, + apr_pstrdup( pool, "Fail to call kded_kdevsvnd via DCOP." ) ); + return err; + } + + QDataStream stream2 ( reply, IO_ReadOnly ); + stream2 >> result; + + if ( result.isNull() ) { //cancelled + *log_msg = NULL; + svn_error_t *err = svn_error_create( SVN_ERR_CANCELLED, NULL, + apr_pstrdup( pool, "Commit interruppted" ) ); + return err; + } + + message = svn_stringbuf_create( result.utf8(), pool ); + *log_msg = message->data; + + return SVN_NO_ERROR; +} + +void kio_svnProtocol::notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision) { + kdDebug(9036) << "NOTIFY : " << path << " updated at revision " << revision << " action : " << action << ", kind : " << kind << " , content_state : " << content_state << ", prop_state : " << prop_state << endl; + + QString userstring; + struct notify_baton *nb = ( struct notify_baton* ) baton; + + //// Convert notification to a user readable string + switch ( action ) { + case svn_wc_notify_add : //add + if (mime_type && (svn_mime_type_is_binary (mime_type))) + userstring = i18n( "A (bin) %1" ).arg( path ); + else + userstring = i18n( "A %1" ).arg( path ); + break; + case svn_wc_notify_copy: //copy + userstring = i18n( "Copied %1 " ).arg( path ); + break; + case svn_wc_notify_delete: //delete + nb->received_some_change = TRUE; + userstring = i18n( "D %1" ).arg( path ); + break; + case svn_wc_notify_restore : //restore + userstring=i18n( "Restored %1." ).arg( path ); + break; + case svn_wc_notify_revert : //revert + userstring=i18n( "Reverted %1." ).arg( path ); + break; + case svn_wc_notify_failed_revert: //failed revert + userstring=i18n( "Failed to revert %1.\nTry updating instead." ).arg( path ); + break; + case svn_wc_notify_resolved: //resolved + userstring=i18n( "Resolved conflicted state of %1." ).arg( path ); + break; + case svn_wc_notify_skip: //skip + if ( content_state == svn_wc_notify_state_missing ) + userstring=i18n("Skipped missing target %1.").arg( path ); + else + userstring=i18n("Skipped %1.").arg( path ); + break; + case svn_wc_notify_update_delete: //update_delete + nb->received_some_change = TRUE; + userstring=i18n( "D %1" ).arg( path ); + break; + case svn_wc_notify_update_add: //update_add + nb->received_some_change = TRUE; + userstring=i18n( "A %1" ).arg( path ); + break; + case svn_wc_notify_update_update: //update_update + { + /* If this is an inoperative dir change, do no notification. + An inoperative dir change is when a directory gets closed + without any props having been changed. */ + if (! ((kind == svn_node_dir) + && ((prop_state == svn_wc_notify_state_inapplicable) + || (prop_state == svn_wc_notify_state_unknown) + || (prop_state == svn_wc_notify_state_unchanged)))) { + nb->received_some_change = TRUE; + + if (kind == svn_node_file) { + if (content_state == svn_wc_notify_state_conflicted) + userstring = "C"; + else if (content_state == svn_wc_notify_state_merged) + userstring = "G"; + else if (content_state == svn_wc_notify_state_changed) + userstring = "U"; + } + + if (prop_state == svn_wc_notify_state_conflicted) + userstring += "C"; + else if (prop_state == svn_wc_notify_state_merged) + userstring += "G"; + else if (prop_state == svn_wc_notify_state_changed) + userstring += "U"; + else + userstring += " "; + + if (! ((content_state == svn_wc_notify_state_unchanged + || content_state == svn_wc_notify_state_unknown) + && (prop_state == svn_wc_notify_state_unchanged + || prop_state == svn_wc_notify_state_unknown))) + userstring += QString( " " ) + path; + } + break; + } + case svn_wc_notify_update_completed: //update_completed + { + if (! nb->suppress_final_line) { + if (SVN_IS_VALID_REVNUM (revision)) { + if (nb->is_export) { + if ( nb->in_external ) + userstring = i18n("Exported external at revision %1.").arg( revision ); + else + userstring = i18n("Exported revision %1.").arg( revision ); + } else if (nb->is_checkout) { + if ( nb->in_external ) + userstring = i18n("Checked out external at revision %1.").arg( revision ); + else + userstring = i18n("Checked out revision %1.").arg( revision); + } else { + if (nb->received_some_change) { + if ( nb->in_external ) + userstring=i18n("Updated external to revision %1.").arg( revision ); + else + userstring = i18n("Updated to revision %1.").arg( revision); + } else { + if ( nb->in_external ) + userstring = i18n("External at revision %1.").arg( revision ); + else + userstring = i18n("At revision %1.").arg( revision); + } + } + } else /* no revision */ { + if (nb->is_export) { + if ( nb->in_external ) + userstring = i18n("External export complete."); + else + userstring = i18n("Export complete."); + } else if (nb->is_checkout) { + if ( nb->in_external ) + userstring = i18n("External checkout complete."); + else + userstring = i18n("Checkout complete."); + } else { + if ( nb->in_external ) + userstring = i18n("External update complete."); + else + userstring = i18n("Update complete."); + } + } + } + } + if (nb->in_external) + nb->in_external = FALSE; + break; + case svn_wc_notify_update_external: //update_external + nb->in_external = TRUE; + userstring = i18n("Fetching external item into %1." ).arg( path ); + break; + case svn_wc_notify_status_completed: //status_completed + if (SVN_IS_VALID_REVNUM (revision)) + userstring = i18n( "Status against revision: %1.").arg( revision ); + break; + case svn_wc_notify_status_external: //status_external + userstring = i18n("Performing status on external item at %1.").arg( path ); + break; + case svn_wc_notify_commit_modified: //commit_modified + userstring = i18n( "Sending %1").arg( path ); + break; + case svn_wc_notify_commit_added: //commit_added + if (mime_type && svn_mime_type_is_binary (mime_type)) { + userstring = i18n( "Adding (bin) %1.").arg( path ); + } else { + userstring = i18n( "Adding %1.").arg( path ); + } + break; + case svn_wc_notify_commit_deleted: //commit_deleted + userstring = i18n( "Deleting %1.").arg( path ); + break; + case svn_wc_notify_commit_replaced: //commit_replaced + userstring = i18n( "Replacing %1.").arg( path ); + break; + case svn_wc_notify_commit_postfix_txdelta: //commit_postfix_txdelta + if (! nb->sent_first_txdelta) { + nb->sent_first_txdelta = TRUE; + userstring=i18n("Transmitting file data "); + } else { + userstring="."; + } + break; + + break; + case svn_wc_notify_blame_revision: //blame_revision + userstring = i18n("Blame %1.").arg(path); + break; + default: + break; + } + //// End convert + kio_svnProtocol *p = ( kio_svnProtocol* )nb->master; + if (!p) kdDebug(9036) << " Null Pointer at Line " << __LINE__ << endl; + + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path" , QString::fromUtf8( path )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "action", QString::number( action )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "kind", QString::number( kind )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "mime_t", QString::fromUtf8( mime_type )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "content", QString::number( content_state )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( prop_state )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( revision )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "string", userstring ); + kdDebug(9036) << " kio_svnProtocol::notify() userstring " << userstring << endl; + p->incCounter(); +} + +void kio_svnProtocol::status(void *baton, const char *path, svn_wc_status_t *status) { + kdDebug(9036) << "STATUS : " << path << ", wc text status : " << status->text_status + << ", wc prop status : " << status->prop_status + << ", repos text status : " << status->repos_text_status + << ", repos prop status : " << status->repos_prop_status + << endl; + + QByteArray params; + kio_svnProtocol *p = ( kio_svnProtocol* )baton; + + QDataStream stream(params, IO_WriteOnly); + long int rev = status->entry ? status->entry->revision : 0; + stream << QString::fromUtf8( path ) << status->text_status << status->prop_status << status->repos_text_status << status->repos_prop_status << rev; + + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "path", QString::fromUtf8( path )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "text", QString::number( status->text_status )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "prop", QString::number( status->prop_status )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "reptxt", QString::number( status->repos_text_status )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "repprop", QString::number( status->repos_prop_status )); + p->setMetaData(QString::number( p->counter() ).rightJustify( 10,'0' )+ "rev", QString::number( rev )); + p->incCounter(); +} + +void kio_svnProtocol::progressCallback( apr_off_t processed, apr_off_t total, void *baton, apr_pool_t *pool) +{ + kio_svnProtocol *p = (kio_svnProtocol*)baton; + if( total > -1 ) + p->totalSize( total ); + if( processed > -1 ) + p->processedSize( processed ); +} + +void kio_svnProtocol::wc_resolve( const KURL& wc, bool recurse ) { + kdDebug(9036) << "kio_svnProtocol::wc_resolve() : " << wc.url() << endl; + + apr_pool_t *subpool = svn_pool_create (pool); + + KURL nurl = wc; + nurl.setProtocol( "file" ); + recordCurrentURL( nurl ); + + initNotifier(false, false, false, subpool); + svn_error_t *err = svn_client_resolved(svn_path_canonicalize( nurl.path().utf8(), subpool ), recurse,ctx,subpool); + if ( err ) + error( KIO::ERR_SLAVE_DEFINED, err->message ); + + finished(); + svn_pool_destroy (subpool); +} + +extern "C" +{ + KDE_EXPORT int kdemain(int argc, char **argv) { + KInstance instance( "kio_kdevsvn" ); + + kdDebug(9036) << "*** Starting kio_kdevsvn " << endl; + + if (argc != 4) { + kdDebug(9036) << "Usage: kio_kdevsvn protocol domain-socket1 domain-socket2" << endl; + exit(-1); + } + + kio_svnProtocol slave(argv[2], argv[3]); + slave.dispatchLoop(); + + kdDebug(9036) << "*** kio_kdevsvn Done" << endl; + return 0; + } +} + diff --git a/vcs/subversion/svn_kio.h b/vcs/subversion/svn_kio.h new file mode 100644 index 00000000..6164488a --- /dev/null +++ b/vcs/subversion/svn_kio.h @@ -0,0 +1,163 @@ +/* This file is part of the KDE project + Copyright (C) 2003 Mickael Marchand <marchand@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _svn_H_ +#define _svn_H_ + +#include <qstring.h> +#include <qcstring.h> + +#include <kurl.h> +#include <kio/global.h> +#include <kio/slavebase.h> +#include <subversion-1/svn_pools.h> +#include <subversion-1/svn_auth.h> +#include <subversion-1/svn_client.h> +#include <subversion-1/svn_config.h> +#include <sys/stat.h> +#include <qvaluelist.h> +#include <subversion-1/svn_wc.h> +#include "subversion_global.h" + +class QCString; +class kio_svnProtocol; + +typedef struct kbaton { + svn_stream_t *target_stream; + svn_stringbuf_t *target_string; + svn_stream_t *string_stream; +} kbaton; + +typedef struct kio_svn_callback_baton_t { + const char* base_dir; + apr_hash_t *config; + apr_pool_t *pool; +} kio_svn_callback_baton_t; + +typedef struct notify_baton { + svn_boolean_t received_some_change; + svn_boolean_t is_checkout; + svn_boolean_t is_export; + svn_boolean_t suppress_final_line; + svn_boolean_t sent_first_txdelta; + svn_boolean_t in_external; + svn_boolean_t had_print_error; /* Used to not keep printing error messages + when we've already had one print error. */ + apr_pool_t *pool; /* this pool is cleared after every notification, + so don't keep anything here! */ + kio_svnProtocol *master; +} notify_baton; + + +class kio_svnProtocol : public KIO::SlaveBase +{ + public: + kio_svnProtocol(const QCString &pool_socket, const QCString &app_socket); + virtual ~kio_svnProtocol(); + virtual void special( const QByteArray& data ); + virtual void get(const KURL& url); + virtual void listDir(const KURL& url); + virtual void stat(const KURL& url); + virtual void mkdir(const KURL& url, int permissions); + virtual void mkdir(const KURL::List& list, int permissions); + virtual void del( const KURL& url, bool isfile ); +// virtual void copy(const KURL & src, const KURL& dest, int permissions, bool overwrite); + virtual void rename(const KURL& src, const KURL& dest, bool overwrite); + void checkout( const KURL& repos, const KURL& wc, int revnumber, const QString& revkind ); + void import( const KURL& repos, const KURL& wc ); + void svn_switch( const KURL& wc, const KURL& url, int revnumber, const QString& revkind, bool recurse); + void svn_switch_relocate( const KURL &wc, const KURL &origUrl, const KURL &newUrl, + bool recurse ); + void svn_diff( const KURL& url1, const KURL& url2, int rev1, int rev2, const QString& revkind1, const QString& revkind2, bool recurse, bool pegdiff); + //TODO fix with svn 1.2 : support a KURL::List -> svn_client_update2() + void update( const KURL::List &list, int revnumber, const QString& revkind ); + void commit( const KURL::List& wc ); + void commit2( bool recurse, bool keeplocks, const KURL::List& wc ); + void blame( KURL url, SvnGlobal::UrlMode mode, /*int pegRev, QString pegRevKind,*/ int startRev, QString startRevKind, int endRev, QString endRevKind ); + static svn_error_t* blameReceiver( void *baton, apr_int64_t line_no, svn_revnum_t rev, const char *author, const char *date, const char *line, apr_pool_t *pool ); + void svn_log( int revstart, const QString &revkindstart, int revend, const QString &revkindend, bool discorverChangedPath, bool strictNodeHistory, const KURL::List& targets ); + static svn_error_t* receiveLogMessage(void *baton, apr_hash_t *changed_paths, svn_revnum_t revision, const char *author, const char *date, const char *message, apr_pool_t *pool ); + void add( const KURL::List& wcList ); + //these work using the working copy + void wc_resolve( const KURL& wc, bool recurse = true ); + void wc_delete( const KURL::List& wc ); + void wc_revert( const KURL::List& wc ); + void wc_status(const KURL& wc, bool checkRepos=false, bool fullRecurse=true, bool getAll=true, int revnumber=-1, const QString& revkind="HEAD"); + void wc_status2(const KURL& wc, bool checkRepos=false, bool fullRecurse=true, bool getAll=true, bool noIgnore=false, int revnumber=-1, const QString& revkind="WORKING"); + void svn_info( KURL pathOrUrl, int pegRev, QString pegRevKind, int rev, QString revKind, bool recurse ); + static svn_error_t* infoReceiver( void *baton, const char *path, const svn_info_t *info, apr_pool_t *pool); + void svn_copy( const KURL &srcUrl, int srcRev, const QString &srcRevKind, const KURL &destUrl ); + void svn_merge( const KURL &src1, int rev1, QString revKind1, const KURL &src2, int rev2, QString revKind2, + const KURL &target_wc, + bool recurse, bool ignore_ancestry, bool force, bool dry_run ); + + static svn_error_t* checkAuth(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, svn_boolean_t may_save, apr_pool_t *pool); + static svn_error_t *trustSSLPrompt(svn_auth_cred_ssl_server_trust_t **cred_p, void *, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *cert_info, svn_boolean_t may_save, apr_pool_t *pool); + static svn_error_t *clientCertSSLPrompt(svn_auth_cred_ssl_client_cert_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool); + static svn_error_t *clientCertPasswdPrompt(svn_auth_cred_ssl_client_cert_pw_t **cred_p, void *, const char *realm, svn_boolean_t may_save, apr_pool_t *pool); + static svn_error_t *commitLogPrompt( const char **log_msg, const char **tmp_file, apr_array_header_t *commit_items, void *baton, apr_pool_t *pool ); + static void notify(void *baton, const char *path, svn_wc_notify_action_t action, svn_node_kind_t kind, const char *mime_type, svn_wc_notify_state_t content_state, svn_wc_notify_state_t prop_state, svn_revnum_t revision); + static void status(void *baton, const char *path, svn_wc_status_t *status); + static void progressCallback( apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool); + + QString chooseProtocol ( const QString& kproto ) const; + QString makeSvnURL ( const KURL& url ) const; + void initNotifier(bool is_checkout, bool is_export, bool suppress_final_line, apr_pool_t *spool); + + void recordCurrentURL(const KURL& url); + void popupMessage( const QString& message ); + int counter() { return m_counter; } + void incCounter() { m_counter++; } + svn_opt_revision_t createRevision( int revision, const QString& revkind, apr_pool_t *pool ); + + KURL myURL; + svn_client_ctx_t *ctx; + KIO::AuthInfo info; + + enum SVN_METHOD { + SVN_CHECKOUT=1, //KURL repository, KURL workingcopy, int revnumber=-1, QString revkind(HEAD, ...) //revnumber==-1 => use of revkind + SVN_UPDATE=2, // KURL wc (svn:///tmp/test, int revnumber=-1, QString revkind(HEAD, ...) // revnumber==-1 => use of revkind + SVN_COMMIT=3, + SVN_LOG=4, + SVN_IMPORT=5, + SVN_ADD=6, + SVN_DEL=7, + SVN_REVERT=8, + SVN_STATUS=9, + SVN_MKDIR=10, + SVN_RESOLVE=11, + SVN_SWITCH=12, + SVN_DIFF=13, + SVN_BLAME=14, + SVN_INFO = 15, + SVN_SWITCH_RELOCATE = 16, + SVN_COPY = 17, + SVN_MERGE = 18, + SVN_COMMIT_2=103, + SVN_STATUS_2=109 + + }; + + private: + bool createUDSEntry( const QString& filename, const QString& user, long long int size, bool isdir, time_t mtime, KIO::UDSEntry& entry); + apr_pool_t *pool; + unsigned long int m_counter; +}; + +#endif diff --git a/vcs/subversion/svn_logviewoptiondlgbase.ui b/vcs/subversion/svn_logviewoptiondlgbase.ui new file mode 100644 index 00000000..149c82e1 --- /dev/null +++ b/vcs/subversion/svn_logviewoptiondlgbase.ui @@ -0,0 +1,156 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnLogViewOptionDlgBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnLogViewOptionDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>449</width> + <height>288</height> + </rect> + </property> + <property name="caption"> + <string>Subversion Log View</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="3" column="0"> + <property name="name"> + <cstring>pushButton1</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>checkBox1</cstring> + </property> + <property name="text"> + <string>Do not show logs before branching point</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>buttonGroup2_2</cstring> + </property> + <property name="title"> + <string>End Revision</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>radio5</cstring> + </property> + <property name="text"> + <string>&By Revision Number</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>radio6</cstring> + </property> + <property name="text"> + <string>B&y Revision Specifier</string> + </property> + </widget> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>comboBox2</cstring> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="1"> + <property name="name"> + <cstring>intInput2</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton" row="3" column="1"> + <property name="name"> + <cstring>pushButton2</cstring> + </property> + <property name="text"> + <string>C&ancel</string> + </property> + </widget> + <widget class="QButtonGroup" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string>Start Revision</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>comboBox1</cstring> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="1"> + <property name="name"> + <cstring>intInput1</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + </widget> + <widget class="QRadioButton" row="0" column="0"> + <property name="name"> + <cstring>radio3</cstring> + </property> + <property name="text"> + <string>&By Revision Number</string> + </property> + </widget> + <widget class="QRadioButton" row="1" column="0"> + <property name="name"> + <cstring>radio4</cstring> + </property> + <property name="text"> + <string>B&y Revision Specifier</string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>pushButton1</sender> + <signal>clicked()</signal> + <receiver>SvnLogViewOptionDlgBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>pushButton2</sender> + <signal>clicked()</signal> + <receiver>SvnLogViewOptionDlgBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_logviewwidget.cpp b/vcs/subversion/svn_logviewwidget.cpp new file mode 100644 index 00000000..c6aae452 --- /dev/null +++ b/vcs/subversion/svn_logviewwidget.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "svn_logviewwidget.h" +#include "svn_blamewidget.h" +#include "subversion_core.h" +#include "subversion_global.h" +#include <kdevproject.h> +#include <ktextedit.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <klocale.h> +#include <qradiobutton.h> +#include <qcombobox.h> +#include <knuminput.h> +#include <qcheckbox.h> + +#include <qsplitter.h> +#include <qheader.h> +#include <qlistview.h> +#include <qlayout.h> +#include <qstringlist.h> + +SvnLogViewWidget::SvnLogViewWidget(subversionPart *part, QWidget *parent) + :QWidget(parent), m_part(part) +{ + m_layout = new QGridLayout( this, 1, 1, 11, 6, "SvnLogViewWidgetBaseLayout"); + + splitter1 = new QSplitter( this, "splitter1" ); + splitter1->setOrientation( QSplitter::Horizontal ); + splitter1->setMargin(1); + + listView1 = new QListView( splitter1, "listView1" ); + listView1->addColumn( i18n( "Rev" ) ); + listView1->addColumn( i18n( "Date" ) ); + listView1->addColumn( i18n( "Author" ) ); + listView1->addColumn( i18n( "Comment" ) ); + listView1->resize( QSize(1, 1).expandedTo(minimumSizeHint()) ); + QFont listView1_font( listView1->font() ); + listView1_font.setPointSize( 9 ); + listView1->setFont( listView1_font ); + listView1->setAllColumnsShowFocus( TRUE ); + listView1->setShowSortIndicator( TRUE ); + + textEdit1 = new KTextEdit( splitter1, "textEdit1" ); + textEdit1->resize( QSize(1, 1).expandedTo(minimumSizeHint()) ); + QFont textEdit1_font( textEdit1->font() ); + textEdit1_font.setPointSize( 9 ); + textEdit1->setFont( textEdit1_font ); + textEdit1->setFocusPolicy( QTextEdit::WheelFocus ); + textEdit1->setReadOnly( TRUE ); + + m_layout->addWidget( splitter1, 0, 0 ); + m_layout->setMargin(1); + + resize( QSize(692, 343).expandedTo(minimumSizeHint()) ); + clearWState( WState_Polished ); + + connect( listView1, SIGNAL(clicked( QListViewItem *)), this, SLOT(slotClicked(QListViewItem*)) ); + connect( listView1, SIGNAL(contextMenuRequested( QListViewItem*, const QPoint&, int )), + this, SLOT(contextMenuRequested(QListViewItem*, const QPoint&, int)) ); +} +SvnLogViewWidget::~SvnLogViewWidget() +{ +} + +void SvnLogViewWidget::setLogResult( QValueList<SvnLogHolder> *loglist ) +{ + this->listView1->clear(); + this->textEdit1->clear(); + this->listView1->setSorting( 1, false ); + + for( QValueList<SvnLogHolder>::Iterator it=loglist->begin(); it!=loglist->end(); ++it ){ + + SvnLogHolder holder = *it; + SvnLogViewItem *item = new SvnLogViewItem(this->listView1); + + QString prettyDate = holder.date.left(16).replace(10, 1, ' '); + + item->setText(0, holder.rev ); + item->setText(1, prettyDate ); + item->setText(2, holder.author ); + item->setText(3, holder.logMsg.simplifyWhiteSpace() ); + + item->m_pathList = holder.pathList; + item->m_message = holder.logMsg; + } +// this->listView1->show(); +} + +void SvnLogViewWidget::setRequestedUrl( QString reqUrl ) +{ + m_reqUrl = reqUrl; +} + +void SvnLogViewWidget::slotClicked( QListViewItem *oneItem ) +{ + if( !oneItem ) return; + SvnLogViewItem *item = dynamic_cast<SvnLogViewItem*>( oneItem ); + if( !item ) return; + textEdit1->clear(); + textEdit1->append( item->m_pathList ); + textEdit1->append( "\n\n" ); + textEdit1->append( item->m_message + "\n" ); +} +void SvnLogViewWidget::contextMenuRequested( QListViewItem *item, const QPoint & pos, int col ) +{ + if( !item || col == -1 ) + return; + m_ctxLogItem = dynamic_cast<SvnLogViewItem*>(item); + if( !m_ctxLogItem ) + return; + QPopupMenu *menu = new QPopupMenu(this); + menu->insertItem( i18n("Blame this revision"), this, SLOT(blameThis()) ); + menu->insertItem( i18n("Difference to previous revision"), this, SLOT(diffToPrevious()) ); + menu->exec( pos ); +} +void SvnLogViewWidget::blameThis() +{ + if( !m_ctxLogItem ){ + KMessageBox::error( this, i18n("No revision was clicked"), i18n("error") ); + return; + } + // note that blame is done on single file. + QStringList modifies = QStringList::split( "\n", m_ctxLogItem->m_pathList, false ); + QString selectedPath; + if( modifies.count() > 1 ){ + SvnBlameFileSelectDlg dlg(this); + dlg.setCandidate( &modifies ); + if( dlg.exec() == QDialog::Accepted ){ + selectedPath = dlg.selected(); + } else{ + return; + } + + } else if( modifies.count() == 1 ){ + selectedPath = *( modifies.at(0) ); + } else { + return; + } + + QString relPath = selectedPath.section( '/', 1 ); + + QValueList< SvnGlobal::SvnInfoHolder > holderList = m_part->m_prjInfoMap.values(); + SvnGlobal::SvnInfoHolder holder; + if( holderList.count() > 0 ){ + // get full Url + holder = holderList.first(); + QString absPath = holder.reposRootUrl.url(-1) + '/' + relPath; + kdDebug(9036) << " Blame requested on path " << absPath << endl; + // get revision + int revEnd = m_ctxLogItem->text(0).toInt(); + // final request + m_part->svncore()->blame( KURL(absPath), SvnGlobal::dont_touch, 0, "", revEnd, "" ); + } + else{ + return; + } +} + +void SvnLogViewWidget::diffToPrevious() +{ + if( !m_ctxLogItem ){ + KMessageBox::error( this, i18n("No revision was clicked"), i18n("error") ); + return; + } + int revThis = m_ctxLogItem->text(0).toInt(); + int revPrev = revThis - 1; + kdDebug(9036) << " Diff to prev requested on " << m_reqUrl << endl; + m_part->svncore()->diffAsync( m_reqUrl, m_reqUrl, revPrev, "", revThis, "", + true/*recurse*/, true/*peg_diff*/ ); +} + +SvnLogViewOptionDlg::SvnLogViewOptionDlg( QWidget *parent, const char* name, bool modal, WFlags f ) +: SvnLogViewOptionDlgBase( parent, name, modal,f ) +{ +// radio1->setChecked(true); //repository log + radio4->setChecked(true); //start revistion by revision keyword + radio5->setChecked(true); //end revision by revision number + reinstallRevisionSpecifiers(); + connect( intInput1, SIGNAL(valueChanged(int)), this, SLOT(setStartRevnumRadio()) ); + connect( comboBox1, SIGNAL(activated(const QString&)), this, SLOT(setStartRevkindRadio()) ); + connect( intInput2, SIGNAL(valueChanged(int)), this, SLOT(setEndRevnumRadio()) ); + connect( comboBox2, SIGNAL(activated(const QString&)), this, SLOT(setEndRevkindRadio()) ); +} +SvnLogViewOptionDlg::~SvnLogViewOptionDlg() +{} +void SvnLogViewOptionDlg::reinstallRevisionSpecifiers() +{ + comboBox1->clear(); + comboBox2->clear(); + + QStringList items; + items << "HEAD" << "BASE" << "PREV" << "COMMITTED"; + comboBox1->insertStringList( items ); + comboBox2->insertStringList( items ); +} +int SvnLogViewOptionDlg::revstart() +{ + if( !radio3->isChecked() ){ + return -1; + } else{ + return intInput1->value(); + } +} +QString SvnLogViewOptionDlg::revKindStart() +{ + if( !radio4->isChecked() ){ + return QString(""); + } else{ + return comboBox1->currentText(); + } +} +int SvnLogViewOptionDlg::revend() +{ + if( !radio5->isChecked() ){ + return -1; + } else{ + return intInput2->value(); + } +} +QString SvnLogViewOptionDlg::revKindEnd() +{ + if( !radio6->isChecked() ){ + return QString(""); + } else{ + return comboBox2->currentText(); + } +} +bool SvnLogViewOptionDlg::strictNode() +{ + if( checkBox1->isChecked() ){ + return true; + } else{ + return false; + } +} +void SvnLogViewOptionDlg::setStartRevnumRadio() +{ + radio3->setChecked(true); +} +void SvnLogViewOptionDlg::setStartRevkindRadio() +{ + radio4->setChecked(true); +} +void SvnLogViewOptionDlg::setEndRevnumRadio() +{ + radio5->setChecked(true); +} +void SvnLogViewOptionDlg::setEndRevkindRadio() +{ + radio6->setChecked(true); +} + +#include "svn_logviewwidget.moc" + diff --git a/vcs/subversion/svn_logviewwidget.h b/vcs/subversion/svn_logviewwidget.h new file mode 100644 index 00000000..40bf7e38 --- /dev/null +++ b/vcs/subversion/svn_logviewwidget.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef SVNLOGVIEWWIDGET_H +#define SVNLOGVIEWWIDGET_H + +#include "subversion_widget.h" +#include "svn_logviewoptiondlgbase.h" +// #include "subversion_part.h" +#include <qvaluelist.h> +#include <qlistview.h> +class subversionPart; +// class QWidget; +#include <qwidget.h> +class KTextEdit; +class QSplitter; +class QGridLayout; +class SvnLogViewItem; + +class SvnLogHolder{ + public: + SvnLogHolder(){}; + ~SvnLogHolder(){}; + QString author; + QString date; + QString logMsg; + QString pathList; + QString rev; +}; + +class SvnLogViewWidget : public /*SvnLogViewWidgetBase*/ QWidget { + Q_OBJECT +public: + SvnLogViewWidget(subversionPart *part, QWidget *parent); + virtual ~SvnLogViewWidget(); + void setLogResult( QValueList<SvnLogHolder> *loglist ); + void setRequestedUrl( QString url ); + +protected slots: + void slotClicked( QListViewItem* item ); + void contextMenuRequested( QListViewItem *item, const QPoint & pos, int col ); + void blameThis(); + void diffToPrevious(); + +private: + QString m_reqUrl; + subversionPart *m_part; + SvnLogViewItem* m_ctxLogItem; + + QSplitter* splitter1; + QListView* listView1; + KTextEdit* textEdit1; + QGridLayout* m_layout; + +}; + +class SvnLogViewOptionDlg : public SvnLogViewOptionDlgBase { + Q_OBJECT +public: + SvnLogViewOptionDlg(QWidget *parent=0, const char* name=0, bool modal=TRUE, WFlags f=0); + ~SvnLogViewOptionDlg(); + int revstart(); + QString revKindStart(); + int revend(); + QString revKindEnd(); + bool strictNode(); +public slots: + void reinstallRevisionSpecifiers(); + void setStartRevnumRadio(); + void setStartRevkindRadio(); + void setEndRevnumRadio(); + void setEndRevkindRadio(); +}; + +#endif + diff --git a/vcs/subversion/svn_mergeoptiondlgbase.ui b/vcs/subversion/svn_mergeoptiondlgbase.ui new file mode 100644 index 00000000..0ad25c83 --- /dev/null +++ b/vcs/subversion/svn_mergeoptiondlgbase.ui @@ -0,0 +1,374 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnMergeOptionDialogBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnMergeOptionDialogBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>473</width> + <height>590</height> + </rect> + </property> + <property name="caption"> + <string>Subversion Merge</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QGroupBox" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>groupBox1</cstring> + </property> + <property name="title"> + <string>Destination</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Destination working path</string> + </property> + </widget> + <widget class="KURLRequester" row="1" column="0"> + <property name="name"> + <cstring>dest</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="QButtonGroup" row="1" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup2</cstring> + </property> + <property name="title"> + <string>Source 1</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput" row="3" column="1"> + <property name="name"> + <cstring>revnum1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minValue"> + <number>-1</number> + </property> + </widget> + <widget class="QRadioButton" row="3" column="0"> + <property name="name"> + <cstring>revnumbtn1</cstring> + </property> + <property name="text"> + <string>Number:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QRadioButton" row="3" column="2"> + <property name="name"> + <cstring>revkindbtn1</cstring> + </property> + <property name="text"> + <string>Keyword:</string> + </property> + </widget> + <widget class="KComboBox" row="3" column="3"> + <item> + <property name="text"> + <string>HEAD</string> + </property> + </item> + <item> + <property name="text"> + <string>BASE</string> + </property> + </item> + <item> + <property name="text"> + <string>COMMITTED</string> + </property> + </item> + <item> + <property name="text"> + <string>PREV</string> + </property> + </item> + <property name="name"> + <cstring>revkind1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="currentItem"> + <number>1</number> + </property> + </widget> + <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>src1</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Source URL or working path:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Specify revision as</string> + </property> + </widget> + </grid> + </widget> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>buttonGroup2_2</cstring> + </property> + <property name="title"> + <string>Source 2</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton" row="3" column="0"> + <property name="name"> + <cstring>revnumbtn2</cstring> + </property> + <property name="text"> + <string>Number:</string> + </property> + </widget> + <widget class="QRadioButton" row="3" column="2"> + <property name="name"> + <cstring>revkindbtn2</cstring> + </property> + <property name="text"> + <string>Keyword:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="KURLRequester" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>src2</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Specify revision as</string> + </property> + </widget> + <widget class="KComboBox" row="3" column="3"> + <item> + <property name="text"> + <string>HEAD</string> + </property> + </item> + <item> + <property name="text"> + <string>BASE</string> + </property> + </item> + <item> + <property name="text"> + <string>COMMITTED</string> + </property> + </item> + <item> + <property name="text"> + <string>PREV</string> + </property> + </item> + <property name="name"> + <cstring>revkind2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + <property name="currentItem"> + <number>0</number> + </property> + </widget> + <widget class="KIntNumInput" row="3" column="1"> + <property name="name"> + <cstring>revnum2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minValue"> + <number>-1</number> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>Source URL or working path:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QPushButton" row="7" column="1"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + <spacer row="7" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>171</width> + <height>31</height> + </size> + </property> + </spacer> + <widget class="QPushButton" row="7" column="2"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>forceCheck</cstring> + </property> + <property name="text"> + <string>--force (Force to delete locally modified or unversioned items.)</string> + </property> + </widget> + <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>nonRecurse</cstring> + </property> + <property name="text"> + <string>--non-recursive</string> + </property> + </widget> + <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>ignoreAncestryCheck</cstring> + </property> + <property name="text"> + <string>--ignore-ancestry</string> + </property> + </widget> + <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>dryRunCheck</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>--dry-run (Only receive full result notification + without actually modifying working copy)</string> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>SvnMergeOptionDialogBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>SvnMergeOptionDialogBase</receiver> + <slot>reject()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_mergewidget.cpp b/vcs/subversion/svn_mergewidget.cpp new file mode 100644 index 00000000..6a8fc0b3 --- /dev/null +++ b/vcs/subversion/svn_mergewidget.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "svn_mergewidget.h" +#include "subversion_global.h" +#include <kurlrequester.h> +#include <qradiobutton.h> +#include <knuminput.h> +#include <qcheckbox.h> +#include <kcombobox.h> + +using namespace SvnGlobal; + +SvnMergeDialog::SvnMergeDialog( const KURL &wcTarget, QWidget *parent ) + : SvnMergeOptionDialogBase( parent ) +{ + dest->setURL( wcTarget.prettyURL() ); + + connect( revnumbtn1, SIGNAL(toggled(bool)), revnum1, SLOT(setEnabled(bool)) ); + connect( revnumbtn1, SIGNAL(toggled(bool)), revkind1, SLOT(setDisabled(bool)) ); + connect( revnumbtn2, SIGNAL(toggled(bool)), revnum2, SLOT(setEnabled(bool)) ); + connect( revnumbtn2, SIGNAL(toggled(bool)), revkind2, SLOT(setDisabled(bool)) ); + revkind1->setDisabled(true); + revnum2->setDisabled(true); +} + +SvnMergeDialog::~SvnMergeDialog() +{ +} + +KURL SvnMergeDialog::source1() +{ + return KURL( src1->url() ); +} +SvnRevision SvnMergeDialog::rev1() +{ + SvnRevision rev; + + if( revkindbtn1->isChecked() ){ + rev.revNum = -1; + rev.revKind = revkind1->currentText(); + } else { + rev.revNum = revnum1->value(); + rev.revKind = "UNSPECIFIED"; + } + return rev; +} +KURL SvnMergeDialog::source2() +{ + return KURL( src2->url() ); +} +SvnRevision SvnMergeDialog::rev2() +{ + SvnRevision rev; + + if( revkindbtn2->isChecked() ){ + rev.revNum = -1; + rev.revKind = revkind2->currentText(); + } else { + rev.revNum = revnum2->value(); + rev.revKind = "UNSPECIFIED"; + } + return rev; +} +bool SvnMergeDialog::recurse() +{ + return !(nonRecurse->isChecked()); +} +bool SvnMergeDialog::force() +{ + return forceCheck->isChecked(); +} +bool SvnMergeDialog::ignoreAncestry() +{ + return ignoreAncestryCheck->isChecked(); +} +bool SvnMergeDialog::dryRun() +{ + return dryRunCheck->isChecked(); +} + +#include "svn_mergewidget.moc" diff --git a/vcs/subversion/svn_mergewidget.h b/vcs/subversion/svn_mergewidget.h new file mode 100644 index 00000000..ff54a6da --- /dev/null +++ b/vcs/subversion/svn_mergewidget.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Dukju Ahn (dukjuahn@gmail.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef SVN_MERGEWIDGET_H +#define SVN_MERGEWIDGET_H + +#include "svn_mergeoptiondlgbase.h" +namespace SvnGlobal +{ + class SvnRevision; +} + +class KURL; + +class SvnMergeDialog : public SvnMergeOptionDialogBase +{ + Q_OBJECT +public: + SvnMergeDialog( const KURL &wcTarget, QWidget *parent = NULL ); + virtual ~SvnMergeDialog(); + + KURL source1(); + SvnGlobal::SvnRevision rev1(); + KURL source2(); + SvnGlobal::SvnRevision rev2(); + bool recurse(); + bool force(); + bool ignoreAncestry(); + bool dryRun(); + +}; + +#endif diff --git a/vcs/subversion/svn_switchdlgbase.ui b/vcs/subversion/svn_switchdlgbase.ui new file mode 100644 index 00000000..02257196 --- /dev/null +++ b/vcs/subversion/svn_switchdlgbase.ui @@ -0,0 +1,213 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnSwitchDlgBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnSwitchDlgBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>603</width> + <height>255</height> + </rect> + </property> + <property name="caption"> + <string>Subversion Switch</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>nonRecurseCheck</cstring> + </property> + <property name="text"> + <string>Non-recursive. (Switch its immediate children only)</string> + </property> + </widget> + <widget class="Line" row="5" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget" row="6" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KPushButton" row="0" column="2"> + <property name="name"> + <cstring>cancelBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + <spacer row="0" column="0"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>150</width> + <height>30</height> + </size> + </property> + </spacer> + <widget class="KPushButton" row="0" column="1"> + <property name="name"> + <cstring>okBtn</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>OK</string> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Current Repository URL</string> + </property> + </widget> + <widget class="KLineEdit" row="2" column="1"> + <property name="name"> + <cstring>currentUrlEdit</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Working copy to switch</string> + </property> + </widget> + <widget class="KLineEdit" row="1" column="1"> + <property name="name"> + <cstring>wcUrlEdit</cstring> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + <widget class="QButtonGroup" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Working Mode</string> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QRadioButton"> + <property name="name"> + <cstring>switchOnlyRadio</cstring> + </property> + <property name="text"> + <string>svn switch</string> + </property> + </widget> + <widget class="QRadioButton"> + <property name="name"> + <cstring>relocationRadio</cstring> + </property> + <property name="text"> + <string>svn switch --relocation</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>New destination URL</string> + </property> + </widget> + <widget class="KLineEdit" row="3" column="1"> + <property name="name"> + <cstring>destUrlEdit</cstring> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>okBtn</sender> + <signal>clicked()</signal> + <receiver>SvnSwitchDlgBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>cancelBtn</sender> + <signal>clicked()</signal> + <receiver>SvnSwitchDlgBase</receiver> + <slot>reject()</slot> + </connection> + <connection> + <sender>destUrlEdit</sender> + <signal>returnPressed()</signal> + <receiver>SvnSwitchDlgBase</receiver> + <slot>accept()</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">svn_switchdlgbase.ui.h</include> +</includes> +<slots> + <slot>Form1_destroyed( QObject * )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kpushbutton.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/vcs/subversion/svn_switchwidget.cpp b/vcs/subversion/svn_switchwidget.cpp new file mode 100644 index 00000000..ec1b603c --- /dev/null +++ b/vcs/subversion/svn_switchwidget.cpp @@ -0,0 +1,60 @@ +#include <kurl.h> +#include <klineedit.h> +#include <qcheckbox.h> +#include <qradiobutton.h> + +#include "svn_switchwidget.h" +#include "subversion_global.h" + +SvnSwitchDlg::SvnSwitchDlg( const SvnGlobal::SvnInfoHolder *holder, + const QString &wcPath, QWidget *parent ) + : SvnSwitchDlgBase( parent ) + , m_info( holder ) +{ + connect( switchOnlyRadio, SIGNAL(clicked()), this, SLOT(resetCurrentRepositoryUrlEdit()) ); + connect( relocationRadio , SIGNAL(clicked()), this, SLOT(resetCurrentRepositoryUrlEdit()) ); + // set switch only + switchOnlyRadio->setChecked( true ); + wcUrlEdit->setText( wcPath ); + currentUrlEdit->setText( m_info->url.prettyURL() ); +} + +SvnSwitchDlg::~SvnSwitchDlg() +{} + +const QString SvnSwitchDlg::currentUrl() +{ + return currentUrlEdit->text(); +} +const QString SvnSwitchDlg::destUrl() +{ + return destUrlEdit->text(); +} + +bool SvnSwitchDlg::recursive() +{ + return (! nonRecurseCheck->isChecked() ); +} +bool SvnSwitchDlg::switchOnly() +{ + return switchOnlyRadio->isChecked(); +} +bool SvnSwitchDlg::relocation() +{ + return relocationRadio->isChecked(); +} + +void SvnSwitchDlg::resetCurrentRepositoryUrlEdit() +{ + if( relocation() ){ + // only ROOT repository url should be given + currentUrlEdit->setText( m_info->reposRootUrl.prettyURL() ); + } else if( switchOnly() ){ + // the full URL of item should be given + currentUrlEdit->setText( m_info->url.prettyURL() ); + } else{ + // should not reach here!! + } +} + +#include "svn_switchwidget.moc" diff --git a/vcs/subversion/svn_switchwidget.h b/vcs/subversion/svn_switchwidget.h new file mode 100644 index 00000000..643fb4b9 --- /dev/null +++ b/vcs/subversion/svn_switchwidget.h @@ -0,0 +1,31 @@ +#ifndef SVN_SWITCHWIDGET_H +#define SVN_SWITCHWIDGET_H + +#include "svn_switchdlgbase.h" + +namespace SvnGlobal +{ + class SvnInfoHolder; +} + +class SvnSwitchDlg : public SvnSwitchDlgBase +{ + Q_OBJECT +public: + SvnSwitchDlg( const SvnGlobal::SvnInfoHolder *holder, + const QString &wcPath, QWidget *parent = NULL ); + virtual ~SvnSwitchDlg(); + + const QString currentUrl(); + const QString destUrl(); + bool recursive(); + bool switchOnly(); + bool relocation(); +private slots: + void resetCurrentRepositoryUrlEdit(); + +private: + const SvnGlobal::SvnInfoHolder *m_info; +}; + +#endif diff --git a/vcs/subversion/svnssltrustpromptbase.ui b/vcs/subversion/svnssltrustpromptbase.ui new file mode 100644 index 00000000..a94e345c --- /dev/null +++ b/vcs/subversion/svnssltrustpromptbase.ui @@ -0,0 +1,116 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>SvnSSLTrustPromptBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>SvnSSLTrustPromptBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>504</width> + <height>281</height> + </rect> + </property> + <property name="caption"> + <string>SSL Certificate Trust</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton" row="2" column="0"> + <property name="name"> + <cstring>btnPermanent</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QListView" row="1" column="0" rowspan="1" colspan="3"> + <column> + <property name="text"> + <string></string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string></string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>listView1</cstring> + </property> + </widget> + <widget class="QPushButton" row="2" column="2"> + <property name="name"> + <cstring>btnReject</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QPushButton" row="2" column="1"> + <property name="name"> + <cstring>btnTemporary</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>errMsgLabel</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignVCenter</set> + </property> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>btnPermanent</sender> + <signal>clicked()</signal> + <receiver>SvnSSLTrustPromptBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>btnTemporary</sender> + <signal>clicked()</signal> + <receiver>SvnSSLTrustPromptBase</receiver> + <slot>accept()</slot> + </connection> + <connection> + <sender>btnReject</sender> + <signal>clicked()</signal> + <receiver>SvnSSLTrustPromptBase</receiver> + <slot>accept()</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="11"/> +</UI> |