changeset 58:8af4bb9d9a5a

Version 0.9.83
author joachim99
date Sun, 07 Mar 2004 09:59:09 +0000
parents 023fbd76c1e3
children b9d051fd4fd5
files kdiff3/ChangeLog kdiff3/README kdiff3/TODO kdiff3/configure.in.in kdiff3/src/common.h kdiff3/src/diff.cpp kdiff3/src/diff.h kdiff3/src/difftextwindow.cpp kdiff3/src/directorymergewindow.cpp kdiff3/src/directorymergewindow.h kdiff3/src/fileaccess.cpp kdiff3/src/fileaccess.h kdiff3/src/kdiff3.cpp kdiff3/src/kdiff3.desktop kdiff3/src/kdiff3.h kdiff3/src/kdiff3.pro kdiff3/src/kdiff3_shell.rc kdiff3/src/kdiff3part.desktop kdiff3/src/kreplacements/kreplacements.cpp kdiff3/src/main.cpp kdiff3/src/merger.cpp kdiff3/src/merger.h kdiff3/src/mergeresultwindow.cpp kdiff3/src/optiondialog.cpp kdiff3/src/optiondialog.h kdiff3/src/pdiff.cpp kdiff3/src/version.h
diffstat 27 files changed, 1304 insertions(+), 737 deletions(-) [+]
line wrap: on
line diff
--- a/kdiff3/ChangeLog	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/ChangeLog	Sun Mar 07 09:59:09 2004 +0000
@@ -1,3 +1,35 @@
+Version 0.9.83 - 2004/03/06
+===========================
+- Reading directorys fixed for Win95/98
+- Caseinsensitive filename matching for windows.
+- Autocopy to selection for systems that support this. (Patch by Stefan Partheymueller)
+- Drawing during recalc suppressed in merge result editor.
+- Cursor could go beyond last line in merge result editor. (Corrected NrOfLine-counting.)
+- Windows: Start with invalid cmd-line-options brings up a messagebox with the list of options.
+- Corrected encoding when copying to or pasting from clipboard.
+- Corrected char-by-char-diff at beginning of line. ("012345 12345 xyz" <-> "012345 xyz")
+- Warning when merging with preprocessor or upcase-conversion enabled.
+- Rewrite of preprocessing code should fix several problems. E.g.:
+  - Ignore C/C++-comments only worked with a preprocessor active.
+  - Preprocessor output now is input of line-matching preprocessor.
+  - Paste to diff-window, didn't work if LMPP or Ignore C/C++-Comments was set.
+
+Version 0.9.82 - 2004/02/02
+===========================
+- DirectoryMerge: Running merge op for last item in a folder, performed the
+  merge op for all following items in following folders. (Possible data loss!)
+- Fix: Preprocessors and "Ignore Comments" didn't work at the same time.
+- Fix: Preprocessors crashed with remote files.
+- Open-Dialog: When either input is changed, then reset the output to be empty.
+  (To avoid accidental overwrites.)
+- Icon for "Highlight white space differences."
+- Editor-Option: Line End Style for saving: Dos/Windows "\r\n" vs. Unix "\n"
+- Merge output editor: Corrected wrong encoding for output-filename and 
+  user-typed characters.
+- Speedup for reading directories under Windows.
+- Enhanced progress dialog responsiveness during local file copy.
+- Fix for non-KDE-version: No URL-encoding when dropping files in open dialog.
+
 Version 0.9.81 - 2004/01/08
 ===========================
 - Allow to compile with --enable-final
@@ -40,7 +72,7 @@
 - Default diff-view now again side by side instead of one above the other.
 
 
-Version 0.9.71 - 2003/10/14
+Version 0.9.71 - 2003/10/17
 ===========================
 - Windows-Installer by Sebastien Fricker.
 - Bugfixes for Windows. (Problems with setFont() in paintEvent().)
--- a/kdiff3/README	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/README	Sun Mar 07 09:59:09 2004 +0000
@@ -3,7 +3,7 @@
 
 Author: Joachim Eibl  (joachim.eibl@gmx.de)
 Copyright: (C) 2002-2003 by Joachim Eibl
-KDiff3-Version: 0.9.81
+KDiff3-Version: 0.9.83
 
 
 KDiff3 is a program that
@@ -45,12 +45,12 @@
 
 
 Requirements & Installation:
-   Version 0.9.81 provides special support for KDE3, but it can also be
+   Version 0.9.83 provides special support for KDE3, but it can also be
    built without KDE3 if the Qt-libraries are available.
    (I also tested the program under Windows.)
 
    You always need
-      - kdiff3-0.9.81.tar.gz
+      - kdiff3-0.9.83.tar.gz
 
    For building the KDE3-version
       - KDE>=3.1 and QT>=3.1-libraries.
@@ -67,7 +67,7 @@
    - Make sure your shell-variable QTDIR is correct. (echo $QTDIR).
      If it doesn't contain the correct path, type
         export QTDIR=your_path_to_qt  (e.g. /usr/lib/qt3)
-   - cd into the directory kdiff3-0.9.81 and type
+   - cd into the directory kdiff3-0.9.83 and type
    - ./configure --prefix=/opt/kde3           (your KDE3 directory here)
    - (make clean)                    (Required if you already compiled once.)
    - make                            (Run compilation)
@@ -78,6 +78,9 @@
    If some icons are not visible or don't seem right, probably the prefix
    was wrong. Check where your KDE3 installation is located and
    use that directory with the prefix-option of configure.
+
+   This command should tell you: kde-config --prefix
+
    For SuSE and most distributions the prefix usually is /opt/kde3.
    For Redhat and Mandrake the prefix usually is /usr.
    For a local installation, that doesn't need root rights try
@@ -105,7 +108,7 @@
    - Make sure your shell-variable QTDIR is correct. (echo $QTDIR).
      If it doesn't contain the correct path, type
         export QTDIR=your_path_to_qt  (e.g. /usr/lib/qt)
-   - cd into the directory kdiff3-0.9.81/src and type
+   - cd into the directory kdiff3-0.9.83/src and type
    - make -f Makefile.qt
    - make -f Makefile.qt install     (You must have root-rights for this step.)
      (copies the files into /usr/local/bin and /usr/local/share/doc/kdiff3)
@@ -124,7 +127,7 @@
    - I couldn't test this, so you might have to experiment a bit.
    - Start by generating a Makefile with
    - qmake kdiff3.pro -o Makefile
-   - If you succeed, I'd like to know how so I can document it here.
+   - If you succeed, I'd like to know how, so I can document it here.
 
    
 Start from commandline:
--- a/kdiff3/TODO	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/TODO	Sun Mar 07 09:59:09 2004 +0000
@@ -3,7 +3,78 @@
 TODO
 ====
 
-- Automatic line wrap in the difference windows
+- Automatic line wrap for too long lines in the difference windows
 - Printing of the diff-windows (requires automatic line wrap)
 - Undo function in the merge-editor.
 - More viewing options for directory widget.
+
+- And one observation. When select Cyrillic charset - it looks like it was
+  not saved. When open this dialog again - Latin charset is selected anyway.
+- Add options to specify a language and charset.
+- Ask before saving to a file that already exists (optionally).
+- Don't overwrite existing .orig-file, when saving the second time.
+
+- File Menu: Close (Ctrl-F4): Close current file (check if saved and forget the data)
+- Dirview:
+   - Multiselections: Changing Operations or applying ops for all selected items.
+   - Optionally show size/date for A/B/C
+   - Choose what to see (all or only different items)
+   - If only different items are visible: copy the others nevertheless to destdir.
+   - Improve Ctrl-1/2/3 shortcuts in Dirview.
+   - Warnung wenn Datum in B oder C älter als A ist.
+   - Zielverzeichnis nachträglich änderbar
+   - Bei Kopie von Remote nach lokal: Auf jeden Fall das modification Datum setzen.
+   - Ctrl-Space doesn't work when a file comparison takes place.
+   - Option to allow case-insensitive filename-matching.
+- Options to show/suppress annoying messages
+
+- Unicode-support
+
+- What's this-Help.
+- Tip of the day.
+
+More Statistics before the merge begins:
+- How many files are there?
+- How many files are equal/different?
+- How many files would be copies/merged/ignored?
+
+- Allow to view and merge CVS-conflict files (and diff3-output) and allow to save output
+  with conflicts in diff3 output-format.
+  
+- Provide configure-rules for systems without KDE. (I need help here.)
+
+- Allow different comment-styles (e.g. via a regexp for comments)
+
+- Possibility to jump to next difference in the same line (for very long lines).
+
+- Allow analysis of unified directory-diff/patch-file.
+
+- Add example for line-matching preprocessor to the documentation.
+  Simple testcase: Consider file a.txt (6 lines):
+      aa
+      ba
+      ca
+      da
+      ea
+      fa
+  And file b.txt (3 lines):
+      cg
+      dg
+      eg
+  And the following line matching preprocessor command, that replaces 'g' with 'a':
+      /usr/bin/perl -p -e 's/g/a/;'
+  Without that command the following lines would be placed next to each other:
+      aa - cg
+      ba - dg
+      ca - eg
+      da
+      ea
+      fa
+  But with this command the result of the comparison would be:
+      aa
+      ba
+      ca - cg
+      da - dg
+      ea - eg
+      fa
+
--- a/kdiff3/configure.in.in	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/configure.in.in	Sun Mar 07 09:59:09 2004 +0000
@@ -1,6 +1,6 @@
-#MIN_CONFIG(3.0.0)
+#MIN_CONFIG(3.1)
 
-AM_INIT_AUTOMAKE(kdiff3, 0.9.70)
+AM_INIT_AUTOMAKE(kdiff3, 0.9.82)
 AC_C_BIGENDIAN
 AC_CHECK_KDEMAXPATHLEN
 
--- a/kdiff3/src/common.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/common.h	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           common.h  -  Things that are needed often
                              -------------------
     begin                : Mon Mar 18 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
--- a/kdiff3/src/diff.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/diff.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           diff.cpp  -  description
                              -------------------
     begin                : Mon Mar 18 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -20,6 +20,7 @@
 
 #include "diff.h"
 #include "fileaccess.h"
+#include "optiondialog.h"
 
 #include <kmessagebox.h>
 #include <klocale.h>
@@ -32,7 +33,7 @@
 //using namespace std;
 
 
-int LineData::width()
+int LineData::width() const
 {
    int w=0;
    int j=0;
@@ -110,64 +111,424 @@
 }
 
 
