summaryrefslogtreecommitdiffstats
path: root/parts/diff
diff options
context:
space:
mode:
Diffstat (limited to 'parts/diff')
-rw-r--r--parts/diff/Makefile.am18
-rw-r--r--parts/diff/README3
-rw-r--r--parts/diff/README.dox20
-rw-r--r--parts/diff/diffdlg.cpp48
-rw-r--r--parts/diff/diffdlg.h41
-rw-r--r--parts/diff/diffpart.cpp248
-rw-r--r--parts/diff/diffpart.h59
-rw-r--r--parts/diff/diffwidget.cpp348
-rw-r--r--parts/diff/diffwidget.h107
-rw-r--r--parts/diff/kdevdiff.desktop84
-rw-r--r--parts/diff/kdevdiff.rc9
11 files changed, 985 insertions, 0 deletions
diff --git a/parts/diff/Makefile.am b/parts/diff/Makefile.am
new file mode 100644
index 00000000..300e2deb
--- /dev/null
+++ b/parts/diff/Makefile.am
@@ -0,0 +1,18 @@
+# Here resides the valgrind part
+
+INCLUDES = -I$(top_srcdir)/lib/interfaces \
+ -I$(top_srcdir)/lib/interfaces/extensions $(all_includes)
+
+kde_module_LTLIBRARIES = libkdevdiff.la
+libkdevdiff_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+libkdevdiff_la_LIBADD = $(top_builddir)/lib/libkdevelop.la
+
+libkdevdiff_la_SOURCES = diffpart.cpp diffwidget.cpp
+
+METASOURCES = AUTO
+
+servicedir = $(kde_servicesdir)
+service_DATA = kdevdiff.desktop
+
+rcdir = $(kde_datadir)/kdevdiff
+rc_DATA = kdevdiff.rc
diff --git a/parts/diff/README b/parts/diff/README
new file mode 100644
index 00000000..731741e1
--- /dev/null
+++ b/parts/diff/README
@@ -0,0 +1,3 @@
+Please read the on-line, automaticaly updated KDevelop API documentation at:
+http://www.kdevelop.org
+or read the README.dox file.
diff --git a/parts/diff/README.dox b/parts/diff/README.dox
new file mode 100644
index 00000000..6659ac71
--- /dev/null
+++ b/parts/diff/README.dox
@@ -0,0 +1,20 @@
+/** \class DiffPart
+This DiffPart is an outputview that shows "diffs" between files.
+
+If "kompare" from KDESDK is installed, it'll use
+its widget to display the diff, otherwise
+in a QTextEdit with simple highlighting
+Just right-click on a CVS or Perforce file
+and select "diff to repository" to see it in action.
+
+\authors <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a>
+
+\maintainer <a href="mailto:harry AT kdevelop.org">Harald Fernengel</a>
+
+\feature Shows "diffs" between files
+\feature If "kompare" from KDESDK is installed, it'll use its widget to display the diff otherwise in a QTextEdit with simple highlighting
+\feature Works with all VCS systems supported by KDevelop
+
+\requirement If "kompare" from KDESDK is installed, it'll use its widget to display the diff.
+
+*/
diff --git a/parts/diff/diffdlg.cpp b/parts/diff/diffdlg.cpp
new file mode 100644
index 00000000..049a3d60
--- /dev/null
+++ b/parts/diff/diffdlg.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+
+#include <klocale.h>
+
+#include "diffdlg.h"
+#include "diffwidget.h"
+
+DiffDlg::DiffDlg( QWidget *parent, const char *name ):
+ KDialogBase( parent, name, true, i18n("Difference Viewer"), Ok )
+{
+ diffWidget = new DiffWidget( this, "Main Diff Widget" );
+ setMainWidget( diffWidget );
+
+ QVBoxLayout* layout = new QVBoxLayout( this, 0, spacingHint() );
+ layout->addWidget( diffWidget );
+}
+
+DiffDlg::~DiffDlg()
+{
+}
+
+void DiffDlg::slotClear()
+{
+ diffWidget->slotClear();
+}
+
+void DiffDlg::setDiff( const QString& diff )
+{
+ diffWidget->setDiff( diff );
+}
+
+void DiffDlg::openURL( const KURL& url )
+{
+ diffWidget->openURL( url );
+}
+
+#include "diffdlg.moc"
diff --git a/parts/diff/diffdlg.h b/parts/diff/diffdlg.h
new file mode 100644
index 00000000..6f47dcf2
--- /dev/null
+++ b/parts/diff/diffdlg.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _DIFFDLG_H_
+#define _DIFFDLG_H_
+
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class DiffWidget;
+
+class DiffDlg : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ DiffDlg( QWidget *parent = 0, const char *name = 0 );
+ virtual ~DiffDlg();
+
+public slots:
+ /** The URL has to point to a diff file */
+ void openURL( const KURL& url );
+ /** Pass a diff file in here */
+ void setDiff( const QString& diff );
+ /** clears the difference viewer */
+ void slotClear();
+
+private:
+ DiffWidget* diffWidget;
+
+};
+
+#endif
diff --git a/parts/diff/diffpart.cpp b/parts/diff/diffpart.cpp
new file mode 100644
index 00000000..8f04b060
--- /dev/null
+++ b/parts/diff/diffpart.cpp
@@ -0,0 +1,248 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include "diffpart.h"
+
+#include <sys/stat.h>
+
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+
+#include <klocale.h>
+#include <kdevgenericfactory.h>
+#include <kaction.h>
+#include <kfiledialog.h>
+#include <kprocess.h>
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+#include <kparts/part.h>
+#include <ktexteditor/editinterface.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+
+#include "kdevcore.h"
+#include "kdevmainwindow.h"
+#include "kdevpartcontroller.h"
+#include "kdevplugininfo.h"
+
+#include "diffdlg.h"
+#include "diffwidget.h"
+
+static const KDevPluginInfo data("kdevdiff");
+
+typedef KDevGenericFactory<DiffPart> DiffFactory;
+K_EXPORT_COMPONENT_FACTORY( libkdevdiff, DiffFactory( data ) )
+
+DiffPart::DiffPart(QObject *parent, const char *name, const QStringList &)
+ : KDevDiffFrontend(&data, parent, name ? name : "DiffPart"), proc(0)
+{
+ setInstance(DiffFactory::instance());
+ setXMLFile("kdevdiff.rc");
+
+ diffWidget = new DiffWidget(this, 0, "diffWidget");
+ diffWidget->setIcon( SmallIcon("editcopy") );
+ QString nm( i18n( "Diff" ) );
+ diffWidget->setCaption( i18n( "Diff Output" ) );
+ QWhatsThis::add(diffWidget, i18n("<b>Difference viewer</b><p>Shows output of the diff format. "
+ "Can utilize every installed component that is able to show diff output. "
+ "For example if you have Kompare installed, Difference Viewer can use its graphical diff view."));
+ mainWindow()->embedOutputView( diffWidget, nm, i18n("Output of the diff command") );
+ mainWindow()->setViewAvailable( diffWidget, false );
+
+ KAction *action = new KAction( i18n("Difference Viewer..."), 0,
+ this, SLOT(slotExecDiff()),
+ actionCollection(), "tools_diff" );
+ action->setToolTip(i18n("Difference viewer"));
+ action->setWhatsThis(i18n("<b>Difference viewer</b><p>Shows the contents of a patch file."));
+
+ connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
+ this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
+}
+
+static bool urlIsEqual(const KURL &a, const KURL &b)
+{
+ if (a.isLocalFile() && b.isLocalFile())
+ {
+ struct stat aStat, bStat;
+
+ if ((::stat(QFile::encodeName(a.fileName()), &aStat) == 0)
+ && (::stat(QFile::encodeName(b.fileName()), &bStat) == 0))
+ {
+ return (aStat.st_dev == bStat.st_dev) && (aStat.st_ino == bStat.st_ino);
+ }
+ }
+
+ return a == b;
+}
+
+static KParts::ReadWritePart* partForURL(const KURL &url, KDevPartController* pc)
+{
+ if ( !pc )
+ return 0;
+ QPtrListIterator<KParts::Part> it(*(pc->parts()));
+ for ( ; it.current(); ++it)
+ {
+ KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*>(it.current());
+ if ( rw_part && dynamic_cast<KTextEditor::EditInterface*>(it.current()) && urlIsEqual(url, rw_part->url()) )
+ return rw_part;
+ }
+
+ return 0;
+}
+
+void DiffPart::contextMenu( QPopupMenu* popup, const Context* context )
+{
+ if ( context->hasType( Context::EditorContext ) )
+ {
+ const EditorContext *eContext = static_cast<const EditorContext*>(context);
+ popupFile = eContext->url();
+ }
+ else if ( context->hasType( Context::FileContext ) )
+ {
+ const FileContext * fContext = static_cast<const FileContext*>( context );
+ popupFile.setPath( fContext->urls().first().fileName() ); //@fixme - assuming absolute path. is this correct?
+ }
+ else
+ {
+ return;
+ }
+
+ KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
+ if ( !rw_part ) return;
+
+ if ( partController()->documentState( rw_part->url() ) != Clean )
+ {
+ int id = popup->insertItem( i18n( "Difference to Disk File" ),
+ this, SLOT(localDiff()) );
+ popup->setWhatsThis(id, i18n("<b>Difference to disk file</b><p>Shows the difference between "
+ "the file contents in this editor and the file contents on disk."));
+ }
+}
+
+DiffPart::~DiffPart()
+{
+ if ( diffWidget )
+ mainWindow()->removeView( diffWidget );
+
+ delete proc;
+ delete (DiffWidget*) diffWidget;
+}
+
+void DiffPart::localDiff()
+{
+ KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
+ if ( !rw_part )
+ return;
+
+ KTextEditor::EditInterface* editIface = dynamic_cast<KTextEditor::EditInterface*>(rw_part);
+ if ( !editIface )
+ return;
+ buffer = editIface->text().local8Bit();
+ resultBuffer = resultErr = QString::null;
+
+ delete proc;
+ proc = new KProcess();
+
+ *proc << "diff";
+ *proc << "-u" << popupFile.path() << "-";
+ proc->setWorkingDirectory( popupFile.directory() );
+
+ connect( proc, SIGNAL(processExited( KProcess* )),
+ this, SLOT(processExited( KProcess* )) );
+ connect( proc, SIGNAL(receivedStdout( KProcess*, char*, int )),
+ this, SLOT(receivedStdout( KProcess*, char*, int )) );
+ connect( proc, SIGNAL(receivedStderr( KProcess*, char*, int )),
+ this, SLOT(receivedStderr( KProcess*, char*, int )) );
+ connect( proc, SIGNAL(wroteStdin( KProcess* )),
+ this, SLOT(wroteStdin( KProcess* )) );
+
+ if ( !proc->start( KProcess::NotifyOnExit, KProcess::All ) ) {
+ KMessageBox::error( 0, i18n( "Could not invoke the \"diff\" command." ) );
+ delete proc;
+ proc = 0;
+ return;
+ }
+ proc->writeStdin( buffer.data(), buffer.length() );
+}
+
+void DiffPart::processExited( KProcess* p )
+{
+ // diff has exit status 0 and 1 for success
+ if ( p->normalExit() && ( p->exitStatus() == 0 || p->exitStatus() == 1 ) ) {
+ if ( resultBuffer.isEmpty() )
+ KMessageBox::information( 0, i18n("DiffPart: No differences found.") );
+ else
+ showDiff( resultBuffer );
+ } else {
+ KMessageBox::error( 0, i18n("Diff command failed (%1):\n").arg( p->exitStatus() ) + resultErr );
+ }
+ resultBuffer = resultErr = QString::null;
+ delete proc;
+ proc = 0;
+}
+
+void DiffPart::receivedStdout( KProcess* /* p */, char* buf, int buflen )
+{
+ resultBuffer += QString::fromLocal8Bit( buf, buflen );
+}
+
+void DiffPart::receivedStderr( KProcess* /* p */, char* buf, int buflen )
+{
+ kdDebug(9033) << "received Stderr: " << QString::fromLocal8Bit( buf, buflen ) << endl;
+ resultErr += QString::fromLocal8Bit( buf, buflen );
+}
+
+void DiffPart::wroteStdin( KProcess* p )
+{
+ buffer = 0L;
+ p->closeStdin();
+}
+
+void DiffPart::openURL( const KURL& url )
+{
+ diffWidget->slotClear();
+ diffWidget->openURL( url );
+ mainWindow()->raiseView( diffWidget );
+/*
+ DiffDlg* diffDlg = new DiffDlg( 0, "diffDlg" );
+
+ diffDlg->openURL( url );
+ diffDlg->exec();
+ delete diffDlg;
+*/
+}
+
+void DiffPart::showDiff( const QString& diff )
+{
+ diffWidget->slotClear();
+ diffWidget->setDiff( diff );
+ mainWindow()->setViewAvailable( diffWidget, true );
+ mainWindow()->raiseView( diffWidget );
+/*
+ DiffDlg* diffDlg = new DiffDlg( 0, "diffDlg" );
+
+ diffDlg->setDiff( diff );
+ diffDlg->exec();
+ delete diffDlg;
+*/
+}
+
+void DiffPart::slotExecDiff()
+{
+ KURL url = KFileDialog::getOpenURL( QString::null, QString::null, 0, i18n("Please Select Patch File") );
+
+ if ( url.isEmpty() )
+ return;
+
+ openURL( url );
+}
+
+#include "diffpart.moc"
diff --git a/parts/diff/diffpart.h b/parts/diff/diffpart.h
new file mode 100644
index 00000000..f89d0d18
--- /dev/null
+++ b/parts/diff/diffpart.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _DIFFPART_H_
+#define _DIFFPART_H_
+
+#include <qguardedptr.h>
+#include <qcstring.h>
+
+#include "kdevplugin.h"
+#include "kdevdifffrontend.h"
+
+class QPopupMenu;
+class Context;
+class KProcess;
+class DiffWidget;
+class QCString;
+
+class DiffPart : public KDevDiffFrontend
+{
+ Q_OBJECT
+
+public:
+ DiffPart( QObject *parent, const char *name, const QStringList & );
+ virtual ~DiffPart();
+
+ void openURL( const KURL& url );
+ void showDiff( const QString& diff );
+ void showDiff( const KURL &, const KURL & ) { /** @todo */ }
+
+public slots:
+ void slotExecDiff();
+
+private slots:
+ void contextMenu( QPopupMenu* popup, const Context* context );
+ void localDiff();
+ void processExited( KProcess* p );
+ void receivedStdout( KProcess* p, char* buf, int buflen );
+ void receivedStderr( KProcess* p, char* buf, int buflen );
+ void wroteStdin( KProcess* p );
+
+private:
+ QGuardedPtr<DiffWidget> diffWidget;
+ KURL popupFile;
+ KProcess* proc;
+ QCString buffer;
+ QString resultBuffer;
+ QString resultErr;
+};
+
+#endif
diff --git a/parts/diff/diffwidget.cpp b/parts/diff/diffwidget.cpp
new file mode 100644
index 00000000..0b3399ab
--- /dev/null
+++ b/parts/diff/diffwidget.cpp
@@ -0,0 +1,348 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qtextedit.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qfile.h>
+
+#include <kconfig.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kservice.h>
+#include <ktempfile.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+
+#include <kparts/componentfactory.h>
+#include <kparts/part.h>
+
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+
+#include <kdevmainwindow.h>
+
+#include "diffpart.h"
+#include "diffwidget.h"
+
+// yup, magic value for the popupmenu-id
+static const int POPUP_BASE = 130977;
+
+QStringList KDiffTextEdit::extParts;
+QStringList KDiffTextEdit::extPartsTranslated;
+
+KDiffTextEdit::KDiffTextEdit( QWidget* parent, const char* name ): QTextEdit( parent, name )
+{
+ KConfig* config = kapp->config();
+ config->setGroup( "Diff" );
+ _highlight = config->readBoolEntry( "Highlight", true );
+
+ searchExtParts();
+}
+
+KDiffTextEdit::~KDiffTextEdit()
+{
+ KConfig* config = kapp->config();
+
+ config->setGroup( "Diff" );
+ config->writeEntry( "Highlight", _highlight );
+}
+
+QPopupMenu* KDiffTextEdit::createPopupMenu()
+{
+ return createPopupMenu( QPoint() );
+}
+
+QPopupMenu* KDiffTextEdit::createPopupMenu( const QPoint& p )
+{
+ QPopupMenu* popup = QTextEdit::createPopupMenu( p );
+ if ( !popup )
+ popup = new QPopupMenu( this );
+
+ int i = 0;
+
+ for ( QStringList::Iterator it = extPartsTranslated.begin(); it != extPartsTranslated.end(); ++it ) {
+ popup->insertItem( i18n( "Show in %1" ).arg( *it ), i + POPUP_BASE, i );
+ i++;
+ }
+ if ( !extPartsTranslated.isEmpty() )
+ popup->insertSeparator( i );
+ connect( popup, SIGNAL(activated(int)), this, SLOT(popupActivated(int)) );
+
+ popup->insertItem( SmallIconSet( "filesaveas" ), i18n( "&Save As..." ), this, SLOT(saveAs()), CTRL + Key_S, POPUP_BASE - 2, 0 );
+ popup->setItemEnabled( POPUP_BASE - 2, length() > 0 );
+
+ popup->insertSeparator( 1 );
+
+ popup->insertItem( i18n( "Highlight Syntax" ), this, SLOT(toggleSyntaxHighlight()), 0, POPUP_BASE - 1, 2 );
+ popup->setItemChecked( POPUP_BASE - 1, _highlight );
+ popup->insertSeparator( 3 );
+
+ popup->insertSeparator();
+ popup->insertItem( i18n("Hide view"), parent(), SLOT(hideView()) );
+
+ return popup;
+}
+
+void KDiffTextEdit::saveAs()
+{
+ QString fName = KFileDialog::getSaveFileName();
+ if ( fName.isEmpty() )
+ return;
+
+ QFile f( fName );
+ if ( f.open( IO_WriteOnly ) ) {
+ QTextStream stream( &f );
+ int pCount = paragraphs();
+ for ( int i = 0; i < pCount; ++i )
+ stream << text( i ) << "\n";
+ f.close();
+ } else {
+ KMessageBox::sorry( 0, i18n("Unable to open file."), i18n("Diff Frontend") );
+ }
+}
+
+void KDiffTextEdit::toggleSyntaxHighlight()
+{
+ _highlight = !_highlight;
+ if ( _highlight )
+ applySyntaxHighlight();
+ else
+ clearSyntaxHighlight();
+}
+
+void KDiffTextEdit::applySyntaxHighlight()
+{
+ // the diff has been loaded so we apply a simple highlighting
+ static QColor cAdded( 190, 190, 237);
+ static QColor cRemoved( 190, 237, 190 );
+
+ if ( !_highlight )
+ return;
+
+ int paragCount = paragraphs();
+ for ( int i = 0; i < paragCount; ++i ) {
+ QString txt = text( i );
+ if ( txt.length() > 0 ) {
+ if ( txt.startsWith( "+" ) || txt.startsWith( ">" ) ) {
+ setParagraphBackgroundColor( i, cAdded );
+ } else if ( txt.startsWith( "-" ) || txt.startsWith( "<" ) ) {
+ setParagraphBackgroundColor( i, cRemoved );
+ }
+ }
+ }
+}
+
+void KDiffTextEdit::clearSyntaxHighlight()
+{
+ int paragCount = paragraphs();
+ for ( int i = 0; i < paragCount; ++i ) {
+ clearParagraphBackground( i );
+ }
+}
+
+void KDiffTextEdit::searchExtParts()
+{
+ // only execute once
+ static bool init = false;
+ if ( init )
+ return;
+ init = true;
+
+ // search all parts that can handle text/x-diff
+ KTrader::OfferList offers = KTrader::self()->query("text/x-diff", "('KParts/ReadOnlyPart' in ServiceTypes) and ('text/x-diff' in ServiceTypes) and (DesktopEntryName != 'katepart')");
+ KTrader::OfferList::const_iterator it;
+ for ( it = offers.begin(); it != offers.end(); ++it ) {
+ KService::Ptr ptr = (*it);
+ extPartsTranslated << ptr->name();
+ extParts << ptr->desktopEntryName();
+ }
+ return;
+}
+
+void KDiffTextEdit::popupActivated( int id )
+{
+ id -= POPUP_BASE;
+ if ( id < 0 || id > (int)extParts.count() )
+ return;
+
+ emit externalPartRequested( extParts[ id ] );
+}
+
+DiffWidget::DiffWidget( DiffPart * part, QWidget *parent, const char *name, WFlags f ):
+ QWidget( parent, name, f ), m_part( part ), tempFile( 0 )
+{
+ job = 0;
+ extPart = 0;
+
+ te = new KDiffTextEdit( this, "Main Diff Viewer" );
+ te->setReadOnly( true );
+ te->setTextFormat( QTextEdit::PlainText );
+// te->setMinimumSize( 300, 200 );
+ connect( te, SIGNAL(externalPartRequested(const QString&)), this, SLOT(loadExtPart(const QString&)) );
+
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ layout->addWidget( te );
+}
+
+DiffWidget::~DiffWidget()
+{
+ m_part = 0;
+ delete tempFile;
+}
+
+void DiffWidget::setExtPartVisible( bool visible )
+{
+ if ( !extPart || !extPart->widget() ) {
+ te->show();
+ return;
+ }
+ if ( visible ) {
+ te->hide();
+ extPart->widget()->show();
+ } else {
+ te->show();
+ extPart->widget()->hide();
+ }
+}
+
+void DiffWidget::loadExtPart( const QString& partName )
+{
+ if ( extPart ) {
+ setExtPartVisible( false );
+ delete extPart;
+ extPart = 0;
+ }
+
+ KService::Ptr extService = KService::serviceByDesktopName( partName );
+ if ( !extService )
+ return;
+
+ extPart = KParts::ComponentFactory::createPartInstanceFromService<KParts::ReadOnlyPart>( extService, this, 0, this, 0 );
+ if ( !extPart || !extPart->widget() )
+ return;
+
+ layout()->add( extPart->widget() );
+
+ setExtPartVisible( true );
+
+ if ( te->paragraphs() > 0 )
+ populateExtPart();
+}
+
+void DiffWidget::slotClear()
+{
+ rawDiff = QString();
+ te->clear();
+ if ( extPart )
+ extPart->closeURL();
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotAppend( const QString& str )
+{
+ te->append( str );
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotAppend( KIO::Job*, const QByteArray& ba )
+{
+ slotAppend( QString( ba ) );
+}
+
+void DiffWidget::populateExtPart()
+{
+ if ( !extPart )
+ return;
+
+ bool ok = false;
+ int paragCount = te->paragraphs();
+ if ( extPart->openStream( "text/plain", KURL() ) ) {
+ for ( int i = 0; i < paragCount; ++i )
+ extPart->writeStream( rawDiff.local8Bit() );
+ ok = extPart->closeStream();
+ } else {
+ // workaround for parts that cannot handle streams
+ delete tempFile;
+ tempFile = new KTempFile();
+ tempFile->setAutoDelete( true );
+ *(tempFile->textStream()) << rawDiff.local8Bit() << endl;
+ tempFile->close();
+ ok = extPart->openURL( KURL::fromPathOrURL( tempFile->name() ) );
+ }
+ if ( !ok )
+ setExtPartVisible( false );
+}
+
+// internally for the TextEdit only!
+void DiffWidget::slotFinished()
+{
+ te->applySyntaxHighlight();
+ populateExtPart();
+}
+
+void DiffWidget::setDiff( const QString& diff )
+{
+ slotClear();
+ rawDiff = diff;
+ slotAppend( diff );
+ slotFinished();
+}
+
+void DiffWidget::openURL( const KURL& url )
+{
+ if ( job )
+ job->kill();
+
+ KIO::TransferJob* job = KIO::get( url );
+ if ( !job )
+ return;
+
+ connect( job, SIGNAL(data( KIO::Job *, const QByteArray & )),
+ this, SLOT(slotAppend( KIO::Job*, const QByteArray& )) );
+ connect( job, SIGNAL(result( KIO::Job * )),
+ this, SLOT(slotFinished()) );
+}
+
+void DiffWidget::contextMenuEvent( QContextMenuEvent* /* e */ )
+{
+ QPopupMenu* popup = new QPopupMenu( this );
+
+ if ( !te->isVisible() )
+ {
+ popup->insertItem( i18n("Display &Raw Output"), this, SLOT(showTextEdit()) );
+ popup->insertSeparator();
+ popup->insertItem( i18n("Hide view"), this, SLOT(hideView()) );
+ }
+
+ popup->exec( QCursor::pos() );
+ delete popup;
+}
+
+void DiffWidget::showExtPart()
+{
+ setExtPartVisible( true );
+}
+
+void DiffWidget::showTextEdit()
+{
+ setExtPartVisible( false );
+}
+
+void DiffWidget::hideView()
+{
+ m_part->mainWindow()->setViewAvailable( this, false );
+}
+
+#include "diffwidget.moc"
diff --git a/parts/diff/diffwidget.h b/parts/diff/diffwidget.h
new file mode 100644
index 00000000..665b1110
--- /dev/null
+++ b/parts/diff/diffwidget.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2001 by Harald Fernengel *
+ * harry@kdevelop.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _DIFFWIDGET_H_
+#define _DIFFWIDGET_H_
+
+#include <qwidget.h>
+#include <qtextedit.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+
+class KTempFile;
+class DiffPart;
+
+namespace KIO {
+ class Job;
+}
+
+namespace KParts {
+ class ReadOnlyPart;
+}
+
+// Helper class that displays a modified RMB popup menu
+class KDiffTextEdit: public QTextEdit
+{
+ Q_OBJECT
+public:
+ KDiffTextEdit( QWidget* parent = 0, const char* name = 0 );
+ virtual ~KDiffTextEdit();
+ void applySyntaxHighlight();
+ void clearSyntaxHighlight();
+
+signals:
+ void externalPartRequested( const QString& partName );
+
+protected:
+ virtual QPopupMenu* createPopupMenu( const QPoint& );
+ virtual QPopupMenu* createPopupMenu();
+
+private slots:
+ void popupActivated( int );
+ void toggleSyntaxHighlight();
+ void saveAs();
+
+private:
+ static void searchExtParts();
+ static QStringList extParts;
+ static QStringList extPartsTranslated;
+ bool _highlight;
+};
+
+class DiffWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DiffWidget( DiffPart * part, QWidget *parent = 0, const char *name = 0, WFlags f = 0 );
+ virtual ~DiffWidget();
+
+public slots:
+ /** The URL has to point to a diff file */
+ void openURL( const KURL& url );
+ /** Pass a diff file in here */
+ void setDiff( const QString& diff );
+ /** clears the difference viewer */
+ void slotClear();
+
+private slots:
+ /** appends a piece of "diff" */
+ void slotAppend( const QString& str );
+ /** overloaded for convenience */
+ void slotAppend( KIO::Job*, const QByteArray& ba );
+ /** call this when the whole "diff" has been sent.
+ * Don't call slotAppend afterwards!
+ */
+ void slotFinished();
+ void showExtPart();
+ void showTextEdit();
+ void loadExtPart( const QString& partName );
+ void hideView();
+
+protected:
+ void contextMenuEvent( QContextMenuEvent* e );
+
+private:
+ void setExtPartVisible( bool visible );
+ void populateExtPart();
+
+private:
+ DiffPart * m_part;
+ KDiffTextEdit* te;
+ KIO::Job* job;
+ KParts::ReadOnlyPart* extPart;
+ KTempFile* tempFile;
+ QString rawDiff;
+};
+
+#endif
diff --git a/parts/diff/kdevdiff.desktop b/parts/diff/kdevdiff.desktop
new file mode 100644
index 00000000..f9779903
--- /dev/null
+++ b/parts/diff/kdevdiff.desktop
@@ -0,0 +1,84 @@
+[Desktop Entry]
+Type=Service
+Exec=blubb
+Comment=Difference Viewer
+Comment[ca]=Visor de diferències
+Comment[da]=Diff-fremviser
+Comment[de]=Betrachter für Abweichungen
+Comment[el]=Προβολέας διαφορών
+Comment[es]=Visor de diferencias
+Comment[et]=Erinevuste näitaja
+Comment[eu]=Desberdintasun ikustailea
+Comment[fa]=مشاهده‌گر تفاوت
+Comment[fr]=Afficheur de différences
+Comment[ga]=Amharcán Difríochtaí
+Comment[gl]=Visor de diferenzas
+Comment[hi]=भिन्नता प्रदर्शक
+Comment[hu]=Fájlok közötti eltérések megjelenítése
+Comment[it]=Visualizzatore di differenze
+Comment[ja]=差分ビューア
+Comment[ms]=Pelihat Perbezaan
+Comment[nds]=En Verscheelkieker
+Comment[ne]=फरक दृश्यकर्ता
+Comment[nl]=Weergave van verschillen
+Comment[pl]=Przeglądarka różnic
+Comment[pt]=Visualizador de Diferenças
+Comment[pt_BR]=Visualizador de Diferenças
+Comment[ru]=Просмотр различий
+Comment[sk]=Prezerač rozdielov
+Comment[sl]=Pregledovalnik razlik
+Comment[sr]=Програм за прегледање разлика
+Comment[sr@Latn]=Program za pregledanje razlika
+Comment[sv]=Visning av jämförelser
+Comment[ta]=பாகுபாடு காட்சியாளர்
+Comment[tg]=Намоишгари фарқкунанда
+Comment[tr]=Fark Görüntüleyicisi
+Comment[zh_CN]=差别查看器
+Comment[zh_TW]=比較檢視器
+Name=KDevDiff
+Name[da]=KDevelop diff-fremviser
+Name[de]=Abweichungsansicht (KDevelop)
+Name[hi]=के-डेव-डिफ़
+Name[nds]=KDevelop-Verscheelkieker
+Name[sk]=KDev rozdiel
+Name[sv]=KDevelop jämför
+Name[zh_TW]=KDevelop 比較
+GenericName=Difference Viewer
+GenericName[ca]=Visor de diferències
+GenericName[da]=Diff-fremviser
+GenericName[de]=Betrachter für Abweichungen
+GenericName[el]=Προβολέας διαφορών
+GenericName[es]=Visor de diferencias
+GenericName[et]=Erinevuste näitaja
+GenericName[eu]=Desberdintasun ikustailea
+GenericName[fa]=مشاهده‌گر تفاوت
+GenericName[fr]=Afficheur de différences
+GenericName[ga]=Amharcán Difríochtaí
+GenericName[gl]=Visor de diferenzas
+GenericName[hi]=भिन्नता प्रदर्शक
+GenericName[hu]=Diff-megjelenítő
+GenericName[it]=Visualizzatore delle differenze
+GenericName[ja]=差分ビューア
+GenericName[ms]=Pelihat Perbezaan
+GenericName[nds]=Verscheelkieker
+GenericName[ne]=फरक दृश्यकर्ता
+GenericName[nl]=Weergave van verschillen
+GenericName[pl]=Przeglądarka różnic
+GenericName[pt]=Visualizador de Diferenças
+GenericName[pt_BR]=Visualizador de Diferenças
+GenericName[ru]=Просмотр различий
+GenericName[sk]=Prezerač rozdielov
+GenericName[sl]=Pregledovalnik razlik
+GenericName[sr]=Програм за прегледање разлика
+GenericName[sr@Latn]=Program za pregledanje razlika
+GenericName[sv]=Visning av jämförelser
+GenericName[ta]=வெவ்வேறு பார்வையாளர்கள்
+GenericName[tg]=Намоишгари фарқкунанда
+GenericName[tr]=Fark Görüntüleyicisi
+GenericName[zh_CN]=差别查看器
+GenericName[zh_TW]=比較檢視器
+ServiceTypes=KDevelop/DiffFrontend
+X-KDE-Library=libkdevdiff
+X-KDevelop-Version=5
+X-KDevelop-Properties=CodeEditing
+X-KDevelop-Scope=Core
diff --git a/parts/diff/kdevdiff.rc b/parts/diff/kdevdiff.rc
new file mode 100644
index 00000000..37059573
--- /dev/null
+++ b/parts/diff/kdevdiff.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KDevDiff" version="1">
+<MenuBar>
+ <Menu name="tools" >
+ <Action name="tools_diff" group="tools_file_operations"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
+