summaryrefslogtreecommitdiffstats
path: root/kbabel/catalogmanager/libsvn
diff options
context:
space:
mode:
Diffstat (limited to 'kbabel/catalogmanager/libsvn')
-rw-r--r--kbabel/catalogmanager/libsvn/Makefile.am11
-rw-r--r--kbabel/catalogmanager/libsvn/svndialog.cpp400
-rw-r--r--kbabel/catalogmanager/libsvn/svndialog.h151
-rw-r--r--kbabel/catalogmanager/libsvn/svnhandler.cpp544
-rw-r--r--kbabel/catalogmanager/libsvn/svnhandler.h138
-rw-r--r--kbabel/catalogmanager/libsvn/svnresources.h50
6 files changed, 1294 insertions, 0 deletions
diff --git a/kbabel/catalogmanager/libsvn/Makefile.am b/kbabel/catalogmanager/libsvn/Makefile.am
new file mode 100644
index 00000000..7c340974
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libcatalogmanagersvn.la
+
+# set the include path for X, qt and KDE
+INCLUDES = -I.. -I../../common $(all_includes)
+
+libcatalogmanagersvn_la_SOURCES = svnhandler.cpp svndialog.cpp
+
+noinst_HEADERS = svnhandler.h svndialog.h svnresources.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
diff --git a/kbabel/catalogmanager/libsvn/svndialog.cpp b/kbabel/catalogmanager/libsvn/svndialog.cpp
new file mode 100644
index 00000000..69653591
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svndialog.cpp
@@ -0,0 +1,400 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// Qt include files
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qfileinfo.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextedit.h>
+// KDE include files
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kstringhandler.h>
+// Project specific include files
+#include "svndialog.h"
+
+
+SVNDialog::SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config )
+ : KDialog( parent, "SVN DIALOG", true ), m_tempFile( 0 ), m_config( config )
+{
+ _cmd = cmd;
+ p=0L;
+ setCaption( i18n( "SVN Dialog" ) );
+
+ QString temp;
+
+ QVBoxLayout * layout = new QVBoxLayout( this, 6, 6, "MAIN LAYOUT" );
+
+ // Set the label's text depending on the SVN command.
+ switch ( cmd ) {
+ case SVN::Update:
+ temp = i18n( "Update the following files:" );
+ break;
+ case SVN::Commit:
+ temp = i18n( "Commit the following files:" );
+ break;
+ case SVN::StatusRemote:
+ temp = i18n( "Get remote status for the following files:" );
+ break;
+ case SVN::StatusLocal:
+ temp = i18n( "Get local status for the following files:" );
+ break;
+ case SVN::Diff:
+ temp = i18n( "Get diff for the following files:" );
+ break;
+ case SVN::Info:
+ temp = i18n( "Get information for the following files:" );
+ break;
+ }
+ layout->addWidget( new QLabel( temp, this ) );
+
+ // Widget for showing the list of files.
+ filebox = new QListBox( this );
+ layout->addWidget( filebox );
+
+ // Add special widgets for 'svn commit'.
+ if ( cmd == SVN::Commit ) {
+ QLabel * label;
+
+ // Combobox for displaying old log messages.
+ label = new QLabel( i18n( "&Old messages:" ), this );
+ oldMessages = new QComboBox( this );
+ oldMessages->setDuplicatesEnabled( false );
+ label->setBuddy( oldMessages );
+ layout->addWidget( label );
+ layout->addWidget( oldMessages );
+
+ // Textfield for entering a log message.
+ label = new QLabel( i18n( "&Log message:" ), this );
+ logedit = new QTextEdit( this );
+ label->setBuddy( logedit );
+ layout->addWidget( label );
+ layout->addWidget( logedit );
+
+ connect( oldMessages, SIGNAL( activated( int ) ),
+ this, SLOT( slotComboActivated( int ) ) );
+ }
+
+ QHBoxLayout * buttons = new QHBoxLayout( 0, 0, 6, "BUTTON LAYOUT" );
+ // Add special buttons for 'svn commit'.
+ if ( cmd == SVN::Commit ) {
+ autoAddBox = new QCheckBox( i18n( "Auto&matically add files if necessary" ), this );
+ buttons->addWidget( autoAddBox );
+ }
+ buttons->addItem( new QSpacerItem( 1, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ) );
+
+ // Set the main button's text depending on the SVN comand.
+ switch ( cmd ) {
+ case SVN::Update:
+ temp = i18n( "&Update" );
+ break;
+ case SVN::Commit:
+ temp = i18n( "&Commit" );
+ break;
+ case SVN::StatusRemote:
+ case SVN::StatusLocal:
+ temp = i18n( "&Get Status" );
+ break;
+ case SVN::Diff:
+ temp = i18n( "&Get Diff" );
+ break;
+ case SVN::Info:
+ temp = i18n( "&Get Information" );
+ break;
+ }
+ mainBtn = new QPushButton( temp, this );
+ mainBtn->setDefault( true );
+ buttons->addWidget( mainBtn );
+
+ cancelBtn = new QPushButton( i18n( "C&ancel" ), this );
+ buttons->addWidget( cancelBtn );
+ layout->addLayout( buttons );
+
+ QFrame * line = new QFrame( this );
+ line->setFrameStyle( QFrame::HLine | QFrame::Sunken );
+ layout->addWidget( line );
+
+ layout->addWidget( new QLabel( i18n( "Command output:" ), this ) );
+
+ output = new QTextEdit( this );
+ output->setReadOnly( true );
+ layout->addWidget( output );
+
+ resize( QSize( 600, 450 ).expandedTo( minimumSizeHint( ) ) );
+
+ if ( cmd == SVN::Commit )
+ logedit->setFocus( );
+
+ readSettings( );
+
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( slotExecuteCommand( ) ) );
+ connect( cancelBtn, SIGNAL( clicked( ) ), this, SLOT( reject( ) ) );
+}
+
+void SVNDialog::slotComboActivated( int index )
+{
+ if ( index < 0 || index >= m_logMessages.count() )
+ return;
+ logedit->setText( m_logMessages[index] );
+}
+
+SVNDialog::~SVNDialog()
+{
+ delete m_tempFile;
+ delete p;
+}
+
+void SVNDialog::accept( )
+{
+ saveSettings( );
+ KDialog::accept( );
+}
+
+void SVNDialog::setFiles( const QStringList& files )
+{
+ filebox->insertStringList( files );
+}
+
+void SVNDialog::setCommandLine( const QString& command )
+{
+ _commandLine = command;
+}
+
+void SVNDialog::setAddCommand( const QString& command )
+{
+ _addCommand = command;
+}
+
+void SVNDialog::slotExecuteCommand( )
+{
+ // Nothing to do here.
+ if ( _commandLine.isEmpty( ) ) return;
+
+ kdDebug() << "Preparing KProcess" << endl;
+
+ // Create a new shell process
+ p = new KProcess;
+ p->setUseShell( true, "/bin/sh" );
+
+ if ( _cmd == SVN::Commit ) {
+ // Include command for 'svn add'.
+ if ( autoAddBox->isChecked( ) && !_addCommand.isEmpty( ) )
+ _commandLine.prepend( _addCommand );
+
+ const QString msg( logedit->text() );
+
+ if ( msg.isEmpty() )
+ {
+ // A good commit should never have an empty comment, so ask the user if he really wants it.
+ const int res = KMessageBox::warningContinueCancel( this,
+ i18n( "The commit log message is empty. Do you want to continue?" ) );
+ if ( res != KMessageBox::Continue )
+ return;
+ }
+
+ // Write the commit log message from the input field to a temporary file
+ m_tempFile = new KTempFile;
+ m_tempFile->setAutoDelete( true );
+ QTextStream* stream = m_tempFile->textStream();
+ if ( !stream )
+ {
+ kdError() << "Could not create QTextStream for file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot open temporary file for writing. Aborting.") );
+ return;
+ }
+ stream->setEncoding( QTextStream::UnicodeUTF8 );
+ *stream << msg;
+ m_tempFile->close();
+
+ if ( m_tempFile->status() )
+ {
+ kdError() << "Could not write to file " << m_tempFile->name();
+ delete m_tempFile;
+ m_tempFile = 0;
+ KMessageBox::error( this, i18n( "Cannot write to temporary file. Aborting.") );
+ return;
+ }
+
+ // Change the command line to have the real name of the temporary file
+ _commandLine.replace( "@LOG@FILE@", KProcess::quote( m_tempFile->name() ) );
+
+ // Update the list of log messages
+ if ( !msg.isEmpty() ) {
+ const QString shortLog = KStringHandler::csqueeze( msg, 80 );
+
+
+ // Remove the message from the list if it already exists
+ m_logMessages.remove( msg );
+ // Prepend the current message to the list
+ m_logMessages.prepend( msg );
+
+ // At this time of the process, we do not need the combobox anymore, so we do not squeeze the changed strings.
+ }
+ }
+
+ // Set the KProcess' command line.
+ *p << _commandLine;
+
+ connect( p, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStdout( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ this, SLOT ( slotProcessStderr( KProcess*, char*, int ) ) );
+ connect( p, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( slotProcessExited( KProcess* ) ) );
+
+ output->append( i18n( "[ Starting command ]" ) );
+
+ if ( p->start( KProcess::NotifyOnExit, KProcess::Communication( KProcess::AllOutput ) ) ) {
+ // Disable the main button (and the log edit if in commit mode) to
+ // indicate activity.
+ mainBtn->setEnabled( false );
+ if ( _cmd == SVN::Commit )
+ logedit->setEnabled( false );
+ } else
+ {
+ kdError() << "Process could not be started." << endl;
+ KMessageBox::error( this, i18n( "The process could not be started." ) );
+ }
+}
+
+void SVNDialog::slotProcessStdout( KProcess*, char * buffer, int len )
+{
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ // Set the cursor's position at the end of the output.
+ output->setCursorPosition( output->lines( ), 0 );
+
+ // If the command is 'svn status' or 'svn diff' collect the output of stdout.
+ if ( ( _cmd == SVN::StatusLocal ) || ( _cmd == SVN::StatusRemote ) || ( _cmd == SVN::Diff ) )
+ _statusOutput += QString::fromLocal8Bit( buffer, len );
+}
+
+void SVNDialog::slotProcessStderr( KProcess*, char * buffer, int len )
+{
+ // If an error occurs while executing the command display stderr in
+ // another color.
+ QColor oldColor( output->color( ) );
+ output->setColor( Qt::red );
+ output->append( QString::fromLocal8Bit( buffer, len ) );
+ output->setColor( oldColor );
+ output->setCursorPosition( output->lines( ), 0 );
+}
+
+void SVNDialog::slotProcessExited( KProcess * p )
+{
+ if ( p->exitStatus( ) )
+ output->append( i18n( "[ Exited with status %1 ]" ).arg( p->exitStatus( ) ) );
+ else
+ output->append( i18n( "[ Finished ]" ) );
+
+ // The command is finished. Now we can reconnect the main button.
+ disconnect( mainBtn, 0, 0, 0 );
+ if ( _cmd == SVN::Diff )
+ mainBtn->setText( i18n( "&Show Diff" ) );
+ else
+ mainBtn->setText( i18n( "&Close" ) );
+ connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( accept( ) ) );
+
+ // Reenable the button and the log edit now that the process is finished.
+ mainBtn->setEnabled( true );
+ if ( _cmd == SVN::Commit )
+ logedit->setEnabled( true );
+}
+
+QString SVNDialog::statusOutput( )
+{
+ return _statusOutput;
+}
+
+void SVNDialog::readSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "SVNSupport" );
+
+ if ( _cmd == SVN::Commit ) {
+ autoAddBox->setChecked( config->readBoolEntry( "AutoAddFiles", true ) );
+
+ // Fill the combobox with old messages.
+ m_logMessages.clear();
+ m_squeezedLogMessages.clear();
+ for ( int cnt = 0; cnt < 10; cnt++ )
+ if ( config->hasKey( QString( "CommitLogMessage%1" ).arg( cnt ) ) )
+ {
+ const QString logMessage = config->readEntry( QString( "CommitLogMessage%1" ).arg( cnt ) );
+ if ( !logMessage.isEmpty() )
+ {
+ // If the message is too long, cut it to 80 characters (or the combo box becomes too wide)
+ // ### FIXME: if the string matches the squeezed 80 chars, it might overwrite another entry
+ const QString shortLog = KStringHandler::csqueeze( logMessage );
+ m_logMessages.append( logMessage );
+ m_squeezedLogMessages.append( shortLog );
+ oldMessages->insertItem( shortLog );
+ }
+ }
+
+ }
+}
+
+void SVNDialog::saveSettings( )
+{
+ KSharedConfig * config = m_config;
+ config->setGroup( "SVNSupport" );
+ if ( _cmd == SVN::Commit ) {
+ config->writeEntry( "AutoAddFiles", autoAddBox->isChecked( ) );
+
+ // Write the log messages to the config file.
+ int cnt = 0;
+ QStringList::const_iterator it;
+ for ( it = m_logMessages.constBegin( ); it != m_logMessages.constEnd( ) && cnt < 10 ; ++it, ++cnt )
+ config->writeEntry( QString( "CommitLogMessage%1" ).arg( cnt ), *it );
+ }
+ m_config->sync();
+}
+
+#include "svndialog.moc"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kbabel/catalogmanager/libsvn/svndialog.h b/kbabel/catalogmanager/libsvn/svndialog.h
new file mode 100644
index 00000000..0c824fa8
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svndialog.h
@@ -0,0 +1,151 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNDIALOG_H
+#define SVNDIALOG_H
+
+// KDE include files
+#include <kdialog.h>
+// Project specific include files
+#include "svnresources.h"
+// Forwarding Qt classes
+class QCheckBox;
+class QComboBox;
+class QListBox;
+class QPushButton;
+class QString;
+class QStringList;
+class QTextEdit;
+// Forwarding KDE classes
+class KProcess;
+class KTempFile;
+class KSharedConfig;
+
+/**
+ * This class represents the dialog which is used for executing SVN commands
+ * in KBabel's Catalog Manager. The dialog shows the list of files to be
+ * processed as well as the output from the command.
+ *
+ * In Commit mode there is also an option for automatically executing
+ * 'svn add' if necessary.
+ *
+ * @short Dialog for SVN support in Catalog Manager
+ */
+class SVNDialog : public KDialog
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Constructor for creating the dialog.
+ * @param cmd The type of command to be executed.
+ */
+ SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config );
+ ~SVNDialog();
+ /**
+ * Set the list of files which will be used for the SVN command.
+ * @param files The list of files.
+ */
+ void setFiles( const QStringList& files );
+ /**
+ * Set the command line for the execution of the SVN command.
+ * @param command The command line.
+ */
+ void setCommandLine( const QString& command );
+ /**
+ * Set the command line for adding files to the SVN repository.
+ * This method is only used together with a 'svn commit' for automatically
+ * adding files which are not yet in the repository.
+ * @param command The command line.
+ */
+ void setAddCommand( const QString& command );
+ /**
+ * Return the output of a 'svn status' command.
+ * @returns The complete output.
+ */
+ QString statusOutput( );
+
+ protected:
+ /**
+ * This method is overwritten so that the settings can be saved after
+ * pressing the 'Close' button.
+ */
+ virtual void accept( );
+ /** Read the dialog's settings. */
+ void readSettings( );
+ /** Save the dialog's settings. */
+ void saveSettings( );
+
+ protected slots:
+ /** Slot for executing the SVN Command. */
+ void slotExecuteCommand( );
+ /** Slot for processing the stdout of the SVN Command. */
+ void slotProcessStdout( KProcess*, char * buffer, int len );
+ /** Slot for processing the stderr of the SVN Command. */
+ void slotProcessStderr( KProcess*, char * buffer, int len );
+ /** Slot for post-processing after the SVN command is fninished. */
+ void slotProcessExited( KProcess * p );
+ /// Slot for combox having been activated
+ void slotComboActivated( int );
+
+ private:
+ SVN::Command _cmd;
+
+ QPushButton * mainBtn;
+ QPushButton * cancelBtn;
+ QListBox * filebox;
+ QComboBox * oldMessages;
+ QTextEdit * logedit;
+ QTextEdit * output;
+ QCheckBox * autoAddBox;
+
+ KProcess * p;
+
+ QString _commandLine;
+ QString _addCommand;
+ QString _statusOutput;
+
+ /// Log messages (long version)
+ QStringList m_logMessages;
+ /// Log messages (short version)
+ QStringList m_squeezedLogMessages;
+
+ /// Temporary file (for commits)
+ KTempFile* m_tempFile;
+
+ /// Configuration data (of the KBabel project)
+ KSharedConfig* m_config;
+};
+
+#endif // SVNDIALOG_H
diff --git a/kbabel/catalogmanager/libsvn/svnhandler.cpp b/kbabel/catalogmanager/libsvn/svnhandler.cpp
new file mode 100644
index 00000000..8117fe62
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnhandler.cpp
@@ -0,0 +1,544 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+// System include files
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+// Qt include files
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qdom.h>
+// KDE include files
+#include <kapplication.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kprocess.h>
+// project specific include files
+#include "svnhandler.h"
+
+SVNHandler::SVNHandler( const QString& poBaseDir, const QString& potBaseDir )
+{
+ setPOBaseDir( poBaseDir );
+ setPOTBaseDir( potBaseDir );
+ _autoUpdateTemplates = false;
+}
+
+void SVNHandler::setPOBaseDir( const QString& dir )
+{
+ // check if '.svn/entries' exists in the PO base directory
+ if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) {
+ _isPORepository = true;
+ _poBaseDir = dir;
+ } else
+ _isPORepository = false;
+ emit signalIsPORepository( _isPORepository );
+}
+
+void SVNHandler::setPOTBaseDir( const QString& dir )
+{
+ // check if '.svn/entries' exists in the POT base directory
+ if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) {
+ _isPOTRepository = true;
+ _potBaseDir = dir;
+ } else
+ _isPOTRepository = false;
+ emit signalIsPOTRepository( _isPOTRepository );
+}
+
+QString SVNHandler::fileStatus( const FileStatus status ) const
+{
+ switch ( status ) {
+ case NO_REPOSITORY:
+ return i18n( "No SVN repository" );
+ break;
+ case NOT_IN_SVN:
+ return i18n( "Not in SVN" );
+ break;
+ case LOCALLY_ADDED:
+ return i18n( "Locally added" );
+ break;
+ case LOCALLY_REMOVED:
+ return i18n( "Locally removed" );
+ break;
+ case LOCALLY_MODIFIED:
+ return i18n( "Locally modified" );
+ break;
+ case UP_TO_DATE:
+ return i18n( "Up-to-date" );
+ break;
+ case CONFLICT:
+ return i18n( "Conflict" );
+ break;
+ case ERROR_IN_WC:
+ return i18n( "Error in Working Copy" );
+ default:
+ return i18n( "Unknown" );
+ break;
+ }
+}
+
+SVNHandler::FileStatus SVNHandler::fstatus( const QString& filename ) const
+{
+ // no valid repository
+ if ( !_isPORepository )
+ return NO_REPOSITORY;
+
+ QString fn( filename );
+ fn = fn.remove( QRegExp( "/$" ) );
+
+ QFileInfo info( fn );
+
+ // check if '.svn/entries' exists.
+ QFile entries( info.dir( true ).path( ) + "/.svn/entries" );
+
+ if ( !entries.exists() )
+ return NOT_IN_SVN;
+
+ KProcess proc;
+ SVNOutputCollector out( &proc );
+
+ proc << "svn" << "status" << "-v" << "--xml" << info.absFilePath();
+
+ if( !proc.start( KProcess::Block, KProcess::Stdout ) )
+ return ERROR_IN_WC;
+
+ QDomDocument doc;
+ QString errorMsg;
+ int errorLine, errorCol;
+ QDomNodeList nodelist;
+ QDomNode node;
+ QDomElement entry, wcStatus;
+
+ // Parse the output.
+ if ( !doc.setContent( out.getOutput(), &errorMsg, &errorLine, &errorCol ) ) {
+ kdDebug(8109) << "Cannot parse \"svn status -v --xml\" output for"
+ << filename << endl << "Line: " << errorLine << " Column: "
+ << errorCol << " Error: " << errorMsg << endl;
+ goto no_status_xml;
+ }
+
+ // There should be only one "entry" element. If it doesn't exist, path
+ // isn't repo path at all.
+ nodelist = doc.elementsByTagName("entry");
+ if (nodelist.count() < 1)
+ return NOT_IN_SVN;
+
+ entry = nodelist.item(0).toElement();
+
+ // Shouldn't fail, but just in case there is some weird error.
+ if ( entry.attributeNode("path").value() != info.absFilePath() )
+ return ERROR_IN_WC;
+
+ for ( node = entry.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ if ( !node.isElement() )
+ continue;
+ if (node.toElement().tagName() == "wc-status")
+ break;
+ }
+
+ if ( node.isNull() )
+ return ERROR_IN_WC;
+
+ wcStatus = node.toElement();
+
+ if ( wcStatus.attributeNode("item").value() == "normal" )
+ return UP_TO_DATE;
+ if ( wcStatus.attributeNode("item").value() == "modified" )
+ return LOCALLY_MODIFIED;
+ if ( wcStatus.attributeNode("item").value() == "conflicted" )
+ return CONFLICT;
+ if ( wcStatus.attributeNode("item").value() == "unversioned" )
+ return NOT_IN_SVN;
+ // TODO Ignored entry should have separate return value probably.
+ if ( wcStatus.attributeNode("item").value() == "ignored" )
+ return NOT_IN_SVN;
+ if ( wcStatus.attributeNode("item").value() == "added" )
+ return LOCALLY_ADDED;
+ if ( wcStatus.attributeNode("item").value() == "deleted" )
+ return LOCALLY_REMOVED;
+ // TODO What to do with "missing", "incomplete", "replaced", "merged",
+ // "obstructed", "external"? Can these appear at all in our case?
+
+ return ERROR_IN_WC;
+
+no_status_xml:
+ if ( !entries.open( IO_ReadOnly ) )
+ return ERROR_IN_WC; // we already know that it is a repository
+
+ // Parse the entries file
+ if ( !doc.setContent( &entries, &errorMsg, &errorLine, &errorCol ) ) {
+ kdDebug() << "Cannot parse .svn/entries file for " << filename << endl
+ << "Line: " << errorLine << " Column: " << errorCol << " Error: " << errorMsg << endl;
+ return ERROR_IN_WC;
+ }
+ entries.close();
+
+ QDomElement element;
+ // File name that we are searching
+ const QString findName = info.fileName();
+ // The entries are <entry> elements, so we have to check them
+ QDomNode child = doc.documentElement().firstChild();
+ for ( ; !child.isNull() ; child = child.nextSibling() )
+ {
+ if ( !child.isElement() )
+ continue;
+ element = child.toElement();
+ if ( element.tagName() != "entry" ) {
+ // We have another kind of element, so skip it
+ // Should not happend with svn 1.1.x
+ continue;
+ }
+ const QString name = element.attribute("name");
+ if ( name == findName )
+ break;
+ }
+
+ if ( child.isNull() ) {
+ // We have not found an entry for the file
+ return NOT_IN_SVN;
+ }
+
+ // ### TODO: should we check the attribute kind to be file and not dir?
+
+ // ### TODO: what do copy and move add here?
+ const QString onSchedule = element.attribute( "schedule" );
+ if ( onSchedule == "delete" )
+ return LOCALLY_REMOVED;
+ else if ( onSchedule == "added" )
+ return LOCALLY_ADDED;
+
+ if ( element.hasAttribute( "conflict-new" ) || element.hasAttribute( "conflict-old" ) || element.hasAttribute( "conflict-wrk" ) ) {
+ return CONFLICT;
+ }
+
+ // Note: we do not check the property time stamp
+ const QString textTimeStamp( element.attribute( "text-time" ) );
+
+ // calculate the UTC time from the file's last modified date
+ struct stat st;
+ lstat( QFile::encodeName(fn), &st );
+ struct tm * tm_p = gmtime( &st.st_mtime );
+ const int year = tm_p->tm_year + 1900;
+ const int month = tm_p->tm_mon + 1;
+ QString fileTime;
+ fileTime.sprintf( "%04i-%02i-%02iT%02i:%02i:%02i.000000Z",
+ year, month, tm_p->tm_mday, tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec );
+ //kdDebug() << "File: " << filename << " SVN time: " << textTimeStamp << " File time: " << fileTime << endl;
+ if ( fileTime > textTimeStamp ) // ISO 8601 dates/times can be compared as strings if they have the exact same format.
+ return LOCALLY_MODIFIED;
+
+ return UP_TO_DATE;
+
+}
+
+QString SVNHandler::svnStatus( const QString& filename ) const
+{
+ return map[filename];
+}
+
+void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config)
+{
+ // Unlike cvs, svn works also from outside the repository(as long as the path is in a repository of course!)
+ // ### FIXME: wrong, svn commit cannot work if the current directory is not a SVN one
+ execSVNCommand( parent, cmd, QStringList( filename ), templates, config );
+}
+
+void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config )
+{
+ if ( !_isPORepository ) {
+ // This message box should never be visible but who knows... ;-)
+ KMessageBox::sorry( parent, i18n( "This is not a valid SVN repository. "
+ "The SVN commands cannot be executed." ) );
+ return;
+ }
+
+ // ### TODO: instead of making a QString, use KProcess directly, so that it cares about quoting.
+ // ### TODO: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.)
+ QString command("cd " + (templates ? _potBaseDir : _poBaseDir) + " && svn ");
+ switch ( cmd ) {
+ case SVN::Update:
+ command += "update --non-interactive";
+ break;
+ case SVN::Commit:
+ // The svn client allows to choose the encoding, so we select UTF-8
+ command += "commit -F @LOG@FILE@ --encoding UTF-8 --non-interactive";
+ checkToAdd( files );
+ break;
+ case SVN::StatusRemote:
+ command += "status -u --non-interactive";
+ break;
+ case SVN::StatusLocal:
+ command += "status --non-interactive";
+ break;
+ case SVN::Diff:
+ command += "diff --non-interactive";
+ break;
+ case SVN::Info:
+ command += "info"; // Does not allow --non-interactive (at least svn 1.1.4).
+ }
+
+ QRegExp rx;
+ if (templates)
+ rx.setPattern(_potBaseDir + "/?");
+ else
+ rx.setPattern(_poBaseDir + "/?");
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ QString temp = *it;
+ temp.remove(rx);
+ command += " \'" + temp + "\'";
+ }
+
+ showDialog( parent, cmd, files, command, config );
+}
+
+void SVNHandler::setAutoUpdateTemplates( bool update )
+{
+ _autoUpdateTemplates = update;
+}
+
+void SVNHandler::showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config )
+{
+ SVNDialog * dia = new SVNDialog( cmd, parent, config );
+ dia->setFiles( files );
+ dia->setCommandLine( commandLine );
+ if ( cmd == SVN::Commit ) {
+ dia->setAddCommand( _addCommand );
+ }
+
+ if ( dia->exec( ) == KDialog::Accepted ) {
+ if ( cmd == SVN::StatusLocal || cmd == SVN::StatusRemote )
+ processStatusOutput( dia->statusOutput( ) );
+ if ( cmd == SVN::Diff )
+ processDiff( dia->statusOutput( ) );
+ }
+
+ delete dia;
+
+ // file status display update necessary in Catalog Manager
+ if ( cmd == SVN::Commit )
+ emit signalFilesCommitted( files );
+}
+
+bool SVNHandler::isInSvn( const QString& path )
+{
+ if ( path.isEmpty() )
+ return false;
+
+ /*
+ * We need to check if a file is in a SVN repository.
+ *
+ * But as we want to do it quickly (because this function will be called for a few files in a row)
+ * we should avoid to parse the .svn/entries files
+ *
+ * Therefore we only check for the SVN auxilary files that are typical for a file controlled by SVN:
+ * - for a directory: checks if the directory has a .svn/entries file
+ * - for a file: check if there is a corresponding file in .svn/text-base/
+ */
+
+ const QFileInfo info( path );
+ if ( info.isDir() ) {
+ // It is a directory, so find a .svn/entries file
+ QDir dir( path );
+ return dir.exists( ".svn/entries", true );
+ }
+ else {
+ // It is a file, so find the corresponding file in .svn/text-base
+ QDir dir( info.dirPath() );
+ if ( ! dir.cd( ".svn/text-base" ) ) {
+ // There is not even a .svn/text-base directory, so the file is not under control
+ return false;
+ }
+ const QString textBaseFilename( info.fileName() + ".svn-base" );
+ return dir.exists( textBaseFilename, true );
+ }
+}
+
+void SVNHandler::checkToAdd( const QStringList& files )
+{
+ if ( files.isEmpty( ) )
+ return;
+
+ QStringList toBeAdded;
+
+ QStringList::ConstIterator it;
+ for ( it = files.begin( ); it != files.end( ); ++it ) {
+ // check for every entry if it needs to be added
+ if ( ! isInSvn( *it ) ) {
+ QFileInfo info( *it );
+ QString temp; // will hold the dir path
+ if ( info.isDir( ) ) {
+ toBeAdded << *it;
+ temp = *it;
+ } else {
+ toBeAdded << *it;
+ temp = QFileInfo( *it ).dirPath( true );
+ }
+
+ // ### TODO: does SVN really needs this or does it do it automatically?
+ // check recursivlely if parent dirs have to be added as well
+ while ( ! isInSvn( temp ) && toBeAdded.findIndex( temp ) == -1 ) {
+ toBeAdded << temp;
+ temp = QFileInfo( temp ).dirPath( true );
+ }
+
+ }
+ }
+
+ // remove an old command
+ _addCommand = QString();
+
+ // ### TODO: does SVN really need this?
+ // make sure the directories are added before the files
+ toBeAdded.sort( );
+
+ // ### TODO: try to make this better
+ // create a command line for adding the files and dirs
+ for ( it = toBeAdded.begin( ); it != toBeAdded.end( ); ++it ) {
+ QFileInfo info( *it );
+ _addCommand += "cd " + info.dirPath( true ) + " && svn add " + info.fileName( ) + "; ";
+ }
+}
+
+// ### TODO: convert to SVN
+void SVNHandler::processStatusOutput( const QString& status )
+{
+ if ( !_isPORepository )
+ return;
+
+#if 0
+ // at first we need to extract the name of the base directory on the server
+ QFile f( _poBaseDir + "/SVN/Root" ); // ### FIXME
+ if ( !f.open( IO_ReadOnly ) )
+ return;
+
+ QTextStream stream( &f );
+ // extract the string after the last colon in the first line
+ QString basedir = stream.readLine( ).section( ':', -1 );
+
+ f.close( );
+
+ // divide the complete status output in little chunks for every file
+ QStringList entries = QStringList::split( QRegExp( "={67,67}" ), status );
+ QStringList::Iterator it;
+ for ( it = entries.begin( ); it != entries.end( ); ++it ) {
+ QString entr = *it;
+ // translate the filename from repository to local
+ QRegExp rx( basedir + ".*,v" );
+ int pos = entr.find( rx );
+ QString file = _poBaseDir + entr.mid( pos + basedir.length( ),
+ rx.matchedLength( ) - basedir.length( ) - 2 );
+
+ entr = "<qt>" + entr + "</qt>";
+
+ // TODO: do some markup
+
+ map.replace( file, entr );
+ }
+#endif
+}
+
+void SVNHandler::processDiff( QString output )
+{
+ output.remove( QRegExp( "\\[ .* \\]$" ));
+ output.remove( QRegExp( "^" + i18n("[ Starting command ]" ).replace("[","\\[").replace("]","\\]")));
+
+ KTempFile tmpFile;
+ *(tmpFile.textStream()) << output;
+ tmpFile.close();
+
+ QString error;
+ if ( KApplication::startServiceByName( "Kompare", tmpFile.name(), &error ) )
+ KMessageBox::error( 0, error );
+}
+
+bool SVNHandler::isConsideredModified( const FileStatus status ) const
+{
+ /*
+ * A file is modified if it is either:
+ * - locally modified for SVN
+ * - directory under SVN control but not the file
+ */
+
+ // ### TODO: what about moved and copied?
+ return status == LOCALLY_MODIFIED || status == NOT_IN_SVN;
+}
+
+SVNOutputCollector::SVNOutputCollector( KProcess* p )
+ : m_process(0)
+{
+ setProcess( p );
+}
+
+void SVNOutputCollector::setProcess( KProcess* p )
+{
+ if( m_process )
+ m_process->disconnect( this );
+
+ m_process = p;
+ if( p ) {
+ connect( p, SIGNAL(receivedStdout(KProcess*, char*, int)),
+ this, SLOT(slotGatherStdout(KProcess*, char*, int)) );
+ connect( p, SIGNAL(receivedStderr(KProcess*, char*, int)),
+ this, SLOT(slotGatherStderr(KProcess*, char*, int)) );
+ }
+
+ m_gatheredOutput.truncate( 0 );
+ m_stderrOutput.truncate( 0 );
+ m_stdoutOutput.truncate( 0 );
+}
+
+void SVNOutputCollector::slotGatherStderr( KProcess*, char* data, int len )
+{
+ m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) );
+ m_stderrOutput.append( QString::fromLocal8Bit( data, len ) );
+}
+
+void SVNOutputCollector::slotGatherStdout( KProcess*, char* data, int len )
+{
+ m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) );
+ m_stdoutOutput.append( QString::fromLocal8Bit( data, len ) );
+}
+
+#include "svnhandler.moc"
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kbabel/catalogmanager/libsvn/svnhandler.h b/kbabel/catalogmanager/libsvn/svnhandler.h
new file mode 100644
index 00000000..67c86d73
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnhandler.h
@@ -0,0 +1,138 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNHANDLER_H
+#define SVNHANDLER_H
+
+// Qt include files
+#include <qmap.h>
+#include <qobject.h>
+// Project specific include files
+#include "svndialog.h"
+#include "svnresources.h"
+// Forwarding Qt classes
+class QString;
+class QStringList;
+
+class KSharedConfig;
+
+/**
+ * This class is the backend for SVN support in Catalog Manager.
+ *
+ * @short Backend for SVN support in Catalog Manager
+ */
+class SVNHandler : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum FileStatus {
+ NO_REPOSITORY,
+ NOT_IN_SVN,
+ LOCALLY_ADDED,
+ LOCALLY_REMOVED,
+ LOCALLY_MODIFIED,
+ CONFLICT,
+ UP_TO_DATE,
+ ERROR_IN_WC ///< The working copy has data that cannot be handled
+ };
+
+ SVNHandler( const QString& poBaseDir = QString::null, const QString& potBaseDir = QString::null );
+
+ void setPOBaseDir( const QString& dir );
+ void setPOTBaseDir( const QString& dir );
+
+ FileStatus fstatus( const QString& filename ) const;
+ QString fileStatus( const FileStatus status ) const;
+ QString svnStatus( const QString& filename ) const;
+
+ void execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config );
+ void execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config );
+
+ void setAutoUpdateTemplates( bool update );
+
+ /**
+ * True if the file was modified or has another status considered as a modification
+ */
+ bool isConsideredModified( const FileStatus status ) const;
+
+ signals:
+ void signalIsPORepository( bool );
+ void signalIsPOTRepository( bool );
+ void signalFilesCommitted( const QStringList& );
+
+ private:
+ void showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config );
+ /// Check quickly if the file is part of a SVN repository
+ bool isInSvn( const QString& path );
+ void checkToAdd( const QStringList& files );
+ void processStatusOutput( const QString& status );
+ void processDiff( QString output );
+
+ private:
+ QString _poBaseDir;
+ QString _potBaseDir;
+ bool _isPORepository;
+ bool _isPOTRepository;
+ bool _autoUpdateTemplates;
+ QString _addCommand;
+
+ /** Mapping the output of 'svn status' against the filename. */
+ QMap<QString,QString> map;
+};
+
+class SVNOutputCollector: public QObject
+{
+ Q_OBJECT
+
+ public:
+ SVNOutputCollector( KProcess* );
+ void setProcess( KProcess* );
+
+ const QString& getOutput() const { return m_gatheredOutput; }
+ const QString& getStderr() const { return m_stderrOutput; }
+ const QString& getStdout() const { return m_stdoutOutput; }
+
+ private slots:
+ void slotGatherStderr( KProcess*, char*, int );
+ void slotGatherStdout( KProcess*, char*, int );
+
+ private:
+ QString m_gatheredOutput;
+ QString m_stderrOutput;
+ QString m_stdoutOutput;
+ KProcess* m_process;
+};
+
+#endif // SVNHANDLER_H
diff --git a/kbabel/catalogmanager/libsvn/svnresources.h b/kbabel/catalogmanager/libsvn/svnresources.h
new file mode 100644
index 00000000..d9032a4f
--- /dev/null
+++ b/kbabel/catalogmanager/libsvn/svnresources.h
@@ -0,0 +1,50 @@
+/* ****************************************************************************
+ This file is part of KBabel
+
+ Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de>
+ Copyright (C) 2005 by Nicolas GOUTTE <goutte@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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this program with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+
+**************************************************************************** */
+
+
+#ifndef SVNRESOURCES_H
+#define SVNRESOURCES_H
+
+namespace SVN {
+ enum Command
+ {
+ Update, ///< svn update
+ Commit, ///< svn commit
+ StatusLocal, ///< svn status
+ StatusRemote, ///< svn status -u
+ Diff, ///< svn diff
+ Info ///< svn info
+ };
+}
+
+#endif // SVNRESOURCES_H