-// class needed during preprocess phase
-class LineDataRef
+
+
+static bool isLineOrBufEnd( const char* p, int i, int size )
 {
-   const LineData* m_pLd;
-public:
-   LineDataRef(const LineData* pLd){ m_pLd = pLd; }
+   return 
+      i>=size        // End of file
+      || p[i]=='\n'  // Normal end of line
 
-   bool operator<(const LineDataRef& ldr2) const
-   {
-      const LineData* pLd1 = m_pLd;
-      const LineData* pLd2 = ldr2.m_pLd;
-      const char* p1 = pLd1->pFirstNonWhiteChar;
-      const char* p2 = pLd2->pFirstNonWhiteChar;
+      // No support for Mac-end of line yet, because incompatible with GNU-diff-routines.      
+      // || ( p[i]=='\r' && (i>=size-1 || p[i+1]!='\n') 
+      //                 && (i==0        || p[i-1]!='\n') )  // Special case: '\r' without '\n'
+      ;
+}
 
-      int size1=pLd1->size;
-      int size2=pLd2->size;
 
-      int i1=min2(pLd1->pFirstNonWhiteChar - pLd1->pLine,size1);
-      int i2=min2(pLd2->pFirstNonWhiteChar - pLd2->pLine,size2);
-      for(;;)
-      {
-         while( i1<size1 && isWhite( p1[i1] ) ) ++i1;
-         while( i2<size2 && isWhite( p2[i2] ) ) ++i2;
-         if ( i1==size1 || i2==size2 )
-         {
-            if ( i1==size1 && i2==size2 ) return false;  // Equal
-            if ( i1==size1 ) return true;  // String 1 is shorter than string 2
-            if ( i2==size2 ) return false; // String 1 is longer than string 2
-         }
-         if ( p1[i1]==p2[i2] ) { ++i1; ++i2; continue; }
-         return  p1[i1]<p2[i2];
-      }
-   }
-};
+/* Features of class SourceData:
+- Read a file (from the given URL) or accept data via a string.
+- Allocate and free buffers as necessary.
+- Run a preprocessor, when specified.
+- Run the line-matching preprocessor, when specified.
+- Run other preprocessing steps: Uppercase, ignore comments, 
+                                 remove carriage return, ignore numbers.
+
+Order of operation:
+ 1. If data was given via a string then save it to a temp file. (see setData())
+ 2. If the specified file is nonlocal (URL) copy it to a temp file.
+ 3. If a preprocessor was specified, run the input file through it.
+ 4. Read the output of the preprocessor.
+ 5. If Uppercase was specified: Turn the read data to uppercase.
+ 6. Write the result to a temp file.
+ 7. If a line-matching preprocessor was specified, run the temp file through it.
+ 8. Read the output of the line-matching preprocessor.
+ 9. If ignore numbers was specified, strip the LMPP-output of all numbers.
+10. If ignore comments was specified, strip the LMPP-output of comments.
+
+Optimizations: Skip unneeded steps.
+*/
+
+SourceData::SourceData()
+{ 
+   m_pOptionDialog = 0;
+   reset();
+}
+
+SourceData::~SourceData()
+{
+   reset();
+}
 
 void SourceData::reset()
 {
+   m_normalData.reset();
+   m_lmppData.reset();
+   if ( !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+}
+
+void SourceData::setFilename( const QString& filename )
+{
+   if (filename.isEmpty())
+   {
+      reset();
+   }
+   else
+   {
+      FileAccess fa( filename );
+      setFileAccess( fa );
+   }
+}
+
+bool SourceData::isEmpty() 
+{ 
+   return getFilename().isEmpty(); 
+}
+
+bool SourceData::hasData() 
+{ 
+   return m_normalData.m_pBuf != 0;
+}
+
+void SourceData::setOptionDialog( OptionDialog* pOptionDialog )
+{
+   m_pOptionDialog = pOptionDialog;
+}
+
+QString SourceData::getFilename()
+{
+   return m_fileAccess.absFilePath();
+}
+
+QString SourceData::getAliasName()
+{
+   return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName;
+}
+
+void SourceData::setAliasName( const QString& name )
+{
+   m_aliasName = name;
+}
+
+void SourceData::setFileAccess( const FileAccess& fileAccess )
+{
+   m_fileAccess = fileAccess;
+   m_aliasName = QString();
+   if ( !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+}
+
+void SourceData::setData( const QString& data )
+{
+   // Create a temp file for preprocessing:
+   if ( m_tempInputFileName.isEmpty() )
+   {
+      m_tempInputFileName = FileAccess::tempFileName();
+   }
+   
+   FileAccess f( m_tempInputFileName );
+   bool bSuccess = f.writeFile( encodeString(data, m_pOptionDialog), data.length() );
+   if ( !bSuccess )
+   {
+      KMessageBox::error( m_pOptionDialog, i18n("Writing clipboard data to temp file failed.") );
+      return;
+   }
+   
+   m_aliasName = i18n("From Clipboard");
+   m_fileAccess = FileAccess("");  // Effect: m_fileAccess.isValid() is false
+}
+
+const LineData* SourceData::getLineDataForDiff() const 
+{
+   return m_lmppData.m_pBuf==0 ? &m_normalData.m_v[0] : &m_lmppData.m_v[0];
+}
+
+const LineData* SourceData::getLineDataForDisplay() const
+{
+   return &m_normalData.m_v[0];
+}
+
+int  SourceData::getSizeLines() const
+{
+   return m_normalData.m_vSize;
+}
+
+int SourceData::getSizeBytes() const
+{
+   return m_normalData.m_size;
+}
+
+const char* SourceData::getBuf() const
+{
+   return m_normalData.m_pBuf;
+}
+
+bool SourceData::isText()
+{
+   return m_normalData.m_bIsText;
+}
+ 
+bool SourceData::isFromBuffer()
+{
+   return !m_fileAccess.isValid();
+}
+
+
+bool SourceData::isBinaryEqualWith( const SourceData& other ) const
+{
+   return getSizeBytes() == other.getSizeBytes() &&  memcmp( getBuf(), other.getBuf(), getSizeBytes() )==0;
+}
+
+void SourceData::FileData::reset()
+{
    delete (char*)m_pBuf;
    m_pBuf = 0;
    m_v.clear();
    m_size = 0;
    m_vSize = 0;
-   m_bIsText = false;
-   m_bPreserve = false;
-   m_fileAccess = FileAccess("");
+   m_bIsText = true;
 }
 
+bool SourceData::FileData::readFile( const QString& filename )
+{
+   reset();
+   if ( filename.isEmpty() )   { return true; }
+
+   FileAccess fa( filename );
+   m_size = fa.sizeForReading();
+   char* pBuf;
+   m_pBuf = pBuf = new char[m_size+100];  // Alloc 100 byte extra: Savety hack, not nice but does no harm.
+   bool bSuccess = fa.readFile( pBuf, m_size );
+   if ( !bSuccess )
+   {
+      delete pBuf;
+      m_pBuf = 0;
+      m_size = 0;
+   }
+   return bSuccess;
+}
+
+bool SourceData::saveNormalDataAs( const QString& fileName )
+{
+   return m_normalData.writeFile( fileName );
+}
+
+bool SourceData::FileData::writeFile( const QString& filename )
+{
+   if ( filename.isEmpty() )   { return true; }
+
+   FileAccess fa( filename );
+   bool bSuccess = fa.writeFile(m_pBuf, m_size);
+   return bSuccess;
+}
+
+void SourceData::FileData::copyBufFrom( const FileData& src )
+{
+   reset();
+   char* pBuf;   
+   m_size = src.m_size;
+   m_pBuf = pBuf = new char[m_size+100];
+   memcpy( pBuf, src.m_pBuf, m_size );
+}
+
+void SourceData::readAndPreprocess()
+{
+   QString fileNameIn1;
+   QString fileNameOut1;
+   QString fileNameIn2;
+   QString fileNameOut2;
+   
+   bool bTempFileFromClipboard = !m_fileAccess.isValid();
+      
+   // Detect the input for the preprocessing operations
+   if ( !bTempFileFromClipboard )
+   {
+      if ( m_fileAccess.isLocal() )
+      {
+         fileNameIn1 = m_fileAccess.absFilePath();
+      }
+      else    // File is not local: create a temporary local copy:
+      {
+         if ( m_tempInputFileName.isEmpty() )  { m_tempInputFileName = FileAccess::tempFileName(); }
+      
+         m_fileAccess.copyFile(m_tempInputFileName);
+         fileNameIn1 = m_tempInputFileName;
+      }
+   }
+   else // The input was set via setData(), probably from clipboard.
+   {
+      fileNameIn1 = m_tempInputFileName;
+   }
+      
+   m_normalData.reset();
+   m_lmppData.reset();
+   
+   FileAccess faIn(fileNameIn1);
+   int fileInSize = faIn.size();
+   
+   if ( fileInSize > 0 )
+   {  
+
+#ifdef _WIN32
+      QString catCmd = "type";
+      fileNameIn1.replace( '/', "\\" );
+#else
+      QString catCmd = "cat";
+#endif
+      
+      // Run the first preprocessor
+      if ( m_pOptionDialog->m_PreProcessorCmd.isEmpty() )
+      {
+         // No preprocessing: Read the file directly:
+         m_normalData.readFile( fileNameIn1 );
+      }
+      else
+      {
+         QString ppCmd = m_pOptionDialog->m_PreProcessorCmd;
+         fileNameOut1 = FileAccess::tempFileName();
+         QString cmd = catCmd + " \"" + fileNameIn1 + "\" | " + ppCmd  + " >\"" + fileNameOut1+"\"";
+         ::system( encodeString(cmd, m_pOptionDialog) );
+         bool bSuccess = m_normalData.readFile( fileNameOut1 );
+         if ( fileInSize >0 && ( !bSuccess || m_normalData.m_size==0 ) )
+         {
+            KMessageBox::error(m_pOptionDialog, 
+               i18n("Preprocessing possibly failed. Check this command:\n\n  %1"
+                  "\n\nThe preprocessing command will be disabled now."
+               ).arg(cmd) );
+            m_pOptionDialog->m_PreProcessorCmd = "";
+            m_normalData.readFile( fileNameIn1 );
+         }
+      }
+
+      // Internal Preprocessing: Uppercase-conversion   
+      bool bInternalPreprocessing = false;
+      if ( m_pOptionDialog->m_bUpCase )
+      {
+         int i;
+         char* pBuf = const_cast<char*>(m_normalData.m_pBuf);
+         for(i=0; i<m_normalData.m_size; ++i)
+         {
+            pBuf[i] = toupper(pBuf[i]);
+         }
+         
+         bInternalPreprocessing = true;
+      }
+      
+      // LineMatching Preprocessor
+      if ( ! m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty() )
+      {
+         if ( bInternalPreprocessing )  
+         {
+            // write data to file after internal preprocessing before running the external LMPP-cmd.
+            if ( !fileNameOut1.isEmpty() )
+            {
+               FileAccess::removeFile( fileNameOut1 );
+               fileNameOut1="";
+            }
+            
+            fileNameIn2 = FileAccess::tempFileName();
+            bool bSuccess = m_normalData.writeFile( fileNameIn2 );
+            if ( !bSuccess )
+            {
+               KMessageBox::error(m_pOptionDialog, i18n("Error writing temporary file: %1").arg(fileNameIn2) );
+            }
+         }
+         else
+         {
+            fileNameIn2 = fileNameOut1.isEmpty() ? fileNameIn1 : fileNameOut1;
+         }
+      
+         QString ppCmd = m_pOptionDialog->m_LineMatchingPreProcessorCmd;
+         fileNameOut2 = FileAccess::tempFileName();
+         QString cmd = catCmd + " \"" + fileNameIn2 + "\" | " + ppCmd  + " >\"" + fileNameOut2 + "\"";
+         ::system( encodeString(cmd, m_pOptionDialog) );
+         bool bSuccess = m_lmppData.readFile( fileNameOut2 );
+         if ( FileAccess(fileNameIn2).size()>0 && ( !bSuccess || m_lmppData.m_size==0 ) )
+         {
+            KMessageBox::error(m_pOptionDialog, 
+               i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n  %1"
+                    "\n\nThe line-matching-preprocessing command will be disabled now."
+                   ).arg(cmd) );
+            m_pOptionDialog->m_LineMatchingPreProcessorCmd = "";
+            m_lmppData.readFile( fileNameIn2 );
+         }
+         FileAccess::removeFile( fileNameOut2 );
+         
+         if ( bInternalPreprocessing && !fileNameIn2.isEmpty() )
+         {
+            FileAccess::removeFile( fileNameIn2 );
+            fileNameIn2="";
+         }
+      }
+      else if ( m_pOptionDialog->m_bIgnoreComments )
+      {
+         // We need a copy of the normal data.
+         m_lmppData.copyBufFrom( m_normalData );
+      }
+      else
+      {  // We don't need any lmpp data at all.
+         m_lmppData.reset();
+      }
+   }            
+   
+   m_normalData.preprocess( m_pOptionDialog->m_bPreserveCarriageReturn );
+   m_lmppData.preprocess( false );
+   
+   if ( m_lmppData.m_vSize < m_normalData.m_vSize )
+   {
+      // This probably is the fault of the LMPP-Command, but not worth reporting.
+      m_lmppData.m_v.resize( m_normalData.m_vSize );
+      for(int i=m_lmppData.m_vSize; i<m_normalData.m_vSize; ++i )
+      {  // Set all empty lines to point to the end of the buffer.
+         m_lmppData.m_v[i].pLine = m_lmppData.m_pBuf+m_lmppData.m_size;
+      }
+      
+      m_lmppData.m_vSize = m_normalData.m_vSize;
+   }
+   
+   // Ignore comments
+   if ( m_pOptionDialog->m_bIgnoreComments )
+   {
+      m_lmppData.removeComments();
+      int vSize = min2(m_normalData.m_vSize, m_lmppData.m_vSize);
+      for(int i=0; i<vSize; ++i )
+      {
+         m_normalData.m_v[i].bContainsPureComment = m_lmppData.m_v[i].bContainsPureComment;
+      }
+   }
+      
+   // Remove unneeded temporary files. (A temp file from clipboard must not be deleted.)
+   if ( !bTempFileFromClipboard && !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+   
+   if ( !fileNameOut1.isEmpty() )
+   {
+      FileAccess::removeFile( fileNameOut1 );
+      fileNameOut1="";
+   }
+}
+
+
 /** Prepare the linedata vector for every input line.*/
-void SourceData::preprocess( bool bPreserveCR )
+void SourceData::FileData::preprocess( bool bPreserveCR )
 {
    const char* p = m_pBuf;
    m_bIsText = true;
    int lines = 1;
-
    int i;
    for( i=0; i<m_size; ++i )
    {
-      if (p[i]=='\n')
+      if ( isLineOrBufEnd(p,i,m_size) )
       {
          ++lines;
       }
@@ -184,7 +545,7 @@
    int whiteLength = 0;
    for( i=0; i<=m_size; ++i )
    {
-      if ( i==m_size ||  p[i]=='\n' )        // The last line does not end with a linefeed.
+      if ( isLineOrBufEnd( p, i, m_size ) )
       {
          m_v[lineIdx].pLine = &p[ i-lineLength ];
          while ( !bPreserveCR  &&  lineLength>0  &&  m_v[lineIdx].pLine[lineLength-1]=='\r'  )
@@ -237,7 +598,7 @@
       {
          bWhite = false;
          ++i;
-         for( ; i<size && p[i]!='\'' && p[i]!='\n'; ++i)
+         for( ; !isLineOrBufEnd(p,i,size) && p[i]!='\''; ++i)
             ;
          if (p[i]=='\'') ++i;
       }
@@ -247,7 +608,7 @@
       {
          bWhite = false;
          ++i;
-         for( ; i<size && !(p[i]=='"' && p[i-1]!='\\') && p[i]!='\n'; ++i)
+         for( ; !isLineOrBufEnd(p,i,size) && !(p[i]=='"' && p[i-1]!='\\'); ++i)
             ;
          if (p[i]=='"') ++i;
       }
@@ -258,7 +619,7 @@
          int commentStart = i;
          bCommentInLine = true;
          i+=2;
-         for( ; i<size && p[i]!='\n'; ++i)
+         for( ; !isLineOrBufEnd(p,i,size); ++i)
             ;
          if ( !bWhite )
          {
@@ -273,7 +634,7 @@
          int commentStart = i;
          bCommentInLine = true;
          i+=2;
-         for( ; i<size && p[i]!='\n'; ++i)
+         for( ; !isLineOrBufEnd(p,i,size); ++i)
          {
             if ( i+1<size && p[i]=='*' && p[i+1]=='/')  // end of the comment
             {
@@ -293,7 +654,7 @@
       }
 
 
-      if (p[i]=='\n' || i>=size )
+      if ( isLineOrBufEnd(p,i,size) )
       {
          return;
       }
@@ -307,7 +668,7 @@
 // Modifies the input data, and replaces C/C++ comments with whitespace
 // when the line contains other data too. If the line contains only
 // a comment or white data, remember this in the flag bContainsPureComment.
-void SourceData::removeComments( LineData* pLD )
+void SourceData::FileData::removeComments()
 {
    int line=0;
    char* p = (char*)m_pBuf;
@@ -324,7 +685,7 @@
          int commentStart = i;
          bCommentInLine = true;
 
-         for( ; i<size && p[i]!='\n'; ++i)
+         for( ; !isLineOrBufEnd(p,i,size); ++i)
          {
             if ( i+1<size && p[i]=='*' && p[i+1]=='/')  // end of the comment
             {
@@ -346,8 +707,8 @@
       }
 
       // end of line
-      assert( i>=size || p[i]=='\n');
-      pLD[line].bContainsPureComment = bCommentInLine && bWhite;
+      assert( isLineOrBufEnd(p,i,size));
+      m_v[line].bContainsPureComment = bCommentInLine && bWhite;
 /*      std::cout << line << " : " <<
        ( bCommentInLine ?  "c" : " " ) <<
        ( bWhite ? "w " : "  ") <<
@@ -357,171 +718,8 @@
    }
 }
 
-// read and preprocess file for line matching input data
-void SourceData::readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase, bool bRemoveComments )
-{
-   if ( ( ppCmd.isEmpty() && !bRemoveComments ) || pOrigSource->m_bPreserve )
-   {
-      reset();
-   }
-   else
-   {
-      setFilename( pOrigSource->m_fileAccess.absFilePath() );
-      readPPFile( false, ppCmd, bUpCase );
-      if ( m_vSize < pOrigSource->m_vSize )
-      {
-         m_v.resize( pOrigSource->m_vSize );
-         m_vSize = pOrigSource->m_vSize;
-      }
-   }
-   if ( bRemoveComments && m_vSize==pOrigSource->m_vSize )
-      removeComments( &pOrigSource->m_v[0] );
-}
 
 
-void SourceData::readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase )
-{
-   if ( !m_bPreserve )
-   {
-      if ( ! ppCmd.isEmpty() && !m_fileName.isEmpty() && FileAccess::exists( m_fileName ) )
-      {
-         QString fileNameOut = FileAccess::tempFileName();
-#ifdef _WIN32
-         QString cmd = QString("type ") + m_fileName + " | " + ppCmd  + " >" + fileNameOut;
-#else
-         QString cmd = QString("cat ") + m_fileName + " | " + ppCmd  + " >" + fileNameOut;
-#endif
-         ::system( cmd.ascii() );
-         readFile( fileNameOut, true, bUpCase );
-         FileAccess::removeFile( fileNameOut );
-      }
-      else
-      {
-         readFile( m_fileAccess.absFilePath(), true, bUpCase );
-      }
-   }
-   preprocess( bPreserveCR );
-}
-
-void SourceData::readFile( const QString& filename, bool bFollowLinks, bool bUpCase )
-{
-   delete (char*)m_pBuf;
-   m_size = 0;
-   m_pBuf = 0;
-   char* pBuf = 0;
-   if ( filename.isEmpty() )   { return; }
-
-   if ( !bFollowLinks )
-   {
-      FileAccess fi( filename );
-      if ( fi.isSymLink() )
-      {
-         QString s = fi.readLink();
-         m_size = s.length();
-         m_pBuf = pBuf = new char[m_size+100];
-         memcpy( pBuf, s.ascii(), m_size );
-         return;
-      }
-   }
-
-
-   FileAccess fa( filename );
-   m_size = fa.sizeForReading();
-   m_pBuf = pBuf = new char[m_size+100];
-   bool bSuccess = fa.readFile( pBuf, m_size );
-   if ( !bSuccess )
-   {
-      delete pBuf;
-      m_pBuf = 0;
-      m_size = 0;
-      return;
-   }
-
-
-   if ( bUpCase )
-   {
-      int i;
-      for(i=0; i<m_size; ++i)
-      {
-         pBuf[i] = toupper(pBuf[i]);
-      }
-   }
-
-}
-
-void SourceData::setData( const QString& data, bool bUpCase )
-{
-   delete (char*)m_pBuf;
-   m_size = data.length();
-   m_pBuf = 0;
-
-   char* pBuf = 0;
-   m_pBuf = pBuf = new char[m_size+100];
-
-   memcpy( pBuf, data.ascii(), m_size );
-   if ( bUpCase )
-   {
-      int i;
-      for(i=0; i<m_size; ++i)
-      {
-         pBuf[i] = toupper(pBuf[i]);
-      }
-   }
-   m_bPreserve = true;
-   m_fileName="";
-   m_aliasName = i18n("From Clipboard");
-   m_fileAccess = FileAccess("");
-}
-
-void SourceData::setFilename( const QString& filename )
-{
-   FileAccess fa( filename );
-   setFileAccess( fa );
-}
-
-QString SourceData::getFilename()
-{
-   return m_fileName;
-}
-
-QString SourceData::getAliasName()
-{
-   return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName;
-}
-
-void SourceData::setAliasName( const QString& name )
-{
-   m_aliasName = name;
-}
-
-void SourceData::setFileAccess( const FileAccess& fileAccess )
-{
-   m_fileAccess = fileAccess;
-   m_aliasName = QString();
-   m_bPreserve = false;
-   m_fileName = m_fileAccess.absFilePath();
-}
-
-void prepareOccurances( LineData* p, int size )
-{
-   // Special analysis: Find out how often this line occurs
-   // Only problem: A simple search will cost O(N^2).
-   // To avoid this we will use a map. Then the cost will only be
-   // O(N*log N). (A hash table would be even better.)
-
-   std::map<LineDataRef,int> occurancesMap;
-   int i;
-   for( i=0; i<size; ++i )
-   {
-      ++occurancesMap[ LineDataRef( &p[i] ) ];
-   }
-
-   for( i=0; i<size; ++i )
-   {
-      p[i].occurances = occurancesMap[ LineDataRef( &p[i] ) ];
-   }
-}
-
 // First step
 void calcDiff3LineListUsingAB(
    const DiffList* pDiffListAB,
@@ -580,13 +778,13 @@
          ++lineB;
       }
 
-      d3ll.push_back( d3l );      
+      d3ll.push_back( d3l );
    }
 }
 
 
 // Second step
-void calcDiff3LineListUsingAC(       
+void calcDiff3LineListUsingAC(
    const DiffList* pDiffListAC,
    Diff3LineList& d3ll
    )
@@ -617,13 +815,13 @@
       if( d.nofEquals>0 )
       {
          // Find the corresponding lineA
-         while( (*i3).lineA!=lineA ) 
+         while( (*i3).lineA!=lineA )
 
             ++i3;
          (*i3).lineC = lineC;
          (*i3).bAEqC = true;
          (*i3).bBEqC = (*i3).bAEqB;
-                  
+
          --d.nofEquals;
          ++lineA;
          ++lineC;
@@ -655,7 +853,7 @@
 }
 
 // Third step
-void calcDiff3LineListUsingBC(       
+void calcDiff3LineListUsingBC(
    const DiffList* pDiffListBC,
    Diff3LineList& d3ll
    )
@@ -728,7 +926,7 @@
                while( i3 != i3b && i3!=d3ll.end() )
 
                {
-                  if ( (*i3).lineB != -1 ) 
+                  if ( (*i3).lineB != -1 )
                      ++nofDisturbingLines;
                   ++i3;
                }
@@ -740,7 +938,7 @@
 
                   while( i3 != i3b )
                   {
-                     if ( (*i3).lineB != -1 ) 
+                     if ( (*i3).lineB != -1 )
                      {
                         Diff3Line d3l;
                         d3l.lineB = (*i3).lineB;
@@ -778,7 +976,7 @@
                int nofDisturbingLines = 0;
                while( i3 != i3c && i3!=d3ll.end() )
                {
-                  if ( (*i3).lineC != -1 ) 
+                  if ( (*i3).lineC != -1 )
                      ++nofDisturbingLines;
                   ++i3;
                }
@@ -789,7 +987,7 @@
                   i3 = i3b;
                   while( i3 != i3c )
                   {
-                     if ( (*i3).lineC != -1 ) 
+                     if ( (*i3).lineC != -1 )
                      {
                         Diff3Line d3l;
                         d3l.lineC = (*i3).lineC;
@@ -816,7 +1014,7 @@
                }
             }
          }
-                  
+
          --d.nofEquals;
          ++lineB;
          ++lineC;
@@ -861,8 +1059,8 @@
    int li=0;
    for( ; it!=d3ll.end(); ++it, ++li )
    {
-      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",  
-         li, (*it).lineA, (*it).lineB, (*it).lineC, 
+      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",
+         li, (*it).lineA, (*it).lineB, (*it).lineC,
          (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
    }
    printf("\n");*/
@@ -873,8 +1071,8 @@
 #endif
 
 // Fourth step
-void calcDiff3LineListTrim(       
-   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
+void calcDiff3LineListTrim(
+   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC
    )
 {
    const Diff3Line d3l_empty;
@@ -974,7 +1172,7 @@
          (*i).lineA = (*i3).lineA;
          (*i).lineB = (*i3).lineB;
          (*i).bAEqB = true;
-                  
+
          (*i3).lineA = -1;
          (*i3).lineB = -1;
          (*i3).bAEqB = false;
@@ -993,7 +1191,7 @@
          (*i).lineA = (*i3).lineA;
          (*i).lineC = (*i3).lineC;
          (*i).bAEqC = true;
-                  
+
          (*i3).lineA = -1;
          (*i3).lineC = -1;
          (*i3).bAEqC = false;
@@ -1012,7 +1210,7 @@
          (*i).lineB = (*i3).lineB;
          (*i).lineC = (*i3).lineC;
          (*i).bBEqC = true;
-                  
+
          (*i3).lineB = -1;
          (*i3).lineC = -1;
          (*i3).bBEqC = false;
@@ -1052,8 +1250,8 @@
    int li=0;
    for( ; it!=d3ll.end(); ++it, ++li )
    {
-      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",  
-         li, (*it).lineA, (*it).lineB, (*it).lineC, 
+      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",
+         li, (*it).lineA, (*it).lineB, (*it).lineC,
          (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
 
    }
@@ -1061,7 +1259,7 @@
 }
 
 void calcWhiteDiff3Lines(
-   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
+   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC
    )
 {
    Diff3LineList::iterator i3 = d3ll.begin();
@@ -1294,8 +1492,8 @@
 void fineDiff(
    Diff3LineList& diff3LineList,
    int selector,
-   LineData* v1,
-   LineData* v2,
+   const LineData* v1,
+   const LineData* v2,
    bool& bTextsTotalEqual
    )
 {
@@ -1325,9 +1523,21 @@
 
             // Optimize the diff list.
             DiffList::iterator dli;
+            bool bUsefulFineDiff = false;
             for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
             {
-               if( dli->nofEquals < 4  &&  (dli->diff1>0 || dli->diff2>0)  )
+               if( dli->nofEquals >= 4 )
+               {
+                  bUsefulFineDiff = true;
+                  break;
+               }
+            }
+
+            for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
+            {
+               if( dli->nofEquals < 4  &&  (dli->diff1>0 || dli->diff2>0) 
+                  && !( bUsefulFineDiff && dli==pDiffList->begin() )
+               )
                {
                   dli->diff1 += dli->nofEquals;
                   dli->diff2 += dli->nofEquals;
@@ -1365,7 +1575,7 @@
    {
       d3lv[j] = &(*i);
    }
-   assert( j==(int)d3lv.size() );   
+   assert( j==(int)d3lv.size() );
 }
 
 
--- a/kdiff3/src/diff.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/diff.h	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           diff.h  -  description
                              -------------------
     begin                : Mon Mar 18 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -28,7 +28,7 @@
 #include "common.h"
 #include "fileaccess.h"
 
-
+class OptionDialog;
 
 // Each range with matching elements is followed by a range with differences on either side.
 // Then again range of matching elements should follow.
@@ -123,47 +123,74 @@
    int size;
 
    LineData(){ pLine=0; size=0; occurances=0; bContainsPureComment=false; }
-   int width();  // Calcs width considering tabs.
+   int width() const;  // Calcs width considering tabs.
    int occurances;
-   bool whiteLine(){ return pFirstNonWhiteChar-pLine == size; }
+   bool whiteLine() const { return pFirstNonWhiteChar-pLine == size; }
    bool bContainsPureComment;
 };
 
-void prepareOccurances( LineData* p, int size );
-
 
 class SourceData
 {
 public:
-   SourceData(){ m_pBuf=0;m_size=0;m_vSize=0;m_bIsText=false;m_bPreserve=false; }
-   const char* m_pBuf;
-   int m_size;
-   int m_vSize; // Nr of lines in m_pBuf1 and size of m_v1, m_dv12 and m_dv13
-   std::vector<LineData> m_v;
-   bool m_bIsText;
-   bool m_bPreserve;
-   void reset();
-   void readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase );
-   void readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase, bool bRemoveComments );
-   void readFile(const QString& filename, bool bFollowLinks, bool bUpCase );
-   void preprocess(bool bPreserveCR );
-   void removeComments( LineData* pLD );
-   void setData( const QString& data, bool bUpCase );
+   SourceData();
+   ~SourceData();
+   
+   void setOptionDialog( OptionDialog* pOptionDialog );
+   
+   int getSizeLines() const;
+   int getSizeBytes() const;
+   const char* getBuf() const;
+   const LineData* getLineDataForDisplay() const;
+   const LineData* getLineDataForDiff() const;
+
    void setFilename(const QString& filename);
    void setFileAccess( const FileAccess& fa );
    FileAccess& getFileAccess();
    QString getFilename();
    void setAliasName(const QString& a);
    QString getAliasName();
-   bool isEmpty() { return getFilename().isEmpty(); }
-private:
-   QString m_fileName;
+   bool isEmpty();  // File was set
+   bool hasData();  // Data was readable
+   bool isText();   // is it pure text (vs. binary data)
+   bool isFromBuffer();  // was it set via setData() (vs. setFileAccess() or setFilename())
+   void setData( const QString& data );
+   
+   void readAndPreprocess();
+   bool saveNormalDataAs( const QString& fileName );
+   
+   bool isBinaryEqualWith( const SourceData& other ) const;
+   
+   void reset();
+
+private:   
    QString m_aliasName;
    FileAccess m_fileAccess;
+   OptionDialog* m_pOptionDialog;
+   QString m_tempInputFileName;
+
+   struct FileData
+   {   
+      FileData(){ m_pBuf=0; m_size=0; }
+      ~FileData(){ reset(); }
+      const char* m_pBuf;
+      int m_size;
+      int m_vSize; // Nr of lines in m_pBuf1 and size of m_v1, m_dv12 and m_dv13
+      std::vector<LineData> m_v;
+      bool m_bIsText;
+      bool readFile( const QString& filename );
+      bool writeFile( const QString& filename );
+      void preprocess(bool bPreserveCR );
+      void reset();
+      void removeComments();
+      void copyBufFrom( const FileData& src );
+   };
+   FileData m_normalData;
+   FileData m_lmppData;   
 };
 
-void calcDiff3LineListTrim( Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC );
-void calcWhiteDiff3Lines(   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC );
+void calcDiff3LineListTrim( Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC );
+void calcWhiteDiff3Lines(   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC );
 
 void calcDiff3LineVector( const Diff3LineList& d3ll, Diff3LineVector& d3lv );
 
@@ -214,6 +241,7 @@
 class OptionDialog;
 
 QString decodeString( const char*s , OptionDialog* );
+QCString encodeString( const QString& s , OptionDialog* );
 
 class DiffTextWindow : public QWidget
 {
@@ -226,7 +254,7 @@
       );
    void init(
       const QString& fileName,
-      LineData* pLineData,
+      const LineData* pLineData,
       int size,
       const Diff3LineVector* pDiff3LineVector,
       int winIdx,
@@ -271,7 +299,7 @@
 
 private:
    bool m_bPaintingAllowed;
-   LineData* m_pLineData;
+   const LineData* m_pLineData;
    int m_size;
    QString m_filename;
 
@@ -438,6 +466,7 @@
    void slotAutoSolve();
    void slotUnsolve();
    void slotSetFastSelectorLine(int);
+   void setPaintingAllowed(bool);
 
 signals:
    void scroll( int deltaX, int deltaY );
@@ -463,6 +492,8 @@
    const Diff3LineList* m_pDiff3LineList;
    const TotalDiffStatus* m_pTotalDiffStatus;
 
+   bool m_bPaintingAllowed;
+
 private:
    class MergeEditLine
    {
@@ -496,19 +527,33 @@
    private:
       typedef std::list<MergeEditLine> BASE;
       int m_size;
+      int* m_pTotalSize;
    public:
       typedef std::list<MergeEditLine>::iterator iterator;
       typedef std::list<MergeEditLine>::const_iterator const_iterator;
-      MergeEditLineList(){m_size=0;}
-      void clear()                             { m_size=0; BASE::clear();          }
-      void push_back( const MergeEditLine& m)  { ++m_size; BASE::push_back(m);     }
-      void push_front( const MergeEditLine& m) { ++m_size; BASE::push_front(m);    }
-      iterator erase( iterator i )             { --m_size; return BASE::erase(i);  }
-      iterator insert( iterator i, const MergeEditLine& m ) { ++m_size; return BASE::insert(i,m); }
+      MergeEditLineList(){m_size=0; m_pTotalSize=0; }
+      void clear()                             { ds(-m_size); BASE::clear();          }
+      void push_back( const MergeEditLine& m)  { ds(+1); BASE::push_back(m);     }
+      void push_front( const MergeEditLine& m) { ds(+1); BASE::push_front(m);    }
+      iterator erase( iterator i )             { ds(-1); return BASE::erase(i);  }
+      iterator insert( iterator i, const MergeEditLine& m ) { ds(+1); return BASE::insert(i,m); }
       int size(){ /*assert(int(BASE::size())==m_size);*/ return m_size;}
       iterator begin(){return BASE::begin();}
       iterator end(){return BASE::end();}
       bool empty() { return m_size==0; }
+      
+      void setTotalSizePtr(int* pTotalSize)
+      {
+         m_pTotalSize = pTotalSize;
+         *m_pTotalSize += m_size;
+      }
+      
+   private:
+      void ds(int deltaSize) 
+      { 
+         m_size+=deltaSize; 
+         if (m_pTotalSize!=0)  *m_pTotalSize+=deltaSize;
+      }
    };
 
    friend class MergeEditLine;
@@ -569,6 +614,7 @@
    int m_firstColumn;
    int m_nofColumns;
    int m_nofLines;
+   int m_totalSize; //Same as m_nofLines, but calculated differently
    bool m_bMyUpdate;
    bool m_bInsertMode;
    QString m_fileName;
@@ -597,8 +643,8 @@
 void fineDiff(
    Diff3LineList& diff3LineList,
    int selector,
-   LineData* v1,
-   LineData* v2,
+   const LineData* v1,
+   const LineData* v2,
    bool& bTextsTotalEqual
    );
 
--- a/kdiff3/src/difftextwindow.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/difftextwindow.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           difftextwindow.cpp  -  description
                              -------------------
     begin                : Mon Apr 8 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -59,7 +59,7 @@
 
 void DiffTextWindow::init(
    const QString& filename,
-   LineData* pLineData,
+   const LineData* pLineData,
    int size,
    const Diff3LineVector* pDiff3LineVector,
    int winIdx,
@@ -862,7 +862,7 @@
    if (lineIdx==-1) return QCString();
    else
    {
-      LineData* ld = &m_pLineData[lineIdx];
+      const LineData* ld = &m_pLineData[lineIdx];
       return QCString( ld->pLine, ld->size + 1 );
    }
    return QCString();
@@ -962,13 +962,15 @@
             int spaces = 1;
             if ( pLine[i]=='\t' )
             {
-
                spaces = tabber( outPos, g_tabSize );
             }
 
             if( selection.within( line, outPos ) )
             {
-              selectionString += pLine[i];
+               char buf[2];
+               buf[0] = pLine[i];
+               buf[1] = '\0';
+               selectionString += decodeString( buf, m_pOptionDialog );
             }
 
             outPos += spaces;
@@ -983,8 +985,6 @@
          }
       }
 
-
-
       ++line;
    }
 
@@ -1041,3 +1041,17 @@
    else
       return QString(s);
 }
+
+QCString encodeString( const QString& s , OptionDialog* pOptions )
+{
+   if ( pOptions->m_bStringEncoding )
+   {
+      QTextCodec* c = QTextCodec::codecForLocale();
+      if (c!=0)
+         return c->fromUnicode( s );
+      else
+         return QCString( s.ascii() );
+   }
+   else
+      return QCString( s.ascii() );
+}
--- a/kdiff3/src/directorymergewindow.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/directorymergewindow.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -1,8 +1,8 @@
 /***************************************************************************
                           directorymergewindow.cpp
-                             -------------------
+                             -----------------
     begin                : Sat Oct 19 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -347,6 +347,15 @@
       calcDirStatus( bThreeDirs, static_cast<DirMergeItem*>(p), nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
 }
 
+static QString sortString(const QString& s)
+{
+#ifdef _WIN32
+   return s.upper();
+#else
+   return s;
+#endif
+}
+
 bool DirectoryMergeWindow::init
    (
    FileAccess& dirA,
@@ -439,7 +448,7 @@
 
       for (i=dirListA.begin(); i!=dirListA.end();++i )
       {
-         MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath())];
          //std::cout <<i->filePath()<<std::endl;
          mfi.m_bExistsInA = true;
          mfi.m_fileInfoA = *i;
@@ -461,7 +470,7 @@
 
       for (i=dirListB.begin(); i!=dirListB.end();++i )
       {
-         MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath())];
          mfi.m_bExistsInB = true;
          mfi.m_fileInfoB = *i;
       }
@@ -483,7 +492,7 @@
 
       for (i=dirListC.begin(); i!=dirListC.end();++i )
       {
-         MergeFileInfos& mfi = m_fileMergeMap[i->filePath()];
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath())];
          mfi.m_bExistsInC = true;
          mfi.m_fileInfoC = *i;
       }
@@ -949,7 +958,6 @@
    t.start();
    for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j )
    {
-      const QString& fileName = j->first;
       MergeFileInfos& mfi = j->second;
 
       mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() :
@@ -957,6 +965,9 @@
                       mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() :
                       QString("");
 
+      // const QString& fileName = j->first;
+      const QString& fileName = mfi.m_subPath;
+
       g_pProgressDialog->setInformation(
          i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
          +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
@@ -994,7 +1005,7 @@
       }
       else
       {
-         MergeFileInfos& dirMfi = m_fileMergeMap[dirPart]; // parent
+         MergeFileInfos& dirMfi = m_fileMergeMap[sortString(dirPart)]; // parent
          assert(dirMfi.m_pDMI!=0);
          new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi );
          mfi.m_pParent = &dirMfi;
--- a/kdiff3/src/directorymergewindow.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/directorymergewindow.h	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           directorymergewindow.h
                              -------------------
     begin                : Sat Oct 19 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
--- a/kdiff3/src/fileaccess.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/fileaccess.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -35,6 +35,7 @@
 #ifdef _WIN32
 #include <sys/utime.h>
 #include <io.h>
+#include <windows.h>
 #else
 #include <unistd.h>          // Needed for creating symbolic links via symlink().
 #include <utime.h>
@@ -204,9 +205,11 @@
        S_IXOTH    00001     others have execute permission
 */
 
+#ifdef KREPLACEMENTS_H
+void FileAccess::setUdsEntry( const KIO::UDSEntry& ){}  // not needed if KDE is not available
+#else
 void FileAccess::setUdsEntry( const KIO::UDSEntry& e )
 {
-#ifndef KREPLACEMENTS_H
    KIO::UDSEntry::const_iterator ei;
    long acc = 0;
    long fileType = 0;
@@ -262,8 +265,8 @@
       m_name = m_path.mid( pos );
    }
    m_bHidden = m_name[0]=='.';
+}
 #endif
-}
 
 
 bool FileAccess::isValid() const       {   return m_bValidData;  }
@@ -342,7 +345,7 @@
    return false;
 }
 
-bool FileAccess::writeFile( void* pSrcBuffer, unsigned long length )
+bool FileAccess::writeFile( const void* pSrcBuffer, unsigned long length )
 {
    if (m_bLocal)
    {
@@ -424,7 +427,7 @@
          for(int i=0; ;++i)
          {
             // short filenames for WIN98 because for system() the command must not exceed 120 characters.
-            fileName = tmpDir + "/" + QString::number(i);
+            fileName = tmpDir + "\\" + QString::number(i);
             if ( ! FileAccess::exists(fileName) )
                break;
          }
@@ -624,7 +627,7 @@
    }
 }
 
-bool FileAccessJobHandler::put(void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions )
+bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions )
 {
    if ( maxLength>0 )
    {
@@ -1167,6 +1170,7 @@
       m_bSuccess = QDir::setCurrent( m_pFileAccess->absFilePath() );
       if ( m_bSuccess )
       {
+#ifndef _WIN32
          m_bSuccess = true;
          QDir dir( "." );
 
@@ -1192,6 +1196,75 @@
                pDirList->push_back( FileAccess( nicePath(*fi) ) );
             }
          }
+#else
+         QString pattern ="*.*";
+         WIN32_FIND_DATA findData;
+         WIN32_FIND_DATAA& findDataA=*(WIN32_FIND_DATAA*)&findData;  // Needed for Win95
+
+         HANDLE searchHandle = QT_WA_INLINE( 
+                 FindFirstFile( (TCHAR*)pattern.ucs2(), &findData ),
+                 FindFirstFileA( pattern.local8Bit(), &findDataA )
+              );
+
+         if ( searchHandle != INVALID_HANDLE_VALUE )
+         {
+            QString absPath = m_pFileAccess->absFilePath();
+            QString relPath = m_pFileAccess->filePath();
+            bool bFirst=true;
+            while( ! g_pProgressDialog->wasCancelled() )
+            {
+               if (!bFirst)
+               {
+                  if ( ! QT_WA_INLINE(
+                            FindNextFile(searchHandle,&findData),
+                            FindNextFileA(searchHandle,&findDataA)) )
+                     break;
+               }
+               bFirst = false;
+               FileAccess fa;
+               fa.m_size = findData.nFileSizeLow ;//+ findData.nFileSizeHigh;
+
+               FILETIME ft;
+               SYSTEMTIME t;
+               FileTimeToLocalFileTime( &findData.ftLastWriteTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_modificationTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+               FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_accessTime       = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+               FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_creationTime     = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+
+               int  a = findData.dwFileAttributes;
+               fa.m_bWritable   = ( a & FILE_ATTRIBUTE_READONLY) == 0; 
+               fa.m_bDir        = ( a & FILE_ATTRIBUTE_DIRECTORY ) != 0;
+               fa.m_bFile       = !fa.m_bDir;
+               fa.m_bHidden     = ( a & FILE_ATTRIBUTE_HIDDEN) != 0;
+
+               fa.m_bExecutable = false; // Useless on windows
+               fa.m_bExists     = true;
+               fa.m_bReadable   = true;
+               fa.m_bLocal      = true;
+               fa.m_bValidData  = true;
+               fa.m_bSymLink    = false;
+               fa.m_fileType    = 0;
+
+               fa.m_name = QT_WA_INLINE( 
+                  QString::fromUcs2(findData.cFileName),
+                  QString::fromLocal8Bit(findDataA.cFileName) 
+                  );
+
+               fa.m_path = fa.m_name;
+               fa.m_absFilePath = absPath + "/" + fa.m_name;
+               fa.m_url.setPath( fa.m_absFilePath );
+               if ( fa.m_name!="." && fa.m_name!=".." )
+                  pDirList->push_back( fa );
+            }
+            FindClose( searchHandle );
+         }
+         else
+         {
+            return false;
+         }
+#endif
       }
    }
    else
--- a/kdiff3/src/fileaccess.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/fileaccess.h	Sun Mar 07 09:59:09 2004 +0000
@@ -57,7 +57,7 @@
    bool isLocal() const;
 
    bool readFile(void* pDestBuffer, unsigned long maxLength );
-   bool writeFile(void* pSrcBuffer, unsigned long length );
+   bool writeFile(const void* pSrcBuffer, unsigned long length );
    bool listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
                  const QString& filePattern, const QString& fileAntiPattern,
                  const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore );
@@ -121,7 +121,7 @@
    FileAccessJobHandler( FileAccess* pFileAccess );
 
    bool get( void* pDestBuffer, long maxLength );
-   bool put( void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume=false, int permissions=-1 );
+   bool put( const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume=false, int permissions=-1 );
    bool stat(int detailLevel=2, bool bWantToWrite=false );
    bool copyFile( const QString& dest );
    bool rename( const QString& dest );
--- a/kdiff3/src/kdiff3.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           kdiff3.cpp  -  description
                              -------------------
     begin                : Don Jul 11 12:31:29 CEST 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -108,6 +108,16 @@
    // Needed before any file operations via FileAccess happen.
    g_pProgressDialog = new ProgressDialog(this);
 
+   // All default values must be set before calling readOptions().
+   m_pOptionDialog = new OptionDialog( m_pKDiff3Shell!=0, this );
+   connect( m_pOptionDialog, SIGNAL(applyClicked()), this, SLOT(slotRefresh()) );
+   
+   m_pOptionDialog->readOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+   m_sd1.setOptionDialog(m_pOptionDialog);
+   m_sd2.setOptionDialog(m_pOptionDialog);
+   m_sd3.setOptionDialog(m_pOptionDialog);
+   
    // Option handling: Only when pParent==0 (no parent)
    KCmdLineArgs *args = isPart() ? 0 : KCmdLineArgs::parsedArgs();
 
@@ -165,12 +175,8 @@
    m_pFindDialog = new FindDialog( this );
    connect( m_pFindDialog, SIGNAL(findNext()), this, SLOT(slotEditFindNext()));
 
-   // All default values must be set before calling readOptions().
-   m_pOptionDialog = new OptionDialog( m_pKDiff3Shell!=0, this );
-   connect( m_pOptionDialog, SIGNAL(applyClicked()), this, SLOT(slotRefresh()) );
-
    readOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
-
+   
    autoAdvance->setChecked( m_pOptionDialog->m_bAutoAdvance );
    showWhiteSpaceCharacters->setChecked( m_pOptionDialog->m_bShowWhiteSpaceCharacters );
    showWhiteSpace->setChecked( m_pOptionDialog->m_bShowWhiteSpace );
@@ -230,35 +236,31 @@
       init( m_bAuto );
       if ( m_bAuto )
       {
-         const char* pBuf = 0;
-         unsigned int size = 0;
+         SourceData* pSD=0;
          if ( m_sd3.isEmpty() )
          {
-            if ( m_totalDiffStatus.bBinaryAEqB ){ pBuf=m_sd1.m_pBuf; size=m_sd1.m_size; }
+            if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd1; }
          }
          else
          {
-            if      ( m_totalDiffStatus.bBinaryBEqC ){ pBuf=m_sd3.m_pBuf; size=m_sd3.m_size; }
-            else if ( m_totalDiffStatus.bBinaryAEqB ){ pBuf=m_sd3.m_pBuf; size=m_sd3.m_size; }
-            else if ( m_totalDiffStatus.bBinaryAEqC ){ pBuf=m_sd2.m_pBuf; size=m_sd2.m_size; }
+            if      ( m_totalDiffStatus.bBinaryBEqC ){ pSD = &m_sd3; } // B==C (assume A is old)
+            else if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd3; } // assuming C has changed
+            else if ( m_totalDiffStatus.bBinaryAEqC ){ pSD = &m_sd2; } // assuming B has changed
          }
 
-         if ( pBuf!=0 )
+         if ( pSD!=0 )
          {
             // Save this file directly, not via the merge result window.
             bool bSuccess = false;
-            if ( m_pOptionDialog->m_bDmCreateBakFiles && QDir().exists( m_outputFilename ) )
+            FileAccess fa( m_outputFilename );
+            if ( m_pOptionDialog->m_bDmCreateBakFiles && fa.exists() )
             {
                QString newName = m_outputFilename + ".orig";
-               if ( QDir().exists( newName ) ) QFile::remove(newName);
-               if ( !QDir().exists( newName ) ) QDir().rename( m_outputFilename, newName );
+               if ( FileAccess::exists( newName ) ) FileAccess::removeFile( newName );
+               if ( !FileAccess::exists( newName ) ) fa.rename( newName );
             }
-            QFile file( m_outputFilename );
-            if ( file.open( IO_WriteOnly ) )
-            {
-               bSuccess = (long)size == file.writeBlock ( pBuf, size );
-               file.close();
-            }
+            
+            bSuccess = pSD->saveNormalDataAs( m_outputFilename );
             if ( bSuccess ) ::exit(0);
             else KMessageBox::error( this, i18n("Saving failed.") );
          }
@@ -280,17 +282,17 @@
    if ( ! m_bDirCompare  &&  m_pKDiff3Shell!=0 )
    {
       bool bFileOpenError = false;
-      if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0  ||
-         ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
-         ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+      if ( ! m_sd1.isEmpty() && !m_sd1.hasData()  ||
+           ! m_sd2.isEmpty() && !m_sd2.hasData()  ||
+           ! m_sd3.isEmpty() && !m_sd3.hasData() )
       {
          QString text( i18n("Opening of these files failed:") );
          text += "\n\n";
-         if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+         if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
             text += " - " + m_sd1.getAliasName() + "\n";
-         if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+         if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
             text += " - " + m_sd2.getAliasName() + "\n";
-         if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+         if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
             text += " - " + m_sd3.getAliasName() + "\n";
 
          KMessageBox::sorry( this, text, i18n("File Open Error") );
@@ -353,6 +355,7 @@
 #include "xpm/iconC.xpm"
 #include "xpm/autoadvance.xpm"
 #include "xpm/showwhitespace.xpm"
+#include "xpm/showwhitespacechars.xpm"
 #include "xpm/showlinenumbers.xpm"
 //#include "reload.xpm"
 
@@ -370,8 +373,8 @@
    chooseC = new KToggleAction(i18n("Select Line(s) From C"), QIconSet(QPixmap(iconC)), CTRL+Key_3, this, SLOT(slotChooseC()), ac, "merge_choose_c");
    autoAdvance = new KToggleAction(i18n("Automatically Go to Next Unsolved Conflict After Source Selection"), QIconSet(QPixmap(autoadvance)), 0, this, SLOT(slotAutoAdvanceToggled()), ac, "merge_autoadvance");
 
-   showWhiteSpaceCharacters = new KToggleAction(i18n("Show Space && Tabulator Characters for Differences"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_show_whitespace_characters");
-   showWhiteSpace = new KToggleAction(i18n("Show White Space"), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_show_whitespace");
+   showWhiteSpaceCharacters = new KToggleAction(i18n("Show Space && Tabulator Characters for Differences"), QIconSet(QPixmap(showwhitespacechars)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_show_whitespace_characters");
+   showWhiteSpace = new KToggleAction(i18n("Show White Space"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_show_whitespace");
 
    showLineNumbers = new KToggleAction(i18n("Show Line Numbers"), QIconSet(QPixmap(showlinenumbers)), 0, this, SLOT(slotShowLineNumbersToggled()), ac, "merge_showlinenumbers");
    chooseAEverywhere = new KAction(i18n("Choose A Everywhere"), CTRL+SHIFT+Key_1, this, SLOT(slotChooseAEverywhere()), ac, "merge_choose_a_everywhere");
@@ -467,7 +470,6 @@
          m_pKDiff3Shell->move( pos );
       }
    }
-   m_pOptionDialog->readOptions( config );
 
    slotRefresh();
 }
--- a/kdiff3/src/kdiff3.desktop	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3.desktop	Sun Mar 07 09:59:09 2004 +0000
@@ -2,17 +2,25 @@
 [Desktop Entry]
 Encoding=UTF-8
 Name=KDiff3
+Name[hi]=के-डिफ3
 Name[sv]=Kdiff3
+Name[ta]=கேடிஃபà¯3
 Name[xx]=xxKDiff3xx
 GenericName=Diff/Patch Frontend
 GenericName[da]=Forende for diff/patch
 GenericName[es]=Interfaz Diff/Patch
-GenericName[hu]=grafikus diff/patch-felület
+GenericName[et]=Võrdlemise ja liitmise rakendus
+GenericName[fr]=Interface graphique à diff / patch
+GenericName[hu]=Grafikus diff/patch
 GenericName[it]=Interfaccia per diff/patch
-GenericName[pt]=Interface para o Diff/Patch
-GenericName[pt_BR]=Interface para o Diff/Patch
+GenericName[nl]=Een schil voor Diff/Patch
+GenericName[pt]=Interface do Diff/Patch
+GenericName[pt_BR]=Um front-end para Diff/Patch
+GenericName[ru]=ГрафичеÑкий Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ðº Diff и Patch
 GenericName[sr]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° Diff и Patch
 GenericName[sv]=Jämförelse- och programfixgränssnitt
+GenericName[ta]= ஒர௠கேடியி à®®à¯à®©à¯à®®à¯à®©à¯ˆà®¯à®¿à®²à¯ இரà¯à®¨à¯à®¤à¯ எஸà¯à®Žà®®à¯à®Žà®¸à¯à®…னà¯à®ªà¯à®ªà¯
+GenericName[zh_CN]=Diff/Patch å‰ç«¯
 GenericName[zu]=Diff/PatchIsiqalo sokugcina
 Exec=kdiff3 %i %m -caption "%c"
 Icon=kdiff3
@@ -22,14 +30,19 @@
 Comment[ca]=Una eina per a comparar i fusionar fitxers o directoris
 Comment[da]=Et indfletningsværktøj for filer og mapper
 Comment[de]=Programm zum Vergleichen und Zusammenführen von Dateien und Verzeichnissen
+Comment[el]=Ένα εÏγαλείο σÏγκÏισης και συγχώνευσης αÏχείων και καταλόγων
 Comment[es]=Una herramienta para mezclar y comparar archivos y directorios
 Comment[et]=Failide ja kataloogide võrdlemise ja liitmise vahend
+Comment[fr]=Un outil de comparaison et de fusion de fichiers et dossiers
+Comment[hi]=à¤à¤• फाइल तथा डिरेकà¥à¤Ÿà¥à¤°à¥€ तà¥à¤²à¤¨à¤¾ तथा विलीन उपकरण
 Comment[hu]=Segédprogram fájlok, könyvtárak összehasonlításához
 Comment[it]=Uno strumento di confronto e unione di file e directory
 Comment[nl]=Hulpmiddel voor het vergelijken en samenvoegen van bestanden en mappen
 Comment[pt]=Uma Ferramenta de Comparação e Junção de Ficheiros e Pastas
 Comment[pt_BR]=Uma Comparação de Arquivos e Pastas e uma Ferramenta para Mesclar Diferenças
+Comment[ru]=Утилита ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¸ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² и каталогов
 Comment[sr]=Ðлат за поређење и Ñтапање фајлова и директоријума
 Comment[sv]=Ett jämförelseverktyg för fil- och katalogjämförelser
 Comment[xx]=xxA File And Directory Comparison And Merge Toolxx
+Comment[zh_CN]=一个文件和目录的比较åŠåˆå¹¶å·¥å…·
 Terminal=0
--- a/kdiff3/src/kdiff3.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3.h	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           kdiff3.h  -  description
                              -------------------
     begin                : Don Jul 11 12:31:29 CEST 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -220,10 +220,6 @@
     SourceData m_sd2;
     SourceData m_sd3;
 
-    SourceData m_sdlm1;  // SourceData for Line Matching only.
-    SourceData m_sdlm2;
-    SourceData m_sdlm3;
-
    QString m_outputFilename;
    bool m_bDefaultFilename;
 
@@ -250,7 +246,7 @@
 
    bool improveFilenames();
 
-   bool runDiff( LineData* p1, int size1, LineData* p2, int size2, DiffList& diffList );
+   bool runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList );
    bool canContinue();
 
    void choose(int choice);
@@ -340,9 +336,11 @@
 
    QCheckBox* m_pMerge;
    virtual void accept();
+   virtual bool eventFilter(QObject* o, QEvent* e);
 private:
    OptionDialog* m_pOptions;
    void selectURL( QComboBox* pLine, bool bDir, int i, bool bSave );
+   bool m_bInputFileNameChanged;
 private slots:
    void selectFileA();
    void selectFileB();
@@ -353,6 +351,7 @@
    void selectOutputName();
    void selectOutputDir();
    void internalSlot(int);
+   void inputFilenameChanged();
 signals:
    void internalSignal(bool);
 };
--- a/kdiff3/src/kdiff3.pro	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3.pro	Sun Mar 07 09:59:09 2004 +0000
@@ -11,7 +11,7 @@
 
 win32 {
    QMAKE_CXXFLAGS_DEBUG  -= -Zi
-   QMAKE_CXXFLAGS_DEBUG  += -GX -GR -Z7
+   QMAKE_CXXFLAGS_DEBUG  += -GX -GR -Z7 /FR
    QMAKE_LFLAGS_DEBUG  += /PDB:NONE
    QMAKE_CXXFLAGS_RELEASE  += -GX -GR -DNDEBUG
    RC_FILE = kdiff3.rc
--- a/kdiff3/src/kdiff3_shell.rc	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3_shell.rc	Sun Mar 07 09:59:09 2004 +0000
@@ -94,6 +94,7 @@
   <Action name="merge_choose_b"/>
   <Action name="merge_choose_c"/>
   <Action name="merge_autoadvance"/>
+  <Action name="merge_show_whitespace"/>
   <Action name="merge_show_whitespace_characters"/>
   <Action name="merge_showlinenumbers"/>
 </ToolBar>
--- a/kdiff3/src/kdiff3part.desktop	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kdiff3part.desktop	Sun Mar 07 09:59:09 2004 +0000
@@ -1,9 +1,12 @@
 [Desktop Entry]
 Encoding=UTF-8
 Name=KDiff3Part
+Name[hi]=के-डिफ3पारà¥à¤Ÿ
 Name[pt_BR]=Componente KDiff3
 Name[sv]=Kdiff3-del
+Name[ta]=கேடிஃபà¯3 பகà¯à®¤à®¿
 Name[xx]=xxKDiff3Partxx
+Name[zh_CN]=KDiff3 组件
 MimeType=text/x-diff
 ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
 X-KDE-Library=libkdiff3part
--- a/kdiff3/src/kreplacements/kreplacements.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -141,7 +141,7 @@
 int  KMessageBox::warningYesNo( QWidget* parent, const QString& text, const QString& caption,
    const QString& button1, const QString& button2 )
 {
-   return  0 == QMessageBox::warning( parent, caption, text, button1, button2 ) ? Yes : No;
+   return  0 == QMessageBox::warning( parent, caption, text, button1, button2, QString::null, 1, 1 ) ? Yes : No;
 }
 
 int KMessageBox::warningYesNoCancel( QWidget* parent, const QString& text, const QString& caption,
@@ -419,6 +419,65 @@
 {
 }
 
+// safeStringJoin and safeStringSplit allow to convert a stringlist into a string and back
+// safely, even if the individual strings in the list contain the separator character.
+static QString safeStringJoin(const QStringList& sl, char sepChar=',', char metaChar='\\' )
+{
+   // Join the strings in the list, using the separator ','
+   // If a string contains the separator character, it will be replaced with "\,".
+   // Any occurances of "\" (one backslash) will be replaced with "\\" (2 backslashes)
+   
+   assert(sepChar!=metaChar);
+   
+   QString sep;
+   sep += sepChar;
+   QString meta;
+   meta += metaChar;   
+   
+   QString safeString;
+   
+   QStringList::const_iterator i;
+   for (i=sl.begin(); i!=sl.end(); ++i)
+   {
+      QString s = *i;
+      s.replace(meta, meta+meta);   //  "\" -> "\\"
+      s.replace(sep, meta+sep);     //  "," -> "\,"
+      if ( i==sl.begin() )
+         safeString = s;
+      else
+         safeString += sep + s;
+   }
+   return safeString;
+}
+
+// Split a string that was joined with safeStringJoin
+static QStringList safeStringSplit(const QString& s, char sepChar=',', char metaChar='\\' )
+{
+   assert(sepChar!=metaChar);
+   QStringList sl;
+   // Miniparser
+   int i=0;
+   int len=s.length();
+   QString b;
+   for(i=0;i<len;++i)
+   {
+      if      ( i+1<len && s[i]==metaChar && s[i+1]==metaChar ){ b+=metaChar; ++i; }
+      else if ( i+1<len && s[i]==metaChar && s[i+1]==sepChar ){ b+=sepChar; ++i; }
+      else if ( s[i]==sepChar )  // real separator
+      {
+         sl.push_back(b);
+         b="";
+      }
+      else { b+=s[i]; }     
+   }
+   if ( !b.isEmpty() )
+      sl.push_back(b);
+
+   return sl;
+}
+
+
+
 static QString numStr(int n)
 {
    QString s;
@@ -493,18 +552,7 @@
 
 void KConfig::writeEntry(const QString& k, const QStringList& v, char separator )
 {
-   QString s;
-
-   QStringList::ConstIterator i = v.begin();
-   for( i=v.begin(); i!= v.end(); ++i )
-   {
-      s += *i;
-
-      if ( !(*i).isEmpty() )
-         s += separator;
-   }
-
-   m_map[k] = s;
+   m_map[k] = safeStringJoin(v, separator);
 }
 
 
@@ -600,24 +648,14 @@
    return sval;
 }
 
-QStringList KConfig::readListEntry(const QString& k, char /*separator*/ )
+QStringList KConfig::readListEntry(const QString& k, char separator )
 {
    QStringList strList;
 
    std::map<QString,QString>::iterator i = m_map.find( k );
    if ( i!=m_map.end() )
    {
-      QString s = i->second;
-      int idx=0;
-      for(;;)
-      {
-         QString sec = subSection( s, idx, '|' ); //s.section('|',idx,idx);
-         if ( sec.isEmpty() )
-            break;
-         else
-            strList.append(sec);
-         ++idx;
-      }
+      strList = safeStringSplit( i->second, separator );
    }
    return strList;
 }
@@ -1042,7 +1080,7 @@
 
 QString KCmdLineArgs::arg(int idx)
 {
-   return QString(s_vArg[idx]);
+   return QString::fromLocal8Bit( s_vArg[idx] );
 }
 
 void KCmdLineArgs::clear()
@@ -1155,21 +1193,27 @@
          }
          if (j==nofOptions)
          {
-            using std::cerr;
-            using std::endl;
-            cerr << "Unknown option: " << s_argv[i] << endl<<endl;
+            QString s;
+            s = QString("Unknown option: ") +  s_argv[i] + "\n";
 
-            cerr << "Usage when starting via commandline: "                      << endl;
-            cerr << "- Comparing 2 files:     kdiff3 file1 file2  "              << endl;
-            cerr << "- Merging 2 files:       kdiff3 file1 file2 -o outputfile " << endl;
-            cerr << "- Comparing 3 files:     kdiff3 file1 file2 file3         " << endl;
-            cerr << "- Merging 3 files:       kdiff3 file1 file2 file3 -o outputfile " << endl;
-            cerr << "     Note that file1 will be treated as base of file2 and file3." << endl;
-            cerr << endl;
-            cerr << "If you start without arguments, then a dialog will appear"        << endl;
-            cerr << "where you can select your files via a filebrowser."               << endl;
-            cerr << endl;
-            cerr << "For more documentation, see the help-menu or the subdirectory doc. " << endl;
+            s += "KDiff3-Usage when starting via commandline: \n";
+            s += "- Comparing 2 files:\t\tkdiff3 file1 file2\n";
+            s += "- Merging 2 files:  \t\tkdiff3 file1 file2 -o outputfile\n";
+            s += "- Comparing 3 files:\t\tkdiff3 file1 file2 file3\n";
+            s += "- Merging 3 files:  \t\tkdiff3 file1 file2 file3 -o outputfile\n";
+            s += "     Note that file1 will be treated as base of file2 and file3.\n";
+            s += "\n";
+            s += "If you start without arguments, then a dialog will appear\n";
+            s += "where you can select your files via a filebrowser.\n";
+            s += "\n";
+            s += "For more documentation, see the help-menu or the subdirectory doc.\n";
+#ifdef _WIN32 
+            // A windows program has no console
+            KMessageBox::information(0, s,i18n("KDiff3-Usage"));
+#else
+            std::cerr << s.latin1() << std::endl;
+#endif
+            
             ::exit(-1);
          }
       }
@@ -1250,4 +1294,5 @@
 
 
 
+
 #include "kreplacements.moc"
--- a/kdiff3/src/main.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/main.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           main.cpp  -  Where everything starts.
                              -------------------
     begin                : Don Jul 11 12:31:29 CEST 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -93,6 +93,7 @@
    {
       return ::_spawnvp(_P_WAIT , "cleardiffmrg_orig", argv );      
    }
+   
 #endif
    QApplication::setColorSpec( QApplication::ManyColor ); // Grab all 216 colors
 
@@ -106,12 +107,13 @@
    KApplication app;
 #ifdef KREPLACEMENTS_H
    QString translationDir = getTranslationDir();
+   QString locale = QTextCodec::locale();
    QTranslator kdiff3Translator( 0 );
-   kdiff3Translator.load( QString("kdiff3_")+QTextCodec::locale(), translationDir );
+   kdiff3Translator.load( QString("kdiff3_")+locale, translationDir );
    app.installTranslator( &kdiff3Translator );
    
    QTranslator qtTranslator( 0 );
-   qtTranslator.load( QString("qt_")+QTextCodec::locale(), translationDir );
+   qtTranslator.load( QString("qt_")+locale, translationDir );
    app.installTranslator( &qtTranslator );
 #endif
 
--- a/kdiff3/src/merger.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/merger.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           merger.cpp  -  description
                              -------------------
     begin                : Sun Mar 24 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
--- a/kdiff3/src/merger.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/merger.h	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           merger.h  -  description
                              -------------------
     begin                : Sun Mar 24 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
--- a/kdiff3/src/mergeresultwindow.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/mergeresultwindow.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -2,7 +2,7 @@
                           mergeresultwindow.cpp  -  description
                              -------------------
     begin                : Sun Apr 14 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -27,6 +27,7 @@
 #include <optiondialog.h>
 #include <klocale.h>
 #include <kmessagebox.h>
+#include <iostream>
 
 int g_bAutoSolve = true;
 
@@ -45,6 +46,7 @@
    m_firstColumn = 0;
    m_nofColumns = 0;
    m_nofLines = 0;
+   m_totalSize = 0;
    m_bMyUpdate = false;
    m_bInsertMode = true;
    m_scrollDeltaX = 0;
@@ -58,8 +60,9 @@
 
    m_pDiff3LineList = 0;
    m_pTotalDiffStatus = 0;
-   
+
    m_pOptionDialog = pOptionDialog;
+   m_bPaintingAllowed = false;
 
    m_cursorXPos=0;
    m_cursorOldXPos=0;
@@ -255,6 +258,7 @@
       }
 
       m_mergeLineList.clear();
+      m_totalSize = 0;
       int lineIdx = 0;
       Diff3LineList::const_iterator it;
       for( it=m_pDiff3LineList->begin(); it!=m_pDiff3LineList->end(); ++it, ++lineIdx )
@@ -302,6 +306,7 @@
                   back->bConflict = false;
                }
             }
+            ml.mergeEditLineList.setTotalSizePtr(&m_totalSize);
             m_mergeLineList.push_back( ml );
          }
 
@@ -393,7 +398,6 @@
                        melsrc==3 ? mel.id3l()->lineC : -1;
 
          if ( srcLine == -1 && oldSrcLine==-1 && oldSrc == melsrc )
-
             melIt = ml.mergeEditLineList.erase( melIt );
          else
             ++melIt;
@@ -434,7 +438,7 @@
 
 int MergeResultWindow::getNofLines()
 {
-   return m_nofLines;
+   return m_totalSize;
 }
 
 int MergeResultWindow::getNofVisibleColumns()
@@ -791,6 +795,12 @@
 
       ml.mergeEditLineList.push_back(mel);
    }
+   
+   if ( m_cursorYPos >= m_totalSize )
+   {
+      m_cursorYPos = m_totalSize-1;
+      m_cursorXPos = 0;
+   }
 
    update();
    emit updateAvailabilities();
@@ -1056,9 +1066,14 @@
    }
 }
 
+void MergeResultWindow::setPaintingAllowed(bool bPaintingAllowed)
+{
+   m_bPaintingAllowed = bPaintingAllowed;
+}
+
 void MergeResultWindow::paintEvent( QPaintEvent* e )
 {
-   if (m_pDiff3LineList==0) return;
+   if (m_pDiff3LineList==0 || !m_bPaintingAllowed) return;
 
    bool bOldSelectionContainsData = m_selection.bSelectionContainsData;
    const QFontMetrics& fm = fontMetrics();
@@ -1079,9 +1094,7 @@
       //int visibleLines = height() / fontHeight;
 
       {  // Draw the topline
-         QString s;
-         s.sprintf(" Output : %s ", m_fileName.ascii() );
-         // s.sprintf(" Output : %s : Line %d",(const char*) m_fileName, m_firstLine+1 );
+         QString s = " " +i18n("Output") + " : " + m_fileName + " ";
          if (m_bModified)
             s += i18n("[Modified]");
 
@@ -1145,6 +1158,7 @@
       if ( line != m_nofLines || nofColumns != m_nofColumns )
       {
          m_nofLines = line;
+         assert( m_nofLines == m_totalSize );
 
          m_nofColumns = nofColumns;
          emit resizeSignal();
@@ -1223,7 +1237,7 @@
 
    int yOffset = topLineYOffset - m_firstLine * fontHeight;
 
-   line = min2( ( y - yOffset ) / fontHeight, m_nofLines-1 );
+   line = min2( ( y - yOffset ) / fontHeight, m_totalSize-1 );
    pos  = ( x - xOffset ) / fontWidth;
 }
 
@@ -1438,7 +1452,7 @@
          if( !melIt->isEditableText() )  break;
          if (x>=stringLength)
          {
-            if ( y<m_nofLines-1 )
+            if ( y<m_totalSize-1 )
             {
                setModified();
                QCString s1( ps, stringLength+1 );
@@ -1581,7 +1595,7 @@
       case  Key_Right:
          if ( !bCtrl )
          {
-            ++x;  if(x>stringLength && y<m_nofLines-1){ ++y; x=0; }
+            ++x;  if(x>stringLength && y<m_totalSize-1){ ++y; x=0; }
          }
 
          else
@@ -1620,9 +1634,9 @@
                   t.fill( ' ', spaces );
                }
                if ( m_bInsertMode )
-                  s.insert( x, t.ascii() );
+                  s.insert( x, encodeString(t, m_pOptionDialog) );
                else
-                  s.replace( x, t.length(), t.ascii() );
+                  s.replace( x, t.length(), encodeString(t, m_pOptionDialog) );
 
                melIt->setString( s );
                x += t.length();
@@ -1632,7 +1646,7 @@
       }
    }
 
-   y = minMaxLimiter( y, 0, m_nofLines-1 );
+   y = minMaxLimiter( y, 0, m_totalSize-1 );
 
    calcIteratorFromLineNr( y, mlIt, melIt );
    ps = melIt->getString( this, stringLength );
@@ -1744,7 +1758,10 @@
 
                   if( m_selection.within( line, outPos ) )
                   {
-                    selectionString += pLine[i];
+                     char buf[2];
+                     buf[0] = pLine[i];
+                     buf[1] = '\0';
+                     selectionString += decodeString( buf, m_pOptionDialog );
                   }
 
                   outPos += spaces;
@@ -1752,7 +1769,7 @@
             }
             else if ( mel.isConflict() )
             {
-               selectionString += "<Merge Conflict>";
+               selectionString += i18n("<Merge Conflict>");
             }
             
             if( m_selection.within( line, outPos ) )
@@ -1866,9 +1883,9 @@
             {
                // Remove the line
                if ( mlIt->mergeEditLineList.size()>1 )
-               {   mlIt->mergeEditLineList.erase( melIt ); --m_nofLines; }
+                  mlIt->mergeEditLineList.erase( melIt );
                else
-               {   melIt->setRemoved();  }
+                  melIt->setRemoved();
             }
          }
 
