diff options
Diffstat (limited to 'vcs/subversion')
58 files changed, 9346 insertions, 0 deletions
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> |