summaryrefslogtreecommitdiffstats
path: root/kompare/libdiff2
diff options
context:
space:
mode:
Diffstat (limited to 'kompare/libdiff2')
-rw-r--r--kompare/libdiff2/Makefile.am37
-rw-r--r--kompare/libdiff2/cvsdiffparser.cpp160
-rw-r--r--kompare/libdiff2/cvsdiffparser.h61
-rw-r--r--kompare/libdiff2/difference.cpp137
-rw-r--r--kompare/libdiff2/difference.h223
-rw-r--r--kompare/libdiff2/diffhunk.cpp115
-rw-r--r--kompare/libdiff2/diffhunk.h69
-rw-r--r--kompare/libdiff2/diffmodel.cpp409
-rw-r--r--kompare/libdiff2/diffmodel.h150
-rw-r--r--kompare/libdiff2/diffmodellist.cpp29
-rw-r--r--kompare/libdiff2/diffmodellist.h49
-rw-r--r--kompare/libdiff2/diffparser.cpp81
-rw-r--r--kompare/libdiff2/diffparser.h38
-rw-r--r--kompare/libdiff2/kompare.h144
-rw-r--r--kompare/libdiff2/komparemodellist.cpp1423
-rw-r--r--kompare/libdiff2/komparemodellist.h213
-rw-r--r--kompare/libdiff2/kompareprocess.cpp269
-rw-r--r--kompare/libdiff2/kompareprocess.h67
-rw-r--r--kompare/libdiff2/levenshteintable.cpp332
-rw-r--r--kompare/libdiff2/levenshteintable.h69
-rw-r--r--kompare/libdiff2/parser.cpp139
-rw-r--r--kompare/libdiff2/parser.h58
-rw-r--r--kompare/libdiff2/parserbase.cpp739
-rw-r--r--kompare/libdiff2/parserbase.h133
-rw-r--r--kompare/libdiff2/perforceparser.cpp223
-rw-r--r--kompare/libdiff2/perforceparser.h44
26 files changed, 5411 insertions, 0 deletions
diff --git a/kompare/libdiff2/Makefile.am b/kompare/libdiff2/Makefile.am
new file mode 100644
index 00000000..6f9048d8
--- /dev/null
+++ b/kompare/libdiff2/Makefile.am
@@ -0,0 +1,37 @@
+INCLUDES = \
+ -I$(top_srcdir)/kompare/libdialogpages \
+ -I$(top_srcdir)/kompare/komparepart \
+ -I$(top_srcdir)/kompare/interfaces $(all_includes)
+
+noinst_HEADERS = \
+ levenshteintable.h \
+ kompare.h \
+ kompareprocess.h \
+ komparemodellist.h \
+ diffmodel.h \
+ difference.h \
+ diffhunk.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libdiff2.la
+
+# the Part's source, library search path, and link libraries
+libdiff2_la_SOURCES = \
+ kompareprocess.cpp \
+ komparemodellist.cpp \
+ diffmodellist.cpp \
+ diffmodel.cpp \
+ difference.cpp \
+ diffhunk.cpp \
+ levenshteintable.cpp \
+ parser.cpp \
+ parserbase.cpp \
+ cvsdiffparser.cpp \
+ diffparser.cpp \
+ perforceparser.cpp
+
+libdiff2_la_LDFLAGS = $(all_libraries)
+libdiff2_la_LIBADD = $(LIB_KFILE)
+
diff --git a/kompare/libdiff2/cvsdiffparser.cpp b/kompare/libdiff2/cvsdiffparser.cpp
new file mode 100644
index 00000000..d210eb66
--- /dev/null
+++ b/kompare/libdiff2/cvsdiffparser.cpp
@@ -0,0 +1,160 @@
+/**************************************************************************
+** cvsdiffparser.cpp
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** ( at your option ) any later version.
+**
+***************************************************************************/
+
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include "cvsdiffparser.h"
+#include "komparemodellist.h"
+
+
+using namespace Diff2;
+
+CVSDiffParser::CVSDiffParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ // The regexps needed for context cvs diff parsing, the rest is the same as in parserbase.cpp
+ // third capture in header1 is non optional for cvs diff, it is the revision
+ m_contextDiffHeader1.setPattern( "\\*\\*\\* ([^\\t]+)\\t([^\\t]+)\\t(.*)\\n" );
+ m_contextDiffHeader2.setPattern( "--- ([^\\t]+)\\t([^\\t]+)(|\\t(.*))\\n" );
+
+ m_normalDiffHeader.setPattern( "Index: (.*)\\n" );
+}
+
+CVSDiffParser::~CVSDiffParser()
+{
+}
+
+enum Kompare::Format CVSDiffParser::determineFormat()
+{
+// kdDebug(8101) << "Determining the format of the CVSDiff" << endl;
+
+ QRegExp normalRE ( "[0-9]+[0-9,]*[acd][0-9]+[0-9,]*" );
+ QRegExp unifiedRE( "^--- [^\\t]+\\t" );
+ QRegExp contextRE( "^\\*\\*\\* [^\\t]+\\t" );
+ QRegExp rcsRE ( "^[acd][0-9]+ [0-9]+" );
+ QRegExp edRE ( "^[0-9]+[0-9,]*[acd]" );
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ if( (*it).find( normalRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from a RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ else if( (*it).find( edRE, 0 ) == 0 )
+ {
+// kdDebug(8101) << "Difflines are from an ED diff..." << endl;
+ return Kompare::Ed;
+ }
+ ++it;
+ }
+// kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
+
+bool CVSDiffParser::parseNormalDiffHeader()
+{
+ kdDebug(8101) << "CVSDiffParser::parseNormalDiffHeader()" << endl;
+ bool result = false;
+
+ QStringList::ConstIterator diffEnd = m_diffLines.end();
+
+ while ( m_diffIterator != diffEnd )
+ {
+ if ( m_normalDiffHeader.exactMatch( *m_diffIterator ) )
+ {
+ kdDebug(8101) << "Matched length Header = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Matched string Header = " << m_normalDiffHeader.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceFile ( m_normalDiffHeader.cap( 1 ) );
+ m_currentModel->setDestinationFile ( m_normalDiffHeader.cap( 1 ) );
+
+ result = true;
+
+ ++m_diffIterator;
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "No match for: " << ( *m_diffIterator ) << endl;
+ }
+ ++m_diffIterator;
+ }
+
+ if ( result == false )
+ {
+ // Set this to the first line again and hope it is a single file diff
+ m_diffIterator = m_diffLines.begin();
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_singleFileDiff = true;
+ }
+
+ return result;
+}
+
+
+bool CVSDiffParser::parseEdDiffHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseEdHunkHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSHunkHeader()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseEdHunkBody()
+{
+ return false;
+}
+
+bool CVSDiffParser::parseRCSHunkBody()
+{
+ return false;
+}
+
diff --git a/kompare/libdiff2/cvsdiffparser.h b/kompare/libdiff2/cvsdiffparser.h
new file mode 100644
index 00000000..88fef485
--- /dev/null
+++ b/kompare/libdiff2/cvsdiffparser.h
@@ -0,0 +1,61 @@
+/**************************************************************************
+** cvsdiffparser.h
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 _CVSDIFF_PARSER_H
+#define _CVSDIFF_PARSER_H
+
+#include <qregexp.h>
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class KompareModelList;
+
+class CVSDiffParser : public ParserBase
+{
+public:
+ CVSDiffParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~CVSDiffParser();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+
+protected:
+// virtual bool parseContextDiffHeader();
+ virtual bool parseEdDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+// virtual bool parseUnifiedDiffHeader();
+
+// virtual bool parseContextHunkHeader();
+ virtual bool parseEdHunkHeader();
+// virtual bool parseNormalHunkHeader();
+ virtual bool parseRCSHunkHeader();
+// virtual bool parseUnifiedHunkHeader();
+
+// virtual bool parseContextHunkBody();
+ virtual bool parseEdHunkBody();
+// virtual bool parseNormalHunkBody();
+ virtual bool parseRCSHunkBody();
+// virtual bool parseUnifiedHunkBody();
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/difference.cpp b/kompare/libdiff2/difference.cpp
new file mode 100644
index 00000000..8cbb4093
--- /dev/null
+++ b/kompare/libdiff2/difference.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+ difference.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@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.
+**
+***************************************************************************/
+
+#include "difference.h"
+#include "levenshteintable.h"
+
+using namespace Diff2;
+
+Difference::Difference( int sourceLineNo, int destinationLineNo, int type ) :
+ m_type( type ),
+ m_sourceLineNo( sourceLineNo ),
+ m_destinationLineNo( destinationLineNo ),
+ m_applied( false )
+{
+}
+
+Difference::~Difference()
+{
+}
+
+void Difference::addSourceLine( QString line )
+{
+ m_sourceLines.append( new DifferenceString( line ) );
+}
+
+void Difference::addDestinationLine( QString line )
+{
+ m_destinationLines.append( new DifferenceString( line ) );
+}
+
+int Difference::sourceLineCount() const
+{
+ return m_sourceLines.count();
+}
+
+int Difference::destinationLineCount() const
+{
+ return m_destinationLines.count();
+}
+
+void Difference::apply( bool apply )
+{
+ m_applied = apply;
+}
+
+void Difference::determineInlineDifferences()
+{
+ LevenshteinTable table;
+ if ( m_type != Difference::Change )
+ return;
+
+ // Do nothing for now when the slc != dlc
+ // One could try to find the closest matching destination string for any
+ // of the source strings but this is compute intensive
+ if ( sourceLineCount() != destinationLineCount() )
+ return;
+
+ int slc = sourceLineCount();
+
+ for ( int i = 0; i < slc; ++i )
+ {
+ DifferenceString* sl = sourceLineAt( i );
+ DifferenceString* dl = destinationLineAt( i );
+
+ // FIXME: If the table cant be created dont do the rest
+ table.createTable( sl, dl );
+
+ table.createListsOfMarkers();
+ }
+}
+
+QString Difference::recreateDifference() const
+{
+ QString difference;
+
+ // source
+ DifferenceStringListConstIterator stringIt = m_sourceLines.begin();
+ DifferenceStringListConstIterator sEnd = m_sourceLines.end();
+
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ switch ( m_type )
+ {
+ case Change:
+ case Delete:
+ difference += "-";
+ break;
+ default:
+ // Insert but this is not possible in source
+ // Unchanged will be handled in destination
+ // since they are the same
+// kdDebug( 8101 ) << "Go away, nothing to do for you in source..." << endl;
+ continue;
+ }
+ difference += (*stringIt)->string();
+ }
+
+ //destination
+ stringIt = m_destinationLines.begin();
+ sEnd = m_destinationLines.end();
+
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ switch ( m_type )
+ {
+ case Change:
+ case Insert:
+ difference += "+";
+ break;
+ case Unchanged:
+ difference += " ";
+ break;
+ default: // Delete but this is not possible in destination
+// kdDebug( 8101 ) << "Go away, nothing to do for you in destination..." << endl;
+ continue;
+ }
+ difference += (*stringIt)->string();
+ }
+
+ return difference;
+}
diff --git a/kompare/libdiff2/difference.h b/kompare/libdiff2/difference.h
new file mode 100644
index 00000000..91065891
--- /dev/null
+++ b/kompare/libdiff2/difference.h
@@ -0,0 +1,223 @@
+/***************************************************************************
+ difference.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+#ifndef DIFFERENCE_H
+#define DIFFERENCE_H
+
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+
+#include <kdebug.h>
+
+class QString;
+
+namespace Diff2
+{
+
+class LevenshteinTable;
+
+class Marker
+{
+public:
+ enum Type { Start = 0, End = 1 };
+
+public:
+ Marker()
+ {
+ m_type = Marker::Start;
+ m_offset = 0;
+ }
+ Marker( enum Marker::Type type, unsigned int offset )
+ {
+ m_type = type;
+ m_offset = offset;
+ }
+ ~Marker() {}
+
+public:
+ enum Marker::Type type() const { return m_type; }
+ unsigned int offset() const { return m_offset; }
+
+ void setType ( enum Marker::Type type ) { m_type = type; }
+ void setOffset( unsigned int offset ) { m_offset = offset; }
+
+private:
+ enum Marker::Type m_type;
+ unsigned int m_offset;
+};
+
+typedef QValueList<Marker*> MarkerList;
+typedef QValueList<Marker*>::iterator MarkerListIterator;
+typedef QValueList<Marker*>::const_iterator MarkerListConstIterator;
+
+class DifferenceString
+{
+public:
+ DifferenceString()
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString()" << endl;
+ }
+ DifferenceString( const QString& string, const MarkerList& markerList = MarkerList() ) :
+ m_string( string ),
+ m_markerList( markerList )
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString( " << string << ", " << markerList << " )" << endl;
+ calculateHash();
+ }
+ DifferenceString( const DifferenceString& ds ) :
+ m_string( ds.m_string ),
+ m_conflict( ds.m_conflict ),
+ m_hash( ds.m_hash ),
+ m_markerList( ds.m_markerList )
+ {
+// kdDebug(8101) << "DifferenceString::DifferenceString( const DifferenceString& " << ds << " )" << endl;
+ }
+ ~DifferenceString() {}
+
+public:
+ const QString& string() const
+ {
+ return m_string;
+ }
+ const QString& conflictString() const
+ {
+ return m_conflict;
+ }
+ const MarkerList& markerList()
+ {
+ return m_markerList;
+ }
+ void setString( const QString& string )
+ {
+ m_string = string;
+ calculateHash();
+ }
+ void setConflictString( const QString& conflict )
+ {
+ m_conflict = conflict;
+ }
+ void setMarkerList( const MarkerList& markerList )
+ {
+ m_markerList = markerList;
+ }
+ void prepend( Marker* marker )
+ {
+ m_markerList.prepend( marker );
+ }
+ bool operator==( const DifferenceString& ks )
+ {
+ if ( m_hash != ks.m_hash )
+ return false;
+ return m_string == ks.m_string;
+ }
+
+protected:
+ void calculateHash()
+ {
+ unsigned short const* str = reinterpret_cast<unsigned short const*>( m_string.unicode() );
+ const unsigned int len = m_string.length();
+
+ m_hash = 1315423911;
+
+ for ( unsigned int i = 0; i < len; i++ )
+ {
+ m_hash ^= ( m_hash << 5 ) + str[i] + ( m_hash >> 2 );
+ }
+ }
+
+private:
+ QString m_string;
+ QString m_conflict;
+ unsigned int m_hash;
+ MarkerList m_markerList;
+};
+
+typedef QValueVector<DifferenceString*> DifferenceStringList;
+typedef QValueVector<DifferenceString*>::iterator DifferenceStringListIterator;
+typedef QValueVector<DifferenceString*>::const_iterator DifferenceStringListConstIterator;
+
+class Difference
+{
+public:
+ enum Type { Change, Insert, Delete, Unchanged };
+
+public:
+ Difference( int sourceLineNo, int destinationLineNo, int type = Difference::Unchanged );
+ ~Difference();
+
+public:
+ int type() const { return m_type; };
+
+ int sourceLineNumber() const { return m_sourceLineNo; }
+ int destinationLineNumber() const { return m_destinationLineNo; }
+
+ int sourceLineCount() const;
+ int destinationLineCount() const;
+
+ DifferenceString* sourceLineAt( int i ) { return m_sourceLines[ i ]; }
+ DifferenceString* destinationLineAt( int i ) { return m_destinationLines[ i ]; }
+
+ const DifferenceStringList sourceLines() const { return m_sourceLines; }
+ const DifferenceStringList destinationLines() const { return m_destinationLines; }
+
+ bool hasConflict() const
+ {
+ return m_conflicts;
+ }
+ void setConflict( bool conflicts )
+ {
+ m_conflicts = conflicts;
+ }
+
+ void apply( bool apply );
+ bool applied() const { return m_applied; }
+
+ void setType( int type ) { m_type = type; }
+
+ void addSourceLine( QString line );
+ void addDestinationLine( QString line );
+
+ /** This method will calculate the differences between the individual strings and store them as Markers */
+ void determineInlineDifferences();
+
+ QString recreateDifference() const;
+
+private:
+ int m_type;
+
+ int m_sourceLineNo;
+ int m_destinationLineNo;
+
+ DifferenceStringList m_sourceLines;
+ DifferenceStringList m_destinationLines;
+
+ bool m_applied;
+ bool m_conflicts;
+
+ LevenshteinTable* m_tableXXX; // now unused
+};
+
+typedef QValueList<Difference*> DifferenceList;
+typedef QValueList<Difference*>::iterator DifferenceListIterator;
+typedef QValueList<Difference*>::const_iterator DifferenceListConstIterator;
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/diffhunk.cpp b/kompare/libdiff2/diffhunk.cpp
new file mode 100644
index 00000000..f980dd93
--- /dev/null
+++ b/kompare/libdiff2/diffhunk.cpp
@@ -0,0 +1,115 @@
+/***************************************************************************
+ diffhunk.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@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.
+**
+***************************************************************************/
+
+
+#include "difference.h"
+#include "diffhunk.h"
+
+using namespace Diff2;
+
+DiffHunk::DiffHunk( int sourceLine, int destinationLine, QString function, Type type ) :
+ m_sourceLine( sourceLine ),
+ m_destinationLine( destinationLine ),
+ m_function( function ),
+ m_type( type )
+{
+}
+
+DiffHunk::~DiffHunk()
+{
+}
+
+void DiffHunk::add( Difference* diff )
+{
+ m_differences.append( diff );
+}
+
+int DiffHunk::sourceLineCount() const
+{
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int lineCount = 0;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ lineCount += (*diffIt)->sourceLineCount();
+
+ return lineCount;
+}
+
+int DiffHunk::destinationLineCount() const
+{
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int lineCount = 0;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ lineCount += (*diffIt)->destinationLineCount();
+
+ return lineCount;
+}
+
+QString DiffHunk::recreateHunk() const
+{
+ QString hunk;
+ QString differences;
+
+ // recreate body
+ DifferenceListConstIterator diffIt = m_differences.begin();
+ DifferenceListConstIterator dEnd = m_differences.end();
+
+ int slc = 0; // source line count
+ int dlc = 0; // destination line count
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ switch ( (*diffIt)->type() )
+ {
+ case Difference::Unchanged:
+ case Difference::Change:
+ slc += (*diffIt)->sourceLineCount();
+ dlc += (*diffIt)->destinationLineCount();
+ break;
+ case Difference::Insert:
+ dlc += (*diffIt)->destinationLineCount();
+ break;
+ case Difference::Delete:
+ slc += (*diffIt)->sourceLineCount();
+ break;
+ }
+ differences += (*diffIt)->recreateDifference();
+ }
+
+ // recreate header
+ hunk += QString::fromLatin1( "@@ -%1,%3 +%2,%4 @@" )
+ .arg( m_sourceLine )
+ .arg( m_destinationLine )
+ .arg( slc )
+ .arg( dlc );
+
+ if ( !m_function.isEmpty() )
+ hunk += " " + m_function;
+
+ hunk += QString::fromLatin1( "\n" );
+
+ hunk += differences;
+
+ kdDebug( 8101 ) << hunk << endl;
+ return hunk;
+}
diff --git a/kompare/libdiff2/diffhunk.h b/kompare/libdiff2/diffhunk.h
new file mode 100644
index 00000000..8a76babb
--- /dev/null
+++ b/kompare/libdiff2/diffhunk.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ diffhunk.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+#ifndef DIFFHUNK_H
+#define DIFFHUNK_H
+
+#include "difference.h"
+
+namespace Diff2
+{
+
+class Difference;
+
+class DiffHunk
+{
+public:
+ enum Type { Normal, AddedByBlend };
+
+public:
+ DiffHunk( int sourceLine, int destinationLine, QString function = QString::null, Type type = Normal );
+ ~DiffHunk();
+
+ const DifferenceList& differences() const { return m_differences; };
+ const QString& function() const { return m_function; };
+
+ int sourceLineNumber() const { return m_sourceLine; };
+ int destinationLineNumber() const { return m_destinationLine; };
+
+ int sourceLineCount() const;
+ int destinationLineCount() const;
+
+ const Type type() const { return m_type; }
+ void setType( Type type ) { m_type = type; }
+
+ void add( Difference* diff );
+
+ QString recreateHunk() const;
+
+private:
+ int m_sourceLine;
+ int m_destinationLine;
+ DifferenceList m_differences;
+ QString m_function;
+ Type m_type;
+};
+
+typedef QValueList<DiffHunk*> DiffHunkList;
+typedef QValueList<DiffHunk*>::iterator DiffHunkListIterator;
+typedef QValueList<DiffHunk*>::const_iterator DiffHunkListConstIterator;
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/diffmodel.cpp b/kompare/libdiff2/diffmodel.cpp
new file mode 100644
index 00000000..54c33457
--- /dev/null
+++ b/kompare/libdiff2/diffmodel.cpp
@@ -0,0 +1,409 @@
+/***************************************************************************
+ diffmodel.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@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.
+**
+***************************************************************************/
+
+#include <qregexp.h>
+#include <qvaluelist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "difference.h"
+#include "diffhunk.h"
+#include "diffmodel.h"
+
+using namespace Diff2;
+
+/** */
+DiffModel::DiffModel( const QString& source, const QString& destination ) :
+ m_source( source ),
+ m_destination( destination ),
+ m_sourcePath( "" ),
+ m_destinationPath( "" ),
+ m_sourceFile( "" ),
+ m_destinationFile( "" ),
+ m_sourceTimestamp( "" ),
+ m_destinationTimestamp( "" ),
+ m_sourceRevision( "" ),
+ m_destinationRevision( "" ),
+ m_appliedCount( 0 ),
+ m_modified( false ),
+ m_diffIndex( 0 ),
+ m_selectedDifference( 0 ),
+ m_blended( false )
+{
+ splitSourceInPathAndFileName();
+ splitDestinationInPathAndFileName();
+}
+
+DiffModel::DiffModel() :
+ m_source( "" ),
+ m_destination( "" ),
+ m_sourcePath( "" ),
+ m_destinationPath( "" ),
+ m_sourceFile( "" ),
+ m_destinationFile( "" ),
+ m_sourceTimestamp( "" ),
+ m_destinationTimestamp( "" ),
+ m_sourceRevision( "" ),
+ m_destinationRevision( "" ),
+ m_appliedCount( 0 ),
+ m_modified( false ),
+ m_diffIndex( 0 ),
+ m_selectedDifference( 0 ),
+ m_blended( false )
+{
+}
+
+/** */
+DiffModel::~DiffModel()
+{
+}
+
+void DiffModel::splitSourceInPathAndFileName()
+{
+ int pos;
+
+ if( ( pos = m_source.findRev( "/" ) ) >= 0 )
+ m_sourcePath = m_source.mid( 0, pos+1 );
+
+ if( ( pos = m_source.findRev( "/" ) ) >= 0 )
+ m_sourceFile = m_source.mid( pos+1, m_source.length() - pos );
+ else
+ m_sourceFile = m_source;
+
+ kdDebug(8101) << m_source << " was split into " << m_sourcePath << " and " << m_sourceFile << endl;
+}
+
+void DiffModel::splitDestinationInPathAndFileName()
+{
+ int pos;
+
+ if( ( pos = m_destination.findRev( "/" ) )>= 0 )
+ m_destinationPath = m_destination.mid( 0, pos+1 );
+
+ if( ( pos = m_destination.findRev( "/" ) ) >= 0 )
+ m_destinationFile = m_destination.mid( pos+1, m_destination.length() - pos );
+ else
+ m_destinationFile = m_source;
+
+ kdDebug(8101) << m_destination << " was split into " << m_destinationPath << " and " << m_destinationFile << endl;
+}
+
+DiffModel& DiffModel::operator=( const DiffModel& model )
+{
+ if ( &model != this ) // Guard from self-assignment
+ {
+ m_source = model.m_source;
+ m_destination = model.m_destination;
+ m_sourcePath = model.m_sourcePath;
+ m_sourceFile = model.m_sourceFile;
+ m_sourceTimestamp = model.m_sourceTimestamp;
+ m_sourceRevision = model.m_sourceRevision;
+ m_destinationPath = model.m_destinationPath;
+ m_destinationFile = model.m_destinationFile;
+ m_destinationTimestamp = model.m_destinationTimestamp;
+ m_destinationRevision = model.m_destinationRevision;
+ m_appliedCount = model.m_appliedCount;
+ m_modified = model.m_modified;
+
+ m_diffIndex = model.m_diffIndex;
+ m_selectedDifference = model.m_selectedDifference;
+ }
+
+ return *this;
+}
+
+bool DiffModel::operator<( const DiffModel& model )
+{
+ if ( localeAwareCompareSource( model ) < 0 )
+ return true;
+ return false;
+}
+
+int DiffModel::localeAwareCompareSource( const DiffModel& model )
+{
+ int result = m_sourcePath.localeAwareCompare( model.m_sourcePath );
+
+ if ( result == 0 )
+ return m_sourceFile.localeAwareCompare( model.m_sourceFile );
+
+ return result;
+}
+
+QString DiffModel::recreateDiff() const
+{
+ // For now we'll always return a diff in the diff format
+ QString diff;
+
+ // recreate header
+ QString tab = QString::fromLatin1( "\t" );
+ QString nl = QString::fromLatin1( "\n" );
+ diff += QString::fromLatin1( "--- %1\t%2" ).arg( m_source ).arg( m_sourceTimestamp );
+ if ( !m_sourceRevision.isEmpty() )
+ diff += tab + m_sourceRevision;
+ diff += nl;
+ diff += QString::fromLatin1( "+++ %1\t%2" ).arg( m_destination ).arg( m_destinationTimestamp );
+ if ( !m_destinationRevision.isEmpty() )
+ diff += tab + m_destinationRevision;
+ diff += nl;
+
+ // recreate body by iterating over the hunks
+ DiffHunkListConstIterator hunkIt = m_hunks.begin();
+ DiffHunkListConstIterator hEnd = m_hunks.end();
+
+ for ( ; hunkIt != hEnd; ++hunkIt )
+ {
+ if ((*hunkIt)->type() != DiffHunk::AddedByBlend)
+ diff += (*hunkIt)->recreateHunk();
+ }
+
+ return diff;
+}
+
+DifferenceList* DiffModel::allDifferences()
+{
+ if ( m_hunks.count() != 0 )
+ {
+ DiffHunkListConstIterator hunkIt = m_hunks.begin();
+ DiffHunkListConstIterator hEnd = m_hunks.end();
+
+ for ( ; hunkIt != hEnd; ++hunkIt )
+ {
+ DiffHunk* hunk = *hunkIt;
+
+ DifferenceListConstIterator diffIt = hunk->differences().begin();
+ DifferenceListConstIterator dEnd = hunk->differences().end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ m_allDifferences.append( *diffIt );
+ }
+ }
+ return &m_allDifferences;
+ }
+ else
+ {
+ DifferenceList *diffList = new DifferenceList;
+ return diffList;
+ }
+}
+
+Difference* DiffModel::firstDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::firstDifference()" << endl;
+ m_diffIndex = 0;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+
+ m_selectedDifference = m_differences[ m_diffIndex ];
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::lastDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::lastDifference()" << endl;
+ m_diffIndex = m_differences.count() - 1;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+
+ m_selectedDifference = m_differences[ m_diffIndex ];
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::prevDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::prevDifference()" << endl;
+ if ( --m_diffIndex < m_differences.count() )
+ {
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = m_differences[ m_diffIndex ];
+ }
+ else
+ {
+ m_selectedDifference = 0;
+ m_diffIndex = 0;
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ }
+
+ return m_selectedDifference;
+}
+
+Difference* DiffModel::nextDifference()
+{
+ kdDebug( 8101 ) << "DiffModel::nextDifference()" << endl;
+ if ( ++m_diffIndex < m_differences.count() )
+ {
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = m_differences[ m_diffIndex ];
+ }
+ else
+ {
+ m_selectedDifference = 0;
+ m_diffIndex = 0; // just for safety...
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ }
+
+ return m_selectedDifference;
+}
+
+const QString DiffModel::sourceFile() const
+{
+ return m_sourceFile;
+}
+
+const QString DiffModel::destinationFile() const
+{
+ return m_destinationFile;
+}
+
+const QString DiffModel::sourcePath() const
+{
+ return m_sourcePath;
+}
+
+const QString DiffModel::destinationPath() const
+{
+ return m_destinationPath;
+}
+
+void DiffModel::setSourceFile( QString path )
+{
+ m_source = path;
+ splitSourceInPathAndFileName();
+}
+
+void DiffModel::setDestinationFile( QString path )
+{
+ m_destination = path;
+ splitDestinationInPathAndFileName();
+}
+
+void DiffModel::setSourceTimestamp( QString timestamp )
+{
+ m_sourceTimestamp = timestamp;
+}
+
+void DiffModel::setDestinationTimestamp( QString timestamp )
+{
+ m_destinationTimestamp = timestamp;
+}
+
+void DiffModel::setSourceRevision( QString revision )
+{
+ m_destinationRevision = revision;
+}
+
+void DiffModel::setDestinationRevision( QString revision )
+{
+ m_destinationRevision = revision;
+}
+
+void DiffModel::addHunk( DiffHunk* hunk )
+{
+ m_hunks.append( hunk );
+}
+
+void DiffModel::addDiff( Difference* diff )
+{
+ m_differences.append( diff );
+}
+
+void DiffModel::applyDifference( bool apply )
+{
+ if ( apply && !m_selectedDifference->applied() )
+ m_appliedCount++;
+ else if ( !apply && m_selectedDifference->applied() )
+ m_appliedCount--;
+
+ bool modified;
+
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ if ( m_appliedCount == 0 )
+ modified = false;
+ else
+ modified = true;
+
+ emit setModified( modified );
+
+ m_modified = modified;
+
+ m_selectedDifference->apply( apply );
+}
+
+void DiffModel::applyAllDifferences( bool apply )
+{
+ bool modified;
+
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ if ( apply )
+ {
+ m_appliedCount = m_differences.count();
+ modified = true;
+ }
+ else
+ {
+ m_appliedCount = 0;
+ modified = false;
+ }
+
+ emit setModified( modified );
+
+ m_modified = modified;
+
+ DifferenceListIterator diffIt = m_differences.begin();
+ DifferenceListIterator dEnd = m_differences.end();
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ (*diffIt)->apply( apply );
+ }
+}
+
+void DiffModel::slotSetModified( bool modified )
+{
+ // Not setting the m_modified yet so i can still query the current
+ // modified status from the slot that is connected to the signal
+ emit setModified( modified );
+
+ m_modified = modified;
+}
+
+bool DiffModel::setSelectedDifference( Difference* diff )
+{
+ kdDebug(8101) << "diff = " << diff << endl;
+ kdDebug(8101) << "m_selectedDifference = " << m_selectedDifference << endl;
+
+ if ( diff != m_selectedDifference )
+ {
+ if ( ( m_differences.findIndex( diff ) ) == -1 )
+ return false;
+ // Dont set m_diffIndex if it cant be found
+ m_diffIndex = m_differences.findIndex( diff );
+ kdDebug( 8101 ) << "m_diffIndex = " << m_diffIndex << endl;
+ m_selectedDifference = diff;
+ }
+
+ return true;
+}
+
+#include "diffmodel.moc"
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/kompare/libdiff2/diffmodel.h b/kompare/libdiff2/diffmodel.h
new file mode 100644
index 00000000..11c424b5
--- /dev/null
+++ b/kompare/libdiff2/diffmodel.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ diffmodel.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+#ifndef DIFFMODEL_H
+#define DIFFMODEL_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+#include "diffhunk.h"
+#include "kompare.h"
+
+namespace Diff2
+{
+
+class DiffHunk;
+class Difference;
+
+class DiffModel : public QObject
+{
+Q_OBJECT
+public:
+
+ DiffModel( const QString& srcBaseURL, const QString& destBaseURL );
+ DiffModel();
+ DiffModel( const DiffModel& ) : QObject() {};
+ ~DiffModel();
+
+ int parseDiff( enum Kompare::Format format, const QStringList& list );
+
+ QString recreateDiff() const;
+
+ int hunkCount() const { return m_hunks.count(); }
+ int differenceCount() const { return m_differences.count(); }
+ int appliedCount() const { return m_appliedCount; }
+
+ DiffHunk* hunkAt( int i ) { return *( m_hunks.at( i ) ); }
+ const Difference* differenceAt( int i ) { return *( m_differences.at( i ) ); }
+
+ DiffHunkList* hunks() { return &m_hunks; }
+ const DiffHunkList* hunks() const { return &m_hunks; }
+ DifferenceList* differences() { return &m_differences; }
+ const DifferenceList* differences() const { return &m_differences; }
+
+ DifferenceList* allDifferences();
+
+ int findDifference( Difference* diff ) const { return m_differences.findIndex( diff ); }
+
+ Difference* firstDifference();
+ Difference* lastDifference();
+ Difference* prevDifference();
+ Difference* nextDifference();
+
+ const QString source() const { return m_source; }
+ const QString destination() const { return m_destination; }
+ const QString sourceFile() const;
+ const QString destinationFile() const;
+ const QString sourcePath() const;
+ const QString destinationPath() const;
+ const QString sourceTimestamp() const { return m_sourceTimestamp; }
+ const QString destinationTimestamp() const { return m_destinationTimestamp; }
+ const QString sourceRevision() const { return m_sourceRevision; }
+ const QString destinationRevision() const { return m_destinationRevision; }
+
+ void setSourceFile( QString path );
+ void setDestinationFile( QString path );
+ void setSourceTimestamp( QString timestamp );
+ void setDestinationTimestamp( QString timestamp );
+ void setSourceRevision( QString revision );
+ void setDestinationRevision( QString revision );
+
+ void addHunk( DiffHunk* hunk );
+ void addDiff( Difference* diff );
+ bool isModified() const { return m_modified; }
+
+ const int diffIndex( void ) const { return m_diffIndex; }
+ void setDiffIndex( int diffIndex ) { m_diffIndex = diffIndex; }
+
+ void applyDifference( bool apply );
+ void applyAllDifferences( bool apply );
+
+ bool setSelectedDifference( Difference* diff );
+
+ DiffModel& operator=( const DiffModel& model );
+ bool operator<( const DiffModel& model );
+
+ int localeAwareCompareSource( const DiffModel& model );
+
+ bool isBlended() const { return m_blended; }
+ void setBlended( bool blended ) { m_blended = blended; }
+
+signals:
+ void setModified( bool modified );
+
+public slots:
+ void slotSetModified( bool modified );
+
+private:
+ void splitSourceInPathAndFileName();
+ void splitDestinationInPathAndFileName();
+
+private:
+ QString m_source;
+ QString m_destination;
+
+ QString m_sourcePath;
+ QString m_destinationPath;
+
+ QString m_sourceFile;
+ QString m_destinationFile;
+
+ QString m_sourceTimestamp;
+ QString m_destinationTimestamp;
+
+ QString m_sourceRevision;
+ QString m_destinationRevision;
+
+ DiffHunkList m_hunks;
+ DifferenceList m_differences;
+ DifferenceList m_allDifferences;
+
+ int m_appliedCount;
+ bool m_modified;
+
+ unsigned int m_diffIndex;
+ Difference* m_selectedDifference;
+
+ bool m_blended;
+};
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/diffmodellist.cpp b/kompare/libdiff2/diffmodellist.cpp
new file mode 100644
index 00000000..200e8108
--- /dev/null
+++ b/kompare/libdiff2/diffmodellist.cpp
@@ -0,0 +1,29 @@
+/*******************************************************************************
+**
+** Filename : diffmodellist.cpp
+** Created on : 26 march, 2004
+** Copyright : (c) 2004 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** 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 <kdebug.h>
+
+#include "diffmodellist.h"
+
+using namespace Diff2;
+
+void DiffModelList::sort()
+{
+ qHeapSort(*this);
+}
+
diff --git a/kompare/libdiff2/diffmodellist.h b/kompare/libdiff2/diffmodellist.h
new file mode 100644
index 00000000..9c4f9807
--- /dev/null
+++ b/kompare/libdiff2/diffmodellist.h
@@ -0,0 +1,49 @@
+/*******************************************************************************
+**
+** Filename : diffmodellist.h
+** Created on : 24 januari, 2004
+** Copyright : (c) 2004 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** 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 DIFFMODELLIST_H
+#define DIFFMODELLIST_H
+
+#include <qvaluelist.h> // include for the base class
+
+#include "diffmodel.h"
+
+namespace Diff2
+{
+
+typedef QValueListIterator<DiffModel*> DiffModelListIterator;
+typedef QValueListConstIterator<DiffModel*> DiffModelListConstIterator;
+
+class DiffModelList : public QValueList<DiffModel*>
+{
+public:
+ DiffModelList() {}
+ DiffModelList( const DiffModelList &list ) : QValueList<DiffModel*>( list ) {}
+ virtual ~DiffModelList()
+ {
+ clear();
+ }
+
+public:
+ virtual void sort();
+
+}; // End of class DiffModelList
+
+} // End of Namespace Diff2
+
+#endif // DIFFMODELLIST_H
diff --git a/kompare/libdiff2/diffparser.cpp b/kompare/libdiff2/diffparser.cpp
new file mode 100644
index 00000000..f98fbde5
--- /dev/null
+++ b/kompare/libdiff2/diffparser.cpp
@@ -0,0 +1,81 @@
+/**************************************************************************
+** diffparser.cpp
+** --------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** ( at your option ) any later version.
+**
+***************************************************************************/
+
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include "diffparser.h"
+
+using namespace Diff2;
+
+DiffParser::DiffParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ // The regexps needed for context diff parsing, the rest is the same as in parserbase.cpp
+ m_contextDiffHeader1.setPattern( "\\*\\*\\* ([^\\t]+)\\t([^\\t]+)\\n" );
+ m_contextDiffHeader2.setPattern( "--- ([^\\t]+)\\t([^\\t]+)\\n" );
+}
+
+DiffParser::~DiffParser()
+{
+}
+
+enum Kompare::Format DiffParser::determineFormat()
+{
+ kdDebug(8101) << "Determining the format of the diff Diff" << endl;
+
+ QRegExp normalRE ( "[0-9]+[0-9,]*[acd][0-9]+[0-9,]*" );
+ QRegExp unifiedRE( "^--- " );
+ QRegExp contextRE( "^\\*\\*\\* " );
+ QRegExp rcsRE ( "^[acd][0-9]+ [0-9]+" );
+ QRegExp edRE ( "^[0-9]+[0-9,]*[acd]" );
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ kdDebug(8101) << (*it) << endl;
+ if( (*it).find( normalRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from an RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ else if( (*it).find( edRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from an ED diff..." << endl;
+ return Kompare::Ed;
+ }
+ ++it;
+ }
+ kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
diff --git a/kompare/libdiff2/diffparser.h b/kompare/libdiff2/diffparser.h
new file mode 100644
index 00000000..72905e3f
--- /dev/null
+++ b/kompare/libdiff2/diffparser.h
@@ -0,0 +1,38 @@
+/**************************************************************************
+** diffparser.h
+** -----------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 _DIFF_PARSER_H
+#define _DIFF_PARSER_H
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class DiffParser : public ParserBase
+{
+public:
+ DiffParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~DiffParser();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/kompare.h b/kompare/libdiff2/kompare.h
new file mode 100644
index 00000000..1ed5c4c7
--- /dev/null
+++ b/kompare/libdiff2/kompare.h
@@ -0,0 +1,144 @@
+/***************************************************************************
+ kompare.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+#ifndef KOMPARE_H
+#define KOMPARE_H
+
+#include <kurl.h>
+
+namespace Kompare
+{
+ enum Format {
+ Context = 0,
+ Ed = 1,
+ Normal = 2,
+ RCS = 3,
+ Unified = 4,
+ SideBySide = 5,
+ UnknownFormat = -1
+ };
+
+ enum Generator {
+ CVSDiff = 0,
+ Diff = 1,
+ Perforce = 2,
+ SubVersion = 3,
+ Reserved2 = 4,
+ Reserved3 = 5,
+ Reserved4 = 6,
+ Reserved5 = 7,
+ Reserved6 = 8,
+ Reserved7 = 9,
+ UnknownGenerator = -1
+ };
+
+ enum Mode {
+ ComparingFiles, // compareFiles
+ ComparingDirs, // compareDirs
+ ShowingDiff, // openDiff
+ BlendingDir, // openDirAnfDiff
+ BlendingFile, // openFileAndDiff
+ UnknownMode // Used to initialize the Infoi struct
+ };
+
+ enum DiffMode {
+ Default,
+ Custom,
+ UnknownDiffMode // Use to initialize the Info struct
+ };
+
+ enum Status {
+ RunningDiff,
+ Parsing,
+ FinishedParsing,
+ FinishedWritingDiff,
+ ReRunningDiff // When a change has been detected after diff has run
+ };
+
+ enum Target {
+ Source,
+ Destination
+ };
+
+ struct Info {
+ Info (
+ enum Mode _mode = UnknownMode,
+ enum DiffMode _diffMode = UnknownDiffMode,
+ enum Format _format = UnknownFormat,
+ enum Generator _generator = UnknownGenerator,
+ KURL _source = KURL(),
+ KURL _destination = KURL(),
+ QString _localSource = "",
+ QString _localDestination = ""
+ )
+ {
+ mode = _mode;
+ diffMode = _diffMode;
+ format = _format;
+ generator = _generator;
+ source = _source;
+ destination = _destination;
+ localSource = _localSource;
+ localDestination = _localDestination;
+ }
+ enum Mode mode;
+ enum DiffMode diffMode;
+ enum Format format;
+ enum Generator generator;
+ KURL source;
+ KURL destination;
+ QString localSource;
+ QString localDestination;
+ };
+} // End of namespace Kompare
+
+/*
+** This should be removed and put somewhere else
+*/
+class KompareFunctions
+{
+public:
+ static QString constructRelativePath( const QString& from, const QString& to )
+ {
+ KURL fromURL( from );
+ KURL toURL( to );
+ KURL root;
+ int upLevels = 0;
+
+ // Find a common root.
+ root = from;
+ while( root.isValid() && !root.isParentOf( toURL ) ) {
+ root = root.upURL();
+ upLevels++;
+ }
+
+ if( !root.isValid() ) return to;
+
+ QString relative;
+ for( ; upLevels > 0; upLevels-- ) {
+ relative += "../";
+ }
+
+ relative += QString( to ).replace( 0, root.path(1).length(), "" );
+
+ return relative;
+ }
+};
+
+#endif
diff --git a/kompare/libdiff2/komparemodellist.cpp b/kompare/libdiff2/komparemodellist.cpp
new file mode 100644
index 00000000..ac3c725a
--- /dev/null
+++ b/kompare/libdiff2/komparemodellist.cpp
@@ -0,0 +1,1423 @@
+/***************************************************************************
+ komparemodellist.cpp - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2004 Otto Bruggeman
+ (C) 2001-2003 John Firebaugh
+ (C) 2007 Kevin Kofler
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ kevin.kofler@chello.at
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <qfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+#include <qvaluelist.h>
+
+#include <kaction.h>
+#include <kcharsets.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <ktempfile.h>
+
+#include "difference.h"
+#include "diffhunk.h"
+#include "diffmodel.h"
+#include "diffmodellist.h"
+#include "kompareprocess.h"
+#include "komparemodellist.h"
+#include "parser.h"
+
+#include "kompare_part.h"
+
+using namespace Diff2;
+
+KompareModelList::KompareModelList( DiffSettings* diffSettings, struct Kompare::Info& info, QObject* parent, const char* name )
+ : QObject( parent, name ),
+ m_diffProcess( 0 ),
+ m_diffSettings( diffSettings ),
+ m_models( 0 ),
+ m_selectedModel( 0 ),
+ m_selectedDifference( 0 ),
+ m_noOfModified( 0 ),
+ m_modelIndex( 0 ),
+ m_info( info ),
+ m_textCodec( 0 )
+{
+ m_applyDifference = new KAction( i18n("&Apply Difference"), "1rightarrow", Qt::Key_Space,
+ this, SLOT(slotActionApplyDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_apply" );
+ m_unApplyDifference = new KAction( i18n("Un&apply Difference"), "1leftarrow", Qt::Key_BackSpace,
+ this, SLOT(slotActionUnApplyDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_unapply" );
+ m_applyAll = new KAction( i18n("App&ly All"), "2rightarrow", Qt::CTRL + Qt::Key_A,
+ this, SLOT(slotActionApplyAllDifferences()),
+ (( KomparePart* )parent)->actionCollection(), "difference_applyall" );
+ m_unapplyAll = new KAction( i18n("&Unapply All"), "2leftarrow", Qt::CTRL + Qt::Key_U,
+ this, SLOT(slotActionUnapplyAllDifferences()),
+ (( KomparePart* )parent)->actionCollection(), "difference_unapplyall" );
+ m_previousFile = new KAction( i18n("P&revious File"), "2uparrow", Qt::CTRL + Qt::Key_PageUp,
+ this, SLOT(slotPreviousModel()),
+ (( KomparePart* )parent)->actionCollection(), "difference_previousfile" );
+ m_nextFile = new KAction( i18n("N&ext File"), "2downarrow", Qt::CTRL + Qt::Key_PageDown,
+ this, SLOT(slotNextModel()),
+ (( KomparePart* )parent)->actionCollection(), "difference_nextfile" );
+ m_previousDifference = new KAction( i18n("&Previous Difference"), "1uparrow", Qt::CTRL + Qt::Key_Up,
+ this, SLOT(slotPreviousDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_previous" );
+ m_nextDifference = new KAction( i18n("&Next Difference"), "1downarrow", Qt::CTRL + Qt::Key_Down,
+ this, SLOT(slotNextDifference()),
+ (( KomparePart* )parent)->actionCollection(), "difference_next" );
+ m_previousDifference->setEnabled( false );
+ m_nextDifference->setEnabled( false );
+
+ m_save = KStdAction::save( this, SLOT(slotSaveDestination()), ((KomparePart*)parent)->actionCollection() );
+ m_save->setEnabled( false );
+
+ updateModelListActions();
+}
+
+KompareModelList::~KompareModelList()
+{
+}
+
+bool KompareModelList::isDirectory( const QString& url ) const
+{
+ QFileInfo fi( url );
+ if ( fi.isDir() )
+ return true;
+ else
+ return false;
+}
+
+bool KompareModelList::isDiff( const QString& mimeType ) const
+{
+ if ( mimeType == "text/x-diff" )
+ return true;
+ else
+ return false;
+}
+
+bool KompareModelList::compare( const QString& source, const QString& destination )
+{
+ bool result = false;
+
+ bool sourceIsDirectory = isDirectory( source );
+ bool destinationIsDirectory = isDirectory( source );
+
+ if ( sourceIsDirectory && destinationIsDirectory )
+ {
+ m_info.mode = Kompare::ComparingDirs;
+ result = compareDirs( source, destination );
+ }
+ else if ( !sourceIsDirectory && !destinationIsDirectory )
+ {
+ QFile sourceFile( source );
+ sourceFile.open( IO_ReadOnly );
+ QString sourceMimeType = ( KMimeType::findByContent( sourceFile.readAll() ) )->name();
+ sourceFile.close();
+ kdDebug(8101) << "Mimetype source : " << sourceMimeType << endl;
+
+ QFile destinationFile( destination );
+ destinationFile.open( IO_ReadOnly );
+ QString destinationMimeType = ( KMimeType::findByContent( destinationFile.readAll() ) )->name();
+ destinationFile.close();
+ kdDebug(8101) << "Mimetype destination: " << destinationMimeType << endl;
+
+ // Not checking if it is a text file/something diff can even compare, we'll let diff handle that
+ if ( !isDiff( sourceMimeType ) && isDiff( destinationMimeType ) )
+ {
+ kdDebug(8101) << "Blending destination into source..." << endl;
+ m_info.mode = Kompare::BlendingFile;
+ result = openFileAndDiff( source, destination );
+ }
+ else if ( isDiff( sourceMimeType ) && !isDiff( destinationMimeType ) )
+ {
+ kdDebug(8101) << "Blending source into destination..." << endl;
+ m_info.mode = Kompare::BlendingFile;
+ result = openFileAndDiff( destination, source );
+ }
+ else
+ {
+ kdDebug(8101) << "Comparing source with destination" << endl;
+ m_info.mode = Kompare::ComparingFiles;
+ result = compareFiles( source, destination );
+ }
+ }
+ else if ( sourceIsDirectory && !destinationIsDirectory )
+ {
+ m_info.mode = Kompare::BlendingDir;
+ result = openDirAndDiff( source, destination );
+ }
+ else
+ {
+ m_info.mode = Kompare::BlendingDir;
+ result = openDirAndDiff( destination, source );
+ }
+
+ return result;
+}
+
+bool KompareModelList::compareFiles( const QString& source, const QString& destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ clear(); // Destroy the old models...
+
+// m_fileWatch = new KDirWatch( this, "filewatch" );
+// m_fileWatch->addFile( m_source );
+// m_fileWatch->addFile( m_destination );
+
+// connect( m_fileWatch, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+// connect( m_fileWatch, SIGNAL( created( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+// connect( m_fileWatch, SIGNAL( deleted( const QString& ) ), this, SLOT( slotFileChanged( const QString& ) ) );
+
+// m_fileWatch->startScan();
+ m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotDiffProcessFinished( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ m_diffProcess->start();
+
+ return true;
+}
+
+bool KompareModelList::compareDirs( const QString& source, const QString& destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ clear(); // Destroy the old models...
+
+// m_dirWatch = new KDirWatch( this, "dirwatch" );
+ // Watch files in the dirs and watch the dirs recursively
+// m_dirWatch->addDir( m_source, true, true );
+// m_dirWatch->addDir( m_destination, true, true );
+
+// connect( m_dirWatch, SIGNAL( dirty ( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+// connect( m_dirWatch, SIGNAL( created( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+// connect( m_dirWatch, SIGNAL( deleted( const QString& ) ), this, SLOT( slotDirectoryChanged( const QString& ) ) );
+
+// m_dirWatch->startScan();
+ m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotDiffProcessFinished( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ m_diffProcess->start();
+
+ return true;
+}
+
+bool KompareModelList::openFileAndDiff( const QString& file, const QString& diff )
+{
+ clear();
+
+ if ( parseDiffOutput( readFile( diff ) ) != 0 )
+ {
+ emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
+ return false;
+ }
+
+ // Do our thing :)
+ if ( !blendOriginalIntoModelList( file ) )
+ {
+ kdDebug(8101) << "Oops cant blend original file into modellist : " << file << endl;
+ emit( i18n( "<qt>There were problems applying the diff <b>%1</b> to the file <b>%2</b>.</qt>" ).arg( diff ).arg( file ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ return true;
+}
+
+bool KompareModelList::openDirAndDiff( const QString& dir, const QString& diff )
+{
+ clear();
+
+ if ( parseDiffOutput( readFile( diff ) ) != 0 )
+ {
+ emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
+ return false;
+ }
+
+ // Do our thing :)
+ if ( !blendOriginalIntoModelList( dir ) )
+ {
+ // Trouble blending the original into the model
+ kdDebug(8101) << "Oops cant blend original dir into modellist : " << dir << endl;
+ emit error( i18n( "<qt>There were problems applying the diff <b>%1</b> to the folder <b>%2</b>.</qt>" ).arg( diff ).arg( dir ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ return true;
+}
+
+void KompareModelList::slotSaveDestination()
+{
+ if ( m_selectedModel )
+ {
+ saveDestination( m_selectedModel );
+ }
+}
+
+bool KompareModelList::saveDestination( DiffModel* model )
+{
+ kdDebug() << "KompareModelList::saveDestination: " << endl;
+
+ if( !model->isModified() )
+ return true;
+
+ KTempFile* temp = new KTempFile();
+
+ if( temp->status() != 0 ) {
+ emit error( i18n( "Could not open a temporary file." ) );
+ temp->unlink();
+ delete temp;
+ return false;
+ }
+
+ QTextStream* stream = temp->textStream();
+ QStringList list;
+
+ DiffHunkListConstIterator hunkIt = model->hunks()->begin();
+ DiffHunkListConstIterator hEnd = model->hunks()->end();
+
+ for( ; hunkIt != hEnd; ++hunkIt )
+ {
+ DiffHunk* hunk = *hunkIt;
+
+ DifferenceListConstIterator diffIt = hunk->differences().begin();
+ DifferenceListConstIterator dEnd = hunk->differences().end();
+
+ Difference* diff;
+ for( ; diffIt != dEnd; ++diffIt )
+ {
+ diff = *diffIt;
+ if( !diff->applied() )
+ {
+ DifferenceStringListConstIterator stringIt = diff->destinationLines().begin();
+ DifferenceStringListConstIterator sEnd = diff->destinationLines().end();
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ list.append( ( *stringIt )->string() );
+ }
+ }
+ else
+ {
+ DifferenceStringListConstIterator stringIt = diff->sourceLines().begin();
+ DifferenceStringListConstIterator sEnd = diff->sourceLines().end();
+ for ( ; stringIt != sEnd; ++stringIt )
+ {
+ list.append( ( *stringIt )->string() );
+ }
+ }
+ }
+ }
+
+ // kdDebug( 8101 ) << "Everything: " << endl << list.join( "\n" ) << endl;
+
+ if( list.count() > 0 )
+ *stream << list.join( "" );
+
+ temp->close();
+ if( temp->status() != 0 ) {
+ emit error( i18n( "<qt>Could not write to the temporary file <b>%1</b>, deleting it.</qt>" ).arg( temp->name() ) );
+ temp->unlink();
+ delete temp;
+ return false;
+ }
+
+ bool result = false;
+
+ if ( m_info.mode == Kompare::ComparingDirs )
+ {
+ QString destination = model->destinationPath() + model->destinationFile();
+ kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
+ kdDebug(8101) << "DestinationURL : " << destination << endl;
+ KIO::UDSEntry entry;
+ if ( !KIO::NetAccess::stat( KURL( destination ).path(), entry, (QWidget*)parent() ) )
+ {
+ if ( !KIO::NetAccess::mkdir( KURL( destination ).path(), (QWidget*)parent() ) )
+ {
+ emit error( i18n( "<qt>Could not create destination directory <b>%1</b>.\nThe file has not been saved.</qt>" ) );
+ return false;
+ }
+ }
+ result = KIO::NetAccess::upload( temp->name(), KURL( destination ), (QWidget*)parent() );
+ }
+ else
+ {
+ kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
+ kdDebug(8101) << "DestinationURL : " << m_destination << endl;
+ result = KIO::NetAccess::upload( temp->name(), KURL( m_destination ), (QWidget*)parent() );
+ }
+
+ if ( !result )
+ {
+ emit error( i18n( "<qt>Could not upload the temporary file to the destination location <b>%1</b>. The temporary file is still available under: <b>%2</b>. You can manually copy it to the right place.</qt>" ).arg( m_destination ).arg( temp->name() ) );
+ }
+ else
+ {
+ //model->slotSetModified( false );
+ temp->unlink();
+ delete temp;
+ }
+
+ return true;
+}
+
+bool KompareModelList::saveAll()
+{
+ if ( !m_models )
+ return false;
+
+ DiffModelListIterator it = m_models->begin();
+ DiffModelListIterator end = m_models->end();
+ for ( ; it != end; ++it )
+ {
+ if( !saveDestination( *it ) )
+ return false;
+ }
+ return true;
+}
+
+void KompareModelList::setEncoding( const QString& encoding )
+{
+ m_encoding = encoding;
+ if ( encoding.lower() == "default" )
+ {
+ m_textCodec = QTextCodec::codecForLocale();
+ }
+ else
+ {
+ kdDebug() << "Encoding : " << encoding << endl;
+ m_textCodec = KGlobal::charsets()->codecForName( encoding.latin1() );
+ kdDebug() << "TextCodec: " << m_textCodec << endl;
+ if ( !m_textCodec )
+ m_textCodec = QTextCodec::codecForLocale();
+ }
+ kdDebug() << "TextCodec: " << m_textCodec << endl;
+}
+
+void KompareModelList::slotDiffProcessFinished( bool success )
+{
+ if ( success )
+ {
+ emit status( Kompare::Parsing );
+ if ( parseDiffOutput( m_diffProcess->diffOutput() ) != 0 )
+ {
+ emit error( i18n( "Could not parse diff output." ) );
+ }
+ else
+ {
+ if ( m_info.mode != Kompare::ShowingDiff )
+ {
+ kdDebug() << "Blend this crap please and dont gimme any conflicts..." << endl;
+ blendOriginalIntoModelList( m_info.localSource );
+ }
+ updateModelListActions();
+ show();
+ }
+ emit status( Kompare::FinishedParsing );
+ }
+ else if ( m_diffProcess->exitStatus() == 0 )
+ {
+ emit error( i18n( "The files are identical." ) );
+ }
+ else
+ {
+ emit error( m_diffProcess->stdErr() );
+ }
+
+ delete m_diffProcess;
+ m_diffProcess = 0;
+}
+
+void KompareModelList::slotDirectoryChanged( const QString& /*dir*/ )
+{
+ // some debug output to see if watching works properly
+ kdDebug(8101) << "Yippie directories are being watched !!! :)" << endl;
+ if ( m_diffProcess )
+ {
+ emit status( Kompare::ReRunningDiff );
+ m_diffProcess->start();
+ }
+}
+
+void KompareModelList::slotFileChanged( const QString& /*file*/ )
+{
+ // some debug output to see if watching works properly
+ kdDebug(8101) << "Yippie files are being watched !!! :)" << endl;
+ if ( m_diffProcess )
+ {
+ emit status( Kompare::ReRunningDiff );
+ m_diffProcess->start();
+ }
+}
+
+QStringList KompareModelList::split( const QString& fileContents )
+{
+ QString contents = fileContents;
+ QStringList list;
+
+ int pos = 0;
+ unsigned int oldpos = 0;
+ // split that does not strip the split char
+#ifdef QT_OS_MAC
+ const char split = '\r';
+#else
+ const char split = '\n';
+#endif
+ while ( ( pos = contents.find( split, oldpos ) ) >= 0 )
+ {
+ list.append( contents.mid( oldpos, pos - oldpos + 1 ) );
+ oldpos = pos + 1;
+ }
+
+ if ( contents.length() > oldpos )
+ {
+ list.append( contents.right( contents.length() - oldpos ) );
+ }
+
+ return list;
+}
+
+QString KompareModelList::readFile( const QString& fileName )
+{
+ QStringList list;
+
+ QFile file( fileName );
+ file.open( IO_ReadOnly );
+
+ QTextStream stream( &file );
+ kdDebug() << "Codec = " << m_textCodec << endl;
+
+ if ( !m_textCodec )
+ m_textCodec = QTextCodec::codecForLocale();
+
+ stream.setCodec( m_textCodec );
+
+ QString contents = stream.read();
+
+ file.close();
+
+ return contents;
+}
+
+bool KompareModelList::openDiff( const QString& diffFile )
+{
+ kdDebug(8101) << "Stupid :) Url = " << diffFile << endl;
+
+ if ( diffFile.isEmpty() )
+ return false;
+
+ QString diff = readFile( diffFile );
+
+ clear(); // Clear the current models
+
+ emit status( Kompare::Parsing );
+
+ if ( parseDiffOutput( diff ) != 0 )
+ {
+ emit error( i18n( "Could not parse diff output." ) );
+ return false;
+ }
+
+ updateModelListActions();
+ show();
+
+ emit status( Kompare::FinishedParsing );
+
+ return true;
+}
+
+QString KompareModelList::recreateDiff() const
+{
+ QString diff;
+
+ DiffModelListConstIterator modelIt = m_models->begin();
+ DiffModelListConstIterator mEnd = m_models->end();
+
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ diff += (*modelIt)->recreateDiff();
+ }
+ return diff;
+}
+
+bool KompareModelList::saveDiff( const QString& url, QString directory, DiffSettings* diffSettings )
+{
+ kdDebug() << "KompareModelList::saveDiff: " << endl;
+
+ m_diffTemp = new KTempFile();
+ m_diffURL = url;
+
+ if( m_diffTemp->status() != 0 ) {
+ emit error( i18n( "Could not open a temporary file." ) );
+ m_diffTemp->unlink();
+ delete m_diffTemp;
+ m_diffTemp = 0;
+ return false;
+ }
+
+ m_diffProcess = new KompareProcess( diffSettings, Kompare::Custom, m_source, m_destination, directory );
+ m_diffProcess->setEncoding( m_encoding );
+
+ connect( m_diffProcess, SIGNAL(diffHasFinished( bool )),
+ this, SLOT(slotWriteDiffOutput( bool )) );
+
+ emit status( Kompare::RunningDiff );
+ return m_diffProcess->start();
+}
+
+void KompareModelList::slotWriteDiffOutput( bool success )
+{
+ kdDebug(8101) << "Success = " << success << endl;
+
+ if( success )
+ {
+ QTextStream* stream = m_diffTemp->textStream();
+
+ *stream << m_diffProcess->diffOutput();
+
+ m_diffTemp->close();
+
+ if( m_diffTemp->status() != 0 )
+ {
+ emit error( i18n( "Could not write to the temporary file." ) );
+ }
+
+ KIO::NetAccess::upload( m_diffTemp->name(), KURL( m_diffURL ), (QWidget*)parent() );
+
+ emit status( Kompare::FinishedWritingDiff );
+ }
+
+ m_diffURL.truncate( 0 );
+ m_diffTemp->unlink();
+
+ delete m_diffTemp;
+ m_diffTemp = 0;
+
+ delete m_diffProcess;
+ m_diffProcess = 0;
+}
+
+void KompareModelList::slotSelectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff )
+{
+// This method will signal all the other objects about a change in selection,
+// it will emit setSelection( const DiffModel*, const Difference* ) to all who are connected
+ kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << model << ", " << diff << " )" << endl;
+ kdDebug(8101) << "Sender is : " << sender()->className() << endl;
+// kdDebug(8101) << kdBacktrace() << endl;
+
+ m_selectedModel = const_cast<DiffModel*>(model);
+ m_modelIndex = m_models->findIndex( m_selectedModel );
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedDifference = const_cast<Difference*>(diff);
+
+ m_selectedModel->setSelectedDifference( m_selectedDifference );
+
+ // setSelected* search for the argument in the lists and return false if not found
+ // if found they return true and set the m_selected*
+ if ( !setSelectedModel( m_selectedModel ) )
+ {
+ // Backup plan
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
+ {
+ // Another backup plan
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( model, diff );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+
+ updateModelListActions();
+}
+
+void KompareModelList::slotSelectionChanged( const Diff2::Difference* diff )
+{
+// This method will emit setSelection( const Difference* ) to whomever is listening
+// when for instance in kompareview the selection has changed
+ kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << diff << " )" << endl;
+ kdDebug(8101) << "Sender is : " << sender()->className() << endl;
+
+ m_selectedDifference = const_cast<Difference*>(diff);
+
+ if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
+ {
+ // Backup plan
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( diff );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+
+ updateModelListActions();
+}
+
+void KompareModelList::slotPreviousModel()
+{
+ if ( ( m_selectedModel = prevModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else
+ {
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotNextModel()
+{
+ if ( ( m_selectedModel = nextModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+ else
+ {
+ m_selectedModel = lastModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+ }
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+DiffModel* KompareModelList::firstModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::firstModel()" << endl;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+
+ m_selectedModel = m_models->first();
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::lastModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::lastModel()" << endl;
+ m_modelIndex = m_models->count() - 1;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+
+ m_selectedModel = m_models->last();
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::prevModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::prevModel()" << endl;
+ if ( --m_modelIndex < m_models->count() )
+ {
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedModel = (*m_models)[ m_modelIndex ];
+ }
+ else
+ {
+ m_selectedModel = 0;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ }
+
+ return m_selectedModel;
+}
+
+DiffModel* KompareModelList::nextModel()
+{
+ kdDebug( 8101 ) << "KompareModelList::nextModel()" << endl;
+ if ( ++m_modelIndex < m_models->count() )
+ {
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ m_selectedModel = (*m_models)[ m_modelIndex ];
+ }
+ else
+ {
+ m_selectedModel = 0;
+ m_modelIndex = 0;
+ kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
+ }
+
+ return m_selectedModel;
+}
+
+void KompareModelList::slotPreviousDifference()
+{
+ kdDebug(8101) << "slotPreviousDifference called" << endl;
+ if ( ( m_selectedDifference = m_selectedModel->prevDifference() ) != 0 )
+ {
+ emit setSelection( m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** no previous difference... ok lets find the previous model..." << endl;
+
+ if ( ( m_selectedModel = prevModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->lastDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+
+ kdDebug(8101) << "**** !!! No previous model, ok backup plan activated..." << endl;
+
+ // Backup plan
+ m_selectedModel = firstModel();
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotNextDifference()
+{
+ kdDebug(8101) << "slotNextDifference called" << endl;
+ if ( ( m_selectedDifference = m_selectedModel->nextDifference() ) != 0 )
+ {
+ emit setSelection( m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** no next difference... ok lets find the next model..." << endl;
+
+ if ( ( m_selectedModel = nextModel() ) != 0 )
+ {
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+ return;
+ }
+
+ kdDebug(8101) << "**** !!! No next model, ok backup plan activated..." << endl;
+
+ // Backup plan
+ m_selectedModel = lastModel();
+ m_selectedDifference = m_selectedModel->lastDifference();
+
+ emit setSelection( m_selectedModel, m_selectedDifference );
+ emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
+ updateModelListActions();
+}
+
+void KompareModelList::slotApplyDifference( bool apply )
+{
+ m_selectedModel->applyDifference( apply );
+ emit applyDifference( apply );
+}
+
+void KompareModelList::slotApplyAllDifferences( bool apply )
+{
+ m_selectedModel->applyAllDifferences( apply );
+ emit applyAllDifferences( apply );
+}
+
+int KompareModelList::parseDiffOutput( const QString& diff )
+{
+ kdDebug(8101) << "KompareModelList::parseDiffOutput" << endl;
+
+ QStringList diffLines = split( diff );
+
+ Parser* parser = new Parser( this );
+ m_models = parser->parse( diffLines );
+
+ m_info.generator = parser->generator();
+ m_info.format = parser->format();
+
+ delete parser;
+
+ if ( m_models )
+ {
+ m_selectedModel = firstModel();
+ kdDebug(8101) << "Ok there are differences..." << endl;
+ m_selectedDifference = m_selectedModel->firstDifference();
+ emit setStatusBarModelInfo( 0, 0, modelCount(), differenceCount(), 0);
+ }
+ else
+ {
+ // Wow trouble, no models, so no differences...
+ kdDebug(8101) << "Now i'll be damned, there should be models here !!!" << endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+bool KompareModelList::blendOriginalIntoModelList( const QString& localURL )
+{
+ kdDebug() << "Hurrah we are blending..." << endl;
+ QFileInfo fi( localURL );
+
+ bool result = false;
+ DiffModel* model;
+
+ QString fileContents;
+
+ if ( fi.isDir() )
+ { // is a dir
+ kdDebug() << "Blend Dir" << endl;
+// QDir dir( localURL, QString::null, QDir::Name|QDir::DirsFirst, QDir::All );
+ DiffModelListIterator modelIt = m_models->begin();
+ DiffModelListIterator mEnd = m_models->end();
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ model = *modelIt;
+ kdDebug(8101) << "Model : " << model << endl;
+ QString filename = model->sourcePath() + model->sourceFile();
+ if ( !filename.startsWith( localURL ) )
+ filename.prepend( localURL );
+ QFileInfo fi2( filename );
+ if ( fi2.exists() )
+ {
+ kdDebug(8101) << "Reading from: " << filename << endl;
+ fileContents = readFile( filename );
+ result = blendFile( model, fileContents );
+ }
+ else
+ {
+ kdDebug(8101) << "File " << filename << " does not exist !" << endl;
+ kdDebug(8101) << "Assume empty file !" << endl;
+ fileContents.truncate( 0 );
+ result = blendFile( model, fileContents );
+ }
+ }
+ kdDebug() << "End of Blend Dir" << endl;
+ }
+ else if ( fi.isFile() )
+ { // is a file
+ kdDebug() << "Blend File" << endl;
+ kdDebug(8101) << "Reading from: " << localURL << endl;
+ fileContents = readFile( localURL );
+
+ result = blendFile( (*m_models)[ 0 ], fileContents );
+ kdDebug() << "End of Blend File" << endl;
+ }
+
+ return result;
+}
+
+bool KompareModelList::blendFile( DiffModel* model, const QString& fileContents )
+{
+ if ( !model )
+ {
+ kdDebug() << "**** model is null :(" << endl;
+ return false;
+ }
+
+ model->setBlended( true );
+
+ int srcLineNo = 1, destLineNo = 1;
+
+ QStringList lines = split( fileContents );
+
+ QStringList::ConstIterator linesIt = lines.begin();
+ QStringList::ConstIterator lEnd = lines.end();
+
+ DiffHunkList* hunks = model->hunks();
+ kdDebug(8101) << "Hunks in hunklist: " << hunks->count() << endl;
+ DiffHunkListIterator hunkIt = hunks->begin();
+
+ DiffHunk* newHunk = 0;
+ Difference* newDiff = 0;
+
+ // FIXME: this approach is not very good, we should first check if the hunk applies cleanly
+ // and without offset and if not use that new linenumber with offset to compare against
+ // This will only work for files we just diffed with kompare but not for blending where
+ // file(s) to patch has/have potentially changed
+
+ for ( ; hunkIt != hunks->end(); ++hunkIt )
+ {
+ // Do we need to insert a new hunk before this one ?
+ DiffHunk* hunk = *hunkIt;
+ if ( srcLineNo < hunk->sourceLineNumber() )
+ {
+ newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
+
+ hunks->insert( hunkIt, newHunk );
+
+ newDiff = new Difference( srcLineNo, destLineNo,
+ Difference::Unchanged );
+
+ newHunk->add( newDiff );
+
+ while ( srcLineNo < hunk->sourceLineNumber() && linesIt != lEnd )
+ {
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+ }
+
+ // Now we add the linecount difference for the hunk that follows
+ int size = hunk->sourceLineCount();
+
+ for ( int i = 0; i < size; ++i )
+ {
+ ++linesIt;
+ }
+
+ srcLineNo += size;
+ destLineNo += (*hunkIt)->destinationLineCount();
+ }
+
+ if ( linesIt != lEnd )
+ {
+ newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
+
+ model->addHunk( newHunk );
+
+ newDiff = new Difference( srcLineNo, destLineNo, Difference::Unchanged );
+
+ newHunk->add( newDiff );
+
+ while ( linesIt != lEnd )
+ {
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ ++linesIt;
+ }
+ }
+#if 0
+ DifferenceList hunkDiffList = (*hunkIt)->differences();
+ DifferenceListIterator diffIt = hunkDiffList.begin();
+ DifferenceListIterator dEnd = hunkDiffList.end();
+ kdDebug() << "Number of differences in hunkDiffList = " << diffList.count() << endl;
+
+ DifferenceListIterator tempIt;
+ Difference* diff;
+
+ for ( ; diffIt != dEnd; ++diffIt )
+ {
+ diff = *diffIt;
+ kdDebug() << "*(Diff it) = " << diff << endl;
+ // Check if there are lines in the original file before the difference
+ // that are not yet in the diff. If so create new Unchanged diff
+ if ( srcLineNo < diff->sourceLineNumber() )
+ {
+ newDiff = new Difference( srcLineNo, destLineNo,
+ Difference::Unchanged | Difference::AddedByBlend );
+ newHunk->add( newDiff );
+ while ( srcLineNo < diff->sourceLineNumber() && linesIt != lEnd )
+ {
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ newDiff->addSourceLine( *linesIt );
+ newDiff->addDestinationLine( *linesIt );
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+ }
+ // Now i've got to add that diff
+ switch ( diff->type() )
+ {
+ case Difference::Unchanged:
+ kdDebug(8101) << "Unchanged" << endl;
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+
+ break;
+ case Difference::Change:
+ kdDebug(8101) << "Change" << endl;
+
+ //QStringListConstIterator saveIt = linesIt;
+
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+ srcLineNo++;
+ destLineNo++;
+ ++linesIt;
+ }
+
+ destLineNo += diff->destinationLineCount();
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+
+ break;
+ case Difference::Insert:
+ kdDebug(8101) << "Insert" << endl;
+ destLineNo += diff->destinationLineCount();
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+ break;
+ case Difference::Delete:
+ kdDebug(8101) << "Delete" << endl;
+ kdDebug(8101) << "Number of lines in Delete: " << diff->sourceLineCount() << endl;
+ for ( int i = 0; i < diff->sourceLineCount(); i++ )
+ {
+ if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
+ {
+ kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
+ kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+
+ // Do conflict resolution (well sort of)
+ diff->sourceLineAt( i )->setConflictString( *linesIt );
+ diff->setConflict( true );
+ }
+
+// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *it << endl;
+// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
+ srcLineNo++;
+ ++linesIt;
+ }
+
+ tempIt = diffIt;
+ --diffIt;
+ diffList.remove( tempIt );
+ newHunk->add( diff );
+ newModel->addDiff( diff );
+ break;
+ default:
+ kdDebug(8101) << "****, some diff type we dont know about ???" << endl;
+ }
+ }
+ }
+#endif
+
+/*
+ diffList = newModel->differences();
+
+ diff = diffList.first();
+ kdDebug(8101) << "Count = " << diffList.count() << endl;
+ for ( diff = diffList.first(); diff; diff = diffList.next() )
+ {
+ kdDebug(8101) << "sourcelinenumber = " << diff->sourceLineNumber() << endl;
+ }
+*/
+
+ m_selectedModel = firstModel();
+
+ m_selectedDifference = m_selectedModel->firstDifference();
+
+ return true;
+}
+
+void KompareModelList::show()
+{
+ kdDebug() << "KompareModelList::Show Number of models = " << m_models->count() << endl;
+ emit modelsChanged( m_models );
+ emit setSelection( m_selectedModel, m_selectedDifference );
+}
+
+void KompareModelList::clear()
+{
+ if ( m_models )
+ m_models->clear();
+
+ emit modelsChanged( m_models );
+}
+
+void KompareModelList::swap()
+{
+ QString source = m_source;
+ QString destination = m_destination;
+ if ( m_info.mode == Kompare::ComparingFiles )
+ compareFiles( destination, source );
+ else if ( m_info.mode == Kompare::ComparingDirs )
+ compareDirs( destination, source );
+}
+
+bool KompareModelList::isModified() const
+{
+ if ( m_noOfModified > 0 )
+ return true;
+ return false;
+}
+
+int KompareModelList::modelCount() const
+{
+ return m_models ? m_models->count() : 0;
+}
+
+int KompareModelList::differenceCount() const
+{
+ return m_selectedModel ? m_selectedModel->differenceCount() : -1;
+}
+
+int KompareModelList::appliedCount() const
+{
+ return m_selectedModel ? m_selectedModel->appliedCount() : -1;
+}
+
+void KompareModelList::slotSetModified( bool modified )
+{
+ kdDebug(8101) << "KompareModelList::slotSetModified( " << modified << " );" << endl;
+ kdDebug(8101) << "Before: m_noOfModified = " << m_noOfModified << endl;
+
+ // If selectedModel emits its signal setModified it does not set the model
+ // internal m_modified bool yet, it only does that after the emit.
+ if ( modified && !m_selectedModel->isModified() )
+ m_noOfModified++;
+ else if ( !modified && m_selectedModel->isModified() )
+ m_noOfModified--;
+
+ kdDebug(8101) << "After : m_noOfModified = " << m_noOfModified << endl;
+
+ if ( m_noOfModified < 0 )
+ {
+ kdDebug(8101) << "Wow something is ****ed up..." << endl;
+ }
+ else if ( m_noOfModified == 0 )
+ {
+ emit setModified( false );
+ }
+ else // > 0 :-)
+ {
+ emit setModified( true );
+ }
+}
+
+bool KompareModelList::setSelectedModel( DiffModel* model )
+{
+ kdDebug(8101) << "KompareModelList::setSelectedModel( " << model << " )" << endl;
+
+ if ( model != m_selectedModel )
+ {
+ if ( m_models->findIndex( model ) == -1 )
+ return false;
+ kdDebug(8101) << "m_selectedModel (was) = " << m_selectedModel << endl;
+ m_modelIndex = m_models->findIndex( model );
+ kdDebug(8101) << "m_selectedModel (is) = " << m_selectedModel << endl;
+ m_selectedModel = model;
+ }
+
+ updateModelListActions();
+
+ return true;
+}
+
+void KompareModelList::updateModelListActions()
+{
+ if ( m_models && m_selectedModel && m_selectedDifference )
+ {
+ if ( ( ( KomparePart* )parent() )->isReadWrite() )
+ {
+ if ( m_selectedModel->appliedCount() != m_selectedModel->differenceCount() )
+ m_applyAll->setEnabled( true );
+ else
+ m_applyAll->setEnabled( false );
+
+ if ( m_selectedModel->appliedCount() != 0 )
+ m_unapplyAll->setEnabled( true );
+ else
+ m_unapplyAll->setEnabled( false );
+
+ m_applyDifference->setEnabled( true );
+ m_unApplyDifference->setEnabled( true );
+ m_save->setEnabled( m_selectedModel->isModified() );
+ }
+ else
+ {
+ m_applyDifference->setEnabled ( false );
+ m_unApplyDifference->setEnabled( false );
+ m_applyAll->setEnabled ( false );
+ m_unapplyAll->setEnabled ( false );
+ m_save->setEnabled ( false );
+ }
+
+ m_previousFile->setEnabled ( hasPrevModel() );
+ m_nextFile->setEnabled ( hasNextModel() );
+ m_previousDifference->setEnabled( hasPrevDiff() );
+ m_nextDifference->setEnabled ( hasNextDiff() );
+ }
+ else
+ {
+ m_applyDifference->setEnabled ( false );
+ m_unApplyDifference->setEnabled ( false );
+ m_applyAll->setEnabled ( false );
+ m_unapplyAll->setEnabled ( false );
+
+ m_previousFile->setEnabled ( false );
+ m_nextFile->setEnabled ( false );
+ m_previousDifference->setEnabled( false );
+ m_nextDifference->setEnabled ( false );
+ m_save->setEnabled ( false );
+ }
+}
+
+bool KompareModelList::hasPrevModel() const
+{
+ kdDebug(8101) << "KompareModelList::hasPrevModel()" << endl;
+
+ if ( m_modelIndex > 0 )
+ {
+// kdDebug(8101) << "has prev model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a prev model, this is the first one..." << endl;
+
+ return false;
+}
+
+bool KompareModelList::hasNextModel() const
+{
+ kdDebug(8101) << "KompareModelList::hasNextModel()" << endl;
+
+ if ( ( unsigned int )m_modelIndex < ( m_models->count() - 1 ) )
+ {
+// kdDebug(8101) << "has next model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a next model, this is the last one..." << endl;
+ return false;
+}
+
+bool KompareModelList::hasPrevDiff() const
+{
+// kdDebug(8101) << "KompareModelList::hasPrevDiff()" << endl;
+ int index = m_selectedModel->diffIndex();
+
+ if ( index > 0 )
+ {
+// kdDebug(8101) << "has prev difference in same model" << endl;
+ return true;
+ }
+
+ if ( hasPrevModel() )
+ {
+// kdDebug(8101) << "has prev difference but in prev model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a prev difference, not even in the previous model because there is no previous model" << endl;
+
+ return false;
+}
+
+bool KompareModelList::hasNextDiff() const
+{
+// kdDebug(8101) << "KompareModelList::hasNextDiff()" << endl;
+ int index = m_selectedModel->diffIndex();
+
+ if ( index < ( m_selectedModel->differenceCount() - 1 ) )
+ {
+// kdDebug(8101) << "has next difference in same model" << endl;
+ return true;
+ }
+
+ if ( hasNextModel() )
+ {
+// kdDebug(8101) << "has next difference but in next model" << endl;
+ return true;
+ }
+
+// kdDebug(8101) << "doesn't have a next difference, not even in next model because there is no next model" << endl;
+
+ return false;
+}
+
+void KompareModelList::slotActionApplyDifference()
+{
+ if ( !m_selectedDifference->applied() )
+ slotApplyDifference( true );
+ slotNextDifference();
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionUnApplyDifference()
+{
+ if ( m_selectedDifference->applied() )
+ slotApplyDifference( false );
+ slotPreviousDifference();
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionApplyAllDifferences()
+{
+ slotApplyAllDifferences( true );
+ updateModelListActions();
+}
+
+void KompareModelList::slotActionUnapplyAllDifferences()
+{
+ slotApplyAllDifferences( false );
+ updateModelListActions();
+}
+
+#include "komparemodellist.moc"
+
+/* vim: set ts=4 sw=4 noet: */
diff --git a/kompare/libdiff2/komparemodellist.h b/kompare/libdiff2/komparemodellist.h
new file mode 100644
index 00000000..8ba264fb
--- /dev/null
+++ b/kompare/libdiff2/komparemodellist.h
@@ -0,0 +1,213 @@
+/***************************************************************************
+ komparemodellist.h - description
+ -------------------
+ begin : Tue Jun 26 2001
+ copyright : (C) 2001-2003 by John Firebaugh
+ and Otto Bruggeman
+ email : jfirebaugh@kde.org
+ otto.bruggeman@home.nl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 KOMPAREMODELLIST_H
+#define KOMPAREMODELLIST_H
+
+#include <qobject.h>
+
+#include "diffmodel.h"
+#include "diffmodellist.h"
+#include "kompare.h"
+
+class QFile;
+
+class KAction;
+class KDirWatch;
+class KTempFile;
+
+class DiffSettings;
+class KompareProcess;
+
+namespace Diff2
+{
+
+class KompareModelList : public QObject
+{
+ Q_OBJECT
+public:
+ KompareModelList( DiffSettings* diffSettings, struct Kompare::Info& info, QObject* parent = 0, const char* name = 0 );
+ ~KompareModelList();
+
+public:
+ // Swap source with destination and show differences
+ void swap();
+
+ /* Comparing methods */
+ bool compare( const QString& source, const QString& destination );
+
+ bool compareFiles( const QString& source, const QString& destination );
+ bool compareDirs( const QString& source, const QString& destination );
+
+ bool openDiff( const QString& diff );
+
+ bool openFileAndDiff( const QString& file, const QString& diff );
+ bool openDirAndDiff( const QString& dir, const QString& diff );
+
+ bool saveDiff( const QString& url, QString directory, DiffSettings* diffSettings );
+ bool saveAll();
+
+ bool saveDestination( DiffModel* model );
+
+ void setEncoding( const QString& encoding );
+
+ QString recreateDiff() const;
+
+ // This parses the difflines and creates new models
+ int parseDiffOutput( const QString& diff );
+
+ // Call this to emit the signals to the rest of the "world" to show the diff
+ void show();
+
+ // This will blend the original URL (dir or file) into the diffmodel,
+ // this is like patching but with a twist
+ bool blendOriginalIntoModelList( const QString& localURL );
+
+ enum Kompare::Mode mode() const { return m_info.mode; };
+ const DiffModelList* models() const { return m_models; };
+
+ int modelCount() const;
+ int differenceCount() const;
+ int appliedCount() const;
+
+ const DiffModel* modelAt( int i ) const { return *( m_models->at( i ) ); };
+ int findModel( DiffModel* model ) const { return m_models->findIndex( model ); };
+
+ bool isModified() const;
+
+ int currentModel() const { return m_models->findIndex( m_selectedModel ); };
+ int currentDifference() const { return m_selectedModel ? m_selectedModel->findDifference( m_selectedDifference ) : -1; };
+
+ const DiffModel* selectedModel() const { return m_selectedModel; };
+ const Difference* selectedDifference() const { return m_selectedDifference; };
+
+ void clear();
+
+private:
+ Diff2::DiffModel* firstModel();
+ Diff2::DiffModel* lastModel();
+ Diff2::DiffModel* prevModel();
+ Diff2::DiffModel* nextModel();
+
+ bool setSelectedModel( Diff2::DiffModel* model );
+
+ void updateModelListActions();
+
+protected:
+ bool blendFile( DiffModel* model, const QString& lines );
+
+signals:
+ void status( Kompare::Status status );
+ void setStatusBarModelInfo( int modelIndex, int differenceIndex, int modelCount, int differenceCount, int appliedCount );
+ void error( QString error );
+ void modelsChanged( const Diff2::DiffModelList* models );
+ void setSelection( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void setSelection( const Diff2::Difference* diff );
+ void applyDifference( bool apply );
+ void applyAllDifferences( bool apply );
+ void applyDifference( const Diff2::Difference* diff, bool apply );
+
+ // Emits true when m_noOfModified > 0, false when m_noOfModified == 0
+ void setModified( bool modified );
+
+public slots:
+ void slotSelectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff );
+ void slotSelectionChanged( const Diff2::Difference* diff );
+
+ void slotApplyDifference( bool apply );
+ void slotApplyAllDifferences( bool apply );
+ void slotPreviousModel();
+ void slotNextModel();
+ void slotPreviousDifference();
+ void slotNextDifference();
+
+ // This slot is called by the diffmodels whenever their status changes to modified or unmodified
+ void slotSetModified( bool modified );
+
+protected slots:
+ void slotDiffProcessFinished( bool success );
+ void slotWriteDiffOutput( bool success );
+
+ void slotActionApplyDifference();
+ void slotActionUnApplyDifference();
+ void slotActionApplyAllDifferences();
+ void slotActionUnapplyAllDifferences();
+
+ /** Save the currently selected destination in a multi-file diff,
+ or the single destination if a single file diff. */
+ void slotSaveDestination();
+
+private slots:
+ void slotDirectoryChanged( const QString& );
+ void slotFileChanged( const QString& );
+
+private: // Helper methods
+ bool isDirectory( const QString& url ) const;
+ bool isDiff( const QString& mimetype ) const;
+ QString readFile( const QString& fileName );
+
+ bool hasPrevModel() const;
+ bool hasNextModel() const;
+ bool hasPrevDiff() const;
+ bool hasNextDiff() const;
+
+ QStringList split( const QString& diff );
+
+private:
+ KTempFile* m_diffTemp;
+ QString m_diffURL;
+
+ KompareProcess* m_diffProcess;
+
+ DiffSettings* m_diffSettings;
+
+ DiffModelList* m_models;
+
+ QString m_source;
+ QString m_destination;
+
+ DiffModel* m_selectedModel;
+ Difference* m_selectedDifference;
+
+ KDirWatch* m_dirWatch;
+ KDirWatch* m_fileWatch;
+
+ int m_noOfModified;
+ unsigned int m_modelIndex;
+
+ struct Kompare::Info& m_info;
+
+ KAction* m_applyDifference;
+ KAction* m_unApplyDifference;
+ KAction* m_applyAll;
+ KAction* m_unapplyAll;
+ KAction* m_previousFile;
+ KAction* m_nextFile;
+ KAction* m_previousDifference;
+ KAction* m_nextDifference;
+
+ KAction* m_save;
+
+ QString m_encoding;
+ QTextCodec* m_textCodec;
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/kompareprocess.cpp b/kompare/libdiff2/kompareprocess.cpp
new file mode 100644
index 00000000..2d5eac00
--- /dev/null
+++ b/kompare/libdiff2/kompareprocess.cpp
@@ -0,0 +1,269 @@
+/***************************************************************************
+ kompareprocess.cpp - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ (C) 2007 Kevin Kofler
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+ kevin.kofler@chello.at
+****************************************************************************/
+
+/***************************************************************************
+**
+** 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 <qdir.h>
+#include <qstringlist.h>
+#include <qtextcodec.h>
+
+#include <kcharsets.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "diffsettings.h"
+#include "kompareprocess.h"
+
+KompareProcess::KompareProcess( DiffSettings* diffSettings, enum Kompare::DiffMode mode, QString source, QString destination, QString dir )
+ : KProcess(),
+ m_diffSettings( diffSettings ),
+ m_mode( mode ),
+ m_textDecoder( 0 )
+{
+ setUseShell( true );
+
+ // connect the stdout and stderr signals
+ connect( this, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ SLOT ( slotReceivedStdout( KProcess*, char*, int ) ) );
+ connect( this, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ SLOT ( slotReceivedStderr( KProcess*, char*, int ) ) );
+
+ // connect the signal that indicates that the proces has exited
+ connect( this, SIGNAL( processExited( KProcess* ) ),
+ SLOT ( slotProcessExited( KProcess* ) ) );
+
+ *this << "LANG=C";
+
+ // Write command and options
+ if( m_mode == Kompare::Default )
+ {
+ writeDefaultCommandLine();
+ }
+ else
+ {
+ writeCommandLine();
+ }
+
+ if( !dir.isEmpty() ) {
+ QDir::setCurrent( dir );
+ }
+
+ // Write file names
+ *this << "--";
+ *this << KProcess::quote( constructRelativePath( dir, source ) );
+ *this << KProcess::quote( constructRelativePath( dir, destination ) );
+}
+
+void KompareProcess::writeDefaultCommandLine()
+{
+ if ( !m_diffSettings || m_diffSettings->m_diffProgram.isEmpty() )
+ {
+ *this << "diff" << "-dr";
+ }
+ else
+ {
+ *this << m_diffSettings->m_diffProgram << "-dr";
+ }
+
+ *this << "-U" << QString::number( m_diffSettings->m_linesOfContext );
+}
+
+void KompareProcess::writeCommandLine()
+{
+ // load the executable into the KProcess
+ if ( m_diffSettings->m_diffProgram.isEmpty() )
+ {
+ kdDebug(8101) << "Using the first diff in the path..." << endl;
+ *this << "diff";
+ }
+ else
+ {
+ kdDebug(8101) << "Using a user specified diff, namely: " << m_diffSettings->m_diffProgram << endl;
+ *this << m_diffSettings->m_diffProgram;
+ }
+
+ switch( m_diffSettings->m_format ) {
+ case Kompare::Unified :
+ *this << "-U" << QString::number( m_diffSettings->m_linesOfContext );
+ break;
+ case Kompare::Context :
+ *this << "-C" << QString::number( m_diffSettings->m_linesOfContext );
+ break;
+ case Kompare::RCS :
+ *this << "-n";
+ break;
+ case Kompare::Ed :
+ *this << "-e";
+ break;
+ case Kompare::SideBySide:
+ *this << "-y";
+ break;
+ case Kompare::Normal :
+ case Kompare::UnknownFormat :
+ default:
+ break;
+ }
+
+ if ( m_diffSettings->m_largeFiles )
+ {
+ *this << "-H";
+ }
+
+ if ( m_diffSettings->m_ignoreWhiteSpace )
+ {
+ *this << "-b";
+ }
+
+ if ( m_diffSettings->m_ignoreAllWhiteSpace )
+ {
+ *this << "-w";
+ }
+
+ if ( m_diffSettings->m_ignoreEmptyLines )
+ {
+ *this << "-B";
+ }
+
+ if ( m_diffSettings->m_ignoreChangesDueToTabExpansion )
+ {
+ *this << "-E";
+ }
+
+ if ( m_diffSettings->m_createSmallerDiff )
+ {
+ *this << "-d";
+ }
+
+ if ( m_diffSettings->m_ignoreChangesInCase )
+ {
+ *this << "-i";
+ }
+
+ if ( m_diffSettings->m_ignoreRegExp && !m_diffSettings->m_ignoreRegExpText.isEmpty() )
+ {
+ *this << "-I " << KProcess::quote( m_diffSettings->m_ignoreRegExpText );
+ }
+
+ if ( m_diffSettings->m_showCFunctionChange )
+ {
+ *this << "-p";
+ }
+
+ if ( m_diffSettings->m_convertTabsToSpaces )
+ {
+ *this << "-t";
+ }
+
+ if ( m_diffSettings->m_recursive )
+ {
+ *this << "-r";
+ }
+
+ if ( m_diffSettings->m_newFiles )
+ {
+ *this << "-N";
+ }
+
+// This option is more trouble than it is worth... please do not ever enable it unless you want really weird crashes
+// if ( m_diffSettings->m_allText )
+// {
+// *this << "-a";
+// }
+
+ if ( m_diffSettings->m_excludeFilePattern )
+ {
+ QStringList::ConstIterator it = m_diffSettings->m_excludeFilePatternList.begin();
+ QStringList::ConstIterator end = m_diffSettings->m_excludeFilePatternList.end();
+ for ( ; it != end; ++it )
+ {
+ *this << "-x" << KProcess::quote( *it );
+ }
+ }
+
+ if ( m_diffSettings->m_excludeFilesFile && !m_diffSettings->m_excludeFilesFileURL.isEmpty() )
+ {
+ *this << "-X" << KProcess::quote( m_diffSettings->m_excludeFilesFileURL );
+ }
+}
+
+KompareProcess::~KompareProcess()
+{
+}
+
+void KompareProcess::setEncoding( const QString& encoding )
+{
+ if ( encoding.lower() == "default" )
+ {
+ m_textDecoder = QTextCodec::codecForLocale()->makeDecoder();
+ }
+ else
+ {
+ QTextCodec* textCodec = KGlobal::charsets()->codecForName( encoding.latin1() );
+ if ( textCodec )
+ m_textDecoder = textCodec->makeDecoder();
+ else
+ {
+ kdDebug(8101) << "Using locale codec as backup..." << endl;
+ textCodec = QTextCodec::codecForLocale();
+ m_textDecoder = textCodec->makeDecoder();
+ }
+ }
+}
+
+void KompareProcess::slotReceivedStdout( KProcess* /* process */, char* buffer, int length )
+{
+ // add all output to m_stdout
+ if ( m_textDecoder )
+ m_stdout += m_textDecoder->toUnicode( buffer, length );
+ else
+ kdDebug(8101) << "KompareProcess::slotReceivedStdout : No decoder !!!" << endl;
+}
+
+void KompareProcess::slotReceivedStderr( KProcess* /* process */, char* buffer, int length )
+{
+ // add all output to m_stderr
+ if ( m_textDecoder )
+ m_stderr += m_textDecoder->toUnicode( buffer, length );
+ else
+ kdDebug(8101) << "KompareProcess::slotReceivedStderr : No decoder !!!" << endl;
+}
+
+bool KompareProcess::start()
+{
+#ifndef NDEBUG
+ QString cmdLine;
+ QValueList<QCString>::ConstIterator it = arguments.begin();
+ for (; it != arguments.end(); ++it )
+ cmdLine += "\"" + (*it) + "\" ";
+ kdDebug(8101) << cmdLine << endl;
+#endif
+ return( KProcess::start( KProcess::NotifyOnExit, KProcess::AllOutput ) );
+}
+
+void KompareProcess::slotProcessExited( KProcess* /* proc */ )
+{
+ // exit status of 0: no differences
+ // 1: some differences
+ // 2: error but there may be differences !
+ kdDebug(8101) << "Exited with exit status : " << exitStatus() << endl;
+ emit diffHasFinished( normalExit() && exitStatus() != 0 );
+}
+
+#include "kompareprocess.moc"
+
diff --git a/kompare/libdiff2/kompareprocess.h b/kompare/libdiff2/kompareprocess.h
new file mode 100644
index 00000000..06a4a5ce
--- /dev/null
+++ b/kompare/libdiff2/kompareprocess.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ kompareprocess.h - description
+ -------------------
+ begin : Sun Mar 4 2001
+ copyright : (C) 2001-2003 by Otto Bruggeman
+ and John Firebaugh
+ email : otto.bruggeman@home.nl
+ jfirebaugh@kde.org
+****************************************************************************/
+
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+***************************************************************************/
+
+#ifndef KOMPAREPROCESS_H
+#define KOMPAREPROCESS_H
+
+#include <kprocess.h>
+
+#include "kompare.h"
+
+class QTextCodec;
+
+class DiffSettings;
+
+class KompareProcess : public KProcess, public KompareFunctions
+{
+ Q_OBJECT
+
+public:
+ KompareProcess( DiffSettings* diffSettings, enum Kompare::DiffMode mode, QString source, QString destination, QString directory = QString::null );
+ ~KompareProcess();
+
+ bool start();
+
+ QString diffOutput() { return m_stdout; }
+ QString stdOut() { return m_stdout; }
+ QString stdErr() { return m_stderr; }
+
+ void setEncoding( const QString& encoding );
+
+signals:
+ void diffHasFinished( bool finishedNormally );
+
+protected:
+ void writeDefaultCommandLine();
+ void writeCommandLine();
+
+protected slots:
+ void slotReceivedStdout( KProcess*, char*, int );
+ void slotReceivedStderr( KProcess*, char*, int );
+ void slotProcessExited( KProcess* proc );
+
+private:
+ DiffSettings* m_diffSettings;
+ enum Kompare::DiffMode m_mode;
+ QString m_stdout;
+ QString m_stderr;
+ QTextDecoder* m_textDecoder;
+};
+
+#endif
diff --git a/kompare/libdiff2/levenshteintable.cpp b/kompare/libdiff2/levenshteintable.cpp
new file mode 100644
index 00000000..54525aef
--- /dev/null
+++ b/kompare/libdiff2/levenshteintable.cpp
@@ -0,0 +1,332 @@
+/*******************************************************************************
+**
+** Filename : levenshteintable.cpp
+** Created on : 08 november, 2003
+** Copyright : (c) 2003 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** 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 <iostream>
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "levenshteintable.h"
+
+#include "difference.h"
+
+using namespace Diff2;
+
+LevenshteinTable::LevenshteinTable()
+ : m_width( 256 ),
+ m_height( 256 ),
+ m_size( m_height * m_width ),
+ m_table( new unsigned int[ m_size ] ),
+ m_source( 0 ),
+ m_destination( 0 )
+{
+}
+
+LevenshteinTable::LevenshteinTable( unsigned int width, unsigned int height )
+ : m_width( width ),
+ m_height( height ),
+ m_size( m_width * m_height ),
+ m_table( new unsigned int[ m_size ] ),
+ m_source( 0 ),
+ m_destination( 0 )
+{
+}
+
+LevenshteinTable::~LevenshteinTable()
+{
+ delete[] m_table;
+ m_source = 0;
+ m_destination = 0;
+}
+
+int LevenshteinTable::getContent( unsigned int posX, unsigned int posY ) const
+{
+// kdDebug(8101) << "Width = " << m_width << ", height = " << m_height << ", posX = " << posX << ", posY = " << posY << endl;
+ return m_table[ posY * m_width + posX ];
+}
+
+int LevenshteinTable::setContent( unsigned int posX, unsigned int posY, int value )
+{
+ m_table[ posY * m_width + posX ] = value;
+
+ return 0;
+}
+
+bool LevenshteinTable::setSize( unsigned int width, unsigned int height )
+{
+ // Set a limit of 16.7 million entries, will be about 64 MB of ram, that should be plenty
+ if ( ( ( width ) * ( height ) ) > ( 256 * 256 * 256 ) )
+ return false;
+
+ if ( ( ( width ) * ( height ) ) > m_size )
+ {
+ delete[] m_table;
+
+ m_size = width * height;
+ m_table = new unsigned int[ m_size ];
+ }
+
+ m_width = width;
+ m_height = height;
+
+ return true;
+}
+
+void LevenshteinTable::dumpLevenshteinTable()
+{
+ for ( unsigned int i = 0; i < m_height; ++i )
+ {
+ for ( unsigned int j = 0; j < m_width; ++j )
+ {
+ std::cout.width( 3 );
+ std::cout << getContent( j, i );
+ }
+ std::cout << std::endl;
+ }
+}
+
+unsigned int LevenshteinTable::createTable( DifferenceString* source, DifferenceString* destination )
+{
+ m_source = source;
+ m_destination = destination;
+
+ QString s = ' ' + source->string(); // Optimization, so i dont have to subtract 1 from the indexes every
+ QString d = ' ' + destination->string(); // single time and add 1 to the width and height of the table
+
+ unsigned int m = s.length();
+ unsigned int n = d.length();
+
+ const QChar* sq = s.unicode();
+ const QChar* dq = d.unicode();
+
+ if ( m == 1 )
+ return --n;
+
+ if ( n == 1 )
+ return --m;
+
+ if ( !setSize( m, n ) )
+ return 0;
+
+ unsigned int i;
+ unsigned int j;
+
+ // initialize first row
+ for ( i = 0; i < m; ++i )
+ setContent( i, 0, i );
+ // initialize first column
+ for ( j = 0; j < n; ++j )
+ setContent( 0, j, j );
+
+ int cost = 0, north = 0, west = 0, northwest = 0;
+
+ ushort si, dj;
+ // Optimization, calculate row wise instead of column wise, wont trash the cache so much with large strings
+ for ( j = 1; j < n; ++j )
+ {
+ dj = dq[ j ];
+
+ for ( i = 1; i < m; ++i )
+ {
+ si = sq[ i ];
+ if ( si == dj )
+ cost = 0;
+ else
+ cost = 1;
+
+ north = getContent( i, j-1 ) + 1;
+ west = getContent( i-1, j ) + 1;
+ northwest = getContent( i-1, j-1 ) + cost;
+
+ setContent( i, j, kMin( north, kMin( west, northwest ) ) );
+ }
+ }
+
+ return getContent( m-1, n-1 );
+}
+
+int LevenshteinTable::chooseRoute( int c1, int c2, int c3 )
+{
+// kdDebug(8101) << "c1 = " << c1 << ", c2 = " << c2 << ", c3 = " << c3 << endl;
+ // preference order: c2, c3, c1, hopefully this will work out for me
+ if ( c2 <= c1 && c2 <= c3 )
+ return 1;
+
+ if ( c3 <= c2 && c3 <= c1 )
+ return 2;
+
+ return 0;
+}
+
+void LevenshteinTable::createListsOfMarkers()
+{
+// std::cout << source.latin1() << std::endl;
+// std::cout << destination.latin1() << std::endl;
+// dumpLevenshteinTable();
+
+ unsigned int x = m_width-1;
+ unsigned int y = m_height-1;
+
+ Marker* c = 0;
+
+ int n, nw, w, direction, currentValue;
+ while ( x > 0 && y > 0 )
+ {
+ currentValue = getContent( x, y );
+
+ nw = getContent( x - 1, y - 1 );
+ n = getContent( x, y - 1 );
+ w = getContent( x - 1, y );
+
+ direction = chooseRoute( n, nw, w );
+
+ switch ( direction )
+ {
+ case 0: // north
+// kdDebug(8101) << "Picking north" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_destination->markerList().isEmpty() )
+ c = m_destination->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( n == currentValue )
+ m_destination->prepend( new Marker( Marker::Start, y ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( n < currentValue )
+ m_destination->prepend( new Marker( Marker::End, y ) );
+ }
+
+ --y;
+ break;
+ case 1: // northwest
+// kdDebug(8101) << "Picking northwest" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_destination->markerList().isEmpty() )
+ c = m_destination->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( nw == currentValue )
+ m_destination->prepend( new Marker( Marker::Start, y ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( nw < currentValue )
+ m_destination->prepend( new Marker( Marker::End, y ) );
+ }
+
+ if ( !m_source->markerList().isEmpty() )
+ c = m_source->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( nw == currentValue )
+ m_source->prepend( new Marker( Marker::Start, x ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( nw < currentValue )
+ m_source->prepend( new Marker( Marker::End, x ) );
+ }
+
+ --y;
+ --x;
+ break;
+ case 2: // west
+// kdDebug(8101) << "Picking west" << endl;
+// kdDebug(8101) << "Source[" << ( x - 1 ) << "] = " << QString( source[ x-1 ] ) << ", destination[" << ( y - 1 ) << "] = " << QString( destination[ y-1 ] ) << endl;
+
+ if ( !m_source->markerList().isEmpty() )
+ c = m_source->markerList().first();
+ else
+ c = 0;
+
+ if ( c && c->type() == Marker::End )
+ {
+// kdDebug(8101) << "End found: CurrentValue: " << currentValue << endl;
+ if ( w == currentValue )
+ m_source->prepend( new Marker( Marker::Start, x ) );
+ // else: the change continues, dont do anything
+ }
+ else
+ {
+// kdDebug(8101) << "CurrentValue: " << currentValue << endl;
+ if ( w < currentValue )
+ m_source->prepend( new Marker( Marker::End, x ) );
+ }
+
+ --x;
+ break;
+ }
+ }
+
+// kdDebug(8101) << "Source string: " << m_source->string() << endl;
+// c = m_source->markerList()->first();
+// QStringList list;
+// unsigned int prevValue = 0;
+// for ( ; c; c = m_source->markerList()->next() )
+// {
+// kdDebug(8101) << "Source Marker Entry : Type: " << c->type() << ", Offset: " << c->offset() << endl;
+// list.append( m_source->string().mid( prevValue, c->offset() - prevValue ) );
+// prevValue = c->offset();
+// }
+// if ( prevValue < m_source->string().length() - 1 )
+// {
+// list.append( m_source->string().mid( prevValue, m_source->string().length() - prevValue ) );
+// }
+// kdDebug(8101) << "Source Resulting stringlist : " << list.join("\n") << endl;
+
+// list.clear();
+// prevValue = 0;
+
+// kdDebug(8101) << "Destination string: " << m_destination->string() << endl;
+// for ( ; c; c = m_destination->markerList()->next() )
+// {
+// kdDebug(8101) << "Destination Marker Entry : Type: " << c->type() << ", Offset: " << c->offset() << endl;
+// list.append( m_destination->string().mid( prevValue, c->offset() - prevValue ) );
+// prevValue = c->offset();
+// }
+// if ( prevValue < m_destination->string().length() - 1 )
+// {
+// list.append( m_destination->string().mid( prevValue, m_destination->string().length() - prevValue ) );
+// }
+// kdDebug(8101) << "Destination Resulting string : " << list.join("\n") << endl;
+}
+
diff --git a/kompare/libdiff2/levenshteintable.h b/kompare/libdiff2/levenshteintable.h
new file mode 100644
index 00000000..201d1c10
--- /dev/null
+++ b/kompare/libdiff2/levenshteintable.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+**
+** Filename : levenshteintable.h
+** Created on : 08 november, 2003
+** Copyright : (c) 2003 Otto Bruggeman
+** Email : bruggie@home.nl
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** 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 _LEVENSHTEIN_H
+#define _LEVENSHTEIN_H
+
+#include "difference.h"
+
+class QString;
+
+namespace Diff2 {
+
+class Marker;
+
+class LevenshteinTable
+{
+public:
+ LevenshteinTable();
+ LevenshteinTable( unsigned int width, unsigned int height );
+ ~LevenshteinTable();
+
+public:
+ int getContent( unsigned int posX, unsigned int posY ) const;
+ int setContent( unsigned int posX, unsigned int posY, int value );
+ bool setSize ( unsigned int width, unsigned int height );
+
+ unsigned int width() const { return m_width; };
+ unsigned int height() const { return m_height; };
+
+ /** Debug method to check if the table is properly filled */
+ void dumpLevenshteinTable( void );
+
+ /** This will calculate the levenshtein distance of 2 strings */
+ unsigned int createTable( DifferenceString* s, DifferenceString* d );
+
+ void createListsOfMarkers( void );
+ int chooseRoute( int c1, int c2, int c3 );
+
+protected:
+ LevenshteinTable( const LevenshteinTable& table );
+ const LevenshteinTable& operator = ( const LevenshteinTable& table );
+
+private:
+ unsigned int m_width;
+ unsigned int m_height;
+ unsigned int m_size;
+ unsigned int* m_table;
+ DifferenceString* m_source;
+ DifferenceString* m_destination;
+};
+
+} // namespace Diff2
+
+#endif // _LEVENSHTEIN_H
diff --git a/kompare/libdiff2/parser.cpp b/kompare/libdiff2/parser.cpp
new file mode 100644
index 00000000..04ff7a4a
--- /dev/null
+++ b/kompare/libdiff2/parser.cpp
@@ -0,0 +1,139 @@
+/**************************************************************************
+** parser.cpp
+** -------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 <kdebug.h>
+
+#include "parser.h"
+#include "cvsdiffparser.h"
+#include "diffparser.h"
+#include "perforceparser.h"
+#include "diffmodel.h"
+
+using namespace Diff2;
+
+Parser::Parser( const KompareModelList* list ) :
+ m_list( list )
+{
+}
+
+Parser::~Parser()
+{
+}
+
+int Parser::cleanUpCrap( QStringList& diffLines )
+{
+ QStringList::Iterator it = diffLines.begin();
+
+ int nol = 0;
+
+ QString noNewLine( "\\ No newline" );
+
+ for ( ; it != diffLines.end(); ++it )
+ {
+ if ( (*it).startsWith( noNewLine ) )
+ {
+ it = diffLines.remove( it );
+ // correcting the advance of the iterator because of the remove
+ --it;
+ QString temp( *it );
+ temp.truncate( temp.find( '\n' ) );
+ *it = temp;
+ ++nol;
+ }
+ }
+
+ return nol;
+}
+
+DiffModelList* Parser::parse( QStringList& diffLines )
+{
+ /* Basically determine the generator then call the parse method */
+ ParserBase* parser;
+
+ m_generator = determineGenerator( diffLines );
+
+ int nol = cleanUpCrap( diffLines );
+ kdDebug(8101) << "Cleaned up " << nol << " line(s) of crap from the diff..." << endl;
+
+ switch( m_generator )
+ {
+ case Kompare::CVSDiff :
+ kdDebug(8101) << "It is a CVS generated diff..." << endl;
+ parser = new CVSDiffParser( m_list, diffLines );
+ break;
+ case Kompare::Diff :
+ kdDebug(8101) << "It is a diff generated diff..." << endl;
+ parser = new DiffParser( m_list, diffLines );
+ break;
+ case Kompare::Perforce :
+ kdDebug(8101) << "It is a Perforce generated diff..." << endl;
+ parser = new PerforceParser( m_list, diffLines );
+ break;
+ default:
+ // Nothing to delete, just leave...
+ return 0L;
+ }
+
+ m_format = parser->format();
+ DiffModelList* modelList = parser->parse();
+ if ( modelList )
+ {
+ kdDebug(8101) << "Modelcount: " << modelList->count() << endl;
+ DiffModelListIterator modelIt = modelList->begin();
+ DiffModelListIterator mEnd = modelList->end();
+ for ( ; modelIt != mEnd; ++modelIt )
+ {
+ kdDebug(8101) << "Hunkcount: " << (*modelIt)->hunkCount() << endl;
+ kdDebug(8101) << "Diffcount: " << (*modelIt)->differenceCount() << endl;
+ }
+ }
+
+ delete parser;
+
+ return modelList;
+}
+
+enum Kompare::Generator Parser::determineGenerator( const QStringList& diffLines )
+{
+ // Shit have to duplicate some code with this method and the ParserBase derived classes
+ QString cvsDiff ( "Index: " );
+ QString perforceDiff( "==== " );
+
+ QStringList::ConstIterator it = diffLines.begin();
+ QStringList::ConstIterator linesEnd = diffLines.end();
+
+ while ( it != linesEnd )
+ {
+ if ( ( *it ).startsWith( cvsDiff ) )
+ {
+ kdDebug(8101) << "Diff is a CVSDiff" << endl;
+ return Kompare::CVSDiff;
+ }
+ else if ( ( *it ).startsWith( perforceDiff ) )
+ {
+ kdDebug(8101) << "Diff is a Perforce Diff" << endl;
+ return Kompare::Perforce;
+ }
+ ++it;
+ }
+
+ kdDebug(8101) << "We'll assume it is a diff Diff" << endl;
+
+ // For now we'll assume it is a diff file diff, later we might
+ // try to really determine if it is a diff file diff.
+ return Kompare::Diff;
+}
diff --git a/kompare/libdiff2/parser.h b/kompare/libdiff2/parser.h
new file mode 100644
index 00000000..0ffae23a
--- /dev/null
+++ b/kompare/libdiff2/parser.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+** parser.h
+** --------
+** begin : Tue Jul 30 23:53:52 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 _DIFF2_PARSER_H
+#define _DIFF2_PARSER_H
+
+#include "diffmodellist.h"
+#include "kompare.h"
+
+namespace Diff2
+{
+
+class DiffModel;
+class KompareModelList;
+
+class Parser
+{
+public:
+ Parser( const KompareModelList* list );
+ ~Parser();
+
+public:
+ DiffModelList* parse( QStringList& diffLines );
+
+ enum Kompare::Generator generator() const { return m_generator; };
+ enum Kompare::Format format() const { return m_format; };
+
+private:
+ /** Which program was used to generate the output */
+ enum Kompare::Generator determineGenerator( const QStringList& diffLines );
+
+ int cleanUpCrap( QStringList& diffLines );
+
+private:
+ enum Kompare::Generator m_generator;
+ enum Kompare::Format m_format;
+
+ const KompareModelList* m_list;
+};
+
+} // End of namespace Diff2
+
+#endif
+
diff --git a/kompare/libdiff2/parserbase.cpp b/kompare/libdiff2/parserbase.cpp
new file mode 100644
index 00000000..303f7b22
--- /dev/null
+++ b/kompare/libdiff2/parserbase.cpp
@@ -0,0 +1,739 @@
+/**************************************************************************
+** parserbase.cpp
+** -------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 <qobject.h>
+
+#include <kdebug.h>
+
+#include "diffmodel.h"
+#include "diffhunk.h"
+#include "difference.h"
+#include "komparemodellist.h"
+
+#include "parserbase.h"
+
+using namespace Diff2;
+
+ParserBase::ParserBase( const KompareModelList* list, const QStringList& diff ) :
+ m_diffLines( diff ),
+ m_currentModel( 0 ),
+ m_models( 0 ),
+ m_diffIterator( m_diffLines.begin() ),
+ m_singleFileDiff( false ),
+ m_list( list )
+{
+// kdDebug(8101) << diff << endl;
+// kdDebug(8101) << m_diffLines << endl;
+ m_models = new DiffModelList();
+
+ // used in contexthunkheader
+ m_contextHunkHeader1.setPattern( "\\*{15} ?(.*)\\n" ); // capture is for function name
+ m_contextHunkHeader2.setPattern( "\\*\\*\\* ([0-9]+),([0-9]+) \\*\\*\\*\\*\\n" );
+ // used in contexthunkbody
+ m_contextHunkHeader3.setPattern( "--- ([0-9]+),([0-9]+) ----\\n" );
+
+ m_contextHunkBodyRemoved.setPattern( "- (.*)" );
+ m_contextHunkBodyAdded.setPattern ( "\\+ (.*)" );
+ m_contextHunkBodyChanged.setPattern( "! (.*)" );
+ m_contextHunkBodyContext.setPattern( " (.*)" );
+ m_contextHunkBodyLine.setPattern ( "[-\\+! ] (.*)" );
+
+ // This regexp sucks... i'll see what happens
+ m_normalDiffHeader.setPattern( "diff (?:(?:-|--)[a-zA-Z0-9=\\\"]+ )*(?:|-- +)(.*) +(.*)\\n" );
+
+ m_normalHunkHeaderAdded.setPattern ( "([0-9]+)a([0-9]+)(|,[0-9]+)(.*)\\n" );
+ m_normalHunkHeaderRemoved.setPattern( "([0-9]+)(|,[0-9]+)d([0-9]+)(.*)\\n" );
+ m_normalHunkHeaderChanged.setPattern( "([0-9]+)(|,[0-9]+)c([0-9]+)(|,[0-9]+)(.*)\\n" );
+
+ m_normalHunkBodyRemoved.setPattern ( "< (.*)" );
+ m_normalHunkBodyAdded.setPattern ( "> (.*)" );
+ m_normalHunkBodyDivider.setPattern ( "---" );
+
+ m_unifiedDiffHeader1.setPattern ( "--- ([^\\t]+)(?:\\t([^\\t]+)(?:\\t?)(.*))?\\n" );
+ m_unifiedDiffHeader2.setPattern ( "\\+\\+\\+ ([^\\t]+)(?:\\t([^\\t]+)(?:\\t?)(.*))?\\n" );
+ m_unifiedHunkHeader.setPattern ( "@@ -([0-9]+)(|,([0-9]+)) \\+([0-9]+)(|,([0-9]+)) @@(?: ?)(.*)\\n" );
+ m_unifiedHunkBodyAdded.setPattern ( "\\+(.*)" );
+ m_unifiedHunkBodyRemoved.setPattern( "-(.*)" );
+ m_unifiedHunkBodyContext.setPattern( " (.*)" );
+ m_unifiedHunkBodyLine.setPattern ( "([-+ ])(.*)" );
+}
+
+ParserBase::~ParserBase()
+{
+ if ( m_models )
+ m_models = 0; // dont delete this, i pass it around...
+}
+
+enum Kompare::Format ParserBase::determineFormat()
+{
+ // Write your own format detection routine damn it :)
+ return Kompare::UnknownFormat;
+}
+
+DiffModelList* ParserBase::parse()
+{
+ switch( determineFormat() )
+ {
+ case Kompare::Context :
+ return parseContext();
+ case Kompare::Ed :
+ return parseEd();
+ case Kompare::Normal :
+ return parseNormal();
+ case Kompare::RCS :
+ return parseRCS();
+ case Kompare::Unified :
+ return parseUnified();
+ default: // Unknown and SideBySide for now
+ return 0L;
+ }
+}
+
+bool ParserBase::parseContextDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() )
+ {
+ if ( !m_contextDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+ continue;
+ }
+// kdDebug(8101) << "Matched length Header1 = " << m_contextDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_contextDiffHeader1.cap( 0 ) << endl;
+ if ( m_diffIterator != m_diffLines.end() && m_contextDiffHeader2.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Matched length Header2 = " << m_contextDiffHeader2.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header2 = " << m_contextDiffHeader2.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel( m_contextDiffHeader1.cap( 1 ), m_contextDiffHeader2.cap( 1 ) );
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceTimestamp ( m_contextDiffHeader1.cap( 2 ) );
+ m_currentModel->setSourceRevision ( m_contextDiffHeader1.cap( 4 ) );
+ m_currentModel->setDestinationTimestamp( m_contextDiffHeader2.cap( 2 ) );
+ m_currentModel->setDestinationRevision ( m_contextDiffHeader2.cap( 4 ) );
+
+ ++m_diffIterator;
+ result = true;
+
+ break;
+ }
+ else
+ {
+ // We're screwed, second line does not match or is not there...
+ break;
+ }
+ // Dont inc the Iterator because the second line might be the first line of
+ // the context header and the first hit was a fluke (impossible imo)
+ // maybe we should return false here because the diff is broken ?
+ }
+
+ return result;
+}
+
+bool ParserBase::parseEdDiffHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseNormalDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() )
+ {
+ if ( m_normalDiffHeader.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Matched length Header = " << m_normalDiffHeader.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header = " << m_normalDiffHeader.cap( 0 ) << endl;
+
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceFile ( m_normalDiffHeader.cap( 1 ) );
+ m_currentModel->setDestinationFile ( m_normalDiffHeader.cap( 2 ) );
+
+ result = true;
+
+ ++m_diffIterator;
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "No match for: " << ( *m_diffIterator ) << endl;
+ }
+ ++m_diffIterator;
+ }
+
+ if ( result == false )
+ {
+ // Set this to the first line again and hope it is a single file diff
+ m_diffIterator = m_diffLines.begin();
+ m_currentModel = new DiffModel();
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_singleFileDiff = true;
+ }
+
+ return result;
+}
+
+bool ParserBase::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseUnifiedDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedDiffHeader()" << endl;
+ bool result = false;
+
+ while ( m_diffIterator != m_diffLines.end() ) // dont assume we start with the diffheader1 line
+ {
+ if ( !m_unifiedDiffHeader1.exactMatch( *m_diffIterator ) )
+ {
+ ++m_diffIterator;
+ continue;
+ }
+// kdDebug(8101) << "Matched length Header1 = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_unifiedDiffHeader1.cap( 0 ) << endl;
+ ++m_diffIterator;
+ if ( m_diffIterator != m_diffLines.end() && m_unifiedDiffHeader2.exactMatch( *m_diffIterator ) )
+ {
+ m_currentModel = new DiffModel( m_unifiedDiffHeader1.cap( 1 ), m_unifiedDiffHeader2.cap( 1 ) );
+ QObject::connect( m_currentModel, SIGNAL( setModified( bool ) ), m_list, SLOT( slotSetModified( bool ) ) );
+ m_currentModel->setSourceTimestamp( m_unifiedDiffHeader1.cap( 2 ) );
+ m_currentModel->setSourceRevision( m_unifiedDiffHeader1.cap( 4 ) );
+ m_currentModel->setDestinationTimestamp( m_unifiedDiffHeader2.cap( 2 ) );
+ m_currentModel->setDestinationRevision( m_unifiedDiffHeader2.cap( 4 ) );
+
+ ++m_diffIterator;
+ result = true;
+
+ break;
+ }
+ else
+ {
+ // We're screwed, second line does not match or is not there...
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool ParserBase::parseContextHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextHunkHeader()" << endl;
+
+ if ( m_diffIterator == m_diffLines.end() )
+ return false;
+
+ if ( !m_contextHunkHeader1.exactMatch( *(m_diffIterator) ) )
+ return false; // big fat trouble, aborting...
+
+ ++m_diffIterator;
+
+ if ( m_diffIterator == m_diffLines.end() )
+ return false;
+
+ if ( !m_contextHunkHeader2.exactMatch( *(m_diffIterator) ) )
+ return false; // big fat trouble, aborting...
+
+ ++m_diffIterator;
+
+ return true;
+}
+
+bool ParserBase::parseEdHunkHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseNormalHunkHeader()" << endl;
+ if ( m_diffIterator != m_diffLines.end() )
+ {
+// kdDebug(8101) << "Header = " << *m_diffIterator << endl;
+ if ( m_normalHunkHeaderAdded.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Insert;
+ }
+ else if ( m_normalHunkHeaderRemoved.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Delete;
+ }
+ else if ( m_normalHunkHeaderChanged.exactMatch( *m_diffIterator ) )
+ {
+ m_normalDiffType = Difference::Change;
+ }
+ else
+ return false;
+
+ ++m_diffIterator;
+ return true;
+ }
+
+ return false;
+}
+
+bool ParserBase::parseRCSHunkHeader()
+{
+ return false;
+}
+
+bool ParserBase::parseUnifiedHunkHeader()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedHunkHeader()" << endl;
+
+ if ( m_unifiedHunkHeader.exactMatch( *m_diffIterator ) )
+ {
+ ++m_diffIterator;
+ return true;
+ }
+ else
+ {
+// kdDebug(8101) << "This is not a unified hunk header : " << (*m_diffIterator) << endl;
+ return false;
+ }
+
+}
+
+bool ParserBase::parseContextHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseContextHunkBody()" << endl;
+
+ // Storing the src part of the hunk for later use
+ QStringList oldLines;
+ for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
+// kdDebug(8101) << "Added old line: " << *m_diffIterator << endl;
+ oldLines.append( *m_diffIterator );
+ }
+
+ if( !m_contextHunkHeader3.exactMatch( *m_diffIterator ) )
+ return false;
+
+ ++m_diffIterator;
+
+ // Storing the dest part of the hunk for later use
+ QStringList newLines;
+ for( ; m_diffIterator != m_diffLines.end() && m_contextHunkBodyLine.exactMatch( *m_diffIterator ); ++m_diffIterator ) {
+// kdDebug(8101) << "Added new line: " << *m_diffIterator << endl;
+ newLines.append( *m_diffIterator );
+ }
+
+ QString function = m_contextHunkHeader1.cap( 1 );
+// kdDebug(8101) << "Captured function: " << function << endl;
+ int linenoA = m_contextHunkHeader2.cap( 1 ).toInt();
+// kdDebug(8101) << "Source line number: " << linenoA << endl;
+ int linenoB = m_contextHunkHeader3.cap( 1 ).toInt();
+// kdDebug(8101) << "Dest line number: " << linenoB << endl;
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
+
+ m_currentModel->addHunk( hunk );
+
+ QStringList::Iterator oldIt = oldLines.begin();
+ QStringList::Iterator newIt = newLines.begin();
+
+ Difference* diff;
+ while( oldIt != oldLines.end() || newIt != newLines.end() )
+ {
+ if( oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ) )
+ {
+// kdDebug(8101) << "Delete: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Delete );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ for( ; oldIt != oldLines.end() && m_contextHunkBodyRemoved.exactMatch( *oldIt ); ++oldIt )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyRemoved.cap( 1 ) << endl;
+ diff->addSourceLine( m_contextHunkBodyRemoved.cap( 1 ) );
+ linenoA++;
+ }
+ }
+ else if( newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ) )
+ {
+// kdDebug(8101) << "Insert: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Insert );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ for( ; newIt != newLines.end() && m_contextHunkBodyAdded.exactMatch( *newIt ); ++newIt )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyAdded.cap( 1 ) << endl;
+ diff->addDestinationLine( m_contextHunkBodyAdded.cap( 1 ) );
+ linenoB++;
+ }
+ }
+ else if( ( oldIt == oldLines.end() || m_contextHunkBodyContext.exactMatch( *oldIt ) ) &&
+ ( newIt == newLines.end() || m_contextHunkBodyContext.exactMatch( *newIt ) ) )
+ {
+// kdDebug(8101) << "Unchanged: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ // Dont add this diff with addDiff to the model... no unchanged differences allowed in there...
+ diff->setType( Difference::Unchanged );
+ hunk->add( diff );
+ while( ( oldIt == oldLines.end() || m_contextHunkBodyContext.exactMatch( *oldIt ) ) &&
+ ( newIt == newLines.end() || m_contextHunkBodyContext.exactMatch( *newIt ) ) &&
+ ( oldIt != oldLines.end() || newIt != newLines.end() ) )
+ {
+ QString l;
+ if( oldIt != oldLines.end() )
+ {
+ l = m_contextHunkBodyContext.cap( 1 );
+// kdDebug(8101) << "old: " << l << endl;
+ ++oldIt;
+ }
+ if( newIt != newLines.end() )
+ {
+ l = m_contextHunkBodyContext.cap( 1 );
+// kdDebug(8101) << "new: " << l << endl;
+ ++newIt;
+ }
+ diff->addSourceLine( l );
+ diff->addDestinationLine( l );
+ linenoA++;
+ linenoB++;
+ }
+ }
+ else if( ( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) ) ||
+ ( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) ) )
+ {
+// kdDebug(8101) << "Changed: " << endl;
+ diff = new Difference( linenoA, linenoB );
+ diff->setType( Difference::Change );
+ m_currentModel->addDiff( diff );
+// kdDebug(8101) << "Difference added" << endl;
+ hunk->add( diff );
+ while( oldIt != oldLines.end() && m_contextHunkBodyChanged.exactMatch( *oldIt ) )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
+ diff->addSourceLine( m_contextHunkBodyChanged.cap( 1 ) );
+ linenoA++;
+ ++oldIt;
+ }
+ while( newIt != newLines.end() && m_contextHunkBodyChanged.exactMatch( *newIt ) )
+ {
+// kdDebug(8101) << " " << m_contextHunkBodyChanged.cap( 1 ) << endl;
+ diff->addDestinationLine( m_contextHunkBodyChanged.cap( 1 ) );
+ linenoB++;
+ ++newIt;
+ }
+ }
+ else
+ return false;
+ diff->determineInlineDifferences();
+ }
+
+ return true;
+}
+
+bool ParserBase::parseEdHunkBody()
+{
+ return false;
+}
+
+bool ParserBase::parseNormalHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseNormalHunkBody" << endl;
+
+ QString type = QString::null;
+
+ int linenoA = 0, linenoB = 0;
+
+ if ( m_normalDiffType == Difference::Insert )
+ {
+ linenoA = m_normalHunkHeaderAdded.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderAdded.cap( 2 ).toInt();
+ }
+ else if ( m_normalDiffType == Difference::Delete )
+ {
+ linenoA = m_normalHunkHeaderRemoved.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderRemoved.cap( 3 ).toInt();
+ }
+ else if ( m_normalDiffType == Difference::Change )
+ {
+ linenoA = m_normalHunkHeaderChanged.cap( 1 ).toInt();
+ linenoB = m_normalHunkHeaderChanged.cap( 3 ).toInt();
+ }
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB );
+ m_currentModel->addHunk( hunk );
+ Difference* diff = new Difference( linenoA, linenoB );
+ hunk->add( diff );
+ m_currentModel->addDiff( diff );
+
+ diff->setType( m_normalDiffType );
+
+ if ( m_normalDiffType == Difference::Change || m_normalDiffType == Difference::Delete )
+ for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyRemoved.exactMatch( *m_diffIterator ); ++m_diffIterator )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ diff->addSourceLine( m_normalHunkBodyRemoved.cap( 1 ) );
+ }
+ if ( m_normalDiffType == Difference::Change )
+ if( m_diffIterator != m_diffLines.end() && m_normalHunkBodyDivider.exactMatch( *m_diffIterator ) )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ ++m_diffIterator;
+ }
+ else
+ return false;
+ if ( m_normalDiffType == Difference::Insert || m_normalDiffType == Difference::Change )
+ for( ; m_diffIterator != m_diffLines.end() && m_normalHunkBodyAdded.exactMatch( *m_diffIterator ); ++m_diffIterator )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ diff->addDestinationLine( m_normalHunkBodyAdded.cap( 1 ) );
+ }
+
+ return true;
+}
+
+bool ParserBase::parseRCSHunkBody()
+{
+ return false;
+}
+
+bool ParserBase::matchesUnifiedHunkLine( QString line ) const
+{
+ static const QChar context( ' ' );
+ static const QChar added ( '+' );
+ static const QChar removed( '-' );
+
+ QChar first = line[0];
+
+ return ( first == context || first == added || first == removed );
+}
+
+bool ParserBase::parseUnifiedHunkBody()
+{
+// kdDebug(8101) << "ParserBase::parseUnifiedHunkBody" << endl;
+
+ int linenoA = 0, linenoB = 0;
+ bool wasNum;
+
+ // Fetching the stuff we need from the hunkheader regexp that was parsed in parseUnifiedHunkHeader();
+ linenoA = m_unifiedHunkHeader.cap( 1 ).toInt();
+ if( !m_unifiedHunkHeader.cap( 3 ).isEmpty() && m_unifiedHunkHeader.cap( 3 ).toInt(&wasNum) == 0 ) {
+ // If a hunk is an insertion or deletion with no context, the line number given
+ // is the one before the hunk. this isn't what we want, so increment it to fix this.
+ if( wasNum == false )
+ return false;
+ linenoA++;
+ }
+ linenoB = m_unifiedHunkHeader.cap( 4 ).toInt();
+ if( !m_unifiedHunkHeader.cap( 6 ).isEmpty() && m_unifiedHunkHeader.cap( 6 ).toInt(&wasNum) == 0 ) {
+ // see above
+ if( wasNum == false )
+ return false;
+ linenoB++;
+ }
+ QString function = m_unifiedHunkHeader.cap( 7 );
+ for ( int i = 0; i < 9; i++ )
+ {
+// kdDebug(8101) << "Capture " << i << ": " << m_unifiedHunkHeader.cap( i ) << endl;
+ }
+
+ DiffHunk* hunk = new DiffHunk( linenoA, linenoB, function );
+ m_currentModel->addHunk( hunk );
+
+ const QStringList::ConstIterator m_diffLinesEnd = m_diffLines.end();
+
+ const QString context = QString( " " );
+ const QString added = QString( "+" );
+ const QString removed = QString( "-" );
+
+ while( m_diffIterator != m_diffLinesEnd && matchesUnifiedHunkLine( *m_diffIterator ) )
+ {
+ Difference* diff = new Difference( linenoA, linenoB );
+ hunk->add( diff );
+
+ if( (*m_diffIterator).startsWith( context ) )
+ { // context
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( context ); ++m_diffIterator )
+ {
+ diff->addSourceLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ diff->addDestinationLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoA++;
+ linenoB++;
+ }
+ }
+ else
+ { // This is a real difference, not context
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( removed ); ++m_diffIterator )
+ {
+ diff->addSourceLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoA++;
+ }
+ for( ; m_diffIterator != m_diffLinesEnd && (*m_diffIterator).startsWith( added ); ++m_diffIterator )
+ {
+ diff->addDestinationLine( QString( *m_diffIterator ).remove( 0, 1 ) );
+ linenoB++;
+ }
+ if ( diff->sourceLineCount() == 0 )
+ {
+ diff->setType( Difference::Insert );
+// kdDebug(8101) << "Insert difference" << endl;
+ }
+ else if ( diff->destinationLineCount() == 0 )
+ {
+ diff->setType( Difference::Delete );
+// kdDebug(8101) << "Delete difference" << endl;
+ }
+ else
+ {
+ diff->setType( Difference::Change );
+// kdDebug(8101) << "Change difference" << endl;
+ }
+ diff->determineInlineDifferences();
+ m_currentModel->addDiff( diff );
+ }
+ }
+
+ return true;
+}
+
+DiffModelList* ParserBase::parseContext()
+{
+ while ( parseContextDiffHeader() )
+ {
+ while ( parseContextHunkHeader() )
+ parseContextHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseEd()
+{
+ while ( parseEdDiffHeader() )
+ {
+ while ( parseEdHunkHeader() )
+ parseEdHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseNormal()
+{
+ while ( parseNormalDiffHeader() )
+ {
+ while ( parseNormalHunkHeader() )
+ parseNormalHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ if ( m_singleFileDiff )
+ {
+ while ( parseNormalHunkHeader() )
+ parseNormalHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseRCS()
+{
+ while ( parseRCSDiffHeader() )
+ {
+ while ( parseRCSHunkHeader() )
+ parseRCSHunkBody();
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
+DiffModelList* ParserBase::parseUnified()
+{
+ while ( parseUnifiedDiffHeader() )
+ {
+ while ( parseUnifiedHunkHeader() )
+ parseUnifiedHunkBody();
+// kdDebug(8101) << "New model ready to be analyzed..." << endl;
+// kdDebug(8101) << " differenceCount() == " << m_currentModel->differenceCount() << endl;
+ if ( m_currentModel->differenceCount() > 0 )
+ m_models->append( m_currentModel );
+ }
+
+ m_models->sort();
+
+ if ( m_models->count() > 0 )
+ {
+ return m_models;
+ }
+ else
+ {
+ delete m_models;
+ return 0L;
+ }
+}
+
diff --git a/kompare/libdiff2/parserbase.h b/kompare/libdiff2/parserbase.h
new file mode 100644
index 00000000..5e08803e
--- /dev/null
+++ b/kompare/libdiff2/parserbase.h
@@ -0,0 +1,133 @@
+/**************************************************************************
+** parserbase.h
+** -------------------
+** begin : Tue Jul 30 23:53:52 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 _DIFF2_PARSERBASE_H
+#define _DIFF2_PARSERBASE_H
+
+#include <qregexp.h>
+
+#include "kompare.h"
+#include "difference.h"
+#include "diffmodellist.h"
+
+class QStringList;
+class QString;
+
+namespace Diff2
+{
+
+class KompareModelList;
+
+class ParserBase
+{
+public:
+ ParserBase( const KompareModelList* list, const QStringList& diff );
+ virtual ~ParserBase();
+
+public:
+ enum Kompare::Format format() { return determineFormat(); };
+ DiffModelList* parse();
+
+protected:
+ virtual bool parseContextDiffHeader();
+ virtual bool parseEdDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+ virtual bool parseUnifiedDiffHeader();
+
+ virtual bool parseContextHunkHeader();
+ virtual bool parseEdHunkHeader();
+ virtual bool parseNormalHunkHeader();
+ virtual bool parseRCSHunkHeader();
+ virtual bool parseUnifiedHunkHeader();
+
+ virtual bool parseContextHunkBody();
+ virtual bool parseEdHunkBody();
+ virtual bool parseNormalHunkBody();
+ virtual bool parseRCSHunkBody();
+ virtual bool parseUnifiedHunkBody();
+
+ virtual DiffModelList* parseContext();
+ virtual DiffModelList* parseEd();
+ virtual DiffModelList* parseNormal();
+ virtual DiffModelList* parseRCS();
+ virtual DiffModelList* parseUnified();
+
+protected: // Helper methods to speed things up
+ bool matchesUnifiedHunkLine( QString line ) const;
+
+protected:
+ /** What is format of the diff */
+ virtual enum Kompare::Format determineFormat();
+
+protected:
+ // Regexps for context parsing
+ QRegExp m_contextDiffHeader1;
+ QRegExp m_contextDiffHeader2;
+
+ QRegExp m_contextHunkHeader1;
+ QRegExp m_contextHunkHeader2;
+ QRegExp m_contextHunkHeader3;
+
+ QRegExp m_contextHunkBodyRemoved;
+ QRegExp m_contextHunkBodyAdded;
+ QRegExp m_contextHunkBodyChanged;
+ QRegExp m_contextHunkBodyContext;
+ QRegExp m_contextHunkBodyLine; // Added for convenience
+
+ // Regexps for normal parsing
+ QRegExp m_normalDiffHeader;
+
+ QRegExp m_normalHunkHeaderAdded;
+ QRegExp m_normalHunkHeaderRemoved;
+ QRegExp m_normalHunkHeaderChanged;
+
+ QRegExp m_normalHunkBodyRemoved;
+ QRegExp m_normalHunkBodyAdded;
+ QRegExp m_normalHunkBodyDivider;
+
+ enum Difference::Type m_normalDiffType;
+
+ // RegExps for rcs parsing
+ QRegExp m_rcsDiffHeader;
+
+ // Regexps for unified parsing
+ QRegExp m_unifiedDiffHeader1;
+ QRegExp m_unifiedDiffHeader2;
+
+ QRegExp m_unifiedHunkHeader;
+
+ QRegExp m_unifiedHunkBodyAdded;
+ QRegExp m_unifiedHunkBodyRemoved;
+ QRegExp m_unifiedHunkBodyContext;
+ QRegExp m_unifiedHunkBodyLine; // Added for convenience
+
+protected:
+ const QStringList& m_diffLines;
+ DiffModel* m_currentModel;
+ DiffModelList* m_models;
+ QStringList::ConstIterator m_diffIterator;
+
+ bool m_singleFileDiff;
+
+protected:
+ const KompareModelList* m_list;
+};
+
+} // End of namespace Diff2
+
+#endif
diff --git a/kompare/libdiff2/perforceparser.cpp b/kompare/libdiff2/perforceparser.cpp
new file mode 100644
index 00000000..907d88ff
--- /dev/null
+++ b/kompare/libdiff2/perforceparser.cpp
@@ -0,0 +1,223 @@
+/**************************************************************************
+** perforceparser.cpp
+** ------------------
+** begin : Sun Aug 4 15:05:35 2002
+** copyright : (C) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** ( at your option ) any later version.
+**
+***************************************************************************/
+
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include "perforceparser.h"
+
+using namespace Diff2;
+
+PerforceParser::PerforceParser( const KompareModelList* list, const QStringList& diff ) : ParserBase( list, diff )
+{
+ m_contextDiffHeader1.setPattern( "==== (.*) - (.*) ====\\n" );
+ m_contextDiffHeader1.setMinimal( true );
+ m_normalDiffHeader.setPattern ( "==== (.*) - (.*) ====\\n" );
+ m_normalDiffHeader.setMinimal ( true );
+ m_rcsDiffHeader.setPattern ( "==== (.*) - (.*) ====\\n" );
+ m_rcsDiffHeader.setMinimal ( true );
+ m_unifiedDiffHeader1.setPattern( "==== (.*) - (.*) ====\\n" );
+ m_unifiedDiffHeader1.setMinimal( true );
+}
+
+PerforceParser::~PerforceParser()
+{
+}
+
+enum Kompare::Format PerforceParser::determineFormat()
+{
+ kdDebug(8101) << "Determining the format of the Perforce Diff" << endl;
+
+ QRegExp unifiedRE( "^@@" );
+ QRegExp contextRE( "^\\*{15}" );
+ QRegExp normalRE ( "^\\d+(|,\\d+)[acd]\\d+(|,\\d+)" );
+ QRegExp rcsRE ( "^[acd]\\d+ \\d+" );
+ // Summary is not supported since it gives no useful parsable info
+
+ QStringList::ConstIterator it = m_diffLines.begin();
+
+ while( it != m_diffLines.end() )
+ {
+ if( (*it).find( unifiedRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Unified diff..." << endl;
+ return Kompare::Unified;
+ }
+ else if( (*it).find( contextRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Context diff..." << endl;
+ return Kompare::Context;
+ }
+ else if( (*it).find( normalRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a Normal diff..." << endl;
+ return Kompare::Normal;
+ }
+ else if( (*it).find( rcsRE, 0 ) == 0 )
+ {
+ kdDebug(8101) << "Difflines are from a RCS diff..." << endl;
+ return Kompare::RCS;
+ }
+ ++it;
+ }
+ kdDebug(8101) << "Difflines are from an unknown diff..." << endl;
+ return Kompare::UnknownFormat;
+}
+
+bool PerforceParser::parseContextDiffHeader()
+{
+// kdDebug(8101) << "ParserBase::parseContextDiffHeader()" << endl;
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+ if ( m_contextDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+// kdDebug(8101) << "Matched length Header1 = " << m_contextDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_contextDiffHeader1.cap( 0 ) << endl;
+// kdDebug(8101) << "First capture Header1 = " << m_contextDiffHeader1.cap( 1 ) << endl;
+// kdDebug(8101) << "Second capture Header1 = " << m_contextDiffHeader1.cap( 2 ) << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_contextDiffHeader1.cap( 1 ) );
+ destinationFileRE.exactMatch( m_contextDiffHeader1.cap( 2 ) );
+ kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+ kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "Matched length = " << m_contextDiffHeader1.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << m_contextDiffHeader1.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
+bool PerforceParser::parseNormalDiffHeader()
+{
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+ kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+ kdDebug(8101) << "String length = " << (*m_diffIterator).length() << endl;
+ if ( m_normalDiffHeader.exactMatch( *(m_diffIterator)++ ) )
+ {
+ kdDebug(8101) << "Matched length Header1 = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Matched string Header1 = " << m_normalDiffHeader.cap( 0 ) << endl;
+ kdDebug(8101) << "First capture Header1 = \"" << m_normalDiffHeader.cap( 1 ) << "\"" << endl;
+ kdDebug(8101) << "Second capture Header1 = \"" << m_normalDiffHeader.cap( 2 ) << "\"" << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_normalDiffHeader.cap( 1 ) );
+ destinationFileRE.exactMatch( m_normalDiffHeader.cap( 2 ) );
+ kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+ kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+ kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+ kdDebug(8101) << "Matched length = " << m_normalDiffHeader.matchedLength() << endl;
+ kdDebug(8101) << "Captured texts = " << m_normalDiffHeader.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
+bool PerforceParser::parseRCSDiffHeader()
+{
+ return false;
+}
+
+bool PerforceParser::parseUnifiedDiffHeader()
+{
+ bool result = false;
+
+ QStringList::ConstIterator itEnd = m_diffLines.end();
+
+ QRegExp sourceFileRE ( "([^\\#]+)#(\\d+)" );
+ QRegExp destinationFileRE( "([^\\#]+)#(|\\d+)" );
+
+ while ( m_diffIterator != itEnd )
+ {
+// kdDebug(8101) << "Line = " << *m_diffIterator << endl;
+// kdDebug(8101) << "String length = " << (*m_diffIterator).length() << endl;
+ if ( m_unifiedDiffHeader1.exactMatch( *(m_diffIterator)++ ) )
+ {
+// kdDebug(8101) << "Matched length Header1 = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Matched string Header1 = " << m_unifiedDiffHeader1.cap( 0 ) << endl;
+// kdDebug(8101) << "First capture Header1 = \"" << m_unifiedDiffHeader1.cap( 1 ) << "\"" << endl;
+// kdDebug(8101) << "Second capture Header1 = \"" << m_unifiedDiffHeader1.cap( 2 ) << "\"" << endl;
+
+ m_currentModel = new DiffModel();
+ sourceFileRE.exactMatch( m_unifiedDiffHeader1.cap( 1 ) );
+ destinationFileRE.exactMatch( m_unifiedDiffHeader1.cap( 2 ) );
+// kdDebug(8101) << "Matched length = " << sourceFileRE.matchedLength() << endl;
+// kdDebug(8101) << "Matched length = " << destinationFileRE.matchedLength() << endl;
+// kdDebug(8101) << "Captured texts = " << sourceFileRE.capturedTexts() << endl;
+// kdDebug(8101) << "Captured texts = " << destinationFileRE.capturedTexts() << endl;
+// kdDebug(8101) << "Source File : " << sourceFileRE.cap( 1 ) << endl;
+// kdDebug(8101) << "Destination File : " << destinationFileRE.cap( 1 ) << endl;
+ m_currentModel->setSourceFile ( sourceFileRE.cap( 1 ) );
+ m_currentModel->setDestinationFile( destinationFileRE.cap( 1 ) );
+
+ result = true;
+
+ break;
+ }
+ else
+ {
+// kdDebug(8101) << "Matched length = " << m_unifiedDiffHeader1.matchedLength() << endl;
+// kdDebug(8101) << "Captured texts = " << m_unifiedDiffHeader1.capturedTexts() << endl;
+ }
+ }
+
+ return result;
+}
+
diff --git a/kompare/libdiff2/perforceparser.h b/kompare/libdiff2/perforceparser.h
new file mode 100644
index 00000000..99973167
--- /dev/null
+++ b/kompare/libdiff2/perforceparser.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+** perforceparser.h
+** -------------------
+** begin : Sun Sep 8 20:58:59 2002
+** copyright : (c) 2002-2004 Otto Bruggeman
+** email : otto.bruggeman@home.nl
+**
+***************************************************************************/
+/***************************************************************************
+**
+** 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 _PERFORCE_PARSER_H
+#define _PERFORCE_PARSER_H
+
+#include "parserbase.h"
+
+namespace Diff2
+{
+
+class PerforceParser : public ParserBase
+{
+public:
+ PerforceParser( const KompareModelList* list, const QStringList& diff );
+ virtual ~PerforceParser();
+
+protected:
+ virtual bool parseContextDiffHeader();
+ virtual bool parseNormalDiffHeader();
+ virtual bool parseRCSDiffHeader();
+ virtual bool parseUnifiedDiffHeader();
+
+protected:
+ virtual enum Kompare::Format determineFormat();
+};
+
+} // End of namespace Diff2
+
+#endif