@@ -1901,15 +1918,14 @@
    const char* ps = melIt->getString( this, stringLength );
    int x = convertToPosInText( ps, stringLength, m_cursorXPos );
 
-   QString clipBoard = QApplication::clipboard()->text();
+   QCString clipBoard = encodeString( QApplication::clipboard()->text(), m_pOptionDialog );
 
    QCString currentLine = QCString( ps, x+1 );
    QCString endOfLine = QCString( ps+x, stringLength-x+1 );
    int i;
    for( i=0; i<(int)clipBoard.length(); ++i )
    {
-      QChar uc = clipBoard[i];
-      char c = uc;
+      char c = clipBoard[i];
       if ( c == '\r' ) continue;
       if ( c == '\n' )
       {
@@ -2015,11 +2031,10 @@
 
                if (line>0) // Prepend line feed, but not for first line
                {
-                  #ifdef _WIN32
-                  s.prepend("\r\n"); size+=2;
-                  #else
-                  s.prepend("\n");   size+=1;
-                  #endif
+                  if ( m_pOptionDialog->m_lineEndStyle == eLineEndDos )
+                  {   s.prepend("\r\n"); size+=2; }
+                  else
+                  {   s.prepend("\n");   size+=1; }
                }
 
                if (i==0) neededBufferSize += size;
@@ -2093,7 +2108,6 @@
    update();
 }
 
-
 Overview::Overview( QWidget* pParent, OptionDialog* pOptions )
 : QWidget( pParent, 0, WRepaintNoErase )
 {
--- a/kdiff3/src/optiondialog.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/optiondialog.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -28,6 +28,7 @@
 #include <qvbox.h>
 #include <qvalidator.h>
 #include <qtooltip.h>
+#include <qtextcodec.h>
 
 #include <kapplication.h>
 #include <kcolorbtn.h>
@@ -37,6 +38,7 @@
 #include <kconfig.h>
 #include <kmessagebox.h>
 //#include <kkeydialog.h>
+#include <map>
 
 #include "optiondialog.h"
 #include "diff.h"
@@ -126,25 +128,42 @@
    QColor m_defaultVal;
 };
 
-class OptionLineEdit : public QLineEdit, public OptionItem
+class OptionLineEdit : public QComboBox, public OptionItem
 {
 public:
    OptionLineEdit( const QString& defaultVal, const QString& saveName, QString* pVar,
                    QWidget* pParent, OptionDialog* pOD )
-   : QLineEdit( pParent ), OptionItem( pOD, saveName )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
    {
       m_pVar = pVar;
       m_defaultVal = defaultVal;
+      m_list.push_back(defaultVal);
+      setEditable(true);
    }
-   void setToDefault(){ setText( m_defaultVal );      }
-   void setToCurrent(){ setText( *m_pVar );           }
-   void apply()       { *m_pVar = text();                              }
-   void write(KConfig* config){ config->writeEntry(m_saveName, *m_pVar );   }
-   void read (KConfig* config){ *m_pVar = config->readEntry( m_saveName, *m_pVar ); }
+   void setToDefault(){ setCurrentText( m_defaultVal );      }
+   void setToCurrent(){ setCurrentText( *m_pVar );           }
+   void apply()       { *m_pVar = currentText(); insertText();            }
+   void write(KConfig* config){ config->writeEntry( m_saveName, m_list, '|' );      }
+   void read (KConfig* config){ 
+      m_list = config->readListEntry( m_saveName, '|' ); 
+      if ( !m_list.isEmpty() ) *m_pVar = m_list.front();
+      clear();
+      insertStringList(m_list);
+   }
 private:
+   void insertText()
+   {  // Check if the text exists. If yes remove it and
+      QString current = currentText();
+      m_list.remove( current );
+      m_list.push_front( current );
+      clear();
+      if ( m_list.count()>10 ) m_list.erase( m_list.at(10), m_list.end() );
+      insertStringList(m_list);
+   }
    OptionLineEdit( const OptionLineEdit& ); // private copy constructor without implementation
    QString* m_pVar;
    QString m_defaultVal;
+   QStringList m_list;
 };
 
 #if defined QT_NO_VALIDATOR
@@ -179,23 +198,69 @@
 class OptionComboBox : public QComboBox, public OptionItem
 {
 public:
-   OptionComboBox( int defaultVal, const QString& saveName, int* pVar,
+   OptionComboBox( int defaultVal, const QString& saveName, int* pVarNum,
                    QWidget* pParent, OptionDialog* pOD )
    : QComboBox( pParent ), OptionItem( pOD, saveName )
    {
-      m_pVar = pVar;
+      m_pVarNum = pVarNum;
+      m_pVarStr = 0;
       m_defaultVal = defaultVal;
       setEditable(false);
    }
-   void setToDefault(){ setCurrentItem( m_defaultVal );  }
-   void setToCurrent(){ setCurrentItem( *m_pVar );  }
-   void apply()       { *m_pVar = currentItem();  }
-   void write(KConfig* config){ config->writeEntry(m_saveName, *m_pVar );   }
-   void read (KConfig* config){ *m_pVar = config->readNumEntry( m_saveName, *m_pVar ); }
+   OptionComboBox( int defaultVal, const QString& saveName, QString* pVarStr,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVarNum = 0;
+      m_pVarStr = pVarStr;
+      m_defaultVal = defaultVal;
+      setEditable(false);
+   }
+   void setToDefault()
+   { 
+      setCurrentItem( m_defaultVal ); 
+      if (m_pVarStr!=0){ *m_pVarStr=currentText(); } 
+   }
+   void setToCurrent()
+   { 
+      if (m_pVarNum!=0) setCurrentItem( *m_pVarNum );
+      else              setText( *m_pVarStr );
+   }
+   void apply()       
+   { 
+      if (m_pVarNum!=0){ *m_pVarNum = currentItem(); }
+      else             { *m_pVarStr = currentText(); }
+   }
+   void write(KConfig* config)
+   { 
+      if (m_pVarStr!=0) config->writeEntry(m_saveName, *m_pVarStr );
+      else              config->writeEntry(m_saveName, *m_pVarNum );   
+   }
+   void read (KConfig* config)
+   {
+      if (m_pVarStr!=0)  setText( config->readEntry( m_saveName, currentText() ) );
+      else               *m_pVarNum = config->readNumEntry( m_saveName, *m_pVarNum ); 
+   }
 private:
    OptionComboBox( const OptionIntEdit& ); // private copy constructor without implementation
-   int* m_pVar;
+   int* m_pVarNum;
+   QString* m_pVarStr;
    int m_defaultVal;
+   
+   void setText(const QString& s)
+   {
+      // Find the string in the combobox-list, don't change the value if nothing fits.
+      for( int i=0; i<count(); ++i )
+      {
+         if ( text(i)==s )
+         {
+            if (m_pVarNum!=0) *m_pVarNum = i;
+            if (m_pVarStr!=0) *m_pVarStr = s;
+            setCurrentItem(i);
+            return;
+         }
+      }
+   }
 };
 
 OptionDialog::OptionDialog( bool bShowDirMergeSettings, QWidget *parent, char *name )
@@ -211,6 +276,9 @@
   setupOtherOptions();
   if (bShowDirMergeSettings)
      setupDirectoryMergePage();
+     
+  // setupRegionalPage();
+
   //setupKeysPage();
 
   // Initialize all values in the dialog
@@ -372,7 +440,24 @@
       "Off: You must explicitely copy e.g. via Ctrl-C."
       ));
    ++line;
-
+   
+   label = new QLabel( i18n("Line End Style:"), page );
+   gbox->addWidget( label, line, 0 );
+   #ifdef _WIN32
+   int defaultLineEndStyle = eLineEndDos;
+   #else
+   int defaultLineEndStyle = eLineEndUnix;
+   #endif
+   OptionComboBox* pLineEndStyle = new OptionComboBox( defaultLineEndStyle, "LineEndStyle", &m_lineEndStyle, page, this );
+   gbox->addWidget( pLineEndStyle, line, 1 );
+   pLineEndStyle->insertItem( "Unix", eLineEndUnix );
+   pLineEndStyle->insertItem( "Dos/Windows", eLineEndDos );
+   QToolTip::add( label, i18n(
+      "Sets the line endings for when a edited file is saved.\n"
+      "DOS/Windows: CR+LF; Unix: LF; with CR=0D, LF=0A")
+      );
+   ++line;
+      
    OptionCheckBox* pStringEncoding = new OptionCheckBox( i18n("Use locale encoding"), true, "LocaleEncoding", &m_bStringEncoding, page, this );
    gbox->addMultiCellWidget( pStringEncoding, line, line, 0, 1 );
    QToolTip::add( pStringEncoding, i18n(
@@ -464,7 +549,7 @@
    pWhiteSpace2FileMergeDefault->insertItem( i18n("Manual choice"), 0 );
    pWhiteSpace2FileMergeDefault->insertItem( "A", 1 );
    pWhiteSpace2FileMergeDefault->insertItem( "B", 2 );
-   QToolTip::add( pWhiteSpace2FileMergeDefault, i18n(
+   QToolTip::add( label, i18n(
       "Allow the merge algorithm to automatically select an input for "
       "white-space-only changes." )
       );
@@ -478,7 +563,7 @@
    pWhiteSpace3FileMergeDefault->insertItem( "A", 1 );
    pWhiteSpace3FileMergeDefault->insertItem( "B", 2 );
    pWhiteSpace3FileMergeDefault->insertItem( "C", 3 );
-   QToolTip::add( pWhiteSpace3FileMergeDefault, i18n(
+   QToolTip::add( label, i18n(
       "Allow the merge algorithm to automatically select an input for "
       "white-space-only changes." )
       );
@@ -612,6 +697,63 @@
    topLayout->addStretch(10);
 }
 
+static void insertCodecs(OptionComboBox* p)
+{
+   std::multimap<QString,QString> m;  // Using the multimap for case-insensitive sorting.
+   int i;
+   for(i=0;;++i)
+   {
+      QTextCodec* pCodec = QTextCodec::codecForIndex ( i );
+      if ( pCodec != 0 )  m.insert( std::make_pair( QString(pCodec->mimeName()).upper(), pCodec->mimeName()) );
+      else                break;
+   }
+   
+   p->insertItem( i18n("Auto"), 0 );
+   std::multimap<QString,QString>::iterator mi;
+   for(mi=m.begin(), i=0; mi!=m.end(); ++mi, ++i)
+      p->insertItem(mi->second, i+1);
+}
+
+void OptionDialog::setupRegionalPage( void )
+{
+   QFrame *page = addPage( i18n("Regional Settings"), i18n("Regional Settings"),
+                           BarIcon("locale"/*"charset"*/, KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 3, 2 );
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   QLabel* label;
+#ifdef KREPLACEMENTS_H   
+   label = new QLabel( i18n("Language (restart required)"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pLanguage = new OptionComboBox( 0, "Language", &m_language, page, this );
+   gbox->addWidget( pLanguage, line, 1 );
+   pLanguage->insertItem( i18n("Auto"), 0 );
+   // Read directory: Find all kdiff3_*.qm-files and insert the found files here selection
+   QToolTip::add( label, i18n(
+      "Choose the language of the GUI-strings or \"Auto\".\n" 
+      "For a change of language to take place, quit and restart KDiff3.") 
+      );
+   ++line;
+#endif
+
+   label = new QLabel( i18n("Codec for file contents"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pFileCodec = new OptionComboBox( 0, "FileCodec", &m_fileCodec, page, this );
+   gbox->addWidget( pFileCodec, line, 1 );
+   insertCodecs( pFileCodec );
+   QToolTip::add( label, i18n(
+      "Choose the codec that should be used for your input files\n"
+      "or \"Auto\" if unsure." ) 
+      );
+   ++line;
+      
+   topLayout->addStretch(10);
+}
+
+
 void OptionDialog::setupKeysPage( void )
 {
    //QVBox *page = addVBoxPage( i18n("Keys"), i18n("KeyDialog" ),
@@ -753,4 +895,5 @@
 }
 
 
+
 #include "optiondialog.moc"
--- a/kdiff3/src/optiondialog.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/optiondialog.h	Sun Mar 07 09:59:09 2004 +0000
@@ -35,6 +35,11 @@
 class OptionItem;
 class KKeyDialog;
 
+enum eLineEndStyle
+{
+   eLineEndUnix=0,
+   eLineEndDos
+};
 
 class OptionDialog : public KDialogBase
 {
@@ -64,6 +69,7 @@
     int  m_tabSize;
     bool m_bAutoCopySelection;
     bool m_bStringEncoding;
+    int  m_lineEndStyle;
 
     bool m_bPreserveCarriageReturn;
     bool m_bTryHard;
@@ -105,6 +111,9 @@
     QString m_DmFileAntiPattern;
     QString m_DmDirAntiPattern;
 
+    QString m_language;
+    QString m_fileCodec;
+    
     void saveOptions(KConfig* config);
     void readOptions(KConfig* config);
 
@@ -133,11 +142,13 @@
     void setupDiffPage();
     void setupDirectoryMergePage();
     void setupKeysPage();
+    void setupRegionalPage();
     void setupOtherOptions();
 };
 
 
 
+
 #endif
 
 
--- a/kdiff3/src/pdiff.cpp	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/pdiff.cpp	Sun Mar 07 09:59:09 2004 +0000
@@ -1,8 +1,8 @@
 /***************************************************************************
-                          kdiff.cpp  -  description
-                             -------------------
+                         pdiff.cpp  -  Implementation for class KDiff3App
+                         ---------------
     begin                : Mon Mär 18 20:04:50 CET 2002
-    copyright            : (C) 2002 by Joachim Eibl
+    copyright            : (C) 2002-2004 by Joachim Eibl
     email                : joachim.eibl@gmx.de
  ***************************************************************************/
 
@@ -99,7 +99,7 @@
    return fileName;
 }
 
-bool KDiff3App::runDiff( LineData* p1, int size1, LineData* p2, int size2, DiffList& diffList )
+bool KDiff3App::runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList )
 {
    static GnuDiff gnuDiff;
    
@@ -164,8 +164,11 @@
    
       if (size1-currentLine1==size2-currentLine2 )
       {
-         Diff d( size1-currentLine1,0,0);
-         diffList.push_back(d);
+         if (size1-currentLine1>0)
+         {
+            Diff d( size1-currentLine1,0,0);
+            diffList.push_back(d);
+         }
       }
       else if ( !diffList.empty() )
       {  // Only necessary for a files that end with a newline
@@ -204,209 +207,6 @@
    g_pProgressDialog->setSubCurrent(1.0);
 
    return true;
-#if 0
-
-   if ( m_pOptionDialog->m_bUseExternalDiff )
-   {
-      bool bSuccess=false;
-
-      bool bIgnoreWhiteSpace = m_pOptionDialog->m_bIgnoreWhiteSpace;
-      bool bIgnoreNumbers = m_pOptionDialog->m_bIgnoreNumbers;
-
-      // Create two temp files (Remove all white spaces and carriage returns here)
-      // (Make sure that no existing files are overwritten.)
-      g_pProgressDialog->setSubCurrent(0);
-      QString fileName1 = createTempFile( p1, size1, bIgnoreWhiteSpace, bIgnoreNumbers );
-      g_pProgressDialog->setSubCurrent(0.25);
-      QString fileName2 = createTempFile( p2, size2, bIgnoreWhiteSpace, bIgnoreNumbers );
-      g_pProgressDialog->setSubCurrent(0.5);
-      QString fileNameOut = FileAccess::tempFileName();
-
-      if ( !fileName1.isEmpty() && !fileName2.isEmpty() )
-      {
-         QString cmd;
-#ifdef _WIN32
-         // Under Windows it's better to search for diff.exe
-         char buf[200];
-         int r= SearchPathA( 0, "diff.exe",  0, sizeof(buf), buf, 0 );
-
-         if (r!=0) { cmd = buf; }
-#else
-         // under Un*x I assume that a diff command is in the PATH
-         cmd = "diff";
-#endif
-         if ( !cmd.isEmpty() )
-         {
-            cmd += " -a ";     // -a = treat all files as text
-            if ( m_pOptionDialog->m_bTryHard )
-               cmd += "--minimal ";
-            //if ( m_pOptionDialog->m_bIgnoreWhiteSpace ) This I do myself, see below
-            //   cmd += "--ignore-all-space ";
-            cmd += fileName1+" "+fileName2+" >"+fileNameOut;
-            // Run diff
-            //int status1 = ::system( 0 ); // ==0 if shell not found
-            int status = ::system( cmd.ascii() );
-#ifdef WEXITSTATUS
-            status = WEXITSTATUS(status);
-#endif
-            //if (status<0)
-            //{
-            //   errorString = strerror( errno );
-            //}
-            bSuccess = status>=0 && status!=127;
-         }
-      }
-
-      g_pProgressDialog->setSubCurrent(0.75);
-
-      int currentLine1 = 0;
-      int currentLine2 = 0;
-      if ( bSuccess )
-      {
-         // Parse the output and create the difflist
-         QFile f( fileNameOut );
-         bSuccess = f.open(IO_ReadOnly);
-         if (bSuccess)
-         {
-            const QByteArray buf = f.readAll();
-            unsigned int bufSize=buf.size();
-            unsigned int pos=0;
-            for(pos=0;pos<bufSize;++pos)
-            {
-               unsigned int lineStart = pos;
-               // Find end of line
-               while( buf.at(pos)!='\n' && pos<bufSize )
-                  ++pos;
-
-               // parse it
-               char c = buf.at(lineStart);
-               if ( c == '>' || c == '-' || c=='<' )
-                  continue;  // Not interested in the data
-               else
-               {
-                  QCString line( &buf.at(lineStart), pos-lineStart+1 );
-                  int pa = line.find('a'); // add
-                  int pc = line.find('c'); // change
-                  int pd = line.find('d'); // delete
-                  int p = pa>0 ? pa : (pc > 0 ? pc : pd);
-                  if (p<0) break; // Unexpected error
-                  QCString left = line.left(p);
-                  QCString right = line.mid(p+1);
-                  int pcommaleft = left.find(',');
-                  int pcommaright = right.find(',');
-                  int l1top=-1, l1bottom=-1, l2top=-1, l2bottom=-1;
-                  if (pcommaleft>0)
-                  {
-                     l1top    = left.left(pcommaleft).toInt();
-                     l1bottom = left.mid(pcommaleft+1).toInt();
-                  }
-                  else
-                  {
-                     l1top    = left.toInt();
-                     l1bottom = l1top;
-                  }
-                  if (pcommaright>0)
-                  {
-                     l2top    = right.left(pcommaright).toInt();
-                     l2bottom = right.mid(pcommaright+1).toInt();
-                  }
-                  else
-                  {
-                     l2top    = right.toInt();
-                     l2bottom = l2top;
-                  }
-
-                  Diff d(0,0,0);
-
-                  if ( pa>0 )
-                  {
-                     d.nofEquals = l1top - currentLine1;
-                     d.diff1 = 0;
-                     d.diff2 = l2bottom - l2top + 1;
-                     assert( d.nofEquals == l2top - 1 - currentLine2 );
-                  }
-                  else if ( pd>0 )
-                  {
-                     d.nofEquals = l2top - currentLine2;
-                     d.diff1 = l1bottom - l1top + 1;
-                     d.diff2 = 0;
-                     assert( d.nofEquals == l1top - 1 - currentLine1 );
-                  }
-                  else if ( pc>0 )
-                  {
-                     d.nofEquals = l1top - 1 - currentLine1;
-                     d.diff1 = l1bottom - l1top + 1;
-                     d.diff2 = l2bottom - l2top + 1;
-                     assert( d.nofEquals == l2top - 1 - currentLine2 );
-                  }
-                  else
-                     assert(false);
-
-                  currentLine1 += d.nofEquals + d.diff1;
-                  currentLine2 += d.nofEquals + d.diff2;
-                  diffList.push_back(d);
-               }
-            }
-            if (size1-currentLine1==size2-currentLine2 )
-            {
-               Diff d( size1-currentLine1,0,0);
-               diffList.push_back(d);
-               currentLine1=size1;
-               currentLine2=size2;
-            }
-
-            if ( currentLine1 == size1 && currentLine2 == size2 )
-               bSuccess = true;
-         }
-         else
-         {
-            bSuccess = size1==size2;
-         }
-      }
-      if ( currentLine1==0 && currentLine2==0 )
-      {
-         Diff d( 0, size1, size2 );
-         diffList.push_back(d);
-      }
-
-      g_pProgressDialog->setSubCurrent(1.0);
-
-      if ( !bSuccess )
-      {
-         KMessageBox::sorry(this,
-            i18n("Running the external diff failed.\n"
-                 "Check if the diff works, if the program can write in the temp folder or if the disk is full.\n"
-                 "The external diff option will be disabled now and the internal diff will be used."),
-            i18n("Warning"));
-         m_pOptionDialog->m_bUseExternalDiff = false;
-      }
-
-      FileAccess::removeFile( fileName1 );
-      FileAccess::removeFile( fileName2 );
-      FileAccess::removeFile( fileNameOut );
-   }
-
-   if ( ! m_pOptionDialog->m_bUseExternalDiff )
-   {
-      g_pProgressDialog->setSubCurrent(0.0);
-      if ( size1>0 && p1!=0 && p1->occurances==0 )
-      {
-         prepareOccurances( p1, size1 );
-      }
-      g_pProgressDialog->setSubCurrent(0.25);
-
-      if ( size2>0 && p2!=0 && p2->occurances==0 )
-      {
-         prepareOccurances( p2, size2 );
-      }
-      g_pProgressDialog->setSubCurrent(0.5);
-
-      calcDiff( p1, size1, p2, size2, diffList, 2, m_pOptionDialog->m_maxSearchLength );
-
-      g_pProgressDialog->setSubCurrent(1.0);
-   }
-   return true;
-#endif
 }
 
 
@@ -418,18 +218,44 @@
    if ( bVisibleMergeResultWindow )
    {
       bPreserveCarriageReturn = false;
+      
+      QString msg;
+      
+      if ( !m_pOptionDialog->m_PreProcessorCmd.isEmpty() )
+      {
+         msg += "- " + i18n("PreprocessorCmd: ") + m_pOptionDialog->m_PreProcessorCmd + "\n";
+      }
+      if ( m_pOptionDialog->m_bUpCase )
+      {
+         msg += "- " + i18n("Convert to upper case\n");
+      }
+      if ( !msg.isEmpty() )
+      {
+         int result = KMessageBox::warningYesNo( this,
+                               i18n("The following option(s) you selected might change data:\n") + msg + 
+                               i18n("\nMost likely this is not wanted during a merge.\n"
+                                    "Do you want to disable these settings or continue with these settings active?"),
+                               i18n("Option unsafe for merging"), 
+                               i18n("Use these options during the merge"), i18n("Disable unsafe options")
+                               );
+                               
+         if (result == KMessageBox::No )
+         {
+            m_pOptionDialog->m_PreProcessorCmd = "";
+            m_pOptionDialog->m_bUpCase = false;
+         }
+      }
    }
 
    m_diff3LineList.clear();
 
-   bool bUseLineMatchingPP = !m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty() ||
-                             m_pOptionDialog->m_bIgnoreComments;
-   bool bUpCase = m_pOptionDialog->m_bUpCase;
-
+   // Because of the progressdialog paintevents can occur, but data is invalid,
+   // so painting must be suppressed.
    if (m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed( false );
    if (m_pDiffTextWindow2) m_pDiffTextWindow2->setPaintingAllowed( false );
    if (m_pDiffTextWindow3) m_pDiffTextWindow3->setPaintingAllowed( false );
    if (m_pOverview)        m_pOverview->setPaintingAllowed( false );
+   if (m_pMergeResultWindow) m_pMergeResultWindow->setPaintingAllowed( false );
 
 
    if( m_sd3.isEmpty() )
@@ -441,95 +267,74 @@
 
    // First get all input data.
    g_pProgressDialog->setInformation(i18n("Loading A"));
-   m_sd1.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
-   m_sdlm1.readLMPPFile( &m_sd1, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
+   m_sd1.readAndPreprocess();
    g_pProgressDialog->step();
 
    g_pProgressDialog->setInformation(i18n("Loading B"));
-   m_sd2.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
-   m_sdlm2.readLMPPFile( &m_sd2, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
+   m_sd2.readAndPreprocess();
    g_pProgressDialog->step();
 
-   m_sd3.m_bIsText = true;
    m_totalDiffStatus.reset();
    // Run the diff.
    if ( m_sd3.isEmpty() )
    {
-      m_totalDiffStatus.bBinaryAEqB = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd2.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd2.m_pBuf,m_sd1.m_size)==0);
+      m_totalDiffStatus.bBinaryAEqB = m_sd1.getSizeBytes()!=0 && m_sd1.isBinaryEqualWith( m_sd2 );
       g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
-      if ( !bUseLineMatchingPP )
-         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd2.m_v[0], m_sd2.m_vSize, m_diffList12 );
-      else
-         runDiff( &m_sdlm1.m_v[0], m_sdlm1.m_vSize, &m_sdlm2.m_v[0], m_sdlm2.m_vSize, m_diffList12 );
+      
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12 );
 
       g_pProgressDialog->step();
 
       g_pProgressDialog->setInformation(i18n("Linediff: A <-> B"));
       calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
-      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], m_totalDiffStatus.bTextAEqB );
-      if ( m_sd1.m_size==0 ) m_totalDiffStatus.bTextAEqB=false;
+      fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay(), m_totalDiffStatus.bTextAEqB );
+      if ( m_sd1.getSizeBytes()==0 ) m_totalDiffStatus.bTextAEqB=false;
 
       g_pProgressDialog->step();
    }
    else
    {
       g_pProgressDialog->setInformation(i18n("Loading C"));
-      m_sd3.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
-      m_sdlm3.readLMPPFile( &m_sd3, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
+      m_sd3.readAndPreprocess();
       g_pProgressDialog->step();
 
-      m_totalDiffStatus.bBinaryAEqB = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd2.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd2.m_pBuf,m_sd1.m_size)==0);
-      m_totalDiffStatus.bBinaryAEqC = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd3.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd3.m_pBuf,m_sd1.m_size)==0);
-      m_totalDiffStatus.bBinaryBEqC = (m_sd3.m_size!=0 && m_sd3.m_size==m_sd2.m_size  &&  memcmp(m_sd3.m_pBuf,m_sd2.m_pBuf,m_sd3.m_size)==0);
+      m_totalDiffStatus.bBinaryAEqB = m_sd1.getSizeBytes()!=0 && m_sd1.isBinaryEqualWith(m_sd2);
+      m_totalDiffStatus.bBinaryAEqC = m_sd1.getSizeBytes()!=0 && m_sd1.isBinaryEqualWith(m_sd3);
+      m_totalDiffStatus.bBinaryBEqC = m_sd3.getSizeBytes()!=0 && m_sd3.isBinaryEqualWith(m_sd2);
 
-      if ( !bUseLineMatchingPP )
-      {
-         g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
-         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd2.m_v[0], m_sd2.m_vSize, m_diffList12 );
-         g_pProgressDialog->step();
-         g_pProgressDialog->setInformation(i18n("Diff: B <-> C"));
-         runDiff( &m_sd2.m_v[0], m_sd2.m_vSize, &m_sd3.m_v[0], m_sd3.m_vSize, m_diffList23 );
-         g_pProgressDialog->step();
-         g_pProgressDialog->setInformation(i18n("Diff: A <-> C"));
-         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd3.m_v[0], m_sd3.m_vSize, m_diffList13 );
-         g_pProgressDialog->step();
-      }
-      else
-      {
-         g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
-         runDiff( &m_sdlm1.m_v[0], m_sd1.m_vSize, &m_sdlm2.m_v[0], m_sd2.m_vSize, m_diffList12 );
-         g_pProgressDialog->step();
-         g_pProgressDialog->setInformation(i18n("Diff: B <-> C"));
-         runDiff( &m_sdlm2.m_v[0], m_sd2.m_vSize, &m_sdlm3.m_v[0], m_sd3.m_vSize, m_diffList23 );
-         g_pProgressDialog->step();
-         g_pProgressDialog->setInformation(i18n("Diff: A <-> C"));
-         runDiff( &m_sdlm1.m_v[0], m_sd1.m_vSize, &m_sdlm3.m_v[0], m_sd3.m_vSize, m_diffList13 );
-         g_pProgressDialog->step();
-      }
+      g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12 );
+      g_pProgressDialog->step();
+      g_pProgressDialog->setInformation(i18n("Diff: B <-> C"));
+      runDiff( m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList23 );
+      g_pProgressDialog->step();
+      g_pProgressDialog->setInformation(i18n("Diff: A <-> C"));
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList13 );
+      g_pProgressDialog->step();
 
       calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
       calcDiff3LineListUsingAC( &m_diffList13, m_diff3LineList );
-      calcDiff3LineListTrim( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
+      calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff() );
 
       calcDiff3LineListUsingBC( &m_diffList23, m_diff3LineList );
-      calcDiff3LineListTrim( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
-      debugLineCheck( m_diff3LineList, m_sd1.m_vSize, 1 );
-      debugLineCheck( m_diff3LineList, m_sd2.m_vSize, 2 );
-      debugLineCheck( m_diff3LineList, m_sd3.m_vSize, 3 );
+      calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff() );
+      debugLineCheck( m_diff3LineList, m_sd1.getSizeLines(), 1 );
+      debugLineCheck( m_diff3LineList, m_sd2.getSizeLines(), 2 );
+      debugLineCheck( m_diff3LineList, m_sd3.getSizeLines(), 3 );
 
       g_pProgressDialog->setInformation(i18n("Linediff: A <-> B"));
-      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], m_totalDiffStatus.bTextAEqB );
+      fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay(), m_totalDiffStatus.bTextAEqB );
       g_pProgressDialog->step();
       g_pProgressDialog->setInformation(i18n("Linediff: B <-> C"));
-      fineDiff( m_diff3LineList, 2, &m_sd2.m_v[0], &m_sd3.m_v[0], m_totalDiffStatus.bTextBEqC );
+      fineDiff( m_diff3LineList, 2, m_sd2.getLineDataForDisplay(), m_sd3.getLineDataForDisplay(), m_totalDiffStatus.bTextBEqC );
       g_pProgressDialog->step();
       g_pProgressDialog->setInformation(i18n("Linediff: A <-> C"));
-      fineDiff( m_diff3LineList, 3, &m_sd3.m_v[0], &m_sd1.m_v[0], m_totalDiffStatus.bTextAEqC );
+      fineDiff( m_diff3LineList, 3, m_sd3.getLineDataForDisplay(), m_sd1.getLineDataForDisplay(), m_totalDiffStatus.bTextAEqC );
       g_pProgressDialog->step();
-      if ( m_sd1.m_size==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextAEqC=false; }
-      if ( m_sd2.m_size==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextBEqC=false; }
+      if ( m_sd1.getSizeBytes()==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextAEqC=false; }
+      if ( m_sd2.getSizeBytes()==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextBEqC=false; }
    }
-   calcWhiteDiff3Lines( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
+   calcWhiteDiff3Lines( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff() );
    calcDiff3LineVector( m_diff3LineList, m_diff3LineVector );
 
    // Calc needed lines for display
@@ -542,11 +347,11 @@
    m_bTripleDiff = ! m_sd3.isEmpty();
 
    m_pDiffTextWindow1->init( m_sd1.getAliasName(),
-      &m_sd1.m_v[0], m_sd1.m_vSize, &m_diff3LineVector, 1, m_bTripleDiff );
+      m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), &m_diff3LineVector, 1, m_bTripleDiff );
    m_pDiffTextWindow2->init( m_sd2.getAliasName(),
-      &m_sd2.m_v[0], m_sd2.m_vSize, &m_diff3LineVector, 2, m_bTripleDiff );
+      m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), &m_diff3LineVector, 2, m_bTripleDiff );
    m_pDiffTextWindow3->init( m_sd3.getAliasName(),
-      &m_sd3.m_v[0], m_sd3.m_vSize, &m_diff3LineVector, 3, m_bTripleDiff );
+      m_sd3.getLineDataForDisplay(), m_sd3.getSizeLines(), &m_diff3LineVector, 3, m_bTripleDiff );
 
    if (m_bTripleDiff) m_pDiffTextWindow3->show();
    else               m_pDiffTextWindow3->hide();
@@ -554,9 +359,9 @@
    m_bOutputModified = bVisibleMergeResultWindow;
 
    m_pMergeResultWindow->init(
-      &m_sd1.m_v[0],
-      &m_sd2.m_v[0],
-      m_bTripleDiff ? &m_sd3.m_v[0] : 0,
+      m_sd1.getLineDataForDisplay(),
+      m_sd2.getLineDataForDisplay(),
+      m_bTripleDiff ? m_sd3.getLineDataForDisplay() : 0,
       &m_diff3LineList,
       &m_totalDiffStatus,
       m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename
@@ -571,6 +376,8 @@
    m_pDiffTextWindow2->setPaintingAllowed( true );
    m_pDiffTextWindow3->setPaintingAllowed( true );
    m_pOverview->setPaintingAllowed( true );
+   m_pMergeResultWindow->setPaintingAllowed( true );
+
 
    if ( !bVisibleMergeResultWindow )
       m_pMergeWindowFrame->hide();
@@ -604,7 +411,7 @@
          KMessageBox::information( this, totalInfo );
    }
 
-   if ( bVisibleMergeResultWindow && (!m_sd1.m_bIsText || !m_sd2.m_bIsText || !m_sd3.m_bIsText) )
+   if ( bVisibleMergeResultWindow && (!m_sd1.isText() || !m_sd2.isText() || !m_sd3.isText()) )
    {
       KMessageBox::information( this, i18n(
          "Some inputfiles don't seem to be pure textfiles.\n"
@@ -949,7 +756,8 @@
 
        return true;                        // eat event
    }
-   else if (e->type() == QEvent::Wheel ) {  // wheel event
+   else if (e->type() == QEvent::Wheel )   // wheel event
+   {
        QWheelEvent *w = (QWheelEvent*)e;
        w->accept();
 
@@ -1001,10 +809,9 @@
          if ( bDecodeSuccess && canContinue() )
          {
             raise();
-            bool bUpCase = m_pOptionDialog->m_bUpCase;
-            if      ( o == m_pDiffTextWindow1 ) m_sd1.setData(text, bUpCase);
-            else if ( o == m_pDiffTextWindow2 ) m_sd2.setData(text, bUpCase);
-            else if ( o == m_pDiffTextWindow3 ) m_sd3.setData(text, bUpCase);
+            if      ( o == m_pDiffTextWindow1 ) m_sd1.setData(text);
+            else if ( o == m_pDiffTextWindow2 ) m_sd2.setData(text);
+            else if ( o == m_pDiffTextWindow3 ) m_sd3.setData(text);
             init();
          }
       }
@@ -1037,6 +844,7 @@
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileA() ) );
    QPushButton * button2 = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirA() ) );
+   connect( m_lineA, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
 
    h->addWidget( label,    0, 0 );
    h->addWidget( m_lineA,  0, 1 );
@@ -1052,6 +860,7 @@
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileB() ) );
    button2   = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirB() ) );
+   connect( m_lineB, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
 
    h->addWidget( label,     1, 0 );
    h->addWidget( m_lineB,   1, 1 );
@@ -1067,6 +876,7 @@
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileC() ) );
    button2   = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirC() ) );
+   connect( m_lineC, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
 
    h->addWidget( label,     2, 0 );
    h->addWidget( m_lineC,   2, 1 );
@@ -1122,8 +932,44 @@
 
    QSize sh = sizeHint();
    setFixedHeight( sh.height() );
+   m_bInputFileNameChanged = false;
+
+#ifdef KREPLACEMENTS_H
+   m_lineA->lineEdit()->installEventFilter( this );
+   m_lineB->lineEdit()->installEventFilter( this );
+   m_lineC->lineEdit()->installEventFilter( this );
+   m_lineOut->lineEdit()->installEventFilter( this );
+#endif
 }
 
+// Eventfilter: Only needed under Windows.
+// Without this, files dropped in the line edit have URL-encoding.
+// This eventfilter decodes the filenames as needed by KDiff3.
+bool OpenDialog::eventFilter(QObject* o, QEvent* e)
+{
+   if (e->type()==QEvent::Drop)
+   {
+      QDropEvent* d = static_cast<QDropEvent*>(e);
+
+      if ( !QUriDrag::canDecode( d ) ) {
+         return false;
+      }
+
+      QStringList lst;
+      QUriDrag::decodeLocalFiles( d, lst );
+
+      if ( lst.count() > 0 )
+      {
+         static_cast<QLineEdit*>(o)->setText( lst[0] );
+         static_cast<QLineEdit*>(o)->setFocus();
+      }
+       
+      return true;
+   }
+   return false;
+}
+
+
 void OpenDialog::selectURL( QComboBox* pLine, bool bDir, int i, bool bSave )
 {
    QString current = pLine->currentText();
@@ -1154,6 +1000,18 @@
    emit internalSignal(i!=0);
 }
 
+// Clear the output-filename when any input-filename changed, 
+// because users forgot to change the output and accidently overwrote it with
+// wrong data during a merge.
+void OpenDialog::inputFilenameChanged()
+{   
+   if(!m_bInputFileNameChanged)
+   {
+      m_bInputFileNameChanged=true;
+      m_lineOut->clearEdit();
+   }
+}
+
 void OpenDialog::accept()
 {
    unsigned int maxNofRecentFiles = 10;
@@ -1209,9 +1067,9 @@
    for(;;)
    {
       OpenDialog d(this,
-         m_sd1.m_bPreserve ? QString("") : m_sd1.getAliasName(),
-         m_sd2.m_bPreserve ? QString("") : m_sd2.getAliasName(),
-         m_sd3.m_bPreserve ? QString("") : m_sd3.getAliasName(),
+         m_sd1.isFromBuffer() ? QString("") : m_sd1.getAliasName(),
+         m_sd2.isFromBuffer() ? QString("") : m_sd2.getAliasName(),
+         m_sd3.isFromBuffer() ? QString("") : m_sd3.getAliasName(),
          !m_outputFilename.isEmpty(),
          m_bDefaultFilename ? QString("") : m_outputFilename,
          SLOT(slotConfigure()), m_pOptionDialog );
@@ -1253,17 +1111,17 @@
             m_pDirectoryMergeSplitter->hide();
             init();
 
-            if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0  ||
-                 ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
-                 ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+            if ( ! m_sd1.isEmpty() && !m_sd1.hasData()  ||
+                 ! m_sd2.isEmpty() && !m_sd2.hasData()  ||
+                 ! m_sd3.isEmpty() && !m_sd3.hasData() )
             {
                QString text( i18n("Opening of these files failed:") );
                text += "\n\n";
-               if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+               if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
                   text += " - " + m_sd1.getAliasName() + "\n";
-               if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+               if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
                   text += " - " + m_sd2.getAliasName() + "\n";
-               if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+               if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
                   text += " - " + m_sd3.getAliasName() + "\n";
 
                KMessageBox::sorry( this, text, i18n("File open error") );
@@ -1314,17 +1172,17 @@
    {
       init();
 
-      if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0  ||
-           ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
-           ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+      if ( ! m_sd1.isEmpty() && ! m_sd1.hasData()  ||
+           ! m_sd2.isEmpty() && ! m_sd2.hasData()  ||
+           ! m_sd3.isEmpty() && ! m_sd3.hasData() )
       {
          QString text( i18n("Opening of these files failed:") );
          text += "\n\n";
-         if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+         if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
             text += " - " + m_sd1.getAliasName() + "\n";
-         if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+         if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
             text += " - " + m_sd2.getAliasName() + "\n";
-         if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+         if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
             text += " - " + m_sd3.getAliasName() + "\n";
 
          KMessageBox::sorry( this, text, i18n("File open error") );
@@ -1355,7 +1213,7 @@
 
    if ( !s.isNull() )
    {
-      QApplication::clipboard()->setText( s );
+      QApplication::clipboard()->setText( s, QClipboard::Clipboard );
    }
 
    slotStatusMsg(i18n("Ready."));
@@ -1371,7 +1229,7 @@
    if ( s.isNull() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection();
    if ( !s.isNull() )
    {
-      QApplication::clipboard()->setText( s );
+      QApplication::clipboard()->setText( s, QClipboard::Clipboard );
    }
 
    slotStatusMsg(i18n("Ready."));
@@ -1387,20 +1245,19 @@
    }
    else if ( canContinue() )
    {
-      bool bUpCase = m_pOptionDialog->m_bUpCase;
       if ( m_pDiffTextWindow1->hasFocus() )
       {
-         m_sd1.setData( QApplication::clipboard()->text(), bUpCase );
+         m_sd1.setData( QApplication::clipboard()->text() );
          init();
       }
       else if ( m_pDiffTextWindow2->hasFocus() )
       {
-         m_sd2.setData( QApplication::clipboard()->text(), bUpCase );
+         m_sd2.setData( QApplication::clipboard()->text() );
          init();
       }
       else if ( m_pDiffTextWindow3->hasFocus() )
       {
-         m_sd3.setData( QApplication::clipboard()->text(), bUpCase );
+         m_sd3.setData( QApplication::clipboard()->text() );
          init();
       }
    }
@@ -1585,6 +1442,23 @@
    {
       slotEditCopy();
    }
+   else
+   {
+       QClipboard *clipBoard = QApplication::clipboard();
+
+       if (clipBoard->supportsSelection ())
+       {           
+           QString s;
+           if (               m_pDiffTextWindow1!=0 )   s = m_pDiffTextWindow1->getSelection();
+           if ( s.isNull() && m_pDiffTextWindow2!=0 )   s = m_pDiffTextWindow2->getSelection();
+           if ( s.isNull() && m_pDiffTextWindow3!=0 )   s = m_pDiffTextWindow3->getSelection();
+           if ( s.isNull() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection();
+           if ( !s.isNull() )
+           {
+               clipBoard->setText( s, QClipboard::Selection );
+           }
+       }
+   }
 }
 
 void KDiff3App::slotClipboardChanged()
@@ -1922,15 +1796,15 @@
       if ( !canContinue() ) return;
       if ( m_outputFilename.isEmpty() )
       {
-         if ( !m_sd3.isEmpty() && !m_sd3.m_bPreserve )
+         if ( !m_sd3.isEmpty() && !m_sd3.isFromBuffer() )
          {
             m_outputFilename =  m_sd3.getFilename();
          }
-         else if ( !m_sd2.isEmpty() && !m_sd2.m_bPreserve )
+         else if ( !m_sd2.isEmpty() && !m_sd2.isFromBuffer() )
          {
             m_outputFilename =  m_sd2.getFilename();
          }
-         else if ( !m_sd1.isEmpty() && !m_sd1.m_bPreserve )
+         else if ( !m_sd1.isEmpty() && !m_sd1.isFromBuffer() )
          {
             m_outputFilename =  m_sd1.getFilename();
          }
@@ -2016,7 +1890,7 @@
 
 void KDiff3App::slotUpdateAvailabilities()
 {
-   bool bTextDataAvailable = (m_sd1.m_pBuf != 0 || m_sd2.m_pBuf != 0 || m_sd3.m_pBuf != 0 );
+   bool bTextDataAvailable = ( m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData() );
    if( dirShowBoth->isChecked() )
    {
       if ( m_bDirCompare )
--- a/kdiff3/src/version.h	Sat Jan 31 14:25:47 2004 +0000
+++ b/kdiff3/src/version.h	Sun Mar 07 09:59:09 2004 +0000
@@ -1,2 +1,2 @@
 #undef VERSION
-#define VERSION "0.9.81"
+#define VERSION "0.9.83"