changeset 51:c59d5a3a8ff3

0.9.80
author joachim99
date Tue, 09 Dec 2003 20:29:43 +0000
parents 8c9752066f09
children ba22ec30aa4e
files kdiff3/ChangeLog kdiff3/README kdiff3/README_WIN.txt kdiff3/TODO kdiff3/doc/en/index.docbook kdiff3/src/Makefile.am kdiff3/src/Makefile.qt kdiff3/src/Makefile.win_qt230 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_part.rc kdiff3/src/kdiff3_shell.rc kdiff3/src/kdiff3_tmake.pro kdiff3/src/kdiff3part.desktop kdiff3/src/kreplacements/kreplacements.cpp kdiff3/src/kreplacements/kreplacements.h 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 34 files changed, 1958 insertions(+), 1295 deletions(-) [+]
line wrap: on
line diff
--- a/kdiff3/ChangeLog	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/ChangeLog	Tue Dec 09 20:29:43 2003 +0000
@@ -1,3 +1,33 @@
+Version 0.9.80 - 2003/12/08
+===========================
+New Text Diff/Merge Features:
+- Now using GNU-diff algorithms internally. (Option "External Diff" removed.)
+- Option for treating C/C++ comments as whitespace during diff.
+- Bugfix for locale character encoding (+ new option "Use string encoding")
+- Option for suppressing highlighting in white-space changes.
+  (Also suppresses highlighting in comments and numbers when the
+  respective options are active.)
+- Merge-menu: Choose A/B/C for all unsolved conflicts.
+              Choose A/B/C for all unsolved whitespace conflicts.
+- Options to automatically choose a certain source for whitespace conflicts.
+- Shorcut F5 now used to reload the current file.
+
+New Directory-Comparison/Merge Features:
+- Option to trust filesize. (Some directory services don't copy the date/time correctly.)
+- Shortcut F7 now starts complete directory merge (previously F5).
+- Do the selected merge operation for the selected file/dir only
+  "Run Operation For Current Item" (F6).
+- Shortcuts for selecting the merge operation for the selected item.
+  Ctrl-1/2/3/4/Del select A/B/C/Merge/Delete respectively.
+
+Other Improvements:
+- Several i18n-corrections (by Stephan Binner)
+- Bugfix for option CVS-ignore: Didn't work correctly in subdirectories.
+- Bugfix for remote operations: Operation can now be aborted, when KIO-slaves doesn't respond.
+- Cancel-Button in progress bar.
+- Default diff-view now again side by side instead of one above the other.
+
+
 Version 0.9.71 - 2003/10/14
 ===========================
 - Windows-Installer by Sebastien Fricker.
--- a/kdiff3/README	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/README	Tue Dec 09 20:29:43 2003 +0000
@@ -3,7 +3,7 @@
 
 Author: Joachim Eibl  (joachim.eibl@gmx.de)
 Copyright: (C) 2002-2003 by Joachim Eibl
-KDiff3-Version: 0.9.70
+KDiff3-Version: 0.9.80
 
 
 KDiff3 is a program that
@@ -42,12 +42,12 @@
 
 
 Requirements & Installation:
-   Version 0.9.70 provides special support for KDE3, but it can also be
+   Version 0.9.80 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.70.tar.gz
+      - kdiff3-0.9.80.tar.gz
 
    For building the KDE3-version
       - KDE>=3.1 and QT>=3.1-libraries.
@@ -64,7 +64,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.70 and type
+   - cd into the directory kdiff3-0.9.80 and type
    - ./configure --prefix=/opt/kde3           (your KDE3 directory here)
    - (make clean)                    (Required if you already compiled once.)
    - make                            (Run compilation)
@@ -93,7 +93,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.70/src and type
+   - cd into the directory kdiff3-0.9.80/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)
@@ -110,7 +110,7 @@
         set QTDIR=your_path_to_qt  (e.g. c:\qt)
    - Make sure your VC6 environment variables are set. Run VCVARS32.BAT.
      (Typically located in "c:\programs\Microsoft Visual Studio\VC98\bin")
-   - cd into the directory kdiff3-0.9.70\src and type
+   - cd into the directory kdiff3-0.9.80\src and type
    - nmake /f Makefile.win_qt230
    - For execution the Qt-DLL must be in the path or in the same directory.
  For newer versions of Qt, use qmake and kdiff3.pro to generate
--- a/kdiff3/README_WIN.txt	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/README_WIN.txt	Tue Dec 09 20:29:43 2003 +0000
@@ -3,7 +3,7 @@
 
 Author: Joachim Eibl  (joachim.eibl@gmx.de)
 Copyright: (C) 2002-2003 by Joachim Eibl
-KDiff3-Version: 0.9.71
+KDiff3-Version: 0.9.80
 Homepage: http://kdiff3.sourceforge.net
 
 KDiff3 is a program that
--- a/kdiff3/TODO	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/TODO	Tue Dec 09 20:29:43 2003 +0000
@@ -6,6 +6,4 @@
 - Automatic line wrap in the difference windows
 - Printing of the diff-windows (requires automatic line wrap)
 - Undo function in the merge-editor.
-- Diff should allow to treat C/C++-comments as white space.
-- A inserted or removed linefeed should be detected and treated like white space.
-
+- More viewing options for directory widget.
--- a/kdiff3/doc/en/index.docbook	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/doc/en/index.docbook	Tue Dec 09 20:29:43 2003 +0000
@@ -45,8 +45,8 @@
 (V.MM.LL), it could be used by automation scripts.
 Do NOT change these in the translation. -->
 
-<date>2003-09-15</date>
-<releaseinfo>0.9.70</releaseinfo>
+<date>2003-12-07</date>
+<releaseinfo>0.9.80</releaseinfo>
 
 
 <abstract>
@@ -59,10 +59,10 @@
 <listitem><para>provides an automatic merge-facility,</para></listitem>
 <listitem><para>has an editor for comfortable solving of merge-conflicts,</para></listitem>
 <listitem><para>provides networktransparency via KIO,</para></listitem>
-<listitem><para>and is very colorful (by default) :-)</para></listitem>
+<listitem><para>has options to highlight or hide changes in white-space or comments.</para></listitem>
 </itemizedlist>
 </para><para>
-   This document describes KDiff3-version 0.9.70.
+   This document describes KDiff3-version 0.9.80.
 </para>
 </abstract>
 
@@ -89,6 +89,8 @@
 <keyword>kio</keyword>
 <keyword>networktransparent</keyword>
 <keyword>editor</keyword>
+<keyword>white space</keyword>
+<keyword>comments</keyword>
 </keywordset>
 
 </bookinfo>
@@ -217,6 +219,7 @@
    <listitem><para> Show the line numbers for each line. </para></listitem>
    <listitem><para> Paste clipboard or drag text into a diff input window.</para></listitem>
    <listitem><para> Networktransparency via KIO.</para></listitem>
+   <listitem><para> Can be used as diff-viewer in KDevelop 3.</para></listitem>
    <listitem><para> ...</para></listitem>
 </itemizedlist>
 </sect2>
@@ -445,12 +448,20 @@
    copy and   paste some text containing such a line. But still be careful to
    do so.
 </para><para>
-   The "Merge" menu contains some actions that let you select "A", "B" or
-   "C" everywhere. When you select "Automatically solve simple conflicts" then
-   KDiff3 restarts the merge and solves as many conflicts as it can. "Set deltas
-   to conflicts" does the opposite: Even simple conflicts have to be solved
-   manually then. For all these actions the manual selections that happened
-   before are lost. (KDiff3 will tell you so, before proceeding.)
+   The normal merge will start by solving simple conflicts automatically.
+   But the "Merge"-menu provides some actions for other common needs.
+   If you have to select the same source for most conflicts, then you can
+   choose "A", "B" or "C" everywhere, or only for the remaining unsolved
+   conflicts, or for unsolved whitespace conflicts. If you want to decide every
+   single delta yourself, you can "Set deltas to conflicts". Or if you want to
+   return to the automatic choices of KDiff3 then select
+   "Automatically solve simple conflicts". KDiff3 then restarts the merge.
+   For actions that change your previous modifications KDiff3 will ask for your
+   confirmation before proceeding.
+</para><para>
+   Note: When choosing either source for unsolved whitespace conflicts and
+   the options "Ignore Numbers" or "Ignore C/C++ Comments" are used then changes in
+   numbers or comments will be treated like whitespace too.
 </para>
 </sect1>
 
@@ -592,6 +603,8 @@
       of the previous  line is used for the new line. </para></listitem></varlistentry>
    <varlistentry><term><emphasis>   Auto copy selection:</emphasis></term><listitem><para> Every selection is immediately copied
       to the clipboard   when active and you needn't explicitely copy it. </para></listitem></varlistentry>
+   <varlistentry><term><emphasis>   Use locale encoding:</emphasis></term><listitem><para> For displaying foreign characters.
+      Try changing this if some characters of your language aren't displayed correctly. </para></listitem></varlistentry>
 </variablelist>
 </sect2>
 
@@ -604,10 +617,6 @@
 </para>
 
 <variablelist>
-   <varlistentry><term><emphasis>Ignore white space:</emphasis></term><listitem><para> Default is on. White space will be
-      ignored  in the first  part of the analysis in which the line matching is
-      done. In  the result the  white space differences will be shown nevertheless.
-   </para></listitem></varlistentry>
    <varlistentry><term><emphasis>Preserve Carriage Return:</emphasis></term><listitem><para> Some editors (on some systems) save
       carriage return '\r' and linefeed '\n'-characters at the end of line, while
       others will only save the linefeed '\n'. Usually KDiff3 ignores the carriage
@@ -620,6 +629,9 @@
       done. In the result the differences will be shown nevertheless, but they are treated
       as white space.
    </para></listitem></varlistentry>
+   <varlistentry><term><emphasis>Ignore C/C++ comments:</emphasis></term><listitem><para> Default is off.
+      Changes in comments will be treated like changes in white space.
+   </para></listitem></varlistentry>
    <varlistentry><term><emphasis>Convert to Upper Case:</emphasis></term><listitem><para>  Default is off. Converts the input to upper case
       while reading. Hence the comparison is not case sensitive. Take care during merging
       because the case information will be lost in the merge-result too.
@@ -639,28 +651,21 @@
       You can write your own preprocessor that fulfills your specific needs.
       Each input line must have a corresponding output line.
    </para></listitem></varlistentry>
-   <varlistentry><term><emphasis>Use external diff:</emphasis></term><listitem><para> If you have an external diff-tool (e.g. GNU-diff)
-      you can use it for the line matching phase. For some complicated files this
-      might be better than the internal algorithm of KDiff3.
-   </para></listitem></varlistentry>
-   <varlistentry><term><emphasis>Try Hard:</emphasis></term><listitem><para> Passes the "--minimal"-option to the external diff
-      tool, which then will try hard to find an even smaller delta. This will probably
+   <varlistentry><term><emphasis>Try Hard:</emphasis></term><listitem><para>
+      Try hard to find an even smaller delta. (Default is on.) This will probably
       be effective for complicated and big files. And slow for very big files.
    </para></listitem></varlistentry>
-   <varlistentry><term><emphasis>Ignore trivial matches:</emphasis></term><listitem><para> Default is on. When trivial lines
-      match after an  difference, this will be ignored and the search for a nontrivial
-      matching  line continues. This improves the results for inputs with empty
-      lines and  lines containing only a open or close-brace character, which is
-      often the  case for C/C++-programs.
-   </para></listitem></varlistentry>
-   <varlistentry><term><emphasis>Max search length:</emphasis></term><listitem><para> Searching for a match is aborted after this
-      number of lines. The diff might fail for small values but take too long
-      for  big values. Default is 1000.
-   </para></listitem></varlistentry>
    <varlistentry><term><emphasis>Auto Advance Delay (ms):</emphasis></term><listitem><para> When in auto-advance-mode this setting specifies
       how long to show the result of the selection before jumping to the next unsolved
       conflict.
    </para></listitem></varlistentry>
+   <varlistentry><term><emphasis>White space 2/3-file merge default:</emphasis></term><listitem><para>
+      Automatically solve all white-space conflict by choosing the specified file.
+      (Default is manual choice.) Useful if white-space really isn't important in many files.
+      If you need this only occasionally better use "Choose A/B/C For All Unsolved Whitespace Conflicts"
+      in the merge menu. Note that if you enable either "Ignore numbers" or "Ignore C/C++ comments"
+      then this auto-choice also applies for conflicts in numbers or comments.
+   </para></listitem></varlistentry>
 </variablelist>
 
 </sect2>
@@ -689,6 +694,10 @@
      shown for the input files.</para></listitem></varlistentry>
   <varlistentry><term><emphasis>Show space and tabulator characters for differences:</emphasis></term><listitem><para> Sometimes
      the visible spaces and tabs are disturbing. You can turn this off.</para></listitem></varlistentry>
+  <varlistentry><term><emphasis>Show white space:</emphasis></term><listitem><para> Turn this off to suppress
+      any highlighting of white-space-only changes in the text or overview-columns.
+      (Note that this also applies to changes in numbers or comments if the options "Ignore numbers"
+      or "Ignore C/C++ comments" are active.)</para></listitem></varlistentry>
   <varlistentry><term><emphasis>Show Window A/B/C:</emphasis></term><listitem><para> Sometimes you want to use the space on
       the screen better for long lines. Hide the windows that are not important.
       (In the Windows-menu.)</para></listitem></varlistentry>
@@ -696,8 +705,9 @@
       Switch between diff windows shown next to each other (A left of B left of C) or above
       each other (A above B above C). This should also help for long lines. (In the Windows-menu.)
       </para></listitem></varlistentry>
-  <varlistentry><term><emphasis>Start a merge quickly:</emphasis></term><listitem><para> Sometimes you are viewing the deltas
-      and decide to merge. <inlinemediaobject><imageobject><imagedata fileref="merge_current.png" format="PNG"/></imageobject></inlinemediaobject>
+  <varlistentry><term><emphasis>Start a merge quickly:</emphasis></term><listitem><para>
+      Sometimes you are viewing the deltas and decide to merge.
+      <inlinemediaobject><imageobject><imagedata fileref="merge_current.png" format="PNG"/></imageobject></inlinemediaobject>
       "Merge current file" in the Directory-menu also works if you only compare
       two files. A single click starts the merge and uses the filename of the last
       input-file as the default output filename. (When this is used to restart
@@ -750,7 +760,8 @@
                          take  place, without actually doing them,</para></listitem>
      <listitem><para>... lets you really do the merge, and lets you interact whenever
                          manual interaction is needed,</para></listitem>
-     <listitem><para>... lets you continue the merge after manual interaction with key F5,</para></listitem>
+     <listitem><para>... lets you run the selected operation for all items (key F7) or the selected item (key F6),</para></listitem>
+     <listitem><para>... lets you continue the merge after manual interaction with key F7,</para></listitem>
      <listitem><para>... optionally creates backups, with the ".orig" extension,</para></listitem>
      <listitem><para>...</para></listitem>
 </itemizedlist>
@@ -786,7 +797,7 @@
 
 <para>
    Note that only the comparison starts automatically, not the merge. For this you first must
-   select a menu entry or the key F5. (More details later.)
+   select a menu entry or the key F7. (More details later.)
 </para>
 </sect2>
 </sect1>
@@ -874,12 +885,14 @@
    After comparing the directories KDiff3 also evaluates a proposal for a
    merge  operation. This is shown in the "Operation" column. You can modify
    the operation  by clicking on the operation you want to change. A small menu
-   will popup and allows you to select an operation for that item. This operation
-   will be executed during the merge. It depends on the item and on the merge-mode
-   you are in, what operations are available. The merge-mode is one of
+   will popup and allows you to select an operation for that item. (You can also
+   select the most needed operations via keyboard.
+   Ctrl+1/2/3/4/Del will select A/B/C/Merge/Delete respectively if available.)
+   This operation will be executed during the merge. It depends on the item and
+   on the merge-mode you are in, what operations are available. The merge-mode is one of
 </para>
 <itemizedlist>
-     <listitem><para>Three directory-merge (A is treated as older base of both).</para></listitem>
+     <listitem><para>Three directory-merge ("A" is treated as older base of both).</para></listitem>
      <listitem><para>Two directory-merge.</para></listitem>
      <listitem><para>Two directory-sync-mode (activate via option "Synchronize Directories").</para></listitem>
 </itemizedlist>
@@ -954,6 +967,7 @@
 
 <sect1 id="dothemerge"><title>Doing A Merge</title>
 <para>
+   You can either merge the currently selected item (file or directory), or all items.
    When you have made all your operation choices (in all subdirectories too)
    then you can start the merge.
 </para><para>
@@ -975,19 +989,21 @@
                      in the tree, and hence also not in the destination.</para></listitem>
 </itemizedlist>
 <para>
-   (In the current version, you must do a rescan yourself, after changing
-   options affecting the directory scan.)
+   (In the current version, you must do a rescan via menu "Directory"->"Rescan"
+   yourself, after changing options affecting the directory scan.)
 </para><para>
    If you are satisfied so far, the rest is easy.
 </para><para>
-   In the "Directory"-menu select "Start/Continue directory merge" or press
-   F5 (which is the shortcut).
+   To merge all items: Select "Start/Continue directory merge" in the "Directory"-menu
+   or press F7 (which is the shortcut).
+   To merge only the current item: Select "Run Operation For Current Item"
+   or press F6.
 </para><para>
    If  due to conflicting filetypes still some items with invalid operations
    exist, then a messagebox will appear and these items will be pointed out,
    so you can select a valid operation for the item.
 </para><para>
-   Otherwise a dialog will appear giving you the options "Do it", "Simulate
+   If you merge all items a dialog will appear giving you the options "Do it", "Simulate
    it" and "Cancel".
 </para>
 <itemizedlist>
@@ -1001,18 +1017,24 @@
    (<link linkend="dirmergebigscreenshot">see the big screenshot</link>).
 </para><para>
    When you have finished with a file, again select "Start/Continue directory
-   merge" or the key F5. If you haven't saved yet, a dialog will ask you to
+   merge" or the key F7. If you haven't saved yet, a dialog will ask you to
    do so. Then KDiff3 will continue with the next item.
 </para><para>
    When KDiff3 encounters an error, it will tell you so and will show the
-   verbose-status-information.  At the bottom of this list, there will be some
-   error messages which should  help you to understand the cause of the problem.
-   When you continue merging (F5 key) KDiff3 will give you the choice to retry
-   or skip the item that caused  the problem. This means that before continuing
-   you can choose another operation  or solve the problem by other means.
+   verbose-status-information. At the bottom of this list, there will be some
+   error messages which should help you to understand the cause of the problem.
+   When you continue merging (F7 key) KDiff3 will give you the choice to retry
+   or skip the item that caused the problem. This means that before continuing
+   you can choose another operation or solve the problem by other means.
 </para><para>
    When the merge is complete, then KDiff3 will inform you via a message
    box.
+</para><para>
+   If some items were merged individually then KDiff3 remembers this (while this
+   merge-session goes on), and doesn't merge them again when later the merge for
+   all items is run. Even when the merge was skipped or nothing was saved these
+   items count as completed. Only when you change the merge operation the item
+   will be merged again.
 </para>
 </sect1>
 
@@ -1062,6 +1084,11 @@
          over a slow network, it might be faster to compare the modification dates
          and file length alone. But this speed improvement comes with the price of
          a little uncertainty. Use this option with care. Default is off.</para></listitem></varlistentry>
+   <varlistentry><term><emphasis>Trust the size:</emphasis></term><listitem><para>
+         Similar to trusting the modification date. No real comparison happens. Two
+         files are considered equal if their file-sizes are equal. This is useful
+         when the file-copy operation didn't preserve the modification date.
+         Use this option with care. Default is off.</para></listitem></varlistentry>
    <varlistentry><term><emphasis>Synchronize Directories:</emphasis></term><listitem><para> Activates "Sync-Mode" when two directories
          are compared and no explicit destination directory was specified. In this
          mode the proposed operations will be chosen so that both source directories
@@ -1152,7 +1179,8 @@
 </para>
 <itemizedlist>
 <listitem><para>
-   A path can be relative and can contain "." or "..". This is not possible for URLs which are always absolute.
+   A path can be relative and can contain "." or "..". This is not possible for URLs
+   which are always absolute.
 </para></listitem><listitem><para>
    Special characters must be written with "escaping". ("#"->"%23", space->"%20", etc.)
    E.g. A file with the name "/#foo#" would have the URL "file:/%23foo%23".
@@ -1174,13 +1202,15 @@
 <listitem><para>
    Sometimes there is no support for links.
 </para></listitem><listitem><para>
-   Or there is no way to distinguish if a link points to a file or a directory; always assuming a file. (ftp:, sftp:).
+   Or there is no way to distinguish if a link points to a file or a directory; always
+   assuming a file. (ftp:, sftp:).
 </para></listitem><listitem><para>
    Can't always determine the filesize.
 </para></listitem><listitem><para>
    Limited support for permissions.
 </para></listitem><listitem><para>
-   No possibility to modify permissions or modification time, so permissions or time of a copy will differ from the original.
+   No possibility to modify permissions or modification time, so permissions or time
+   of a copy will differ from the original. (See the option "Trust the size".)
    (Only possible for local files.)
 </para></listitem>
 </itemizedlist>
--- a/kdiff3/src/Makefile.am	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/Makefile.am	Tue Dec 09 20:29:43 2003 +0000
@@ -5,7 +5,7 @@
 # these are the headers for your project
 noinst_HEADERS = kdiff3_part.h kdiff3_shell.h                       \
                  kdiff3.h common.h  diff.h  directorymergewindow.h  \
-                 merger.h optiondialog.h fileaccess.h
+                 merger.h optiondialog.h fileaccess.h version.h
 
 # let automoc handle all of the meta source files (moc)
 METASOURCES = AUTO
@@ -44,7 +44,8 @@
 # the Part's source, library search path, and link libraries
 libkdiff3part_la_SOURCES = kdiff3_part.cpp kdiff3.cpp directorymergewindow.cpp \
                            merger.cpp pdiff.cpp difftextwindow.cpp diff.cpp \
-                           optiondialog.cpp mergeresultwindow.cpp fileaccess.cpp
+                           optiondialog.cpp mergeresultwindow.cpp fileaccess.cpp \
+                           gnudiff_analyze.cpp gnudiff_io.cpp gnudiff_xmalloc.cpp
 libkdiff3part_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
 libkdiff3part_la_LIBADD  = $(LIB_KPARTS) $(LIB_KFILE)
 
--- a/kdiff3/src/Makefile.qt	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/Makefile.qt	Tue Dec 09 20:29:43 2003 +0000
@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building: kdiff3
-# Generated by qmake (1.05a) (Qt 3.1.2-snapshot-20030618) on: Thu Oct  2 22:13:20 2003
+# Generated by qmake (1.06c) (Qt 3.2.1) on: Mon Dec  8 20:06:47 2003
 # Project:  kdiff3.pro
 # Template: app
 # Command: $(QMAKE) -o Makefile kdiff3.pro
@@ -12,8 +12,8 @@
 CXX      = g++
 LEX      = flex
 YACC     = yacc
-CFLAGS   = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT
-CXXFLAGS = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT
+CFLAGS   = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT
+CXXFLAGS = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT
 LEXFLAGS = 
 YACCFLAGS= -d
 INCPATH  = -I$(QTDIR)/mkspecs/default -I. -Ikreplacements -I/usr/include -I$(QTDIR)/include
@@ -28,8 +28,8 @@
 TAR      = tar -cf
 GZIP     = gzip -9f
 COPY     = cp -f
-COPY_FILE= $(COPY) -p
-COPY_DIR = $(COPY) -pR
+COPY_FILE= $(COPY)
+COPY_DIR = $(COPY) -r
 DEL_FILE = rm -f
 SYMLINK  = ln -sf
 DEL_DIR  = rmdir
@@ -43,7 +43,8 @@
 
 ####### Files
 
-HEADERS = diff.h \
+HEADERS = version.h \
+		diff.h \
 		kdiff3.h \
 		merger.h \
 		optiondialog.h \
@@ -64,7 +65,10 @@
 		fileaccess.cpp \
 		kdiff3_shell.cpp \
 		kdiff3_part.cpp \
-		kreplacements/kreplacements.cpp
+		kreplacements/kreplacements.cpp \
+		gnudiff_analyze.cpp \
+		gnudiff_io.cpp \
+		gnudiff_xmalloc.cpp
 OBJECTS = diff.o \
 		difftextwindow.o \
 		kdiff3.o \
@@ -77,7 +81,10 @@
 		fileaccess.o \
 		kdiff3_shell.o \
 		kdiff3_part.o \
-		kreplacements.o
+		kreplacements.o \
+		gnudiff_analyze.o \
+		gnudiff_io.o \
+		gnudiff_xmalloc.o
 FORMS = 
 UICDECLS = 
 UICIMPLS = 
@@ -105,7 +112,7 @@
 first: all
 ####### Implicit rules
 
-.SUFFIXES: .c .cpp .cc .cxx .C
+.SUFFIXES: .c .o .cpp .cc .cxx .C
 
 .cpp.o:
 	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
@@ -126,10 +133,11 @@
 
 all: $(TARGET)
 
-$(TARGET):  $(UICDECLS) $(OBJECTS) $(OBJMOC) 
-	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS)
+$(TARGET):  $(UICDECLS) $(OBJECTS) $(OBJMOC)  
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(LIBS) $(OBJCOMP)
 
 mocables: $(SRCMOC)
+uicables: $(UICDECLS) $(UICIMPLS)
 
 $(MOC): 
 	( cd $(QTDIR)/src/moc ; $(MAKE) )
@@ -146,7 +154,7 @@
 yaccclean:
 lexclean:
 clean: mocclean
-	-$(DEL_FILE) $(OBJECTS) 
+	-$(DEL_FILE) $(OBJECTS)
 	-$(DEL_FILE) *~ core *.core
 
 
@@ -191,10 +199,10 @@
 		xpm/autoadvance.xpm \
 		xpm/showwhitespace.xpm \
 		xpm/showlinenumbers.xpm \
-		xpm/startmerge.xpm \
 		common.h
 
-main.o: main.cpp kdiff3_shell.h
+main.o: main.cpp kdiff3_shell.h \
+		version.h
 
 merger.o: merger.cpp merger.h \
 		diff.h \
@@ -216,10 +224,13 @@
 		kdiff3.h \
 		optiondialog.h \
 		fileaccess.h \
-		common.h
+		gnudiff_diff.h \
+		common.h \
+		gnudiff_system.h
 
 directorymergewindow.o: directorymergewindow.cpp directorymergewindow.h \
 		optiondialog.h \
+		xpm/startmerge.xpm \
 		common.h \
 		fileaccess.h
 
@@ -243,6 +254,16 @@
 		kreplacements/kreplacements.moc
 	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o kreplacements.o kreplacements/kreplacements.cpp
 
+gnudiff_analyze.o: gnudiff_analyze.cpp gnudiff_diff.h \
+		gnudiff_xalloc.h \
+		gnudiff_system.h
+
+gnudiff_io.o: gnudiff_io.cpp gnudiff_diff.h \
+		gnudiff_xalloc.h \
+		gnudiff_system.h
+
+gnudiff_xmalloc.o: gnudiff_xmalloc.cpp gnudiff_xalloc.h
+
 moc_diff.o: moc_diff.cpp diff.h common.h \
 		fileaccess.h
 
@@ -302,7 +323,6 @@
 install_target: 
 	@$(CHK_DIR_EXISTS) "$(INSTALL_ROOT)/usr/local/bin/" || $(MKDIR) "$(INSTALL_ROOT)/usr/local/bin/"
 	-$(COPY) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
-	-strip "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
 
 uninstall_target: 
 	-$(DEL_FILE) "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
--- a/kdiff3/src/Makefile.win_qt230	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/Makefile.win_qt230	Tue Dec 09 20:29:43 2003 +0000
@@ -1,6 +1,6 @@
 #############################################################################
 # Makefile for building kdiff3
-# Generated by tmake at 22:40, 2003/10/01
+# Generated by tmake at 12:39, 2003/12/06
 #     Project: kdiff3_tmake
 #    Template: app
 #############################################################################
@@ -43,7 +43,10 @@
 		fileaccess.cpp \
 		kdiff3_shell.cpp \
 		kdiff3_part.cpp \
-		kreplacements\kreplacements.cpp
+		kreplacements\kreplacements.cpp \
+		gnudiff_analyze.cpp \
+		gnudiff_io.cpp \
+		gnudiff_xmalloc.cpp
 OBJECTS =	diff.obj \
 		difftextwindow.obj \
 		kdiff3.obj \
@@ -56,7 +59,10 @@
 		fileaccess.obj \
 		kdiff3_shell.obj \
 		kdiff3_part.obj \
-		kreplacements\kreplacements.obj
+		kreplacements\kreplacements.obj \
+		gnudiff_analyze.obj \
+		gnudiff_io.obj \
+		gnudiff_xmalloc.obj
 INTERFACES =	
 UICDECLS =	
 UICIMPLS =	
@@ -128,6 +134,9 @@
 	-del kdiff3_shell.obj
 	-del kdiff3_part.obj
 	-del kreplacements\kreplacements.obj
+	-del gnudiff_analyze.obj
+	-del gnudiff_io.obj
+	-del gnudiff_xmalloc.obj
 	-del moc_diff.cpp
 	-del moc_kdiff3.cpp
 	-del moc_optiondialog.cpp
@@ -182,11 +191,11 @@
 		xpm\iconC.xpm \
 		xpm\autoadvance.xpm \
 		xpm\showwhitespace.xpm \
-		xpm\showlinenumbers.xpm \
-		xpm\startmerge.xpm
+		xpm\showlinenumbers.xpm
 
 main.obj: main.cpp \
-		kdiff3_shell.h
+		kdiff3_shell.h \
+		version.h
 
 merger.obj: merger.cpp \
 		merger.h \
@@ -212,7 +221,9 @@
 		fileaccess.h \
 		directorymergewindow.h \
 		kdiff3.h \
-		optiondialog.h
+		optiondialog.h \
+		gnudiff_diff.h \
+		gnudiff_system.h
 
 directorymergewindow.obj: directorymergewindow.cpp \
 		directorymergewindow.h \
@@ -225,7 +236,8 @@
 		xpm\not_there.xpm \
 		xpm\link_arrow.xpm \
 		xpm\file.xpm \
-		xpm\folder.xpm
+		xpm\folder.xpm \
+		xpm\startmerge.xpm
 
 fileaccess.obj: fileaccess.cpp \
 		fileaccess.h \
@@ -251,6 +263,19 @@
 		kreplacements\..\xpm\fileopen.xpm \
 		kreplacements\..\xpm\filesave.xpm
 
+gnudiff_analyze.obj: gnudiff_analyze.cpp \
+		gnudiff_diff.h \
+		gnudiff_system.h \
+		gnudiff_xalloc.h
+
+gnudiff_io.obj: gnudiff_io.cpp \
+		gnudiff_diff.h \
+		gnudiff_system.h \
+		gnudiff_xalloc.h
+
+gnudiff_xmalloc.obj: gnudiff_xmalloc.cpp \
+		gnudiff_xalloc.h
+
 moc_diff.obj: moc_diff.cpp \
 		diff.h \
 		common.h \
--- a/kdiff3/src/common.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/common.h	Tue Dec 09 20:29:43 2003 +0000
@@ -15,13 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #ifndef _COMMON_H
 #define _COMMON_H
 
--- a/kdiff3/src/diff.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/diff.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,19 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.3  2003/10/15 19:54:41  joachim99
- * Handling of pFirstNonWhiteChar corrected.
- *
- * Revision 1.2  2003/10/14 20:49:56  joachim99
- * SourceData::preprocess(): Fix for several subsequent CR-characters.
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #include <stdio.h>
 #include <iostream>
 
@@ -226,16 +213,160 @@
    m_vSize = lines;
 }
 
-// read and prepocess file for line matching input data
-void SourceData::readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase )
+
+// Must not be entered, when within a comment.
+// Returns either at a newline-character p[i]=='\n' or when i==size.
+// A line that contains only comments is still "white".
+// Comments in white lines must remain, while comments in
+// non-white lines are overwritten with spaces.
+static void checkLineForComments(
+   char* p,   // pointer to start of buffer
+   int& i,    // index of current position (in, out)
+   int size,  // size of buffer
+   bool& bWhite,          // false if this line contains nonwhite characters (in, out)
+   bool& bCommentInLine,  // true if any comment is within this line (in, out)
+   bool& bStartsOpenComment  // true if the line ends within an comment (out)
+   )
 {
-   if ( ppCmd.isEmpty() || pOrigSource->m_bPreserve )
+   bStartsOpenComment = false;
+   for(; i<size; ++i )
+   {
+      // A single apostroph ' has prio over a double apostroph " (e.g. '"')
+      // (if not in a string)
+      if ( p[i]=='\'' )
+      {
+         bWhite = false;
+         ++i;
+         for( ; i<size && p[i]!='\'' && p[i]!='\n'; ++i)
+            ;
+         if (p[i]=='\'') ++i;
+      }
+
+      // Strings have priority over comments: e.g. "/* Not a comment, but a string. */"
+      else if ( p[i]=='"' )
+      {
+         bWhite = false;
+         ++i;
+         for( ; i<size && !(p[i]=='"' && p[i-1]!='\\') && p[i]!='\n'; ++i)
+            ;
+         if (p[i]=='"') ++i;
+      }
+
+      // C++-comment
+      else if ( p[i]=='/' && i+1<size && p[i+1] =='/' )
+      {
+         int commentStart = i;
+         bCommentInLine = true;
+         i+=2;
+         for( ; i<size && p[i]!='\n'; ++i)
+            ;
+         if ( !bWhite )
+         {
+            memset( &p[commentStart], ' ', i-commentStart );
+         }
+         return;
+      }
+
+      // C-comment
+      else if ( p[i]=='/' && i+1<size && p[i+1] =='*' )
+      {
+         int commentStart = i;
+         bCommentInLine = true;
+         i+=2;
+         for( ; i<size && p[i]!='\n'; ++i)
+         {
+            if ( i+1<size && p[i]=='*' && p[i+1]=='/')  // end of the comment
+            {
+               i+=2;
+
+               // More comments in the line?
+               checkLineForComments( p, i, size, bWhite, bCommentInLine, bStartsOpenComment );
+               if ( !bWhite )
+               {
+                  memset( &p[commentStart], ' ', i-commentStart );
+               }
+               return;
+            }
+         }
+         bStartsOpenComment = true;
+         return;
+      }
+
+
+      if (p[i]=='\n' || i>=size )
+      {
+         return;
+      }
+      else if ( !isspace(p[i]) )
+      {
+         bWhite = false;
+      }
+   }
+}
+
+// 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 )
+{
+   int line=0;
+   char* p = (char*)m_pBuf;
+   bool bWithinComment=false;
+   int size = m_size;
+   for(int i=0; i<size; ++i )
+   {
+//      std::cout << "2        " << std::string(&p[i], m_v[line].size) << std::endl;
+      bool bWhite = true;
+      bool bCommentInLine = false;
+
+      if ( bWithinComment )
+      {
+         int commentStart = i;
+         bCommentInLine = true;
+
+         for( ; i<size && p[i]!='\n'; ++i)
+         {
+            if ( i+1<size && p[i]=='*' && p[i+1]=='/')  // end of the comment
+            {
+               i+=2;
+
+               // More comments in the line?
+               checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment );
+               if ( !bWhite )
+               {
+                  memset( &p[commentStart], ' ', i-commentStart );
+               }
+               break;
+            }
+         }
+      }
+      else
+      {
+         checkLineForComments( p, i, size, bWhite, bCommentInLine, bWithinComment );
+      }
+
+      // end of line
+      assert( i>=size || p[i]=='\n');
+      pLD[line].bContainsPureComment = bCommentInLine && bWhite;
+/*      std::cout << line << " : " <<
+       ( bCommentInLine ?  "c" : " " ) <<
+       ( bWhite ? "w " : "  ") <<
+       std::string(pLD[line].pLine, pLD[line].size) << std::endl;*/
+
+      ++line;
+   }
+}
+
+// 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
    {
-      m_fileName = pOrigSource->m_fileAccess.absFilePath();
+      setFilename( pOrigSource->m_fileAccess.absFilePath() );
       readPPFile( false, ppCmd, bUpCase );
       if ( m_vSize < pOrigSource->m_vSize )
       {
@@ -243,6 +374,8 @@
          m_vSize = pOrigSource->m_vSize;
       }
    }
+   if ( bRemoveComments && m_vSize==pOrigSource->m_vSize )
+      removeComments( &pOrigSource->m_v[0] );
 }
 
 
@@ -304,37 +437,6 @@
       return;
    }
 
-   /*
-
-   FILE* f = fopen( filename, "rb" );
-   if ( f==0 )
-   {
-      std::cerr << "File open error for file: '"<< filename <<"': ";
-      perror("");
-      return;
-   }
-
-   fseek( f, 0, SEEK_END );
-
-   m_size =  ftell(f);
-
-   fseek( f, 0, SEEK_SET );
-
-   m_pBuf = pBuf = new char[m_size+100];
-   int bytesRead = fread( pBuf, 1, m_size, f );
-   if( bytesRead != m_size )
-   {
-      std::cerr << "File read error for file: '"<< filename <<"': ";
-
-      perror("");
-      fclose(f);
-      m_size = 0;
-      delete pBuf;
-      m_pBuf = 0;
-      return;
-   }
-   fclose( f );
-   */
 
    if ( bUpCase )
    {
@@ -958,7 +1060,7 @@
 */
 }
 
-void calcWhiteDiff3Lines(       
+void calcWhiteDiff3Lines(
    Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
    )
 {
@@ -966,9 +1068,9 @@
 
    for( ; i3!=d3ll.end(); ++i3 )
    {
-      i3->bWhiteLineA = ( (*i3).lineA == -1  ||  pldA[(*i3).lineA].whiteLine() );
-      i3->bWhiteLineB = ( (*i3).lineB == -1  ||  pldB[(*i3).lineB].whiteLine() );
-      i3->bWhiteLineC = ( (*i3).lineC == -1  ||  pldC[(*i3).lineC].whiteLine() );
+      i3->bWhiteLineA = ( (*i3).lineA == -1  ||  pldA[(*i3).lineA].whiteLine() || pldA[(*i3).lineA].bContainsPureComment );
+      i3->bWhiteLineB = ( (*i3).lineB == -1  ||  pldB[(*i3).lineB].whiteLine() || pldB[(*i3).lineB].bContainsPureComment );
+      i3->bWhiteLineC = ( (*i3).lineC == -1  ||  pldC[(*i3).lineC].whiteLine() || pldC[(*i3).lineC].bContainsPureComment );
    }
 }
 
@@ -995,7 +1097,7 @@
             KMessageBox::error(0, i18n(
                "Data loss error:\n"
                "If it is reproducable please contact the author.\n"
-               ), "Severe internal Error" );
+               ), i18n("Severe Internal Error") );
             assert(false);
             std::cerr << "Severe Internal Error.\n";
             ::exit(-1);
@@ -1009,24 +1111,198 @@
       KMessageBox::error(0, i18n(
          "Data loss error:\n"
          "If it is reproducable please contact the author.\n"
-         ), "Severe internal Error" );
+         ), i18n("Severe Internal Error") );
       assert(false);
       std::cerr << "Severe Internal Error.\n";
       ::exit(-1);
    }
 }
 
+inline bool equal( char c1, char c2, bool /*bStrict*/ )
+{
+   // If bStrict then white space doesn't match
+
+   //if ( bStrict &&  ( c1==' ' || c1=='\t' ) )
+   //   return false;
+
+   return c1==c2;
+}
+
+
+// My own diff-invention:
+template <class T>
+void calcDiff( const T* p1, int size1, const T* p2, int size2, DiffList& diffList, int match, int maxSearchRange )
+{
+   diffList.clear();
+
+   const T* p1start = p1;
+   const T* p2start = p2;
+   const T* p1end=p1+size1;
+   const T* p2end=p2+size2;
+   for(;;)
+   {
+      int nofEquals = 0;
+      while( p1!=p1end &&  p2!=p2end && equal(*p1, *p2, false) )
+      {
+         ++p1;
+         ++p2;
+         ++nofEquals;
+      }
+
+      bool bBestValid=false;
+      int bestI1=0;
+      int bestI2=0;
+      int i1=0;
+      int i2=0;
+      for( i1=0; ; ++i1 )
+      {
+         if ( &p1[i1]==p1end || ( bBestValid && i1>= bestI1+bestI2))
+         {
+            break;
+         }
+         for(i2=0;i2<maxSearchRange;++i2)
+         {
+            if( &p2[i2]==p2end ||  ( bBestValid && i1+i2>=bestI1+bestI2) )
+            {
+               break;
+            }
+            else if(  equal( p2[i2], p1[i1], true ) &&
+                      ( match==1 ||  abs(i1-i2)<3  || ( &p2[i2+1]==p2end  &&  &p1[i1+1]==p1end ) ||
+                         ( &p2[i2+1]!=p2end  &&  &p1[i1+1]!=p1end  && equal( p2[i2+1], p1[i1+1], false ))
+                      )
+                   )
+            {
+               if ( i1+i2 < bestI1+bestI2 || bBestValid==false )
+               {
+                  bestI1 = i1;
+                  bestI2 = i2;
+                  bBestValid = true;
+                  break;
+               }
+            }
+         }
+      }
+
+      // The match was found using the strict search. Go back if there are non-strict
+      // matches.
+      while( bestI1>=1 && bestI2>=1 && equal( p1[bestI1-1], p2[bestI2-1], false ) )
+      {
+         --bestI1;
+         --bestI2;
+      }
+
+
+      bool bEndReached = false;
+      if (bBestValid)
+      {
+         // continue somehow
+         Diff d(nofEquals, bestI1, bestI2);
+         diffList.push_back( d );
+
+         p1 += bestI1;
+         p2 += bestI2;
+      }
+      else
+      {
+         // Nothing else to match.
+         Diff d(nofEquals, p1end-p1, p2end-p2);
+         diffList.push_back( d );
+
+         bEndReached = true; //break;
+      }
+
+      // Sometimes the algorithm that chooses the first match unfortunately chooses
+      // a match where later actually equal parts don't match anymore.
+      // A different match could be achieved, if we start at the end.
+      // Do it, if it would be a better match.
+      int nofUnmatched = 0;
+      const T* pu1 = p1-1;
+      const T* pu2 = p2-1;
+      while ( pu1>=p1start && pu2>=p2start && equal( *pu1, *pu2, false ) )
+      {
+         ++nofUnmatched;
+         --pu1;
+         --pu2;
+      }
+
+      Diff d = diffList.back();
+      if ( nofUnmatched > 0 )
+      {
+         // We want to go backwards the nofUnmatched elements and redo
+         // the matching
+         d = diffList.back();
+         Diff origBack = d;
+         diffList.pop_back();
+
+         while (  nofUnmatched > 0 )
+         {
+            if ( d.diff1 > 0  &&  d.diff2 > 0 )
+            {
+               --d.diff1;
+               --d.diff2;
+               --nofUnmatched;
+            }
+            else if ( d.nofEquals > 0 )
+            {
+               --d.nofEquals;
+               --nofUnmatched;
+            }
+
+            if ( d.nofEquals==0 && (d.diff1==0 || d.diff2==0) &&  nofUnmatched>0 )
+            {
+               if ( diffList.empty() )
+                  break;
+               d.nofEquals += diffList.back().nofEquals;
+               d.diff1 += diffList.back().diff1;
+               d.diff2 += diffList.back().diff2;
+               diffList.pop_back();
+               bEndReached = false;
+            }
+         }
+
+         if ( bEndReached )
+            diffList.push_back( origBack );
+         else
+         {
+
+            p1 = pu1 + 1 + nofUnmatched;
+            p2 = pu2 + 1 + nofUnmatched;
+            diffList.push_back( d );
+         }
+      }
+      if ( bEndReached )
+         break;
+   }
+
+#ifndef NDEBUG
+   // Verify difflist
+   {
+      int l1=0;
+      int l2=0;
+      DiffList::iterator i;
+      for( i = diffList.begin(); i!=diffList.end(); ++i )
+      {
+         l1+= i->nofEquals + i->diff1;
+         l2+= i->nofEquals + i->diff2;
+      }
+
+      //if( l1!=p1-p1start || l2!=p2-p2start )
+      if( l1!=size1 || l2!=size2 )
+         assert( false );
+   }
+#endif
+}
 
 void fineDiff(
    Diff3LineList& diff3LineList,
    int selector,
    LineData* v1,
    LineData* v2,
-   int maxSearchLength,
    bool& bTextsTotalEqual
    )
 {
    // Finetuning: Diff each line with deltas
+   int maxSearchLength=500;
    Diff3LineList::iterator i;
    int k1=0;
    int k2=0;
@@ -1066,6 +1342,14 @@
             else if (selector==3){ delete (*i).pFineCA; (*i).pFineCA = pDiffList; }
             else assert(false);
          }
+
+         if ( (v1[k1].bContainsPureComment || v1[k1].whiteLine()) && (v2[k2].bContainsPureComment || v2[k2].whiteLine()))
+         {
+            if      (selector==1){ i->bAEqB = true; }
+            else if (selector==2){ i->bBEqC = true; }
+            else if (selector==3){ i->bAEqC = true; }
+            else assert(false);
+         }
       }
       ++listIdx;
       g_pProgressDialog->setSubCurrent(double(listIdx)/listSize);
--- a/kdiff3/src/diff.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/diff.h	Tue Dec 09 20:29:43 2003 +0000
@@ -15,13 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #ifndef DIFF_H
 #define DIFF_H
 
@@ -108,7 +101,7 @@
    bool bTextAEqB;
 };
 
-void calcDiff3LineListUsingAB(       
+void calcDiff3LineListUsingAB(
    const DiffList* pDiffListAB,
    Diff3LineList& d3ll
    );
@@ -129,10 +122,11 @@
    const char* pFirstNonWhiteChar;
    int size;
 
-   LineData(){ pLine=0; size=0; occurances=0; }
+   LineData(){ pLine=0; size=0; occurances=0; bContainsPureComment=false; }
    int width();  // Calcs width considering tabs.
    int occurances;
    bool whiteLine(){ return pFirstNonWhiteChar-pLine == size; }
+   bool bContainsPureComment;
 };
 
 void prepareOccurances( LineData* p, int size );
@@ -150,9 +144,10 @@
    bool m_bPreserve;
    void reset();
    void readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase );
-   void readLMPPFile( SourceData* pOrigSource, 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 );
    void setFilename(const QString& filename);
    void setFileAccess( const FileAccess& fa );
@@ -218,6 +213,8 @@
 
 class OptionDialog;
 
+QString decodeString( const char*s , OptionDialog* );
+
 class DiffTextWindow : public QWidget
 {
    Q_OBJECT
@@ -337,6 +334,7 @@
 
 public slots:
    void setFirstLine(int firstLine);
+   void slotRedraw();
 signals:
    void setLine(int);
 private:
@@ -376,6 +374,12 @@
 
 void mergeOneLine( const Diff3Line& d, e_MergeDetails& mergeDetails, bool& bConflict, bool& bLineRemoved, int& src, bool bTwoInputs );
 
+enum e_MergeSrcSelector
+{
+   A=1,
+   B=2,
+   C=3
+};
 
 class MergeResultWindow : public QWidget
 {
@@ -398,6 +402,7 @@
    bool saveDocument( const QString& fileName );
    int getNrOfUnsolvedConflicts();
    void choose(int selector);
+   void chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly );
 
    int getNofColumns();
    int getNofLines();
@@ -430,12 +435,6 @@
    void slotGoNextUnsolvedConflict();
    void slotGoPrevConflict();
    void slotGoNextConflict();
-   void slotChooseA();
-   void slotChooseB();
-   void slotChooseC();
-   void slotChooseAEverywhere();
-   void slotChooseBEverywhere();
-   void slotChooseCEverywhere();
    void slotAutoSolve();
    void slotUnsolve();
    void slotSetFastSelectorLine(int);
@@ -452,7 +451,7 @@
    void showPopupMenu( const QPoint& point );
 
 private:
-   void merge(bool bAutoSolve, int defaultSelector);
+   void merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly=false, bool bWhiteSpaceOnly=false );
    QCString getString( int lineIdx );
 
    OptionDialog* m_pOptionDialog;
@@ -517,12 +516,16 @@
    struct MergeLine
    {
       MergeLine()
-      { srcSelect=0; mergeDetails=eDefault; d3lLineIdx = -1; srcRangeLength=0; bConflict=false; bDelta=false;}
+      {
+         srcSelect=0; mergeDetails=eDefault; d3lLineIdx = -1; srcRangeLength=0;
+         bConflict=false; bDelta=false; bWhiteSpaceConflict=false;
+      }
       Diff3LineList::const_iterator id3l;
       e_MergeDetails mergeDetails;
       int d3lLineIdx;  // Needed to show the correct window pos.
       int srcRangeLength; // how many src-lines have this properties
       bool bConflict;
+      bool bWhiteSpaceConflict;
       bool bDelta;
       int srcSelect;
       MergeEditLineList mergeEditLineList;
@@ -596,189 +599,12 @@
    int selector,
    LineData* v1,
    LineData* v2,
-   int maxSearchLength,
    bool& bTextsTotalEqual
    );
 
 
 bool equal( const LineData& l1, const LineData& l2, bool bStrict );
 
-inline bool equal( char c1, char c2, bool /*bStrict*/ )
-{
-   // If bStrict then white space doesn't match
-
-   //if ( bStrict &&  ( c1==' ' || c1=='\t' ) )
-   //   return false;
-
-   return c1==c2;
-}
-
-
-// My own diff-invention:
-template <class T>
-void calcDiff( const T* p1, int size1, const T* p2, int size2, DiffList& diffList, int match, int maxSearchRange )
-{
-   diffList.clear();
-
-   const T* p1start = p1;
-   const T* p2start = p2;
-   const T* p1end=p1+size1;
-   const T* p2end=p2+size2;
-   for(;;)
-   {
-      int nofEquals = 0;
-      while( p1!=p1end &&  p2!=p2end && equal(*p1, *p2, false) )
-      {
-
-
-         ++p1;
-         ++p2;
-         ++nofEquals;
-      }
-
-      bool bBestValid=false;
-      int bestI1=0;
-      int bestI2=0;
-      int i1=0;
-      int i2=0;
-      for( i1=0; ; ++i1 )
-      {
-         if ( &p1[i1]==p1end || ( bBestValid && i1>= bestI1+bestI2))
-         {
-            break;
-         }
-         for(i2=0;i2<maxSearchRange;++i2)
-         {
-            if( &p2[i2]==p2end ||  ( bBestValid && i1+i2>=bestI1+bestI2) )
-            {
-               break;
-            }
-            else if(  equal( p2[i2], p1[i1], true ) &&
-                      ( match==1 ||  abs(i1-i2)<3  || ( &p2[i2+1]==p2end  &&  &p1[i1+1]==p1end ) ||
-                         ( &p2[i2+1]!=p2end  &&  &p1[i1+1]!=p1end  && equal( p2[i2+1], p1[i1+1], false ))
-                      )
-                   )
-            {
-               if ( i1+i2 < bestI1+bestI2 || bBestValid==false )
-               {
-                  bestI1 = i1;
-                  bestI2 = i2;
-                  bBestValid = true;
-                  break;
-               }
-            }
-         }
-      }
-
-      // The match was found using the strict search. Go back if there are non-strict
-      // matches.
-      while( bestI1>=1 && bestI2>=1 && equal( p1[bestI1-1], p2[bestI2-1], false ) )
-      {
-         --bestI1;
-         --bestI2;
-      }
-
-
-      bool bEndReached = false;
-      if (bBestValid)
-      {
-         // continue somehow
-         Diff d(nofEquals, bestI1, bestI2);
-         diffList.push_back( d );
-
-         p1 += bestI1;
-         p2 += bestI2;
-      }
-      else
-      {
-         // Nothing else to match.
-         Diff d(nofEquals, p1end-p1, p2end-p2);
-         diffList.push_back( d );
-
-         bEndReached = true; //break;
-      }
-
-      // Sometimes the algorithm that chooses the first match unfortunately chooses
-      // a match where later actually equal parts don't match anymore.
-      // A different match could be achieved, if we start at the end.
-      // Do it, if it would be a better match.
-      int nofUnmatched = 0;
-      const T* pu1 = p1-1;
-      const T* pu2 = p2-1;
-      while ( pu1>=p1start && pu2>=p2start && equal( *pu1, *pu2, false ) )
-      {
-         ++nofUnmatched;
-         --pu1;
-         --pu2;
-      }
-
-      Diff d = diffList.back();
-      if ( nofUnmatched > 0 )
-      {
-         // We want to go backwards the nofUnmatched elements and redo
-         // the matching
-         d = diffList.back();
-         Diff origBack = d;
-         diffList.pop_back();
-
-         while (  nofUnmatched > 0 )
-         {
-            if ( d.diff1 > 0  &&  d.diff2 > 0 )
-            {
-               --d.diff1;
-               --d.diff2;
-               --nofUnmatched;
-            }
-            else if ( d.nofEquals > 0 )
-            {
-               --d.nofEquals;
-               --nofUnmatched;
-            }
-
-            if ( d.nofEquals==0 && (d.diff1==0 || d.diff2==0) &&  nofUnmatched>0 )
-            {
-               if ( diffList.empty() )
-                  break;
-               d.nofEquals += diffList.back().nofEquals;
-               d.diff1 += diffList.back().diff1;
-               d.diff2 += diffList.back().diff2;
-               diffList.pop_back();
-               bEndReached = false;
-            }
-         }
-
-         if ( bEndReached )
-            diffList.push_back( origBack );
-         else
-         {
-
-            p1 = pu1 + 1 + nofUnmatched;
-            p2 = pu2 + 1 + nofUnmatched;
-            diffList.push_back( d );
-         }
-      }
-      if ( bEndReached )
-         break;
-   }
-
-#ifndef NDEBUG
-   // Verify difflist
-   {
-      int l1=0;
-      int l2=0;
-      DiffList::iterator i;
-      for( i = diffList.begin(); i!=diffList.end(); ++i )
-      {
-         l1+= i->nofEquals + i->diff1;
-         l2+= i->nofEquals + i->diff2;
-      }
-
-      //if( l1!=p1-p1start || l2!=p2-p2start )
-      if( l1!=size1 || l2!=size2 )
-         assert( false );
-   }
-#endif
-}
 
 
 
--- a/kdiff3/src/difftextwindow.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/difftextwindow.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,15 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/11 12:47:09  joachim99
- * Avoid QWidget::setFont() in paintEvent()
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include <iostream>
 #include "diff.h"
 #include "merger.h"
@@ -37,6 +28,7 @@
 #include <optiondialog.h>
 #include <math.h>
 #include <qdragobject.h>
+#include <klocale.h>
 
 #define leftInfoWidth (4+m_lineNumberWidth)   // Nr of information columns on left side
 
@@ -500,7 +492,7 @@
    }
 
    p.fillRect( leftInfoWidth*fontWidth, yOffset, width(), fontHeight, bgColor );
-   
+
    if (pld!=0)
    {
       // First calculate the "changed" information for each character.
@@ -548,11 +540,18 @@
             c = m_cDiffBoth;
          }
 
+         if ( c!=m_pOptionDialog->m_fgColor && whatChanged2==0 && !m_pOptionDialog->m_bShowWhiteSpace )
+         {
+            // The user doesn't want to see highlighted white space.
+            c = m_pOptionDialog->m_fgColor;
+         }
+
          QRect outRect( xOffset + fontWidth*outPos, yOffset, fontWidth*spaces, fontHeight );
          if ( m_invalidRect.intersects( outRect ) )
          {
             if( !selection.within( line, outPos ) )
             {
+
                if( c!=m_pOptionDialog->m_fgColor )
                {
                   QColor lightc = diffBgColor;
@@ -564,7 +563,7 @@
                p.setPen( c );
                if ( s[0]==' '  &&  c!=m_pOptionDialog->m_fgColor  &&  charChanged[i]!=0 )
                {
-                  if ( m_pOptionDialog->m_bShowWhiteSpace )
+                  if ( m_pOptionDialog->m_bShowWhiteSpaceCharacters && m_pOptionDialog->m_bShowWhiteSpace)
                   {
                      p.fillRect( xOffset + fontWidth*outPos, yOffset+fontAscent,
                                  fontWidth*spaces-1, fontDescent+1, c );
@@ -572,7 +571,7 @@
                }
                else
                {
-                  p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) );
+                  p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, decodeString(s,m_pOptionDialog) );
                }
                p.setFont(normalFont);
             }
@@ -583,7 +582,7 @@
                            fontWidth*(spaces), fontHeight, colorGroup().highlight() );
 
                p.setPen( colorGroup().highlightedText() );
-               p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) );
+               p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, decodeString(s,m_pOptionDialog) );
 
                selection.bSelectionContainsData = true;
             }
@@ -617,8 +616,11 @@
    }
    if ( c!=m_pOptionDialog->m_fgColor && whatChanged2==0 )//&& whatChanged==0 )
    {
-      p.setBrushOrigin(0,0);
-      p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Dense5Pattern) );
+      if ( m_pOptionDialog->m_bShowWhiteSpace )
+      {
+         p.setBrushOrigin(0,0);
+         p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Dense5Pattern) );
+      }
    }
    else
    {
@@ -782,11 +784,11 @@
       const char* winId = (   m_winIdx==1 ? (m_bTriple?"A (Base)":"A") :
                             ( m_winIdx==2 ? "B" : "C" ) );
 
-      QString s;
+      QString s = QString(" ")+ winId + " : " + m_filename + " : ";
       if ( l!=-1 )
-         s.sprintf(" %s : %s : Topline %d", winId, m_filename.ascii(), l+1 );
+         s += i18n("Topline %1").arg( l+1 );
       else
-         s.sprintf(" %s : %s: End", winId, m_filename.ascii() );
+         s += i18n("End");
 
       if (hasFocus())
       {
@@ -1021,3 +1023,20 @@
    selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos ) );
    update();
 }
+
+
+#include <qtextcodec.h>
+
+QString decodeString( const char*s , OptionDialog* pOptions )
+{
+   if ( pOptions->m_bStringEncoding )
+   {
+      QTextCodec* c = QTextCodec::codecForLocale();
+      if (c!=0)
+         return c->toUnicode( s );
+      else
+         return QString(s);
+   }
+   else
+      return QString(s);
+}
--- a/kdiff3/src/directorymergewindow.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/directorymergewindow.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,18 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.3  2003/10/15 20:14:03  joachim99
- * Fix for MergeOperation DeleteAB.
- *
- * Revision 1.2  2003/10/11 12:41:57  joachim99
- * Fix for gcc 2.95
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include "directorymergewindow.h"
 #include "optiondialog.h"
 #include <vector>
@@ -37,6 +25,7 @@
 #include <qpixmap.h>
 #include <qimage.h>
 #include <kpopupmenu.h>
+#include <kaction.h>
 #include <qregexp.h>
 #include <qmessagebox.h>
 #include <qlayout.h>
@@ -50,6 +39,7 @@
 #include <iostream>
 #include <assert.h>
 
+static bool conflictingFileTypes(MergeFileInfos& mfi);
 
 class StatusInfo : public QListView
 {
@@ -120,14 +110,14 @@
    {
       if ( fi1.isSymLink() != fi2.isSymLink() )
       {
-         status = "Mix of links and normal files.";
+         status = i18n("Mix of links and normal files.");
          return;
       }
       else if ( fi1.isSymLink() && fi2.isSymLink() )
       {
          bError = false;
          bEqual = fi1.readLink() == fi2.readLink();
-         status = "Link: ";
+         status = i18n("Link: ");
          return;
       }
    }
@@ -135,7 +125,12 @@
    if ( fi1.size()!=fi2.size() )
    {
       bEqual = false;
-      status = "Size. ";
+      status = i18n("Size. ");
+      return;
+   }
+   else if ( m_pOptions->m_bDmTrustSize )
+   {
+      bEqual = true;
       return;
    }
 
@@ -143,7 +138,7 @@
    {
       bEqual = ( fi1.lastModified() == fi2.lastModified()  &&  fi1.size()==fi2.size() );
       bError = false;
-      status = "Date&Size: ";
+      status = i18n("Date & Size: ");
       return;
    }
 
@@ -152,13 +147,13 @@
    TempRemover tr1( fileName1, fi1 );
    if ( !tr1.success() )
    {
-      status = "Creating temp copy of " + fileName1 + " failed.";
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName1);
       return;
    }
    TempRemover tr2( fileName2, fi2 );
    if ( !tr2.success() )
    {
-      status = "Creating temp copy of " + fileName2 + " failed.";
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName2);
       return;
    }
 
@@ -169,7 +164,7 @@
 
    if ( ! file1.open(IO_ReadOnly) )
    {
-      status = "Opening " + fileName1 + " failed.";
+      status = i18n("Opening %1 failed.").arg(fileName1);
       return;
    }
 
@@ -177,7 +172,7 @@
 
    if ( ! file2.open(IO_ReadOnly) )
    {
-      status = "Opening " + fileName2 + " failed.";
+      status = i18n("Opening %1 failed.").arg(fileName2);
       return;
    }
 
@@ -193,13 +188,13 @@
       int len = min2( size, (t_FileSize)buf1.size() );
       if( len != file1.readBlock( &buf1[0], len ) )
       {
-         status = "Error reading from " + fileName1;
+         status = i18n("Error reading from %1").arg(fileName1);
          return;
       }
 
       if( len != file2.readBlock( &buf2[0], len ) )
       {
-         status = "Error reading from " + fileName2;
+         status = i18n("Error reading from %1").arg(fileName2);
          return;
       }
 
@@ -240,18 +235,17 @@
    m_bAllowResizeEvents = true;
    m_bSimulatedMergeStarted=false;
    m_bRealMergeStarted=false;
-   m_bSingleFileOperationStarted=false;
    m_bError = false;
    m_bSyncMode = false;
    m_pStatusInfo = new StatusInfo(0);
    m_pStatusInfo->hide();
    
-   addColumn("Name");
+   addColumn(i18n("Name"));
    addColumn("A");
    addColumn("B");
    addColumn("C");
-   addColumn("Operation");
-   addColumn("Status");
+   addColumn(i18n("Operation"));
+   addColumn(i18n("Status"));
 }
 
 DirectoryMergeWindow::~DirectoryMergeWindow()
@@ -275,7 +269,7 @@
    {
       int result = KMessageBox::warningYesNo(this,
          i18n("You are currently doing a directory merge. Are you sure, you want to abort the merge and rescan the directory?"),
-         i18n("Warning"), i18n("Yes - Rescan"), i18n("No - Continue merging") );
+         i18n("Warning"), i18n("Rescan"), i18n("Continue Merging") );
       if ( result!=KMessageBox::Yes )
          return;
    }
@@ -371,7 +365,7 @@
 
    clear();
 
-   m_pCurrentItemForOperation = 0;
+   m_currentItemForOperation = m_mergeItemList.end();
 
    m_dirA = dirA;
    m_dirB = dirB;
@@ -386,15 +380,15 @@
        QString text( i18n("Opening of directories failed:") );
        text += "\n\n";
        if ( !dirA.isDir() )
-       {  text += "Dir A \"" + m_dirA.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir A \"%1\" does not exist or is not a directory.\n").arg(m_dirA.prettyAbsPath()); }
 
        if ( !dirB.isDir() )
-       {  text += "Dir B \"" + m_dirB.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir B \"%1\" does not exist or is not a directory.\n").arg(m_dirB.prettyAbsPath()); }
 
        if ( m_dirC.isValid() && !m_dirC.isDir() )
-       {  text += "Dir C \"" + m_dirC.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+       {  text += i18n("Dir C \"%1\" does not exist or is not a directory.\n").arg(m_dirC.prettyAbsPath()); }
 
-       KMessageBox::sorry( this, text, i18n("Directory open error") );
+       KMessageBox::sorry( this, text, i18n("Directory Open Error") );
        return false;
    }
 
@@ -404,7 +398,7 @@
       KMessageBox::error(this,
          i18n( "The destination directory must not be the same as A or B when"
          "three directories are merged.\nCheck again before continuing."),
-         "KDiff3: Parameter warning");
+         i18n("Parameter Warning"));
       return false;
    }
 
@@ -431,7 +425,7 @@
    bool bListDirSuccessC = true;
    if ( m_dirA.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory A");
+      g_pProgressDialog->setInformation(i18n("Reading Directory A"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -453,7 +447,7 @@
 
    if ( m_dirB.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory B");
+      g_pProgressDialog->setInformation(i18n("Reading Directory B"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -475,7 +469,7 @@
    e_MergeOperation eDefaultMergeOp;
    if ( m_dirC.isValid() )
    {
-      g_pProgressDialog->setInformation("Reading Directory C");
+      g_pProgressDialog->setInformation(i18n("Reading Directory C"));
       g_pProgressDialog->setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
       ++currentScan;
 
@@ -553,7 +547,7 @@
                         nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
 
       QString s;
-      s = i18n("Directory Comparison Status:") + "\n\n" +
+      s = i18n("Directory Comparison Status") + "\n\n" +
           i18n("Number of subdirectories:") +" "+ QString::number(nofDirs)       + "\n"+
           i18n("Number of equal files:")     +" "+ QString::number(nofEqualFiles) + "\n"+
           i18n("Number of different files:") +" "+ QString::number(nofFiles-nofEqualFiles);
@@ -604,11 +598,91 @@
       setListViewItemOpen( p, true );
 }
 
+static void setMergeOperation( QListViewItem* pLVI, e_MergeOperation eMergeOp )
+{
+   if ( pLVI==0 ) return;
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(pLVI);
+   MergeFileInfos& mfi = *pDMI->m_pMFI;
+
+   mfi.setMergeOperation(eMergeOp );
+}
+
+// Merge current item (merge mode)
+void DirectoryMergeWindow::slotCurrentDoNothing() { setMergeOperation(currentItem(), eNoOperation ); }
+void DirectoryMergeWindow::slotCurrentChooseA()   { setMergeOperation(currentItem(), eCopyAToDest ); }
+void DirectoryMergeWindow::slotCurrentChooseB()   { setMergeOperation(currentItem(), eCopyBToDest ); }
+void DirectoryMergeWindow::slotCurrentChooseC()   { setMergeOperation(currentItem(), eCopyCToDest ); }
+void DirectoryMergeWindow::slotCurrentMerge()
+{
+   bool bThreeDirs = m_dirC.isValid();
+   setMergeOperation(currentItem(), bThreeDirs ? eMergeABCToDest : eMergeABToDest );
+}
+void DirectoryMergeWindow::slotCurrentDelete()    { setMergeOperation(currentItem(), eDeleteFromDest ); }
+// Sync current item
+void DirectoryMergeWindow::slotCurrentCopyAToB()     { setMergeOperation(currentItem(), eCopyAToB ); }
+void DirectoryMergeWindow::slotCurrentCopyBToA()     { setMergeOperation(currentItem(), eCopyBToA ); }
+void DirectoryMergeWindow::slotCurrentDeleteA()      { setMergeOperation(currentItem(), eDeleteA );  }
+void DirectoryMergeWindow::slotCurrentDeleteB()      { setMergeOperation(currentItem(), eDeleteB );  }
+void DirectoryMergeWindow::slotCurrentDeleteAAndB()  { setMergeOperation(currentItem(), eDeleteAB ); }
+void DirectoryMergeWindow::slotCurrentMergeToA()     { setMergeOperation(currentItem(), eMergeToA ); }
+void DirectoryMergeWindow::slotCurrentMergeToB()     { setMergeOperation(currentItem(), eMergeToB ); }
+void DirectoryMergeWindow::slotCurrentMergeToAAndB() { setMergeOperation(currentItem(), eMergeToAB ); }
+
+
+void DirectoryMergeWindow::keyPressEvent( QKeyEvent* e )
+{
+   if ( (e->state() & Qt::ControlButton)!=0 )
+   {
+      bool bThreeDirs = m_dirC.isValid();
+
+      QListViewItem* lvi = currentItem();
+      DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi);
+      MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI;
+
+      if ( pMFI==0 ) return;
+      bool bMergeMode = bThreeDirs || !m_bSyncMode;
+      bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI);
+
+      if ( bMergeMode )
+      {
+         switch(e->key())
+         {
+         case Key_1:      if(pMFI->m_bExistsInA){ slotCurrentChooseA(); }  return;
+         case Key_2:      if(pMFI->m_bExistsInB){ slotCurrentChooseB(); }  return;
+         case Key_3:      if(pMFI->m_bExistsInC){ slotCurrentChooseC(); }  return;
+         case Key_Space:  slotCurrentDoNothing();                          return;
+         case Key_4:      if ( !bFTConflict )   { slotCurrentMerge();   }  return;
+         case Key_Delete: slotCurrentDelete();                             return;
+         default: break;
+         }
+      }
+      else
+      {
+         switch(e->key())
+         {
+         case Key_1:      if(pMFI->m_bExistsInA){ slotCurrentCopyAToB(); }  return;
+         case Key_2:      if(pMFI->m_bExistsInB){ slotCurrentCopyBToA(); }  return;
+         case Key_Space:  slotCurrentDoNothing();                           return;
+         case Key_4:      if ( !bFTConflict ) { slotCurrentMergeToAAndB(); }  return;
+         case Key_Delete: if( pMFI->m_bExistsInA && pMFI->m_bExistsInB ) slotCurrentDeleteAAndB();
+                          else if( pMFI->m_bExistsInA ) slotCurrentDeleteA();
+                          else if( pMFI->m_bExistsInB ) slotCurrentDeleteB();
+                          return;
+         default: break;
+         }
+      }
+   }
+
+   QListView::keyPressEvent(e);
+}
+
+
 void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
 {
    if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
         i18n("This affects all merge operations."),
-        i18n("KDiff3: Changing all merge operations"),i18n("Continue"), i18n("Cancel") ) )
+        i18n("Changing All Merge Operations"),i18n("C&ontinue"), i18n("&Cancel") ) )
    {
       for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
       {
@@ -875,7 +949,7 @@
                       QString("");
 
       g_pProgressDialog->setInformation(
-         "Processing " + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
+         i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
          +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
       if ( g_pProgressDialog->wasCancelled() ) break;
       ++currentIdx;
@@ -1004,10 +1078,10 @@
 
    if ( eDefaultMergeOp == eMergeABCToDest && !bCheckC ) { eDefaultMergeOp = eMergeABToDest; }
    if ( eDefaultMergeOp == eMergeToAB      &&  bCheckC ) { assert(false); }
-   
+
    if ( eDefaultMergeOp == eMergeToA || eDefaultMergeOp == eMergeToB ||
         eDefaultMergeOp == eMergeABCToDest || eDefaultMergeOp == eMergeABToDest || eDefaultMergeOp == eMergeToAB )
-   {   
+   {
       if ( !bCheckC )
       {
          if ( mfi.m_bEqualAB )
@@ -1174,53 +1248,45 @@
 
    bool bThreeDirs = m_dirC.isValid();
 
-   //bool bImmediate = (button==Qt::LeftButton);
-
    KPopupMenu m(this);
-   //if (bImmediate ) m.insertItem("Immediate Mode", eTitleId );
-   //else             m.insertItem("Postponed Mode", eTitleId );
-   //m.setItemEnabled ( eTitleId, false );
    if ( bThreeDirs )
    {
-      m.insertItem("Do nothing", eNoOperation );
+      dirCurrentDoNothing->plug(&m);
       int count=0;
-      if ( mfi.m_bExistsInA ) { m.insertItem("A", eCopyAToDest );  ++count;  }
-      if ( mfi.m_bExistsInB ) { m.insertItem("B", eCopyBToDest );  ++count;  }
-      if ( mfi.m_bExistsInC ) { m.insertItem("C", eCopyCToDest );  ++count;  }
-      if ( !conflictingFileTypes(mfi) && count>1 ) m.insertItem("Merge", eMergeABCToDest );
-      m.insertItem("Delete (if exists)", eDeleteFromDest );
+      if ( mfi.m_bExistsInA ) { dirCurrentChooseA->plug(&m); ++count;  }
+      if ( mfi.m_bExistsInB ) { dirCurrentChooseB->plug(&m); ++count;  }
+      if ( mfi.m_bExistsInC ) { dirCurrentChooseC->plug(&m); ++count;  }
+      if ( !conflictingFileTypes(mfi) && count>1 ) dirCurrentMerge->plug(&m);
+      dirCurrentDelete->plug(&m);
    }
    else if ( m_bSyncMode )
    {
-      m.insertItem("Do nothing", eNoOperation );
-      if ( mfi.m_bExistsInA ) m.insertItem("Copy A to B", eCopyAToB );
-      if ( mfi.m_bExistsInB ) m.insertItem("Copy B to A", eCopyBToA );
-      if ( mfi.m_bExistsInA ) m.insertItem("Delete A", eDeleteA );
-      if ( mfi.m_bExistsInB ) m.insertItem("Delete B", eDeleteB );
+      dirCurrentSyncDoNothing->plug(&m);
+      if ( mfi.m_bExistsInA ) dirCurrentSyncCopyAToB->plug(&m);
+      if ( mfi.m_bExistsInB ) dirCurrentSyncCopyBToA->plug(&m);
+      if ( mfi.m_bExistsInA ) dirCurrentSyncDeleteA->plug(&m);
+      if ( mfi.m_bExistsInB ) dirCurrentSyncDeleteB->plug(&m);
       if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
       {
-         m.insertItem("Delete A and B", eDeleteAB );
+         dirCurrentSyncDeleteAAndB->plug(&m);
          if ( !conflictingFileTypes(mfi))
          {
-            m.insertItem("Merge to A",    eMergeToA );
-            m.insertItem("Merge to B",    eMergeToB );
-            m.insertItem("Merge to A and B",    eMergeToAB );
+            dirCurrentSyncMergeToA->plug(&m);
+            dirCurrentSyncMergeToB->plug(&m);
+            dirCurrentSyncMergeToAAndB->plug(&m);
          }
       }
    }
    else
    {
-      m.insertItem("Do nothing", eNoOperation );
-      if ( mfi.m_bExistsInA ) m.insertItem("A", eCopyAToDest );
-      if ( mfi.m_bExistsInB ) m.insertItem("B", eCopyBToDest );
-      if ( mfi.m_bExistsInA  &&  mfi.m_bExistsInB  && !conflictingFileTypes(mfi) )
-         m.insertItem("Merge", eMergeABToDest );
-      m.insertItem("Delete (if exists)", eDeleteFromDest );
+      dirCurrentDoNothing->plug(&m);
+      if ( mfi.m_bExistsInA ) { dirCurrentChooseA->plug(&m); }
+      if ( mfi.m_bExistsInB ) { dirCurrentChooseB->plug(&m); }
+      if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA  &&  mfi.m_bExistsInB ) dirCurrentMerge->plug(&m);
+      dirCurrentDelete->plug(&m);
    }
 
-   int result = m.exec( p );
-   if (result>=0 )
-      mfi.setMergeOperation( (e_MergeOperation)result );
+   m.exec( p );
 }
 
 // Since Qt 2.3.0 doesn't allow the specification of a compare operator, this trick emulates it.
@@ -1231,14 +1297,14 @@
 #endif
 
 DirMergeItem::DirMergeItem( QListView* pParent, const QString& fileName, MergeFileInfos* pMFI )
-: QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do.") )
 {
    pMFI->m_pDMI = this;
    m_pMFI = pMFI;
 }
 
 DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI )
-: QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do.") )
 {
    pMFI->m_pDMI = this;
    m_pMFI = pMFI;
@@ -1251,30 +1317,36 @@
 
 void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp )
 {
+   if ( eMOp != m_eMergeOperation )
+   {
+      m_bOperationComplete = false;
+      m_pDMI->setText( s_OpStatusCol, "" );
+   }
+
    m_eMergeOperation = eMOp;
-   const char* s=0;
+   QString s;
    bool bDir = m_bDirA || m_bDirB || m_bDirC;
    if( m_pDMI!=0 )
    {
       switch( m_eMergeOperation )
       {
       case eNoOperation:      s=""; m_pDMI->setText(s_OpCol,""); break;
-      case eCopyAToB:         s="Copy A to B";     break;
-      case eCopyBToA:         s="Copy B to A";     break;
-      case eDeleteA:          s="Delete A";        break;
-      case eDeleteB:          s="Delete B";        break;
-      case eDeleteAB:         s="Delete A and B";  break;
-      case eMergeToA:         s="Merge to A";      break;
-      case eMergeToB:         s="Merge to B";      break;
-      case eMergeToAB:        s="Merge to A and B";  break;
+      case eCopyAToB:         s=i18n("Copy A to B");     break;
+      case eCopyBToA:         s=i18n("Copy B to A");     break;
+      case eDeleteA:          s=i18n("Delete A");        break;
+      case eDeleteB:          s=i18n("Delete B");        break;
+      case eDeleteAB:         s=i18n("Delete A & B");    break;
+      case eMergeToA:         s=i18n("Merge to A");      break;
+      case eMergeToB:         s=i18n("Merge to B");      break;
+      case eMergeToAB:        s=i18n("Merge to A & B");  break;
       case eCopyAToDest:      s="A";    break;
       case eCopyBToDest:      s="B";    break;
       case eCopyCToDest:      s="C";    break;
-      case eDeleteFromDest:   s="Delete (if exists)";  break;
-      case eMergeABCToDest:   s= bDir ? "Merge" : "Merge (manual)";  break;
-      case eMergeABToDest:    s= bDir ? "Merge" : "Merge (manual)";  break;
-      case eConflictingFileTypes: s="Error: Conflicting File Types"; break;
-      case eConflictingAges:  s="Error: Dates are equal but files are not."; break;
+      case eDeleteFromDest:   s=i18n("Delete (if exists)");  break;
+      case eMergeABCToDest:   s= bDir ? i18n("Merge") : i18n("Merge (manual)");    break;
+      case eMergeABToDest:    s= bDir ? i18n("Merge") : i18n("Merge (manual)");    break;
+      case eConflictingFileTypes: s=i18n("Error: Conflicting File Types");         break;
+      case eConflictingAges:  s=i18n("Error: Dates are equal but files are not."); break;
       default:                assert(false); break;
       }
       m_pDMI->setText(s_OpCol,s);
@@ -1298,7 +1370,7 @@
 
    if ( m_bRealMergeStarted )
    {
-      KMessageBox::sorry(this,"This operation is currently not possible.","KDiff3");
+      KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
       return;
    }
 
@@ -1320,36 +1392,6 @@
    emit updateAvailabilities();
 }
 
-void DirectoryMergeWindow::mergeCurrentFile()
-{
-   if (!canContinue()) return;
-
-   if ( m_bRealMergeStarted )
-   {
-      KMessageBox::sorry(this,"This operation is currently not possible because diff merge currently runs.","KDiff3");
-      return;
-   }
-
-   if ( isFileSelected() )
-   {
-      DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
-      if ( pDMI != 0 )
-      {
-         MergeFileInfos& mfi = *pDMI->m_pMFI;
-         m_bSingleFileOperationStarted = true;
-         emit startDiffMerge(
-            mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
-            mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
-            mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
-            fullNameDest(mfi),
-            "","",""
-            );
-         m_pCurrentItemForOperation = pDMI;
-         m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
-      }
-   }
-   emit updateAvailabilities();
-}
 
 
 bool DirectoryMergeWindow::isFileSelected()
@@ -1365,33 +1407,41 @@
 
 void DirectoryMergeWindow::mergeResultSaved(const QString& fileName)
 {
-   m_bSingleFileOperationStarted = false;
-   if ( m_pCurrentItemForOperation!=0 && m_pCurrentItemForOperation->m_pMFI==0 )
+   DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() )
+                                               ? 0
+                                               : *m_currentItemForOperation;
+
+   if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 )
    {
-      KMessageBox::error( this, "This should never happen: \n\nmergeResultSaved: m_pMFI=0\n\nIf you know how to reproduce this, please contact the program author.","Program Error" );
+      KMessageBox::error( this, i18n("This should never happen: \n\nmergeResultSaved: m_pMFI=0\n\nIf you know how to reproduce this, please contact the program author."),i18n("Program Error") );
       return;
    }
-   if ( m_pCurrentItemForOperation!=0 && fileName == fullNameDest(*m_pCurrentItemForOperation->m_pMFI) )
+   if ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) )
    {
-      if ( m_pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
+      if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
       {
-         MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
+         MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
          bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
          if (!bSuccess)
          {
-            KMessageBox::error(this, i18n("An error occurred while copying.\n"), "KDiff3: Error" );
-            m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+            KMessageBox::error(this, i18n("An error occurred while copying.\n"), i18n("Error") );
+            m_pStatusInfo->setCaption(i18n("Merge Error"));
             m_pStatusInfo->show();
             if ( m_pStatusInfo->firstChild()!=0 )
                m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
             m_bError = true;
-            m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+            pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
             mfi.m_eMergeOperation = eCopyBToA;
             return;
          }
       }
-      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Done." );
-      m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+      pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Done.") );
+      pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+      if ( m_mergeItemList.size()==1 )
+      {
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
+      }
    }
 
    emit updateAvailabilities();
@@ -1403,76 +1453,246 @@
    checkIfCanContinue( &bCanContinue );
    if ( bCanContinue && !m_bError )
    {
-      if ( m_bRealMergeStarted && m_pCurrentItemForOperation!=0  && ! m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+      DirMergeItem* pCurrentItemForOperation =
+         (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation;
+
+      if ( pCurrentItemForOperation!=0  && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
       {
-         m_pCurrentItemForOperation->setText( s_OpStatusCol, "Not saved." );
-         m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+         pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Not saved.") );
+         pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+         if ( m_mergeItemList.size()==1 )
+         {
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
+         }
       }
    }
    return bCanContinue;
 }
 
-void DirectoryMergeWindow::mergeContinue()
+bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge )
 {
-   if ( ! canContinue() ) return;
+   bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
+   // First decide destname
+   QString destName;
+   switch( mfi.m_eMergeOperation )
+   {
+   case eNoOperation: break;
+   case eDeleteAB:    break;
+   case eMergeToAB:   // let the user save in B. In mergeResultSaved() the file will be copied to A.
+   case eMergeToB:
+   case eDeleteB:
+   case eCopyAToB:    destName = fullNameB(mfi); break;
+   case eMergeToA:
+   case eDeleteA:
+   case eCopyBToA:    destName = fullNameA(mfi); break;
+   case eMergeABToDest:
+   case eMergeABCToDest:
+   case eCopyAToDest:
+   case eCopyBToDest:
+   case eCopyCToDest:
+   case eDeleteFromDest: destName = fullNameDest(mfi); break;
+   default:
+      KMessageBox::error( this, i18n("Unknown merge operation. (This must never happen!)"), i18n("Error") );
+      assert(false);
+   }
 
-   m_bSingleFileOperationStarted = false;
+   bool bSuccess = false;
+   bSingleFileMerge = false;
+   switch( mfi.m_eMergeOperation )
+   {
+   case eNoOperation: bSuccess = true; break;
+   case eCopyAToDest:
+   case eCopyAToB:    bSuccess = copyFLD( fullNameA(mfi), destName ); break;
+   case eCopyBToDest:
+   case eCopyBToA:    bSuccess = copyFLD( fullNameB(mfi), destName ); break;
+   case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
+   case eDeleteFromDest:
+   case eDeleteA:
+   case eDeleteB:     bSuccess = deleteFLD( destName, bCreateBackups ); break;
+   case eDeleteAB:    bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
+                                 deleteFLD( fullNameB(mfi), bCreateBackups ); break;
+   case eMergeABToDest:
+   case eMergeToA:
+   case eMergeToAB:
+   case eMergeToB:      bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
+                                             destName, bSingleFileMerge );
+                        break;
+   case eMergeABCToDest:bSuccess = mergeFLD(
+                                    mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
+                                    mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
+                                    mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
+                                    destName, bSingleFileMerge );
+                        break;
+   default:
+      KMessageBox::error( this, i18n("Unknown merge operation."), i18n("Error") );
+      assert(false);
+   }
 
-   int nrOfItems = 0;
-   int nrOfCompletedItems = 0;
-   int nrOfCompletedSimItems = 0;
+   return bSuccess;
+}
 
-   if ( !m_bSimulatedMergeStarted && !m_bRealMergeStarted )
+
+// Check if the merge can start, and prepare the m_mergeItemList which then contains all
+// items that must be merged.
+void DirectoryMergeWindow::prepareMergeStart( QListViewItem* pBegin, QListViewItem* pEnd, bool bVerbose )
+{
+   if ( bVerbose )
    {
-      // First check if an invalid merge operations exist.
-      for( QListViewItem* p=firstChild(); p!=0; p = treeIterator( p ) )
+      int status = KMessageBox::warningYesNoCancel(this,
+         i18n("The merge is about to begin.\n\n"
+         "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
+         "Choosing \"Simulate it\" will tell you what would happen.\n\n"
+         "Be aware that this program still has beta status "
+         "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
+         i18n("Starting Merge"), i18n("Do It"), i18n("Simulate It") );
+      if (status==KMessageBox::Yes)      m_bRealMergeStarted = true;
+      else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
+      else return;
+   }
+   else
+   {
+      m_bRealMergeStarted = true;
+   }
+
+   m_mergeItemList.clear();
+   if (pBegin == 0)
+      return;
+
+   for( QListViewItem* p = pBegin; p!= pEnd; p = treeIterator( p ) )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+
+      if ( ! pDMI->m_pMFI->m_bOperationComplete )
       {
-         DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+         m_mergeItemList.push_back(pDMI);
+
          if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes )
          {
             ensureItemVisible( pDMI );
             setSelected( pDMI, true );
-            KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), "Error");
+            KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), i18n("Error"));
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
             return;
          }
          if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges )
          {
             ensureItemVisible( pDMI );
             setSelected( pDMI, true );
-            KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), "Error");
+            KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), i18n("Error"));
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
             return;
          }
-         ++nrOfItems;
-         if ( pDMI->m_pMFI->m_bSimOpComplete )
-            ++nrOfCompletedSimItems;
-         if ( pDMI->m_pMFI->m_bOperationComplete )
-            ++nrOfCompletedItems;
       }
-
-      int status = KMessageBox::warningYesNoCancel(this,
-         i18n("The merge is about to begin.\n\n"
-         "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
-         "Choosing \"Simulate it\" will tell you what would happen.\n\n"
-         "Be aware that this program still has beta status "
-         "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
-         i18n("KDiff3: Starting the Merge"), i18n("Do it"), i18n("Simulate it") );
-      if (status==KMessageBox::Yes) m_bRealMergeStarted = true;
-      else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
-      else return;
-
-      m_pStatusInfo->hide();
-      m_pStatusInfo->clear();
    }
 
-   bool bContinueWithCurrentItem = false;
+   m_currentItemForOperation = m_mergeItemList.begin();
+   return;
+}
+
+void DirectoryMergeWindow::slotRunOperationForCurrentItem()
+{
+   if ( ! canContinue() ) return;
+
+   bool bVerbose = false;
+   if ( m_mergeItemList.empty() )
+   {
+      QListViewItem* pBegin = currentItem();
+
+      prepareMergeStart( pBegin, pBegin->nextSibling(), bVerbose );
+      mergeContinue(true, bVerbose);
+   }
+   else
+      mergeContinue(false, bVerbose);
+}
+
+void DirectoryMergeWindow::slotRunOperationForAllItems()
+{
+   if ( ! canContinue() ) return;
+
+   bool bVerbose = true;
+   if ( m_mergeItemList.empty() )
+   {
+      QListViewItem* pBegin = firstChild();
+
+      prepareMergeStart( pBegin, 0, bVerbose );
+      mergeContinue(true, bVerbose);
+   }
+   else
+      mergeContinue(false, bVerbose);
+}
+
+void DirectoryMergeWindow::mergeCurrentFile()
+{
+   if (!canContinue()) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,i18n("This operation is currently not possible because dir merge currently runs."),i18n("Operation Not Possible"));
+      return;
+   }
+
+   if ( isFileSelected() )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
+      if ( pDMI != 0 )
+      {
+         MergeFileInfos& mfi = *pDMI->m_pMFI;
+         m_mergeItemList.clear();
+         m_mergeItemList.push_back( pDMI );
+         m_currentItemForOperation=m_mergeItemList.begin();
+         bool bDummy=false;
+         mergeFLD(
+            mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
+            mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
+            mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
+            fullNameDest(mfi),
+            bDummy
+            );
+      }
+   }
+   emit updateAvailabilities();
+}
+
+
+// When bStart is true then m_currentItemForOperation must still be processed.
+// When bVerbose is true then a messagebox will tell when the merge is complete.
+void DirectoryMergeWindow::mergeContinue(bool bStart, bool bVerbose)
+{
+   if ( m_mergeItemList.empty() )
+      return;
+
+   int nrOfItems = 0;
+   int nrOfCompletedItems = 0;
+   int nrOfCompletedSimItems = 0;
+
+   // Count the number of completed items (for the progress bar).
+   for( MergeItemList::iterator i = m_mergeItemList.begin(); i!=m_mergeItemList.end(); ++i )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>(*i);
+      ++nrOfItems;
+      if ( pDMI->m_pMFI->m_bOperationComplete )
+         ++nrOfCompletedItems;
+      if ( pDMI->m_pMFI->m_bSimOpComplete )
+         ++nrOfCompletedSimItems;
+   }
+
+   m_pStatusInfo->hide();
+   m_pStatusInfo->clear();
+
+   DirMergeItem* pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation;
+
+   bool bContinueWithCurrentItem = bStart;  // true for first item, else false
    bool bSkipItem = false;
-   if ( m_bError && m_pCurrentItemForOperation!=0 )
+   if ( !bStart && m_bError && pCurrentItemForOperation!=0 )
    {
       int status = KMessageBox::warningYesNoCancel(this,
          i18n("There was an error in the last step.\n"
          "Do you want to continue with the item that caused the error or do you want to skip this item?"),
-         i18n("KDiff3: Continue merge after an error"), i18n("Continue with last item"), i18n("Skip item") );
-      if (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
+         i18n("Continue merge after an error"), i18n("Continue With Last Item"), i18n("Skip Item") );
+      if      (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
       else if (status==KMessageBox::No ) bSkipItem = true;
       else return;
       m_bError = false;
@@ -1485,89 +1705,87 @@
    bool bSim = m_bSimulatedMergeStarted;
    while( bSuccess )
    {
-      if ( m_pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
+      if ( pCurrentItemForOperation==0 )
+      {
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
+         break;
+      }
+
+      if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
       {
          if ( bSim )
          {
-            if( m_pCurrentItemForOperation->firstChild()==0 )
+            if( pCurrentItemForOperation->firstChild()==0 )
             {
-               m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
+               pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
             }
          }
          else
          {
-            if( m_pCurrentItemForOperation->firstChild()==0 )
+            if( pCurrentItemForOperation->firstChild()==0 )
             {
-               if( !m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+               if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
                {
-                  m_pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? "Skipped." : "Done." );
-                  m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+                  pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") );
+                  pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
                   bSkipItem = false;
                }
             }
             else
             {
-               m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
+               pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") );
             }
          }
       }
 
-      if ( m_pCurrentItemForOperation==0 )
+      if ( ! bContinueWithCurrentItem )
       {
-         m_pCurrentItemForOperation = static_cast<DirMergeItem*>( firstChild() );
-      }
-      else
-      {
-         if ( ! bContinueWithCurrentItem )
+         // Depth first
+         QListViewItem* pPrevItem = pCurrentItemForOperation;
+         ++m_currentItemForOperation;
+         pCurrentItemForOperation = m_currentItemForOperation==m_mergeItemList.end() ? 0 : *m_currentItemForOperation;
+         if ( (pCurrentItemForOperation==0 || pCurrentItemForOperation->parent()!=pPrevItem->parent()) && pPrevItem->parent()!=0 )
          {
-            // Depth first
-            QListViewItem* pNextItem = m_pCurrentItemForOperation->firstChild();
-            QListViewItem* pCurrentItem = m_pCurrentItemForOperation;
-            while( pCurrentItem!=0 && pNextItem==0 )
+            // Check if the parent may be set to "Done"
+            QListViewItem* pParent = pPrevItem->parent();
+            bool bDone = true;
+            while ( bDone && pParent!=0 )
             {
-               // Find an item on this level that hasn't been operated yet. (Always start at beginning.)
-               if ( pCurrentItem->parent()==0 )
-                  pNextItem = firstChild();
-               else
-                  pNextItem = pCurrentItem->parent()->firstChild();
-
-               while( pNextItem!=0 && ( static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bOperationComplete ||
-                               ( bSim && static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bSimOpComplete ) ) )
+               for( QListViewItem* p = pParent->firstChild(); p!=0; p=p->nextSibling() )
                {
-                  pNextItem = pNextItem->nextSibling();
-               }
-
-               if ( pNextItem == 0 )
-               {
-                  pCurrentItem = pCurrentItem->parent();
-                  if ( pCurrentItem!=0 )
+                  DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+                  if ( !bSim && ! pDMI->m_pMFI->m_bOperationComplete   ||  bSim && pDMI->m_pMFI->m_bSimOpComplete )
                   {
-                     if (bSim)
-                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bSimOpComplete = true;
-                     else
-                     {
-                        pCurrentItem->setText( s_OpStatusCol, "Done." );
-                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bOperationComplete = true;
-                     }
+                     bDone=false;
+                     break;
                   }
                }
+               if ( bDone )
+               {
+                  if (bSim)
+                     static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bSimOpComplete = bDone;
+                  else
+                  {
+                     pParent->setText( s_OpStatusCol, i18n("Done.") );
+                     static_cast<DirMergeItem*>(pParent)->m_pMFI->m_bOperationComplete = bDone;
+                  }
+               }
+               pParent = pParent->parent();
             }
-            m_pCurrentItemForOperation = static_cast<DirMergeItem*>(pNextItem);
          }
       }
 
-      if( m_pCurrentItemForOperation !=0 &&
-         (bSim ? m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete :
-                 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete ))
-         m_pCurrentItemForOperation = 0;
-
-      if ( m_pCurrentItemForOperation==0 )
+      if ( pCurrentItemForOperation == 0 ) // end?
       {
          if ( m_bRealMergeStarted )
          {
-            KMessageBox::information( this, "Merge operation complete.", "The merge is complete." );
+            if (bVerbose)
+            {
+               KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") );
+            }
             m_bRealMergeStarted = false;
-            m_pStatusInfo->setCaption("KDiff3: Merge complete.");
+            m_pStatusInfo->setCaption(i18n("Merge Complete"));
          }
          if ( m_bSimulatedMergeStarted )
          {
@@ -1576,104 +1794,61 @@
             {
                static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false;
             }
-            m_pStatusInfo->setCaption("KDiff3: Simulated merge complete: Check if you agree with the proposed operations.");
+            m_pStatusInfo->setCaption(i18n("Simulated merge complete: Check if you agree with the proposed operations."));
             m_pStatusInfo->show();
          }
          g_pProgressDialog->hide();
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
          return;
       }
 
-      MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
-      bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
+      MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
 
       g_pProgressDialog->setInformation( mfi.m_subPath,
          bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
-         true
+         false // bRedrawUpdate
          );
       g_pProgressDialog->show();
 
-      // First decide destname
-      QString destName;
-      switch( mfi.m_eMergeOperation )
-      {
-      case eNoOperation: break;
-      case eDeleteAB:    break;
-      case eMergeToAB:   // let the user save in B. In mergeResultSaved() the file will be copied to A.
-      case eMergeToB:
-      case eDeleteB:
-      case eCopyAToB:    destName = fullNameB(mfi); break;
-      case eMergeToA:
-      case eDeleteA:
-      case eCopyBToA:    destName = fullNameA(mfi); break;
-      case eMergeABToDest:
-      case eMergeABCToDest:
-      case eCopyAToDest:
-      case eCopyBToDest:
-      case eCopyCToDest:
-      case eDeleteFromDest: destName = fullNameDest(mfi); break;
-      default:
-         KMessageBox::error( this, "Unknown merge operation.(This must never happen!)", "Error" );
-         assert(false);
-      }
+      bSuccess = executeMergeOperation( mfi, bSingleFileMerge );  // Here the real operation happens.
 
-      bSuccess = false;
-      bSingleFileMerge = false;
-      switch( mfi.m_eMergeOperation )
-      {
-      case eNoOperation: bSuccess = true; break;
-      case eCopyAToDest:
-      case eCopyAToB:    bSuccess = copyFLD( fullNameA(mfi), destName ); break;
-      case eCopyBToDest:
-      case eCopyBToA:    bSuccess = copyFLD( fullNameB(mfi), destName ); break;
-      case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
-      case eDeleteFromDest:
-      case eDeleteA:
-      case eDeleteB:     bSuccess = deleteFLD( destName, bCreateBackups ); break;
-      case eDeleteAB:    bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
-                                    deleteFLD( fullNameB(mfi), bCreateBackups ); break;
-      case eMergeABToDest:
-      case eMergeToA:
-      case eMergeToAB:
-      case eMergeToB:      bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
-                                                destName, bSingleFileMerge );
-                           break;
-      case eMergeABCToDest:bSuccess = mergeFLD(
-                                         mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
-                                         mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
-                                         mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
-                                         destName, bSingleFileMerge );
-                           break;
-      default:
-         KMessageBox::error( this, "Unknown merge operation.", "Error" );
-         assert(false);
-      }
       if ( bSuccess )
       {
          if(bSim) ++nrOfCompletedSimItems;
          else     ++nrOfCompletedItems;
          bContinueWithCurrentItem = false;
       }
+
+      if( g_pProgressDialog->wasCancelled() )
+         break;
    }  // end while
 
    g_pProgressDialog->hide();
 
-   setCurrentItem( m_pCurrentItemForOperation );
-   ensureItemVisible( m_pCurrentItemForOperation );
+   setCurrentItem( pCurrentItemForOperation );
+   ensureItemVisible( pCurrentItemForOperation );
    if ( !bSuccess &&  !bSingleFileMerge )
    {
-      KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), "KDiff3: Error" );
-      m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+      KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), i18n("Error") );
+      m_pStatusInfo->setCaption(i18n("Merge Error"));
       m_pStatusInfo->show();
       if ( m_pStatusInfo->firstChild()!=0 )
          m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
       m_bError = true;
-      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+      pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
    }
    else
    {
       m_bError = false;
    }
    emit updateAvailabilities();
+
+   if ( m_currentItemForOperation==m_mergeItemList.end() )
+   {
+      m_mergeItemList.clear();
+      m_bRealMergeStarted=false;
+   }
 }
 
 void DirectoryMergeWindow::allowResizeEvents(bool bAllowResizeEvents )
@@ -1698,16 +1873,16 @@
       bool bSuccess = renameFLD( name, name+".orig" );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error: While deleting "+name+": Creating backup failed." );
+         m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.").arg(name) );
          return false;
       }
    }
    else
    {
       if ( fi.isDir() && !fi.isSymLink() )
-         m_pStatusInfo->addText("delete directory recursively( "+name+" )");
+         m_pStatusInfo->addText(i18n("delete directory recursively( %1 )").arg(name));
       else
-         m_pStatusInfo->addText("delete( "+name+" )");
+         m_pStatusInfo->addText(i18n("delete( %1 )").arg(name));
 
       if ( m_bSimulatedMergeStarted )
       {
@@ -1722,7 +1897,7 @@
          if ( !bSuccess )
          {
              // No Permission to read directory or other error.
-             m_pStatusInfo->addText( "Error: delete dir operation failed while trying to read the directory." );
+             m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") );
              return false;
          }
 
@@ -1741,7 +1916,7 @@
             bSuccess = FileAccess::removeDir( name );
             if ( !bSuccess )
             {
-               m_pStatusInfo->addText( "Error: rmdir( "+name+" ) operation failed." );
+               m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.").arg(name));
                return false;
             }
          }
@@ -1751,7 +1926,7 @@
          bool bSuccess = FileAccess::removeFile( name );
          if ( !bSuccess )
          {
-            m_pStatusInfo->addText( "Error: delete operation failed." );
+            m_pStatusInfo->addText( i18n("Error: delete operation failed.") );
             return false;
          }
       }
@@ -1777,16 +1952,16 @@
          return false;
    }
 
-   m_pStatusInfo->addText("manual merge( "+nameA+ ", "+nameB+","+nameC+" -> " + nameDest +" )" );
+   m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)").arg(nameA).arg(nameB).arg(nameC).arg(nameDest));
    if ( m_bSimulatedMergeStarted )
    {
-      m_pStatusInfo->addText("     Note: After a manual merge the user should continue via F5." );
+      m_pStatusInfo->addText(i18n("     Note: After a manual merge the user should continue via F7.") );
       return true;
    }
 
    bSingleFileMerge = true;
-   m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
-   ensureItemVisible( m_pCurrentItemForOperation );
+   (*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") );
+   ensureItemVisible( *m_currentItemForOperation );
 
    emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","" );
 
@@ -1803,8 +1978,8 @@
       bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles );
       if ( !bSuccess )
       {
-         m_pStatusInfo->addText("Error: copy( "+srcName+ " -> " + destName +" ) failed."
-            "Deleting existing destination failed.");
+         m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed."
+            "Deleting existing destination failed.").arg(srcName).arg(destName));
          return false;
       }
    }
@@ -1813,7 +1988,7 @@
 
    if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks  ||  !fi.isDir() && !m_bFollowDirLinks) )
    {
-      m_pStatusInfo->addText("copyLink( "+srcName+ " -> " + destName +" )");
+      m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )").arg(srcName).arg(destName));
 #ifdef _WIN32
       // What are links?
 #else
@@ -1824,13 +1999,13 @@
       FileAccess destFi(destName);
       if ( !destFi.isLocal() || !fi.isLocal() )
       {
-         m_pStatusInfo->addText("Error: copyLink failed: Remote links are not yet supported.");
+         m_pStatusInfo->addText(i18n("Error: copyLink failed: Remote links are not yet supported."));
          return false;
       }
       QString linkTarget = fi.readLink();
       bool bSuccess = FileAccess::symLink( linkTarget, destName );
       if (!bSuccess)
-         m_pStatusInfo->addText("Error: copyLink failed.");
+         m_pStatusInfo->addText(i18n("Error: copyLink failed."));
       return bSuccess;
 #endif
    }
@@ -1850,7 +2025,7 @@
          return false;
    }
 
-   m_pStatusInfo->addText("copy( "+srcName+ " -> " + destName +" )");
+   m_pStatusInfo->addText(i18n("copy( %1 -> %2 )").arg(srcName).arg(destName));
 
    if ( m_bSimulatedMergeStarted )
    {
@@ -1876,13 +2051,13 @@
       bool bSuccess = deleteFLD( destName, false /*no backup*/ );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error during rename( "+srcName+" -> " + destName + " ): "
-                             "Cannot delete existing destination." );
+         m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): "
+                             "Cannot delete existing destination." ).arg(srcName).arg(destName));
          return false;
       }
    }
 
-   m_pStatusInfo->addText("rename( "+srcName+ " -> " + destName +" )");
+   m_pStatusInfo->addText(i18n("rename( %1 -> %2 )").arg(srcName).arg(destName))	;
    if ( m_bSimulatedMergeStarted )
    {
       return true;
@@ -1891,7 +2066,7 @@
    bool bSuccess = FileAccess( srcName ).rename( destName );
    if (!bSuccess)
    {
-      m_pStatusInfo->addText( "Error: Rename failed." );
+      m_pStatusInfo->addText( i18n("Error: Rename failed.") );
       return false;
    }
 
@@ -1909,8 +2084,8 @@
       bool bSuccess = deleteFLD( name, true );
       if (!bSuccess)
       {
-         m_pStatusInfo->addText( "Error during makeDir of "+name+
-                             "Cannot delete existing file." );
+         m_pStatusInfo->addText( i18n("Error during makeDir of %1. "
+                             "Cannot delete existing file." ).arg(name));
          return false;
       }
    }
@@ -1925,7 +2100,7 @@
    }
 
    if ( ! bQuiet )
-      m_pStatusInfo->addText("makeDir( " + name + " )");
+      m_pStatusInfo->addText(i18n("makeDir( %1 )").arg(name));
 
    if ( m_bSimulatedMergeStarted )
    {
@@ -1935,7 +2110,7 @@
    bool bSuccess = FileAccess::makeDir( name );
    if ( bSuccess == false )
    {
-      m_pStatusInfo->addText( "Error while creating directory." );
+      m_pStatusInfo->addText( i18n("Error while creating directory.") );
       return false;
    }
    return true;
@@ -1962,16 +2137,16 @@
    m_pInfoB = new QLabel(this);        grid->addWidget( m_pInfoB,line,1 ); ++line;
    m_pC = new QLabel("C",this);        grid->addWidget( m_pC,line, 0 );
    m_pInfoC = new QLabel(this);        grid->addWidget( m_pInfoC,line,1 ); ++line;
-   m_pDest = new QLabel("Dest",this);  grid->addWidget( m_pDest,line, 0 );
+   m_pDest = new QLabel(i18n("Dest"),this);  grid->addWidget( m_pDest,line, 0 );
    m_pInfoDest = new QLabel(this);     grid->addWidget( m_pInfoDest,line,1 ); ++line;
 
    m_pInfoList = new QListView(this);  topLayout->addWidget( m_pInfoList );
-   m_pInfoList->addColumn("Dir");
-   m_pInfoList->addColumn("Type");
-   m_pInfoList->addColumn("Size");
-   m_pInfoList->addColumn("Attr");
-   m_pInfoList->addColumn("Last Modification");
-   m_pInfoList->addColumn("Link-Destination");
+   m_pInfoList->addColumn(i18n("Dir"));
+   m_pInfoList->addColumn(i18n("Type"));
+   m_pInfoList->addColumn(i18n("Size"));
+   m_pInfoList->addColumn(i18n("Attr"));
+   m_pInfoList->addColumn(i18n("Last Modification"));
+   m_pInfoList->addColumn(i18n("Link-Destination"));
    setMinimumSize( 100,100 );
 }
 
@@ -1995,7 +2170,7 @@
          new QListViewItem(
             pListView,
             dir,
-            QString( fi.isDir() ? "Dir" : "File" ) + (fi.isSymLink() ? "-Link" : ""),
+            QString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : ""),
             QString::number(fi.size()),
             QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ")
 #ifdef _WIN32
@@ -2012,7 +2187,7 @@
          new QListViewItem(
             pListView,
             dir,
-            "not available",
+            i18n("not available"),
             "",
             "",
             "",
@@ -2032,16 +2207,16 @@
    bool bHideDest = false;
    if ( dirA.absFilePath()==dirDest.absFilePath() )
    {
-      m_pA->setText( "A (Dest): " );  bHideDest=true;
+      m_pA->setText( i18n("A (Dest): ") );  bHideDest=true;
    }
    else
-      m_pA->setText( !dirC.isValid() ? "A:    " : "A (Base): ");
+      m_pA->setText( !dirC.isValid() ? QString("A:    ") : i18n("A (Base): "));
 
    m_pInfoA->setText( dirA.prettyAbsPath() );
 
    if ( dirB.absFilePath()==dirDest.absFilePath() )
    {
-      m_pB->setText( "B (Dest): " );  bHideDest=true;
+      m_pB->setText( i18n("B (Dest): ") );  bHideDest=true;
    }
    else
       m_pB->setText( "B:    " );
@@ -2049,13 +2224,13 @@
 
    if ( dirC.absFilePath()==dirDest.absFilePath() )
    {
-      m_pC->setText( "C (Dest): " );  bHideDest=true;
+      m_pC->setText( i18n("C (Dest): ") );  bHideDest=true;
    }
    else
       m_pC->setText( "C:    " );
    m_pInfoC->setText( dirC.prettyAbsPath() );
 
-   m_pDest->setText( "Dest: " ); m_pInfoDest->setText( dirDest.prettyAbsPath() );
+   m_pDest->setText( i18n("Dest: ") ); m_pInfoDest->setText( dirDest.prettyAbsPath() );
 
    if (!dirC.isValid())    { m_pC->hide(); m_pInfoC->hide();   }
    else                     { m_pC->show(); m_pInfoC->show();   }
@@ -2070,8 +2245,95 @@
    if (!bHideDest)
    {
       FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true );
-      addListViewItem( m_pInfoList, "Dest", dirDest.prettyAbsPath(), fiDest );
+      addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest );
    }
 }
 
+
+void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac )
+{
+#include "xpm/startmerge.xpm"
+   DirectoryMergeWindow* p = this;
+
+   dirStartOperation = new KAction(i18n("Start/Continue Directory Merge"), Key_F7, p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation");
+   dirRunOperationForCurrentItem = new KAction(i18n("Run Operation for Current Item"), Key_F6, p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item");
+   dirCompareCurrent = new KAction(i18n("Compare Selected File"), 0, p, SLOT(compareCurrentFile()), ac, "dir_compare_current");
+   dirMergeCurrent = new KAction(i18n("Merge Current File"), QIconSet(QPixmap(startmerge)), 0, pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current");
+   dirFoldAll = new KAction(i18n("Fold All Subdirs"), 0, p, SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all");
+   dirUnfoldAll = new KAction(i18n("Unfold All Subdirs"), 0, p, SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all");
+   dirRescan = new KAction(i18n("Rescan"), 0, p, SLOT(reload()), ac, "dir_rescan");
+   dirChooseAEverywhere = new KAction(i18n("Choose A for All Items"), 0, p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere");
+   dirChooseBEverywhere = new KAction(i18n("Choose B for All Items"), 0, p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere");
+   dirChooseCEverywhere = new KAction(i18n("Choose C for All Items"), 0, p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere");
+   dirAutoChoiceEverywhere = new KAction(i18n("Auto-Choose Operation for All Items"), 0, p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere");
+   dirDoNothingEverywhere = new KAction(i18n("No Operation for All Items"), 0, p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere");
+
+   dirCurrentDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing");
+   dirCurrentChooseA = new KAction(i18n("A"), 0, p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a");
+   dirCurrentChooseB = new KAction(i18n("B"), 0, p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b");
+   dirCurrentChooseC = new KAction(i18n("C"), 0, p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c");
+   dirCurrentMerge   = new KAction(i18n("Merge"), 0, p, SLOT(slotCurrentMerge()), ac, "dir_current_merge");
+   dirCurrentDelete  = new KAction(i18n("Delete (If Exists)"), 0, p, SLOT(slotCurrentDelete()), ac, "dir_current_delete");
+
+   dirCurrentSyncDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing");
+   dirCurrentSyncCopyAToB = new KAction(i18n("Copy A to B"), 0, p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" );
+   dirCurrentSyncCopyBToA = new KAction(i18n("Copy B to A"), 0, p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" );
+   dirCurrentSyncDeleteA  = new KAction(i18n("Delete A"), 0, p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a");
+   dirCurrentSyncDeleteB  = new KAction(i18n("Delete B"), 0, p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b");
+   dirCurrentSyncDeleteAAndB  = new KAction(i18n("Delete A and B"), 0, p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b");
+   dirCurrentSyncMergeToA   = new KAction(i18n("Merge to A"), 0, p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a");
+   dirCurrentSyncMergeToB   = new KAction(i18n("Merge to B"), 0, p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b");
+   dirCurrentSyncMergeToAAndB   = new KAction(i18n("Merge to A and B"), 0, p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b");
+}
+
+
+void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible )
+{
+   dirStartOperation->setEnabled( bDirCompare );
+   dirRunOperationForCurrentItem->setEnabled( bDirCompare );
+   dirFoldAll->setEnabled( bDirCompare );
+   dirUnfoldAll->setEnabled( bDirCompare );
+
+   dirCompareCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected() );
+
+   dirMergeCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected()
+                                || bDiffWindowVisible );
+
+   dirRescan->setEnabled( bDirCompare );
+
+   dirAutoChoiceEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirDoNothingEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseAEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseBEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   dirChooseCEverywhere->setEnabled( bDirCompare &&  isVisible() );
+
+   bool bThreeDirs = m_dirC.isValid();
+
+   QListViewItem* lvi = currentItem();
+   DirMergeItem* pDMI = lvi==0 ? 0 : static_cast<DirMergeItem*>(lvi);
+   MergeFileInfos* pMFI = pDMI==0 ? 0 : pDMI->m_pMFI;
+
+   bool bItemActive = bDirCompare &&  isVisible() && pMFI!=0;//  &&  hasFocus();
+   bool bMergeMode = bThreeDirs || !m_bSyncMode;
+   bool bFTConflict = pMFI==0 ? false : conflictingFileTypes(*pMFI);
+
+   dirCurrentDoNothing->setEnabled( bItemActive && bMergeMode );
+   dirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC );
+   dirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict );
+   dirCurrentDelete->setEnabled( bItemActive && bMergeMode );
+
+   dirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode );
+   dirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   dirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   dirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB );
+   dirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   dirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   dirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+}
+
+
 #include "directorymergewindow.moc"
--- a/kdiff3/src/directorymergewindow.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/directorymergewindow.h	Tue Dec 09 20:29:43 2003 +0000
@@ -15,16 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/14 20:51:45  joachim99
- * Bugfix for Syncmode.
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #ifndef DIRECTORY_MERGE_WINDOW_H
 #define DIRECTORY_MERGE_WINDOW_H
 
@@ -44,6 +34,9 @@
 class DirectoryMergeInfo;
 class OneDirectoryInfo;
 class QLabel;
+class KAction;
+class KToggleAction;
+class KActionCollection;
 
 enum e_MergeOperation
 {
@@ -146,12 +139,17 @@
    bool isDirectoryMergeInProgress() { return m_bRealMergeStarted; }
    int totalColumnWidth();
    bool isSyncMode() { return m_bSyncMode; }
+   void initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac );
+   void updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible );
+
+   virtual void keyPressEvent( QKeyEvent* e );
 
 public slots:
-   void mergeContinue();
    void reload();
    void mergeCurrentFile();
    void compareCurrentFile();
+   void slotRunOperationForAllItems();
+   void slotRunOperationForCurrentItem();
    void mergeResultSaved(const QString& fileName);
    void slotChooseAEverywhere();
    void slotChooseBEverywhere();
@@ -160,8 +158,25 @@
    void slotNoOpEverywhere();
    void slotFoldAllSubdirs();
    void slotUnfoldAllSubdirs();
+   // Merge current item (merge mode)
+   void slotCurrentDoNothing();
+   void slotCurrentChooseA();
+   void slotCurrentChooseB();
+   void slotCurrentChooseC();
+   void slotCurrentMerge();
+   void slotCurrentDelete();
+   // Sync current item
+   void slotCurrentCopyAToB();
+   void slotCurrentCopyBToA();
+   void slotCurrentDeleteA();
+   void slotCurrentDeleteB();
+   void slotCurrentDeleteAAndB();
+   void slotCurrentMergeToA();
+   void slotCurrentMergeToB();
+   void slotCurrentMergeToAAndB();
 
 protected:
+   void mergeContinue( bool bStart, bool bVerbose );
    void resizeEvent(QResizeEvent* e);
    bool m_bAllowResizeEvents;
 
@@ -171,6 +186,8 @@
    friend class MergeFileInfos;
 
    bool canContinue();
+   void prepareMergeStart( QListViewItem* pBegin, QListViewItem* pEnd, bool bVerbose );
+   bool executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge );
 
    void scanDirectory( const QString& dirName, t_DirectoryList& dirList );
    void scanLocalDirectory( const QString& dirName, t_DirectoryList& dirList );
@@ -206,17 +223,49 @@
    bool m_bFollowFileLinks;
    bool m_bSimulatedMergeStarted;
    bool m_bRealMergeStarted;
-   bool m_bSingleFileOperationStarted;
    bool m_bError;
    bool m_bSyncMode;
    bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff.
 
    OptionDialog* m_pOptions;
    KIconLoader* m_pIconLoader;
-   DirMergeItem* m_pCurrentItemForOperation;
    StatusMessageBox* m_pStatusMessageBox;
    DirectoryMergeInfo* m_pDirectoryMergeInfo;
    StatusInfo* m_pStatusInfo;
+
+   typedef std::list<DirMergeItem*> MergeItemList;
+   MergeItemList m_mergeItemList;
+   MergeItemList::iterator m_currentItemForOperation;
+
+   KAction* dirStartOperation;
+   KAction* dirRunOperationForCurrentItem;
+   KAction* dirCompareCurrent;
+   KAction* dirMergeCurrent;
+   KAction* dirRescan;
+   KAction* dirChooseAEverywhere;
+   KAction* dirChooseBEverywhere;
+   KAction* dirChooseCEverywhere;
+   KAction* dirAutoChoiceEverywhere;
+   KAction* dirDoNothingEverywhere;
+   KAction* dirFoldAll;
+   KAction* dirUnfoldAll;
+
+   KAction* dirCurrentDoNothing;
+   KAction* dirCurrentChooseA;
+   KAction* dirCurrentChooseB;
+   KAction* dirCurrentChooseC;
+   KAction* dirCurrentMerge;
+   KAction* dirCurrentDelete;
+
+   KAction* dirCurrentSyncDoNothing;
+   KAction* dirCurrentSyncCopyAToB;
+   KAction* dirCurrentSyncCopyBToA;
+   KAction* dirCurrentSyncDeleteA;
+   KAction* dirCurrentSyncDeleteB;
+   KAction* dirCurrentSyncDeleteAAndB;
+   KAction* dirCurrentSyncMergeToA;
+   KAction* dirCurrentSyncMergeToB;
+   KAction* dirCurrentSyncMergeToAAndB;
 signals:
    void startDiffMerge(QString fn1,QString fn2, QString fn3, QString ofn, QString,QString,QString);
    void checkIfCanContinue( bool* pbContinue );
--- a/kdiff3/src/fileaccess.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/fileaccess.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -16,6 +16,7 @@
 #include <qlayout.h>
 #include <qlabel.h>
 #include <qapplication.h>
+#include <qpushbutton.h>
 #if QT_VERSION==230
 #else
 #include <qeventloop.h>
@@ -99,10 +100,19 @@
    //       (This is a Win95-bug which has been corrected only in WinNT/2000/XP.)
    if ( !name.isEmpty() )
    {
-      if ( m_url.isLocalFile() || !m_url.isValid() ) // assuming that malformed means relative
+      // FileAccess tries to detect if the given name is an URL or a local file.
+      // This is a problem if the filename looks like an URL (i.e. contains a colon ':').
+      // e.g. "file:f.txt" is a valid filename.
+      // Most of the time it is sufficient to check if the file exists locally.
+      // 2 Problems remain:
+      //   1. When the local file exists and the remote location is wanted nevertheless. (unlikely)
+      //   2. When the local file doesn't exist and should be written to.
+
+      bool bExistsLocal = QDir().exists(name);
+      if ( m_url.isLocalFile() || !m_url.isValid() || bExistsLocal ) // assuming that invalid means relative
       {
          QString localName = name;
-         if ( m_url.isLocalFile() && name.left(5).lower()=="file:" )
+         if ( !bExistsLocal && m_url.isLocalFile() && name.left(5).lower()=="file:" )
          {
             localName = m_url.path(); // I want the path without preceding "file:"
          }
@@ -145,14 +155,25 @@
          jh.stat(2/*all details*/, bWantToWrite); // returns bSuccess, ignored
 
          m_path = name;
+         m_bValidData = true; // After running stat() the variables are initialised
+                              // and valid even if the file doesn't exist and the stat
+                              // query failed.
       }
    }
 }
 
 void FileAccess::addPath( const QString& txt )
 {
-   m_url.addPath( txt );
-   setFile( m_url.url() );  // reinitialise
+   if ( m_url.isValid() )
+   {
+      m_url.addPath( txt );
+      setFile( m_url.url() );  // reinitialise
+   }
+   else
+   {
+      QString slash = (txt.isEmpty() || txt[0]=='/') ? "" : "/";
+      setFile( absFilePath() + slash + txt );
+   }
 }
 
 /*     Filetype:
@@ -540,7 +561,7 @@
 
    connect( pStatJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotStatResult(KIO::Job*)));
 
-   g_pProgressDialog->enterEventLoop();
+   g_pProgressDialog->enterEventLoop( pStatJob, i18n("Getting file status: %1").arg(m_pFileAccess->prettyAbsPath()) );
 
    return m_bSuccess;
 }
@@ -582,7 +603,7 @@
       connect( pJob, SIGNAL(data(KIO::Job*,const QByteArray &)), this, SLOT(slotGetData(KIO::Job*, const QByteArray&)));
       connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Reading file: %1").arg(m_pFileAccess->prettyAbsPath()) );
       return m_bSuccess;
    }
    else
@@ -618,7 +639,7 @@
       connect( pJob, SIGNAL(dataReq(KIO::Job*, QByteArray&)), this, SLOT(slotPutData(KIO::Job*, QByteArray&)));
       connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Writing file: %1").arg(m_pFileAccess->prettyAbsPath()) );
       return m_bSuccess;
    }
    else
@@ -681,7 +702,7 @@
       KIO::SimpleJob* pJob = KIO::mkdir( dirURL );
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Making directory: %1").arg(dirName) );
       return m_bSuccess;
    }
 }
@@ -701,7 +722,7 @@
       KIO::SimpleJob* pJob = KIO::rmdir( dirURL );
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop(pJob, i18n("Removing directory: %1").arg(dirName));
       return m_bSuccess;
    }
 }
@@ -716,7 +737,7 @@
       KIO::SimpleJob* pJob = KIO::file_delete( fileName, false );
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Removing file: %1").arg(fileName) );
       return m_bSuccess;
    }
 }
@@ -731,7 +752,8 @@
       KIO::CopyJob* pJob = KIO::link( linkTarget, linkLocation, false );
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob,
+         i18n("Creating symbolic link: %1 -> %2").arg(linkLocation).arg(linkTarget) );
       return m_bSuccess;
    }
 }
@@ -756,7 +778,8 @@
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
       connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
 
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob,
+         i18n("Renaming file: %1 -> %2").arg(m_pFileAccess->prettyAbsPath()).arg(dest) );
       return m_bSuccess;
    }
 }
@@ -790,7 +813,8 @@
       KIO::FileCopyJob* pJob = KIO::file_copy ( m_pFileAccess->m_url, destUrl.url(), permissions, bOverwrite, bResume, bShowProgress );
       connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
       connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
-      g_pProgressDialog->enterEventLoop();
+      g_pProgressDialog->enterEventLoop( pJob,
+         i18n("Copying file: %1 -> %2").arg(m_pFileAccess->prettyAbsPath()).arg(dest) );
 
       return m_bSuccess;
       // Note that the KIO-slave preserves the original date, if this is supported.
@@ -804,13 +828,13 @@
    bool bReadSuccess = srcFile.open( IO_ReadOnly );
    if ( bReadSuccess == false )
    {
-      m_pFileAccess->m_statusText = "Error during file copy operation: Opening file for reading failed. Filename: " + srcName;
+      m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for reading failed. Filename: %1").arg(srcName);
       return false;
    }
    bool bWriteSuccess = destFile.open( IO_WriteOnly );
    if ( bWriteSuccess == false )
    {
-      m_pFileAccess->m_statusText = "Error during file copy operation: Opening file for writing failed. Filename: " + destName;
+      m_pFileAccess->m_statusText = i18n("Error during file copy operation: Opening file for writing failed. Filename: %1").arg(destName);
       return false;
    }
 
@@ -825,7 +849,7 @@
       Q_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) );
       if ( readSize==-1 )
       {
-         m_pFileAccess->m_statusText = "Error during file copy operation: Reading failed. Filename: "+srcName;
+         m_pFileAccess->m_statusText = i18n("Error during file copy operation: Reading failed. Filename: %1").arg(srcName);
          return false;
       }
       srcSize -= readSize;
@@ -834,7 +858,7 @@
          Q_LONG writeSize = destFile.writeBlock( &buffer[0], readSize );
          if ( writeSize==-1 )
          {
-            m_pFileAccess->m_statusText = "Error during file copy operation: Writing failed. Filename: "+destName;
+            m_pFileAccess->m_statusText = i18n("Error during file copy operation: Writing failed. Filename: %1").arg(destName);
             return false;
          }
          readSize -= writeSize;
@@ -1190,7 +1214,8 @@
          // This line makes the transfer via fish unreliable.:-(
          //connect( pListJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
 
-         g_pProgressDialog->enterEventLoop();
+         g_pProgressDialog->enterEventLoop( pListJob,
+            i18n("Listing directory: %1").arg(m_pFileAccess->prettyAbsPath()) );
       }
    }
 
@@ -1259,75 +1284,6 @@
 }
 
 
-// Return value false means that the directory or some subdirectories
-// were not readable. Probably because of missing permissions.
-bool FileAccessJobHandler::scanLocalDirectory( const QString& dirName, t_DirectoryList* pDirList )
-{
-   bool bSuccess = true;
-   QDir dir( dirName );
-   g_pProgressDialog->setInformation( "Scanning directory: " + dirName, 0, false );
-
-   // First search subdirectorys
-   bool bHidden =  m_bFindHidden;
-   dir.setSorting( QDir::Name | QDir::DirsFirst );
-   dir.setFilter( QDir::Dirs | (bHidden ? QDir::Hidden : 0) );
-   dir.setMatchAllDirs( true );
-
-   const QFileInfoList *fiList = dir.entryInfoList();
-   if ( fiList == 0 )
-   {
-      // No Permission to read directory or other error.
-      return false;
-   }
-
-   QFileInfoListIterator it( *fiList );      // create list iterator
-
-   for ( ; it.current() != 0; ++it )       // for each file...
-   {
-      if ( g_pProgressDialog->wasCancelled() )
-         return true;
-
-      QFileInfo *fi = it.current();
-      if ( fi->isDir() )
-      {
-         if ( fi->fileName() == "." ||  fi->fileName()==".." ||
-            wildcardMultiMatch( m_dirAntiPattern, fi->fileName(), true/*case sensitive*/ ) )
-            continue;
-         else
-         {
-            if ( m_bRecursive )
-               if ( ! fi->isSymLink()  ||  m_bFollowDirLinks  )
-               {
-                  bool bLocalSuccess = scanLocalDirectory( fi->filePath(), pDirList );
-                  if ( ! bLocalSuccess )
-                     bSuccess = false;
-               }
-         }
-      }
-   }
-
-   dir.setFilter( QDir::Files | QDir::Dirs | (bHidden ? QDir::Hidden : 0) );
-   dir.setMatchAllDirs( true );
-   dir.setNameFilter( m_filePattern );
-
-   fiList = dir.entryInfoList();
-   it = *fiList;
-
-   QString sizeString;
-
-   for ( ; it.current() != 0; ++it )       // for each file...
-   {
-      QFileInfo* fi = it.current();
-
-      if ( fi->fileName() == "." ||  fi->fileName()==".."  ||
-           wildcardMultiMatch( fi->isDir() ? m_dirAntiPattern : m_fileAntiPattern, fi->fileName(), true/*case sensitive*/ ) )
-         continue;
-
-      pDirList->push_back( FileAccess( nicePath(*fi) ) );
-   }
-   return bSuccess;
-}
-
 void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l )
 {
    KURL parentUrl( m_pFileAccess->m_absFilePath );
@@ -1377,6 +1333,14 @@
    m_pSubProgressBar = new KProgress(1000, this);
    layout->addWidget( m_pSubProgressBar );
 
+   QHBoxLayout* hlayout = new QHBoxLayout( layout );
+   m_pSlowJobInfo = new QLabel( " ", this);
+   hlayout->addWidget( m_pSlowJobInfo );
+
+   m_pAbortButton = new QPushButton( i18n("Cancel"), this);
+   hlayout->addWidget( m_pAbortButton );
+   connect( m_pAbortButton, SIGNAL(clicked()), this, SLOT(slotAbort()) );
+
    m_dCurrent = 0.0;
    m_dSubMax = 1.0;
    m_dSubMin = 0.0;
@@ -1385,6 +1349,7 @@
    m_t1.start();
    m_t2.start();
    m_bWasCancelled = false;
+   m_pJob = 0;
 }
 
 
@@ -1439,8 +1404,12 @@
 void qt_enter_modal(QWidget*);
 void qt_leave_modal(QWidget*);
 
-void ProgressDialog::enterEventLoop()
+void ProgressDialog::enterEventLoop( KIO::Job* pJob, const QString& jobInfo )
 {
+   m_pJob = pJob;
+   m_currentJobInfo = jobInfo;
+   startTimer( 3000 ); /* 3 s delay */
+
    // instead of using exec() the eventloop is entered and exited often without hiding/showing the window.
 #if QT_VERSION==230
    //qApp->enter_loop();
@@ -1453,6 +1422,8 @@
 
 void ProgressDialog::exitEventLoop()
 {
+   killTimers();
+   m_pJob = 0;
 #if QT_VERSION==230
    //qApp->exit_loop();
 #else
@@ -1467,6 +1438,7 @@
       m_pProgressBar->setProgress( int( 1000.0 * m_dCurrent ) );
       m_pSubProgressBar->setProgress( int( 1000.0 * ( m_dSubCurrent * (m_dSubMax - m_dSubMin) + m_dSubMin ) ) );
       if ( !isVisible() ) show();
+      m_pSlowJobInfo->setText("");
       qApp->processEvents();
       m_t1.restart();
    }
@@ -1485,6 +1457,7 @@
 #include <qtimer.h>
 void ProgressDialog::show()
 {
+   killTimers();
    if ( !isVisible() )
    {
 #if QT_VERSION==230
@@ -1497,13 +1470,28 @@
 
 void ProgressDialog::hide()
 {
+   killTimers();
    // Calling QDialog::hide() directly doesn't always work. (?)
    QTimer::singleShot( 100, this, SLOT(delayedHide()) );
 }
 
 void ProgressDialog::delayedHide()
 {
+   if (m_pJob!=0)
+   {
+      m_pJob->kill(false);
+      m_pJob = 0;
+   }
    QDialog::hide();
+   m_pInformation->setText( "" );
+   m_dSubCurrent = 0;
+   m_dSubMin = 0;
+   m_dSubMax = 1;
+   m_dCurrent = 0;
+   m_pProgressBar->setProgress( 0 );
+   m_pSubProgressBar->setProgress( 0 );
+   m_pSubInformation->setText("");
+   m_pSlowJobInfo->setText("");
 }
 
 void ProgressDialog::reject()
@@ -1512,6 +1500,11 @@
    QDialog::reject();
 }
 
+void ProgressDialog::slotAbort()
+{
+   reject();
+}
+
 bool ProgressDialog::wasCancelled()
 {
    if( m_t2.elapsed()>100 )
@@ -1533,5 +1526,14 @@
    m_dSubCurrent = 0;
 }
 
+void ProgressDialog::timerEvent(QTimerEvent*)
+{
+   if( !isVisible() )
+   {
+      show();
+   }
+   m_pSlowJobInfo->setText( m_currentJobInfo );
+}
+
 
 #include "fileaccess.moc"
--- a/kdiff3/src/fileaccess.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/fileaccess.h	Tue Dec 09 20:29:43 2003 +0000
@@ -187,18 +187,22 @@
    void setSubRangeTransformation( double dMin, double dMax );
 
    void exitEventLoop();
-   void enterEventLoop();
+   void enterEventLoop( KIO::Job* pJob, const QString& jobInfo );
 
    void start();
 
    bool wasCancelled();
    void show();
    void hide();
+
+   virtual void timerEvent(QTimerEvent*);
 private:
    KProgress* m_pProgressBar;
    KProgress* m_pSubProgressBar;
    QLabel* m_pInformation;
    QLabel* m_pSubInformation;
+   QLabel* m_pSlowJobInfo;
+   QPushButton* m_pAbortButton;
    int m_maximum;
    double m_dCurrent;
    double m_dSubCurrent;
@@ -208,11 +212,13 @@
    QTime m_t1;
    QTime m_t2;
    bool m_bWasCancelled;
-
+   KIO::Job* m_pJob;
+   QString m_currentJobInfo;  // Needed if the job doesn't stop after a reasonable time.
 protected:
    virtual void reject();
 private slots:
    void delayedHide();
+   void slotAbort();
 };
 
 extern ProgressDialog* g_pProgressDialog;
--- a/kdiff3/src/kdiff3.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,15 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/11 12:45:25  joachim99
- * Allow CTRL-Tab for Windows
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include "diff.h"
 
 #include <iostream>
@@ -114,6 +105,9 @@
    m_bOutputModified = false;
    m_bTimerBlock = false;
 
+   // Needed before any file operations via FileAccess happen.
+   g_pProgressDialog = new ProgressDialog(this);
+
    // Option handling: Only when pParent==0 (no parent)
    KCmdLineArgs *args = isPart() ? 0 : KCmdLineArgs::parsedArgs();
 
@@ -147,14 +141,14 @@
       m_sd1.setFilename( args->getOption("base") );
       if ( m_sd1.isEmpty() )
       {
-         if ( args->count() > 0 ) m_sd1.setFilename( args->arg(0) );
-         if ( args->count() > 1 ) m_sd2.setFilename( args->arg(1) );
-         if ( args->count() > 2 ) m_sd3.setFilename( args->arg(2) );
+         if ( args->count() > 0 ) m_sd1.setFilename( args->url(0).url() ); // args->arg(0)
+         if ( args->count() > 1 ) m_sd2.setFilename( args->url(1).url() );
+         if ( args->count() > 2 ) m_sd3.setFilename( args->url(2).url() );
       }
       else
       {
-         if ( args->count() > 0 ) m_sd2.setFilename( args->arg(0) );
-         if ( args->count() > 1 ) m_sd3.setFilename( args->arg(1) );
+         if ( args->count() > 0 ) m_sd2.setFilename( args->url(0).url() );
+         if ( args->count() > 1 ) m_sd3.setFilename( args->url(1).url() );
       }
 
       QCStringList aliasList = args->getOptionList("fname");
@@ -163,7 +157,6 @@
       if ( ali != aliasList.end() ) { m_sd2.setAliasName(*ali); ++ali; }
       if ( ali != aliasList.end() ) { m_sd3.setAliasName(*ali); ++ali; }
    }
-   g_pProgressDialog = new ProgressDialog(this);
    ///////////////////////////////////////////////////////////////////
    // call inits to invoke all other construction parts
    initActions(actionCollection());
@@ -178,6 +171,12 @@
 
    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 );
+   showWhiteSpaceCharacters->setEnabled( m_pOptionDialog->m_bShowWhiteSpace );
+   showLineNumbers->setChecked( m_pOptionDialog->m_bShowLineNumbers );
+
    m_pMainSplitter = this; //new QSplitter(this);
    m_pMainSplitter->setOrientation( Vertical );
 //   setCentralWidget( m_pMainSplitter );
@@ -194,7 +193,7 @@
    connect( m_pDirectoryMergeWindow, SIGNAL(checkIfCanContinue(bool*)), this, SLOT(slotCheckIfCanContinue(bool*)));
    connect( m_pDirectoryMergeWindow, SIGNAL(updateAvailabilities()), this, SLOT(slotUpdateAvailabilities()));
 
-   initDirectoryMergeActions();
+   m_pDirectoryMergeWindow->initDirectoryMergeActions( this, actionCollection() );
 
    if ( args!=0 )  args->clear(); // Free up some memory.
 
@@ -294,7 +293,7 @@
          if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
             text += " - " + m_sd3.getAliasName() + "\n";
 
-         KMessageBox::sorry( this, text, i18n("File open error") );
+         KMessageBox::sorry( this, text, i18n("File Open Error") );
          bFileOpenError = true;
       }
 
@@ -313,7 +312,7 @@
    if (ac==0)   KMessageBox::error(0, "actionCollection==0");
 
    fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), ac);
-   fileOpen->setStatusText(i18n("Opens documents for comparison ..."));
+   fileOpen->setStatusText(i18n("Opens documents for comparison..."));
    fileSave = KStdAction::save(this, SLOT(slotFileSave()), ac);
    fileSave->setStatusText(i18n("Saves the merge result. All conflicts must be solved!"));
    fileSaveAs = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), ac);
@@ -337,7 +336,7 @@
    KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), ac);
    KAction* pAction = KStdAction::preferences(this, SLOT(slotConfigure()), ac );
    if ( isPart() )
-      pAction->setText("Configure KDiff3 ...");
+      pAction->setText(i18n("Configure KDiff3..."));
 
 
 #include "xpm/downend.xpm"
@@ -360,24 +359,33 @@
    goCurrent = new KAction(i18n("Go to Current Delta"), QIconSet(QPixmap(currentpos)), CTRL+Key_Space, this, SLOT(slotGoCurrent()), ac, "go_current");
    goTop = new KAction(i18n("Go to First Delta"), QIconSet(QPixmap(upend)), 0, this, SLOT(slotGoTop()), ac, "go_top");
    goBottom = new KAction(i18n("Go to Last Delta"), QIconSet(QPixmap(downend)), 0, this, SLOT(slotGoBottom()), ac, "go_bottom");
-   goPrevDelta = new KAction(i18n("Go to PrevDelta"), QIconSet(QPixmap(up1arrow)), CTRL+Key_Up, this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta");
-   goNextDelta = new KAction(i18n("Go to NextDelta"), QIconSet(QPixmap(down1arrow)), CTRL+Key_Down, this, SLOT(slotGoNextDelta()), ac, "go_next_delta");
+   goPrevDelta = new KAction(i18n("Go to Previous Delta"), QIconSet(QPixmap(up1arrow)), CTRL+Key_Up, this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta");
+   goNextDelta = new KAction(i18n("Go to Next Delta"), QIconSet(QPixmap(down1arrow)), CTRL+Key_Down, this, SLOT(slotGoNextDelta()), ac, "go_next_delta");
    goPrevConflict = new KAction(i18n("Go to Previous Conflict"), QIconSet(QPixmap(up2arrow)), CTRL+Key_PageUp, this, SLOT(slotGoPrevConflict()), ac, "go_prev_conflict");
    goNextConflict = new KAction(i18n("Go to Next Conflict"), QIconSet(QPixmap(down2arrow)), CTRL+Key_PageDown, this, SLOT(slotGoNextConflict()), ac, "go_next_conflict");
    goPrevUnsolvedConflict = new KAction(i18n("Go to Previous Unsolved Conflict"), QIconSet(QPixmap(prevunsolved)), 0, this, SLOT(slotGoPrevUnsolvedConflict()), ac, "go_prev_unsolved_conflict");
    goNextUnsolvedConflict = new KAction(i18n("Go to Next Unsolved Conflict"), QIconSet(QPixmap(nextunsolved)), 0, this, SLOT(slotGoNextUnsolvedConflict()), ac, "go_next_unsolved_conflict");
-   chooseA = new KToggleAction(i18n("Select line(s) from A"), QIconSet(QPixmap(iconA)), CTRL+Key_1, this, SLOT(slotChooseA()), ac, "merge_choose_a");
-   chooseB = new KToggleAction(i18n("Select line(s) from B"), QIconSet(QPixmap(iconB)), CTRL+Key_2, this, SLOT(slotChooseB()), ac, "merge_choose_b");
-   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");
-   showWhiteSpace = new KToggleAction(i18n("Show space and tabulator characters for differences"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_showwhitespace");
-   showLineNumbers = new KToggleAction(i18n("Show line numbers"), QIconSet(QPixmap(showlinenumbers)), 0, this, SLOT(slotShowLineNumbersToggled()), ac, "merge_showlinenumbers");
+   chooseA = new KToggleAction(i18n("Select Line(s) From A"), QIconSet(QPixmap(iconA)), CTRL+Key_1, this, SLOT(slotChooseA()), ac, "merge_choose_a");
+   chooseB = new KToggleAction(i18n("Select Line(s) From B"), QIconSet(QPixmap(iconB)), CTRL+Key_2, this, SLOT(slotChooseB()), ac, "merge_choose_b");
+   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");
+
+   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");
    chooseBEverywhere = new KAction(i18n("Choose B Everywhere"), CTRL+SHIFT+Key_2, this, SLOT(slotChooseBEverywhere()), ac, "merge_choose_b_everywhere");
    chooseCEverywhere = new KAction(i18n("Choose C Everywhere"), CTRL+SHIFT+Key_3, this, SLOT(slotChooseCEverywhere()), ac, "merge_choose_c_everywhere");
-   autoSolve = new KAction(i18n("Automatically solve simple conflicts"), 0, this, SLOT(slotAutoSolve()), ac, "merge_autosolve");
-   unsolve = new KAction(i18n("Set deltas to conflicts"), 0, this, SLOT(slotUnsolve()), actionCollection(), "merge_autounsolve");
-   fileReload  = new KAction(i18n("Reload"), /*QIconSet(QPixmap(reloadIcon)),*/ 0, this, SLOT(slotReload()), ac, "file_reload");
+   chooseAForUnsolvedConflicts = new KAction(i18n("Choose A For All Unsolved Conflicts"), 0, this, SLOT(slotChooseAForUnsolvedConflicts()), ac, "merge_choose_a_for_unsolved_conflicts");
+   chooseBForUnsolvedConflicts = new KAction(i18n("Choose B For All Unsolved Conflicts"), 0, this, SLOT(slotChooseBForUnsolvedConflicts()), ac, "merge_choose_b_for_unsolved_conflicts");
+   chooseCForUnsolvedConflicts = new KAction(i18n("Choose C For All Unsolved Conflicts"), 0, this, SLOT(slotChooseCForUnsolvedConflicts()), ac, "merge_choose_c_for_unsolved_conflicts");
+   chooseAForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose A For All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseAForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_a_for_unsolved_whitespace_conflicts");
+   chooseBForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose B For All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseBForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_b_for_unsolved_whitespace_conflicts");
+   chooseCForUnsolvedWhiteSpaceConflicts = new KAction(i18n("Choose C For All Unsolved Whitespace Conflicts"), 0, this, SLOT(slotChooseCForUnsolvedWhiteSpaceConflicts()), ac, "merge_choose_c_for_unsolved_whitespace_conflicts");
+   autoSolve = new KAction(i18n("Automatically Solve Simple Conflicts"), 0, this, SLOT(slotAutoSolve()), ac, "merge_autosolve");
+   unsolve = new KAction(i18n("Set Deltas to Conflicts"), 0, this, SLOT(slotUnsolve()), actionCollection(), "merge_autounsolve");
+   fileReload  = new KAction(i18n("Reload"), /*QIconSet(QPixmap(reloadIcon)),*/ Key_F5, this, SLOT(slotReload()), ac, "file_reload");
    showWindowA = new KToggleAction(i18n("Show Window A"), 0, this, SLOT(slotShowWindowAToggled()), ac, "win_show_a");
    showWindowB = new KToggleAction(i18n("Show Window B"), 0, this, SLOT(slotShowWindowBToggled()), ac, "win_show_b");
    showWindowC = new KToggleAction(i18n("Show Window C"), 0, this, SLOT(slotShowWindowCToggled()), ac, "win_show_c");
@@ -387,28 +395,10 @@
 #endif
    winFocusPrev = new KAction(i18n("Focus Prev Window"), ALT+Key_Left, this, SLOT(slotWinFocusPrev()), ac, "win_focus_prev");
    winToggleSplitOrientation = new KAction(i18n("Toggle Split Orientation"), 0, this, SLOT(slotWinToggleSplitterOrientation()), ac, "win_toggle_split_orientation");
-}
 
-void KDiff3App::initDirectoryMergeActions()
-{
-#include "xpm/startmerge.xpm"
-   //dirOpen = new KAction(i18n("Open directories ..."), 0, this, SLOT(slotDirOpen()), actionCollection(), "dir_open");
-   dirStartOperation = new KAction(i18n("Start/Continue directory merge"), Key_F5, m_pDirectoryMergeWindow, SLOT(mergeContinue()), actionCollection(), "dir_start_operation");
-   dirCompareCurrent = new KAction(i18n("Compare selected file"), 0, m_pDirectoryMergeWindow, SLOT(compareCurrentFile()), actionCollection(), "dir_compare_current");
-   dirMergeCurrent = new KAction(i18n("Merge current file"), QIconSet(QPixmap(startmerge)), 0, this, SLOT(slotMergeCurrentFile()), actionCollection(), "merge_current");
-   dirShowBoth = new KToggleAction(i18n("Dir and Text Split Screen View"), 0, this, SLOT(slotDirShowBoth()), actionCollection(), "win_dir_show_both");
+   dirShowBoth = new KToggleAction(i18n("Dir && Text Split Screen View"), 0, this, SLOT(slotDirShowBoth()), ac, "win_dir_show_both");
    dirShowBoth->setChecked( true );
-   dirViewToggle = new KAction(i18n("Toggle between Dir and Text View"), 0, this, SLOT(slotDirViewToggle()), actionCollection(), "win_dir_view_toggle");
-   dirFoldAll = new KAction(i18n("Fold all subdirs"), 0, m_pDirectoryMergeWindow, SLOT(slotFoldAllSubdirs()), actionCollection(), "dir_fold_all");
-   dirUnfoldAll = new KAction(i18n("Unfold all subdirs"), 0, m_pDirectoryMergeWindow, SLOT(slotUnfoldAllSubdirs()), actionCollection(), "dir_unfold_all");
-   dirRescan = new KAction(i18n("Rescan"), 0, m_pDirectoryMergeWindow, SLOT(reload()), actionCollection(), "dir_rescan");
-   dirChooseAEverywhere = new KAction(i18n("Choose A for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseAEverywhere()), actionCollection(), "dir_choose_a_everywhere");
-   dirChooseBEverywhere = new KAction(i18n("Choose B for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseBEverywhere()), actionCollection(), "dir_choose_b_everywhere");
-   dirChooseCEverywhere = new KAction(i18n("Choose C for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseCEverywhere()), actionCollection(), "dir_choose_c_everywhere");
-   dirAutoChoiceEverywhere = new KAction(i18n("Auto-choose operation for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotAutoChooseEverywhere()), actionCollection(), "dir_autochoose_everywhere");
-   dirDoNothingEverywhere = new KAction(i18n("No operation for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotNoOpEverywhere()), actionCollection(), "dir_nothing_everywhere");
-   // choose A/B/C/Suggestion/NoOp everywhere
-
+   dirViewToggle = new KAction(i18n("Toggle Between Dir && Text View"), 0, this, SLOT(slotDirViewToggle()), actionCollection(), "win_dir_view_toggle");
 
    m_pMergeEditorPopupMenu = new QPopupMenu( this );
    chooseA->plug( m_pMergeEditorPopupMenu );
@@ -416,6 +406,7 @@
    chooseC->plug( m_pMergeEditorPopupMenu );
 }
 
+
 void KDiff3App::showPopupMenu( const QPoint& point )
 {
    m_pMergeEditorPopupMenu->popup( point );
@@ -441,14 +432,6 @@
       if(toolBar("mainToolBar")!=0)
          config->writeEntry("ToolBarPos", (int) toolBar("mainToolBar")->barPos());
    }
-   m_pOptionDialog->m_bAutoAdvance = autoAdvance->isChecked();
-   m_pOptionDialog->m_bShowWhiteSpace = showWhiteSpace->isChecked();
-   m_pOptionDialog->m_bShowLineNumbers = showLineNumbers->isChecked();
-
-   if ( m_pDiffWindowSplitter!=0 )
-   {
-      m_pOptionDialog->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation()==Horizontal;
-   }
 
    m_pOptionDialog->saveOptions( config );
 }
@@ -498,7 +481,7 @@
    {
       int result = KMessageBox::warningYesNoCancel(this,
          i18n("The merge result hasn't been saved."),
-         i18n("Warning"), i18n("Save and quit"), i18n("Quit without saving") );
+         i18n("Warning"), i18n("Save && Quit"), i18n("Quit Without Saving") );
       if ( result==KMessageBox::Cancel )
          return false;
       else if ( result==KMessageBox::Yes )
@@ -518,7 +501,7 @@
    {
       int result = KMessageBox::warningYesNo(this,
          i18n("You are currently doing a directory merge. Are you sure, you want to abort?"),
-         i18n("Warning"), i18n("Yes - Quit"), i18n("No - Continue merging") );
+         i18n("Warning"), i18n("Quit"), i18n("Continue Merging") );
       if ( result!=KMessageBox::Yes )
          return false;
    }
@@ -558,7 +541,7 @@
 {
   slotStatusMsg(i18n("Saving file with a new filename..."));
 
-  QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save as...") ).url();
+  QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save As...") ).url();
   if(!s.isEmpty())
   {
      m_outputFilename = s;
@@ -659,7 +642,7 @@
    layout->addMultiCellWidget( m_pSearchString, line,line,0,1 );
    ++line;
 
-   m_pCaseSensitive = new QCheckBox(i18n("Case Sensitive"),this);
+   m_pCaseSensitive = new QCheckBox(i18n("Case sensitive"),this);
    layout->addWidget( m_pCaseSensitive, line, 1 );
 
    m_pSearchInA = new QCheckBox(i18n("Search A"),this);
@@ -677,16 +660,16 @@
    m_pSearchInC->setChecked( true );
    ++line;
 
-   m_pSearchInOutput = new QCheckBox(i18n("Search Output"),this);
+   m_pSearchInOutput = new QCheckBox(i18n("Search output"),this);
    layout->addWidget( m_pSearchInOutput, line, 0 );
    m_pSearchInOutput->setChecked( true );
    ++line;
-   
-   QPushButton* pButton = new QPushButton( i18n("Search"), this );
+
+   QPushButton* pButton = new QPushButton( i18n("&Search"), this );
    layout->addWidget( pButton, line, 0 );
    connect( pButton, SIGNAL(clicked()), this, SLOT(accept()));
 
-   pButton = new QPushButton( i18n("Cancel"), this );
+   pButton = new QPushButton( i18n("&Cancel"), this );
    layout->addWidget( pButton, line, 1 );
    connect( pButton, SIGNAL(clicked()), this, SLOT(reject()));
 
--- a/kdiff3/src/kdiff3.desktop	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3.desktop	Tue Dec 09 20:29:43 2003 +0000
@@ -2,14 +2,9 @@
 [Desktop Entry]
 Encoding=UTF-8
 Name=KDiff3
-Name[xx]=xxkdiff3xx
 Exec=kdiff3 %i %m -caption "%c"
 Icon=kdiff3
 Type=Application
 DocPath=kdiff3/kdiff3.html
-Comment=A KDE KPart Application
-Comment[hu]=KPart-alapú KDE-alkalmazás
-Comment[pt_BR]=Um Aplicativo KPart do KDE
-Comment[sv]=Ett KDE Kpart-program
-Comment[xx]=xxA KDE KPart Applicationxx
+Comment=A File And Directory Comparison And Merge Tool
 Terminal=0
--- a/kdiff3/src/kdiff3.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3.h	Tue Dec 09 20:29:43 2003 +0000
@@ -15,13 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #ifndef KDIFF3_H
 #define KDIFF3_H
 
@@ -158,20 +151,6 @@
 // Special KDiff3 specific stuff starts here
     KAction *editFind;
     KAction *editFindNext;
-    KAction *dirOpen;
-    KAction *dirStartOperation;
-    KAction *dirCompareCurrent;
-    KAction *dirMergeCurrent;
-    KToggleAction *dirShowBoth;
-    KAction *dirViewToggle;
-    KAction *dirRescan;
-    KAction* dirChooseAEverywhere;
-    KAction* dirChooseBEverywhere;
-    KAction* dirChooseCEverywhere;
-    KAction* dirAutoChoiceEverywhere;
-    KAction* dirDoNothingEverywhere;
-    KAction* dirFoldAll;
-    KAction* dirUnfoldAll;
 
     KAction *goCurrent;
     KAction *goTop;
@@ -186,11 +165,18 @@
     KToggleAction *chooseB;
     KToggleAction *chooseC;
     KToggleAction *autoAdvance;
+    KToggleAction *showWhiteSpaceCharacters;
     KToggleAction *showWhiteSpace;
     KToggleAction *showLineNumbers;
-    KAction *chooseAEverywhere;
-    KAction *chooseBEverywhere;
-    KAction *chooseCEverywhere;
+    KAction* chooseAEverywhere;
+    KAction* chooseBEverywhere;
+    KAction* chooseCEverywhere;
+    KAction* chooseAForUnsolvedConflicts;
+    KAction* chooseBForUnsolvedConflicts;
+    KAction* chooseCForUnsolvedConflicts;
+    KAction* chooseAForUnsolvedWhiteSpaceConflicts;
+    KAction* chooseBForUnsolvedWhiteSpaceConflicts;
+    KAction* chooseCForUnsolvedWhiteSpaceConflicts;
     KAction *autoSolve;
     KAction *unsolve;
     KToggleAction *showWindowA;
@@ -199,6 +185,8 @@
     KAction *winFocusNext;
     KAction *winFocusPrev;
     KAction* winToggleSplitOrientation;
+    KToggleAction *dirShowBoth;
+    KAction *dirViewToggle;
 
     QPopupMenu* m_pMergeEditorPopupMenu;
 
@@ -225,7 +213,7 @@
     Overview* m_pOverview;
 
     QWidget* m_pCornerWidget;
-    
+
     TotalDiffStatus m_totalDiffStatus;
 
     SourceData m_sd1;
@@ -273,7 +261,7 @@
    KParts::MainWindow*       m_pKDiff3Shell;
    bool m_bAuto;
 
-private slots:
+public slots:
    void resizeDiffTextWindow(int newWidth, int newHeight);
    void resizeMergeResultWindow();
 
@@ -307,6 +295,12 @@
    void slotChooseAEverywhere();
    void slotChooseBEverywhere();
    void slotChooseCEverywhere();
+   void slotChooseAForUnsolvedConflicts();
+   void slotChooseBForUnsolvedConflicts();
+   void slotChooseCForUnsolvedConflicts();
+   void slotChooseAForUnsolvedWhiteSpaceConflicts();
+   void slotChooseBForUnsolvedWhiteSpaceConflicts();
+   void slotChooseCForUnsolvedWhiteSpaceConflicts();
    void slotConfigure();
    void slotConfigureKeys();
    void slotRefresh();
--- a/kdiff3/src/kdiff3.pro	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3.pro	Tue Dec 09 20:29:43 2003 +0000
@@ -4,7 +4,8 @@
                   directorymergewindow.h fileaccess.h kdiff3_shell.h kdiff3_part.h
 SOURCES  = diff.cpp difftextwindow.cpp kdiff3.cpp main.cpp merger.cpp mergeresultwindow.cpp \
                   optiondialog.cpp pdiff.cpp directorymergewindow.cpp fileaccess.cpp \
-                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp
+                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp \
+                  gnudiff_analyze.cpp gnudiff_io.cpp gnudiff_xmalloc.cpp
 TARGET   = kdiff3
 INCLUDEPATH += . ./kreplacements
 
--- a/kdiff3/src/kdiff3_part.rc	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3_part.rc	Tue Dec 09 20:29:43 2003 +0000
@@ -1,5 +1,5 @@
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="kdiff3_part" version="0.9.70">
+<kpartgui name="kdiff3_part" version="9">
 <MenuBar>
   <Menu name="movement"><text>&amp;KDiff3</text>
     <Action name="go_top"/>
--- a/kdiff3/src/kdiff3_shell.rc	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3_shell.rc	Tue Dec 09 20:29:43 2003 +0000
@@ -1,11 +1,12 @@
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="kdiff3_shell" version="0.9.70">
+<kpartgui name="kdiff3_shell" version="9">
 <MenuBar>
   <Menu name="file"><text>&amp;File</text>
     <Action name="file_reload"/>
   </Menu>
   <Menu name="directory"><text>&amp;Directory</text>
     <Action name="dir_start_operation"/>
+    <Action name="dir_run_operation_for_current_item"/>
     <Action name="dir_compare_current"/>
     <Action name="dir_rescan"/>
     <Action name="dir_fold_all"/>
@@ -15,6 +16,25 @@
     <Action name="dir_choose_c_everywhere"/>
     <Action name="dir_autochoose_everywhere"/>
     <Action name="dir_nothing_everywhere"/>
+    <Menu name="dir_current_merge_menu"><text>Current Item Merge Operation</text>
+       <Action name="dir_current_do_nothing"/>
+       <Action name="dir_current_choose_a"/>
+       <Action name="dir_current_choose_b"/>
+       <Action name="dir_current_choose_c"/>
+       <Action name="dir_current_merge"/>
+       <Action name="dir_current_delete"/>
+    </Menu>
+    <Menu name="dir_current_sync_menu"><text>Current Item Sync Operation</text>
+       <Action name="dir_current_sync_do_nothing"/>
+       <Action name="dir_current_sync_copy_a_to_b"/>
+       <Action name="dir_current_sync_copy_b_to_a"/>
+       <Action name="dir_current_sync_delete_a"/>
+       <Action name="dir_current_sync_delete_b"/>
+       <Action name="dir_current_sync_delete_a_and_b"/>
+       <Action name="dir_current_sync_merge_to_a"/>
+       <Action name="dir_current_sync_merge_to_b"/>
+       <Action name="dir_current_sync_merge_to_a_and_b"/>
+    </Menu>
   </Menu>
   <Menu name="movement"><text>&amp;Movement</text>
     <Action name="go_current"/>
@@ -36,10 +56,17 @@
     <Action name="merge_choose_a_everywhere"/>
     <Action name="merge_choose_b_everywhere"/>
     <Action name="merge_choose_c_everywhere"/>
+    <Action name="merge_choose_a_for_unsolved_conflicts"/>
+    <Action name="merge_choose_b_for_unsolved_conflicts"/>
+    <Action name="merge_choose_c_for_unsolved_conflicts"/>
+    <Action name="merge_choose_a_for_unsolved_whitespace_conflicts"/>
+    <Action name="merge_choose_b_for_unsolved_whitespace_conflicts"/>
+    <Action name="merge_choose_c_for_unsolved_whitespace_conflicts"/>
     <Action name="merge_autosolve"/>
     <Action name="merge_autounsolve"/>
-    <Action name="merge_showwhitespace"/>
     <Action name="merge_showlinenumbers"/>
+    <Action name="merge_show_whitespace_characters"/>
+    <Action name="merge_show_whitespace"/>
   </Menu>
   <Menu name="window"><text>&amp;Window</text>
     <Action name="win_focus_prev"/>
@@ -67,7 +94,7 @@
   <Action name="merge_choose_b"/>
   <Action name="merge_choose_c"/>
   <Action name="merge_autoadvance"/>
-  <Action name="merge_showwhitespace"/>
+  <Action name="merge_show_whitespace_characters"/>
   <Action name="merge_showlinenumbers"/>
 </ToolBar>
 </kpartgui>
--- a/kdiff3/src/kdiff3_tmake.pro	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3_tmake.pro	Tue Dec 09 20:29:43 2003 +0000
@@ -4,7 +4,8 @@
                   directorymergewindow.h fileaccess.h kdiff3_shell.h kdiff3_part.h
 SOURCES  = diff.cpp difftextwindow.cpp kdiff3.cpp main.cpp merger.cpp mergeresultwindow.cpp \
                   optiondialog.cpp pdiff.cpp directorymergewindow.cpp fileaccess.cpp \
-                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp
+                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp \
+                  gnudiff_analyze.cpp gnudiff_io.cpp gnudiff_xmalloc.cpp
 TARGET		= kdiff3
 INCLUDEPATH	+= . ./kreplacements
 REQUIRES             = full-config
--- a/kdiff3/src/kdiff3part.desktop	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kdiff3part.desktop	Tue Dec 09 20:29:43 2003 +0000
@@ -1,8 +1,6 @@
 [Desktop Entry]
 Encoding=UTF-8
 Name=KDiff3Part
-Name[sv]=kdiff3-del
-Name[xx]=xxkdiff3Partxx
 MimeType=text/x-diff
 ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
 X-KDE-Library=libkdiff3part
--- a/kdiff3/src/kreplacements/kreplacements.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,14 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/12 11:36:57  joachim99
- * Fix for finding documentation
- *
- * Revision 1.1  2003/10/06 18:48:54  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
 
 #include "kreplacements.h"
 
@@ -94,7 +86,7 @@
       else
       {
          QFileInfo prog( buf );
-         _spawnlp( _P_NOWAIT , prog.filePath(), prog.fileName(), (const char*)helpFile.absFilePath(), NULL );
+         _spawnlp( _P_NOWAIT , prog.filePath(), prog.fileName(), (const char*)("file:///"+helpFile.absFilePath()), NULL );
       }
 
    #else
@@ -291,6 +283,8 @@
    menuBar()->insertItem(tr("&Edit"), editMenu);
    directoryMenu = new QPopupMenu();
    menuBar()->insertItem(tr("&Directory"), directoryMenu);
+   dirCurrentItemMenu = 0;
+   dirCurrentSyncItemMenu = 0;
    movementMenu = new QPopupMenu();
    menuBar()->insertItem(tr("&Movement"), movementMenu);
    mergeMenu = new QPopupMenu();
@@ -616,7 +610,7 @@
 
 
 KAction::KAction(const QString& text, const QIconSet& icon, int accel,
- QWidget* receiver, const char* slot, KActionCollection* actionCollection,
+ QObject* receiver, const char* slot, KActionCollection* actionCollection,
  const QString& name, bool bToggle, bool bMenu
  )
 : QAction ( text, icon, text, accel, actionCollection->m_pMainWindow, name, bToggle )
@@ -637,6 +631,28 @@
    if (bMenu)
    {
       if( name[0]=='g')       addTo( p->movementMenu );
+      else if( name.left(16)=="dir_current_sync")
+	  {
+          if ( p->dirCurrentItemMenu==0 )
+		  {
+			p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current &Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+		  }
+		  addTo( p->dirCurrentItemMenu );
+	  }
+      else if( name.left(11)=="dir_current")
+	  {
+          if ( p->dirCurrentItemMenu==0 )
+		  {
+			p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current &Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+		  }
+		  addTo( p->dirCurrentSyncItemMenu );
+	  }
       else if( name[0]=='d')  addTo( p->directoryMenu );
       else if( name[0]=='f')  addTo( p->fileMenu );
       else if( name[0]=='w')  addTo( p->windowsMenu );
@@ -645,7 +661,7 @@
 }
 
 KAction::KAction(const QString& text, int accel,
- QWidget* receiver, const char* slot, KActionCollection* actionCollection,
+ QObject* receiver, const char* slot, KActionCollection* actionCollection,
  const QString& name, bool bToggle, bool bMenu
  )
 : QAction ( text, text, accel, actionCollection->m_pMainWindow, name, bToggle )
@@ -663,6 +679,28 @@
    if (bMenu)
    {
       if( name[0]=='g') addTo( p->movementMenu );
+      else if( name.left(16)=="dir_current_sync")
+	  {
+          if ( p->dirCurrentItemMenu==0 )
+		  {
+			p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current &Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+		  }
+		  addTo( p->dirCurrentItemMenu );
+	  }
+      else if( name.left(11)=="dir_current")
+	  {
+          if ( p->dirCurrentItemMenu==0 )
+		  {
+			p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current &Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(tr("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+		  }
+		  addTo( p->dirCurrentSyncItemMenu );
+	  }
       else if( name[0]=='d')  addTo( p->directoryMenu );
       else if( name[0]=='f')  addTo( p->fileMenu );
       else if( name[0]=='w')  addTo( p->windowsMenu );
@@ -680,13 +718,13 @@
 }
 
 
-KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
-: KAction( text, icon, accel, parent, slot, actionCollection, name, true, bMenu)
+KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
+: KAction( text, icon, accel, receiver, slot, actionCollection, name, true, bMenu)
 {
 }
 
-KToggleAction::KToggleAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
-: KAction( text, accel, parent, slot, actionCollection, name, true, bMenu)
+KToggleAction::KToggleAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
+: KAction( text, accel, receiver, slot, actionCollection, name, true, bMenu)
 {
 }
 
@@ -941,7 +979,7 @@
    s_homepage = homepage;
 }
 
-KAboutData::KAboutData( const QString& /*name*/, const QString& appName, const QString& version )
+KAboutData::KAboutData( const QString& /*name*/, const QString& /*appName*/, const QString& /*version*/ )
 {
 }
 
@@ -969,7 +1007,7 @@
 
 KCmdLineArgs* KCmdLineArgs::parsedArgs()  // static
 {
-   return &s_cmdLineArgs;   
+   return &s_cmdLineArgs;
 }
 
 void KCmdLineArgs::init( int argc, char**argv, KAboutData* )  // static
--- a/kdiff3/src/kreplacements/kreplacements.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.h	Tue Dec 09 20:29:43 2003 +0000
@@ -17,8 +17,8 @@
 
 /***************************************************************************
  * $Log$
- * Revision 1.1  2003/10/06 18:48:54  joachim99
- * KDiff3 version 0.9.70
+ * Revision 1.2  2003/12/09 20:26:39  joachim99
+ * 0.9.80
  *
  ***************************************************************************/
 
@@ -178,6 +178,8 @@
    QPopupMenu* fileMenu;
    QPopupMenu* editMenu;
    QPopupMenu* directoryMenu;
+   QPopupMenu* dirCurrentItemMenu;
+   QPopupMenu* dirCurrentSyncItemMenu;
    QPopupMenu* movementMenu;
    QPopupMenu* mergeMenu;
    QPopupMenu* windowsMenu;
@@ -231,8 +233,8 @@
 class KAction : public QAction
 {
 public:
-   KAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
-   KAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
+   KAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
+   KAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
    void setStatusText(const QString&);
    void plug(QPopupMenu*);
 };
@@ -240,8 +242,8 @@
 class KToggleAction : public KAction
 {
 public:
-   KToggleAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
-   KToggleAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
+   KToggleAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
+   KToggleAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
    KToggleAction(const QString& text, const QIconSet& icon, int accel, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
    void setChecked(bool);
    bool isChecked();
@@ -332,6 +334,7 @@
 
    int count();
    QString arg(int);
+   KURL url(int i){ return KURL(arg(i)); }
    void clear();
    QString getOption(const QString&);
    QCStringList getOptionList( const QString& );
@@ -391,6 +394,7 @@
    class Job : public QObject
    {
    public:
+      void kill(bool){}
       bool error() {return false;}
       void showErrorDialog( QWidget* ) {}
    };
--- a/kdiff3/src/main.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/main.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,20 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.3  2003/10/14 20:50:46  joachim99
- * Fix for a warning concerning VERSION
- *
- * Revision 1.2  2003/10/07 08:41:06  friseb123
- * Placing the version into a separate include: version.h
- * version.c extract the version number
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #include <kcmdlineargs.h>
 #include <kaboutdata.h>
 #include <klocale.h>
--- a/kdiff3/src/merger.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/merger.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,13 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #include "merger.h"
 #include <assert.h>
 #include <iostream>
--- a/kdiff3/src/merger.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/merger.h	Tue Dec 09 20:29:43 2003 +0000
@@ -15,15 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/11 12:52:28  joachim99
- * Line endings corrected
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #ifndef MERGER_H
 #define MERGER_H
 
--- a/kdiff3/src/mergeresultwindow.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/mergeresultwindow.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,15 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/11 12:48:31  joachim99
- * Avoid QWidget::setFont() in paintEvent()
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include "diff.h"
 #include <stdio.h>
 #include <qpainter.h>
@@ -118,7 +109,6 @@
    update();
 }
 
-const int A=1, B=2, C=3;
 
 // Calculate the merge information for the given Diff3Line.
 // Results will be stored in mergeDetails, bConflict, bLineRemoved and src.
@@ -238,6 +228,8 @@
 {
    if ( ml1.bConflict && ml2.bConflict )
    {
+      // Both lines have conflicts: If one is only a white space conflict and
+      // the other one is a real conflict, then this line returns false.
       return ml1.id3l->bAEqC == ml2.id3l->bAEqC && ml1.id3l->bAEqB == ml2.id3l->bAEqB;
    }
    else
@@ -247,59 +239,85 @@
          );
 }
 
-void MergeResultWindow::merge(bool bAutoSolve, int defaultSelector)
-{   
-   if(m_bModified)
+void MergeResultWindow::merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly, bool bWhiteSpaceOnly )
+{
+   if ( !bConflictsOnly )
    {
-      int result = KMessageBox::warningYesNo(this,
-         i18n("The output has been modified.\n"
-              "If you continue your changes will be lost."),
-         i18n("Warning"), i18n("Continue"), i18n("Cancel"));
-      if ( result==KMessageBox::No )
-         return;
-   }
-   
-   m_mergeLineList.clear();
-   int lineIdx = 0;
-   Diff3LineList::const_iterator it;
-   for( it=m_pDiff3LineList->begin(); it!=m_pDiff3LineList->end(); ++it, ++lineIdx )
-   {
-      const Diff3Line& d = *it;
-
-      MergeLine ml;
-      bool bLineRemoved;
-      mergeOneLine( d, ml.mergeDetails, ml.bConflict, bLineRemoved, ml.srcSelect, m_pldC==0 );
-      
-      ml.d3lLineIdx   = lineIdx;
-      ml.bDelta       = ml.srcSelect != A;
-      ml.id3l         = it;
-      ml.srcRangeLength = 1;
-
-      MergeLine* back = m_mergeLineList.empty() ? 0 : &m_mergeLineList.back();
-
-      bool bSame = back!=0 && sameKindCheck( ml, *back );
-      if( bSame )
+      if(m_bModified)
       {
-         ++back->srcRangeLength;
-      }
-      else
-      {
-         m_mergeLineList.push_back( ml );
+         int result = KMessageBox::warningYesNo(this,
+            i18n("The output has been modified.\n"
+               "If you continue your changes will be lost."),
+            i18n("Warning"), i18n("C&ontinue"), i18n("&Cancel"));
+         if ( result==KMessageBox::No )
+            return;
       }
 
-      if ( ! ml.bConflict )
+      m_mergeLineList.clear();
+      int lineIdx = 0;
+      Diff3LineList::const_iterator it;
+      for( it=m_pDiff3LineList->begin(); it!=m_pDiff3LineList->end(); ++it, ++lineIdx )
       {
-         MergeLine& tmpBack = m_mergeLineList.back();
-         MergeEditLine mel;
-         mel.setSource( ml.srcSelect, ml.id3l, bLineRemoved );
-         tmpBack.mergeEditLineList.push_back(mel);
-      }
-      else if ( back==0  || ! back->bConflict || !bSame )
-      {
-         MergeLine& tmpBack = m_mergeLineList.back();
-         MergeEditLine mel;
-         mel.setConflict();
-         tmpBack.mergeEditLineList.push_back(mel);
+         const Diff3Line& d = *it;
+
+         MergeLine ml;
+         bool bLineRemoved;
+         mergeOneLine( d, ml.mergeDetails, ml.bConflict, bLineRemoved, ml.srcSelect, m_pldC==0 );
+
+         // Automatic solving for only whitespace changes.
+         if ( ml.bConflict &&
+              ( m_pldC==0 && (d.bAEqB || d.bWhiteLineA && d.bWhiteLineB)  ||
+                m_pldC!=0 && (d.bAEqB && d.bAEqC || d.bWhiteLineA && d.bWhiteLineB && d.bWhiteLineC ) ) )
+         {
+            ml.bWhiteSpaceConflict = true;
+         }
+
+         ml.d3lLineIdx   = lineIdx;
+         ml.bDelta       = ml.srcSelect != A;
+         ml.id3l         = it;
+         ml.srcRangeLength = 1;
+
+         MergeLine* back = m_mergeLineList.empty() ? 0 : &m_mergeLineList.back();
+
+         bool bSame = back!=0 && sameKindCheck( ml, *back );
+         if( bSame )
+         {
+            ++back->srcRangeLength;
+            if ( back->bWhiteSpaceConflict && !ml.bWhiteSpaceConflict )
+               back->bWhiteSpaceConflict = false;
+         }
+         else
+         {
+            if (back!=0  &&  back->bWhiteSpaceConflict )
+            {
+               if ( m_pldC==0 && m_pOptionDialog->m_whiteSpace2FileMergeDefault != 0 )  // Only two inputs
+               {
+                  back->srcSelect = m_pOptionDialog->m_whiteSpace2FileMergeDefault;
+                  back->bConflict = false;
+               }
+               else if ( m_pldC!=0 && m_pOptionDialog->m_whiteSpace3FileMergeDefault != 0 )
+               {
+                  back->srcSelect = m_pOptionDialog->m_whiteSpace3FileMergeDefault;
+                  back->bConflict = false;
+               }
+            }
+            m_mergeLineList.push_back( ml );
+         }
+
+         if ( ! ml.bConflict )
+         {
+            MergeLine& tmpBack = m_mergeLineList.back();
+            MergeEditLine mel;
+            mel.setSource( ml.srcSelect, ml.id3l, bLineRemoved );
+            tmpBack.mergeEditLineList.push_back(mel);
+         }
+         else if ( back==0  || ! back->bConflict || !bSame )
+         {
+            MergeLine& tmpBack = m_mergeLineList.back();
+            MergeEditLine mel;
+            mel.setConflict();
+            tmpBack.mergeEditLineList.push_back(mel);
+         }
       }
    }
 
@@ -310,7 +328,8 @@
       for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt )
       {
          MergeLine& ml = *mlIt;
-         if ( ml.bDelta )
+         bool bConflict = ml.mergeEditLineList.empty() || ml.mergeEditLineList.begin()->isConflict();
+         if ( ml.bDelta && ( !bConflictsOnly || bConflict ) && (!bWhiteSpaceOnly || ml.bWhiteSpaceConflict ))
          {
             ml.mergeEditLineList.clear();
             if ( defaultSelector==-1 && ml.bDelta )
@@ -329,11 +348,11 @@
                {
                   MergeEditLine mel;
                   mel.setSource( defaultSelector, d3llit, false );
-                  
+
                   int srcLine = defaultSelector==1 ? d3llit->lineA :
                                 defaultSelector==2 ? d3llit->lineB :
                                 defaultSelector==3 ? d3llit->lineC : -1;
-                                
+
                   if ( srcLine != -1 )
                   {
                      ml.mergeEditLineList.push_back(mel);
@@ -389,7 +408,7 @@
    m_cursorYPos=0;
    m_firstLine = 0;
    m_firstColumn = 0;
-   
+
    m_bModified = false;
    updateAvailabilities();
    update();
@@ -440,12 +459,13 @@
 {
    assert( eDir==eUp || eDir==eDown );
    MergeLineList::iterator i = m_currentMergeLineIt;
+   bool bSkipWhiteConflicts = ! m_pOptionDialog->m_bShowWhiteSpace;
    if( eEndPoint==eEnd )
    {
       if (eDir==eUp) i = m_mergeLineList.begin();     // first mergeline
       else           i = --m_mergeLineList.end();     // last mergeline
 
-      while ( ! i->bDelta   &&   i!=m_mergeLineList.end() )
+      while ( i!=m_mergeLineList.end() && ! i->bDelta )
       {
          if ( eDir==eUp )  ++i;                       // search downwards
          else              --i;                       // search upwards
@@ -458,18 +478,18 @@
          if ( eDir==eUp )  --i;
          else              ++i;
       }
-      while ( i->bDelta == false  &&  i!=m_mergeLineList.end() );
+      while ( i!=m_mergeLineList.end() && ( i->bDelta == false || bSkipWhiteConflicts && i->bWhiteSpaceConflict ) );
    }
-   else if ( eEndPoint == eConflict  &&  i!=m_mergeLineList.end())
+   else if ( eEndPoint == eConflict  &&  i!=m_mergeLineList.end() )
    {
       do
       {
          if ( eDir==eUp )  --i;
          else              ++i;
       }
-      while ( i->bConflict == false  &&  i!=m_mergeLineList.end() );
+      while ( i!=m_mergeLineList.end() && (i->bConflict == false || bSkipWhiteConflicts && i->bWhiteSpaceConflict ) );
    }
-   else if ( eEndPoint == eUnsolvedConflict  &&  i!=m_mergeLineList.end())
+   else if ( i!=m_mergeLineList.end()  &&  eEndPoint == eUnsolvedConflict )
    {
       do
       {
@@ -484,22 +504,24 @@
 
 bool MergeResultWindow::isDeltaAboveCurrent()
 {
+   bool bSkipWhiteConflicts = ! m_pOptionDialog->m_bShowWhiteSpace;
    MergeLineList::iterator i = m_currentMergeLineIt;
    --i;
    for( ; i!=m_mergeLineList.end(); --i )
    {
-      if ( i->bDelta ) return true;
+      if ( i->bDelta && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true;
    }
    return false;
 }
 
 bool MergeResultWindow::isDeltaBelowCurrent()
 {
+   bool bSkipWhiteConflicts = ! m_pOptionDialog->m_bShowWhiteSpace;
    MergeLineList::iterator i = m_currentMergeLineIt;
    ++i;
    for( ; i!=m_mergeLineList.end(); ++i )
    {
-      if ( i->bDelta ) return true;
+      if ( i->bDelta && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true;
    }
    return false;
 }
@@ -770,40 +792,12 @@
    emit updateAvailabilities();
 }
 
-void MergeResultWindow::slotChooseA()
-{
-   choose( A );
-}
-
-void MergeResultWindow::slotChooseB()
-{
-   choose( B );
-}
-
-void MergeResultWindow::slotChooseC()
-{
-   choose( C );
-}
-void MergeResultWindow::slotChooseAEverywhere()
+// bConflictsOnly: automatically choose for conflicts only (true) or for everywhere (false)
+void MergeResultWindow::chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly )
 {
    resetSelection();
-   merge( false, A );
-   emit modified();
-   update();
-}
 
-void MergeResultWindow::slotChooseBEverywhere()
-{
-   resetSelection();
-   merge( false, B );
-   emit modified();
-   update();
-}
-
-void MergeResultWindow::slotChooseCEverywhere()
-{
-   resetSelection();
-   merge( false, C );
+   merge( false, selector, bConflictsOnly, bWhiteSpaceOnly );
    emit modified();
    update();
 }
@@ -980,7 +974,7 @@
          if ( lengthInLine < int(s.length()) )
          {                                // Draw a normal line first
             p.setPen( m_pOptionDialog->m_fgColor );
-            p.drawText( xOffset, yOffset+fontAscent,  QString::fromUtf8( s.mid(m_firstColumn) ) );
+            p.drawText( xOffset, yOffset+fontAscent,  decodeString( s.mid(m_firstColumn),m_pOptionDialog) );
          }
          int firstPosInLine2 = max2( firstPosInLine, m_firstColumn );
          int lengthInLine2 = max2(0,lastPosInLine - firstPosInLine2);
@@ -994,12 +988,12 @@
 
          p.setPen( colorGroup().highlightedText() );
          p.drawText( xOffset + fontWidth*(firstPosInLine2-m_firstColumn), yOffset+fontAscent,
-            QString::fromUtf8( s.mid(firstPosInLine2,lengthInLine2) ) );
+            decodeString( s.mid(firstPosInLine2,lengthInLine2), m_pOptionDialog ) );
       }
       else
       {
          p.setPen( m_pOptionDialog->m_fgColor );
-         p.drawText( xOffset, yOffset+fontAscent, QString::fromUtf8( s.mid(m_firstColumn) ) );
+         p.drawText( xOffset, yOffset+fontAscent, decodeString( s.mid(m_firstColumn), m_pOptionDialog ) );
       }
 
       p.setPen( m_pOptionDialog->m_fgColor );
@@ -1405,6 +1399,7 @@
     scroll( 0, min2(d, getNofVisibleLines()) );
 }
 
+
 void MergeResultWindow::keyPressEvent( QKeyEvent* e )
 {
    int y = m_cursorYPos;
@@ -1961,7 +1956,7 @@
       KMessageBox::error( this,
          i18n("Not all conflicts are solved yet.\n"
               "File not saved.\n"),
-         i18n("There are conflicts left."));
+         i18n("Conflicts Left"));
       return false;
    }
 
@@ -1973,7 +1968,7 @@
       bool bSuccess = file.createBackup(".orig");
       if ( !bSuccess )
       {
-         KMessageBox::error( this, file.getStatusText() + i18n("\n\nFile not saved."), i18n("File save error.") );
+         KMessageBox::error( this, file.getStatusText() + i18n("\n\nFile not saved."), i18n("File Save Error") );
          return false;
       }
    }
@@ -2035,7 +2030,7 @@
    bool bSuccess = file.writeFile( dataArray.data(), neededBufferSize );
    if ( ! bSuccess )
    {
-      KMessageBox::error( this, i18n("Error while writing."), i18n("File save error.") );
+      KMessageBox::error( this, i18n("Error while writing."), i18n("File Save Error") );
       return false;
    }
    g_pProgressDialog->hide();
@@ -2109,6 +2104,12 @@
    update();
 }
 
+void Overview::slotRedraw()
+{
+   m_pixmap.resize( QSize(0,0) );   // make sure that a redraw happens
+   update();
+}
+
 void Overview::setRange( int firstLine, int pageHeight )
 {
    m_firstLine = firstLine;
@@ -2216,15 +2217,18 @@
             }
          }
 
-         // Make sure that lines with conflict are not overwritten.
-         if (  c == m_pOptions->m_colorForConflict )
+         if (!bWhiteSpaceChange || m_pOptions->m_bShowWhiteSpace )
          {
-            p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
-            oldConflictY = oldY;
-         }
-         else if ( c!=m_pOptions->m_bgColor  &&  oldY>oldConflictY )
-         {
-            p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
+            // Make sure that lines with conflict are not overwritten.
+            if (  c == m_pOptions->m_colorForConflict )
+            {
+               p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
+               oldConflictY = oldY;
+            }
+            else if ( c!=m_pOptions->m_bgColor  &&  oldY>oldConflictY )
+            {
+               p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
+            }
          }
 
          oldY = y;
--- a/kdiff3/src/optiondialog.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/optiondialog.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -18,15 +18,6 @@
  *
  */
 
-/***************************************************************************
- * $Log$
- * Revision 1.2  2003/10/11 13:59:39  joachim99
- * Use Courier New as default font under WIN32
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include <qcheckbox.h>
 #include <qcombobox.h>
 #include <qfont.h>
@@ -95,6 +86,26 @@
    bool m_bDefaultVal;
 };
 
+class OptionToggleAction : public OptionItem
+{
+public:
+   OptionToggleAction( bool bDefaultVal, const QString& saveName, bool* pbVar, OptionDialog* pOD )
+   : OptionItem( pOD, saveName )
+   {
+      m_pbVar = pbVar;
+      *m_pbVar = bDefaultVal;
+   }
+   void setToDefault(){}
+   void setToCurrent(){}
+   void apply()       {}
+   void write(KConfig* config){ config->writeEntry(m_saveName, *m_pbVar );   }
+   void read (KConfig* config){ *m_pbVar = config->readBoolEntry( m_saveName, *m_pbVar ); }
+private:
+   OptionToggleAction( const OptionToggleAction& ); // private copy constructor without implementation
+   bool* m_pbVar;
+};
+
+
 class OptionColorButton : public KColorButton, public OptionItem
 {
 public:
@@ -148,7 +159,7 @@
    {
       m_pVar = pVar;
       m_defaultVal = defaultVal;
-      QIntValidator* v = new QIntValidator(this);      
+      QIntValidator* v = new QIntValidator(this);
       v->setRange( rangeMin, rangeMax );
       setValidator( v );
    }
@@ -165,6 +176,27 @@
    int m_defaultVal;
 };
 
+class OptionComboBox : public QComboBox, public OptionItem
+{
+public:
+   OptionComboBox( int defaultVal, const QString& saveName, int* pVar,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+      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 ); }
+private:
+   OptionComboBox( const OptionIntEdit& ); // private copy constructor without implementation
+   int* m_pVar;
+   int m_defaultVal;
+};
 
 OptionDialog::OptionDialog( bool bShowDirMergeSettings, QWidget *parent, char *name )
   :KDialogBase( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel,
@@ -176,6 +208,7 @@
   setupColorPage();
   setupEditPage();
   setupDiffPage();
+  setupOtherOptions();
   if (bShowDirMergeSettings)
      setupDirectoryMergePage();
   //setupKeysPage();
@@ -189,14 +222,22 @@
 {
 }
 
+void OptionDialog::setupOtherOptions()
+{
+   new OptionToggleAction( false, "AutoAdvance", &m_bAutoAdvance, this );
+   new OptionToggleAction( true,  "ShowWhiteSpaceCharacters", &m_bShowWhiteSpaceCharacters, this );
+   new OptionToggleAction( true,  "ShowWhiteSpace", &m_bShowWhiteSpace, this );
+   new OptionToggleAction( false, "ShowLineNumbers", &m_bShowLineNumbers, this );
+   new OptionToggleAction( true,  "HorizDiffWindowSplitting", &m_bHorizDiffWindowSplitting, this );
+}
 
 void OptionDialog::setupFontPage( void )
 {
-   QFrame *page = addPage( i18n("Font"), i18n("Editor and diff output font" ),
+   QFrame *page = addPage( i18n("Font"), i18n("Editor & Diff Output Font" ),
                              BarIcon("fonts", KIcon::SizeMedium ) );
 
    QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
-   
+
    m_fontChooser = new KFontChooser( page,"font",true/*onlyFixed*/,QStringList(),false,6 );
    topLayout->addWidget( m_fontChooser );
 
@@ -204,7 +245,7 @@
    topLayout->addLayout( gbox );
    int line=0;
 
-   OptionCheckBox* pItalicDeltas = new OptionCheckBox( i18n("Italic Font For Deltas"), false, "ItalicForDeltas", &m_bItalicForDeltas, page, this );
+   OptionCheckBox* pItalicDeltas = new OptionCheckBox( i18n("Italic font for deltas"), false, "ItalicForDeltas", &m_bItalicForDeltas, page, this );
    gbox->addMultiCellWidget( pItalicDeltas, line, line, 0, 1 );
    QToolTip::add( pItalicDeltas, i18n(
       "Selects the italic version of the font for differences.\n"
@@ -215,7 +256,7 @@
 
 void OptionDialog::setupColorPage( void )
 {
-  QFrame *page = addPage( i18n("Color"), i18n("Colors in editor and diff output"),
+  QFrame *page = addPage( i18n("Color"), i18n("Colors in Editor & Diff Output"),
      BarIcon("colorize", KIcon::SizeMedium ) );
   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
 
@@ -269,7 +310,7 @@
   ++line;
 
   OptionColorButton* pColorForConflict = new OptionColorButton( red, "ColorForConflict", &m_colorForConflict, page, this );
-  label = new QLabel( pColorForConflict, i18n("Conflict Color:"), page );
+  label = new QLabel( pColorForConflict, i18n("Conflict color:"), page );
   gbox->addWidget( label, line, 0 );
   gbox->addWidget( pColorForConflict, line, 1 );
   ++line;
@@ -294,7 +335,7 @@
 
 void OptionDialog::setupEditPage( void )
 {
-   QFrame *page = addPage( i18n("Editor Settings"), i18n("Editor behaviour"),
+   QFrame *page = addPage( i18n("Editor"), i18n("Editor Behaviour"),
                            BarIcon("edit", KIcon::SizeMedium ) );
    QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
 
@@ -317,14 +358,14 @@
    gbox->addWidget( pTabSize, line, 1 );
    ++line;
 
-   OptionCheckBox* pAutoIndentation = new OptionCheckBox( i18n("Auto Indentation"), true, "AutoIndentation", &m_bAutoIndentation, page, this  );
+   OptionCheckBox* pAutoIndentation = new OptionCheckBox( i18n("Auto indentation"), true, "AutoIndentation", &m_bAutoIndentation, page, this  );
    gbox->addMultiCellWidget( pAutoIndentation, line, line, 0, 1 );
    QToolTip::add( pAutoIndentation, i18n(
       "On: The indentation of the previous line is used for a new line.\n"
       ));
    ++line;
 
-   OptionCheckBox* pAutoCopySelection = new OptionCheckBox( i18n("Auto Copy Selection"), false, "AutoCopySelection", &m_bAutoCopySelection, page, this );
+   OptionCheckBox* pAutoCopySelection = new OptionCheckBox( i18n("Auto copy selection"), false, "AutoCopySelection", &m_bAutoCopySelection, page, this );
    gbox->addMultiCellWidget( pAutoCopySelection, line, line, 0, 1 );
    QToolTip::add( pAutoCopySelection, i18n(
       "On: Any selection is immediately written to the clipboard.\n"
@@ -332,13 +373,20 @@
       ));
    ++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(
+      "Change this if non-ascii-characters aren't displayed correctly."
+      ));
+   ++line;
+
    topLayout->addStretch(10);
 }
 
 
 void OptionDialog::setupDiffPage( void )
 {
-   QFrame *page = addPage( i18n("Diff & Merge Settings"), i18n("Diff & Merge Settings"),
+   QFrame *page = addPage( i18n("Diff & Merge"), i18n("Diff & Merge Settings"),
                            BarIcon("misc", KIcon::SizeMedium ) );
    QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
 
@@ -346,94 +394,60 @@
    topLayout->addLayout( gbox );
    int line=0;
 
-   OptionCheckBox* pIgnoreWhiteSpace = new OptionCheckBox( i18n("Ignore white space"), true, "IgnoreWhiteSpace", &m_bIgnoreWhiteSpace, page, this );
-   gbox->addMultiCellWidget( pIgnoreWhiteSpace, line, line, 0, 1 );
-   QToolTip::add( pIgnoreWhiteSpace, i18n(
-      "On: Text that differs only in white space will match and\n"
-      "be shown on the same line in the different output windows.\n"
-      "Off is useful when whitespace is very important.\n"
-      "On is good for C/C++ and similar languages." )
+   QLabel* label=0;
+
+   OptionCheckBox* pPreserveCarriageReturn = new OptionCheckBox( i18n("Preserve carriage return"), false, "PreserveCarriageReturn", &m_bPreserveCarriageReturn, page, this );
+   gbox->addMultiCellWidget( pPreserveCarriageReturn, line, line, 0, 1 );
+   QToolTip::add( pPreserveCarriageReturn, i18n(
+      "Show carriage return characters '\\r' if they exist.\n"
+      "Helps to compare files that were modified under different operating systems.")
       );
    ++line;
 
-   OptionCheckBox* pPreserveCarriageReturn = new OptionCheckBox( i18n("Preserve Carriage Return"), false, "PreserveCarriageReturn", &m_bPreserveCarriageReturn, page, this );
-   gbox->addMultiCellWidget( pPreserveCarriageReturn, line, line, 0, 1 );
-   QToolTip::add( pPreserveCarriageReturn,
-      "Show carriage return characters '\\r' if they exist.\n"
-      "Helps to compare files that were modified under different operating systems."
+   OptionCheckBox* pIgnoreNumbers = new OptionCheckBox( i18n("Ignore numbers"), false, "IgnoreNumbers", &m_bIgnoreNumbers, page, this );
+   gbox->addMultiCellWidget( pIgnoreNumbers, line, line, 0, 1 );
+   QToolTip::add( pIgnoreNumbers, i18n(
+      "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n"
+      "Might help to compare files with numeric data.")
       );
    ++line;
 
-   OptionCheckBox* pIgnoreNumbers = new OptionCheckBox( i18n("Ignore Numbers"), false, "IgnoreNumbers", &m_bIgnoreNumbers, page, this );
-   gbox->addMultiCellWidget( pIgnoreNumbers, line, line, 0, 1 );
-   QToolTip::add( pIgnoreNumbers,
-      "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n"
-      "Might help to compare files with numeric data."
+   OptionCheckBox* pIgnoreComments = new OptionCheckBox( i18n("Ignore C/C++ Comments"), false, "IgnoreComments", &m_bIgnoreComments, page, this );
+   gbox->addMultiCellWidget( pIgnoreComments, line, line, 0, 1 );
+   QToolTip::add( pIgnoreComments, i18n( "Treat C/C++ comments like white space.")
       );
    ++line;
 
-   OptionCheckBox* pUpCase = new OptionCheckBox( i18n("Convert to Upper Case"), false, "UpCase", &m_bUpCase, page, this );
+   OptionCheckBox* pUpCase = new OptionCheckBox( i18n("Convert to upper case"), false, "UpCase", &m_bUpCase, page, this );
    gbox->addMultiCellWidget( pUpCase, line, line, 0, 1 );
-   QToolTip::add( pUpCase,
-      "Turn all lower case characters to upper case on reading. (e.g.: 'a'->'A')"
+   QToolTip::add( pUpCase, i18n(
+      "Turn all lower case characters to upper case on reading. (e.g.: 'a'->'A')")
       );
    ++line;
 
-   QLabel* label = new QLabel( i18n("Preprocessor-Command"), page );
+   label = new QLabel( i18n("Preprocessor command:"), page );
    gbox->addWidget( label, line, 0 );
    OptionLineEdit* pLE = new OptionLineEdit( "", "PreProcessorCmd", &m_PreProcessorCmd, page, this );
    gbox->addWidget( pLE, line, 1 );
    QToolTip::add( label, i18n("User defined pre-processing. (See the docs for details.)") );
    ++line;
 
-   label = new QLabel( i18n("Line-Matching Preprocessor-Command"), page );
+   label = new QLabel( i18n("Line-matching preprocessor command:"), page );
    gbox->addWidget( label, line, 0 );
    pLE = new OptionLineEdit( "", "LineMatchingPreProcessorCmd", &m_LineMatchingPreProcessorCmd, page, this );
    gbox->addWidget( pLE, line, 1 );
    QToolTip::add( label, i18n("This pre-processor is only used during line matching.\n(See the docs for details.)") );
    ++line;
 
-   OptionCheckBox* pUseExternalDiff = new OptionCheckBox( i18n("Use external diff"), true, "UseExternalDiff", &m_bUseExternalDiff, page, this );
-   gbox->addMultiCellWidget( pUseExternalDiff, line, line, 0, 1 );
-   QToolTip::add( pUseExternalDiff,
-      "Since for complicated files the internal algorithm is not so good yet,\n"
-      "you probably want to use the normal diff tool as line matcher."
+   OptionCheckBox* pTryHard = new OptionCheckBox( i18n("Try hard (slower)"), true, "TryHard", &m_bTryHard, page, this );
+   gbox->addMultiCellWidget( pTryHard, line, line, 0, 1 );
+   QToolTip::add( pTryHard, i18n(
+      "Enables the --minimal option for the external diff.\n"
+      "The analysis of big files will be much slower.")
       );
    ++line;
 
-   OptionCheckBox* pTryHard = new OptionCheckBox( i18n("Try Hard (slow)"), true, "TryHard", &m_bTryHard, page, this );
-   gbox->addMultiCellWidget( pTryHard, line, line, 0, 1 );
-   QToolTip::add( pTryHard,
-      "Enables the --minimal option for the external diff.\n"
-      "The analysis of big files will be much slower."
-      );
-   ++line;
-
-   OptionCheckBox* pIgnoreTrivialMatches = new OptionCheckBox( i18n("Ignore trivial matches"), true, "IgnoreTrivialMatches", &m_bIgnoreTrivialMatches, page, this );
-   gbox->addMultiCellWidget( pIgnoreTrivialMatches, line, line, 0, 1 );
-   QToolTip::add( pIgnoreTrivialMatches, i18n(
-      "When a difference was found, the algorithm searches for matching lines\n"
-      "Short or trivial lines match even when the differences still continue.\n"
-      "Ignoring trivial lines avoids this. Good for C/C++ and similar languages." )
-      );
-   ++line;
-
-   label = new QLabel( i18n("Max search length"), page );
-   gbox->addWidget( label, line, 0 );
-   OptionIntEdit* pMaxSearchLength = new OptionIntEdit( 1000, "MaxSearchLength", &m_maxSearchLength, 100, 100000, page, this );
-   gbox->addWidget( pMaxSearchLength, line, 1 );
-   QToolTip::add( label, i18n(
-      "Diff might fail for too small values but might take too long for big values.\n" )
-      );
-   ++line;
-
-   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pTryHard, SLOT(setEnabled(bool)));
-   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pMaxSearchLength, SLOT(setDisabled(bool)));
-
-   connect( pUseExternalDiff, SIGNAL( toggled(bool)), label, SLOT(setDisabled(bool)));
-   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pIgnoreTrivialMatches, SLOT(setDisabled(bool)));
-
-   label = new QLabel( i18n("Auto Advance Delay (ms)"), page );
+   label = new QLabel( i18n("Auto advance delay (ms):"), page );
    gbox->addWidget( label, line, 0 );
    OptionIntEdit* pAutoAdvanceDelay = new OptionIntEdit( 500, "AutoAdvanceDelay", &m_autoAdvanceDelay, 0, 2000, page, this );
    gbox->addWidget( pAutoAdvanceDelay, line, 1 );
@@ -443,12 +457,39 @@
       );
    ++line;
 
+   label = new QLabel( i18n("White space 2-file merge default:"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pWhiteSpace2FileMergeDefault = new OptionComboBox( 0, "WhiteSpace2FileMergeDefault", &m_whiteSpace2FileMergeDefault, page, this );
+   gbox->addWidget( pWhiteSpace2FileMergeDefault, line, 1 );
+   pWhiteSpace2FileMergeDefault->insertItem( i18n("Manual choice"), 0 );
+   pWhiteSpace2FileMergeDefault->insertItem( "A", 1 );
+   pWhiteSpace2FileMergeDefault->insertItem( "B", 2 );
+   QToolTip::add( pWhiteSpace2FileMergeDefault, i18n(
+      "Allow the merge algorithm to automatically select an input for "
+      "white-space-only changes." )
+      );
+   ++line;
+
+   label = new QLabel( i18n("White space 3-file merge default:"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pWhiteSpace3FileMergeDefault = new OptionComboBox( 0, "WhiteSpace3FileMergeDefault", &m_whiteSpace3FileMergeDefault, page, this );
+   gbox->addWidget( pWhiteSpace3FileMergeDefault, line, 1 );
+   pWhiteSpace3FileMergeDefault->insertItem( i18n("Manual choice"), 0 );
+   pWhiteSpace3FileMergeDefault->insertItem( "A", 1 );
+   pWhiteSpace3FileMergeDefault->insertItem( "B", 2 );
+   pWhiteSpace3FileMergeDefault->insertItem( "C", 3 );
+   QToolTip::add( pWhiteSpace3FileMergeDefault, i18n(
+      "Allow the merge algorithm to automatically select an input for "
+      "white-space-only changes." )
+      );
+   ++line;
+
    topLayout->addStretch(10);
 }
 
 void OptionDialog::setupDirectoryMergePage( void )
 {
-   QFrame *page = addPage( i18n("Directory Merge Settings"), i18n("Directory Merge"),
+   QFrame *page = addPage( i18n("Directory Merge"), i18n("Directory Merge"),
                            BarIcon("folder", KIcon::SizeMedium ) );
    QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
 
@@ -456,11 +497,11 @@
    topLayout->addLayout( gbox );
    int line=0;
 
-   OptionCheckBox* pRecursiveDirs = new OptionCheckBox( i18n("Recursive Directories"), true, "RecursiveDirs", &m_bDmRecursiveDirs, page, this );
+   OptionCheckBox* pRecursiveDirs = new OptionCheckBox( i18n("Recursive directories"), true, "RecursiveDirs", &m_bDmRecursiveDirs, page, this );
    gbox->addMultiCellWidget( pRecursiveDirs, line, line, 0, 1 );
    QToolTip::add( pRecursiveDirs, i18n("Whether to analyze subdirectories or not.") );
    ++line;
-   QLabel* label = new QLabel( i18n("File Pattern(s)"), page );
+   QLabel* label = new QLabel( i18n("File pattern(s):"), page );
    gbox->addWidget( label, line, 0 );
    OptionLineEdit* pFilePattern = new OptionLineEdit( "*", "FilePattern", &m_DmFilePattern, page, this );
    gbox->addWidget( pFilePattern, line, 1 );
@@ -471,7 +512,7 @@
       ));
    ++line;
 
-   label = new QLabel( i18n("File-Anti-Pattern(s)"), page );
+   label = new QLabel( i18n("File-anti-pattern(s):"), page );
    gbox->addWidget( label, line, 0 );
    OptionLineEdit* pFileAntiPattern = new OptionLineEdit( "*.orig;*.o", "FileAntiPattern", &m_DmFileAntiPattern, page, this );
    gbox->addWidget( pFileAntiPattern, line, 1 );
@@ -482,7 +523,7 @@
       ));
    ++line;
 
-   label = new QLabel( i18n("Dir-Anti-Pattern(s)"), page );
+   label = new QLabel( i18n("Dir-anti-pattern(s):"), page );
    gbox->addWidget( label, line, 0 );
    OptionLineEdit* pDirAntiPattern = new OptionLineEdit( "CVS;.deps", "DirAntiPattern", &m_DmDirAntiPattern, page, this );
    gbox->addWidget( pDirAntiPattern, line, 1 );
@@ -493,7 +534,7 @@
       ));
    ++line;
 
-   OptionCheckBox* pUseCvsIgnore = new OptionCheckBox( i18n("Use CVS-Ignore"), false, "UseCvsIgnore", &m_bDmUseCvsIgnore, page, this );
+   OptionCheckBox* pUseCvsIgnore = new OptionCheckBox( i18n("Use .cvsignore"), false, "UseCvsIgnore", &m_bDmUseCvsIgnore, page, this );
    gbox->addMultiCellWidget( pUseCvsIgnore, line, line, 0, 1 );
    QToolTip::add( pUseCvsIgnore, i18n(
       "Extends the antipattern to anything that would be ignored by CVS.\n"
@@ -501,7 +542,7 @@
       ));
    ++line;
 
-   OptionCheckBox* pFindHidden = new OptionCheckBox( i18n("Find Hidden Files and Directories"), true, "FindHidden", &m_bDmFindHidden, page, this );
+   OptionCheckBox* pFindHidden = new OptionCheckBox( i18n("Find hidden files and directories"), true, "FindHidden", &m_bDmFindHidden, page, this );
    gbox->addMultiCellWidget( pFindHidden, line, line, 0, 1 );
 #ifdef _WIN32
    QToolTip::add( pFindHidden, i18n("Finds files and directories with the hidden attribute.") );
@@ -510,7 +551,7 @@
 #endif
    ++line;
 
-   OptionCheckBox* pFollowFileLinks = new OptionCheckBox( i18n("Follow File Links"), false, "FollowFileLinks", &m_bDmFollowFileLinks, page, this );
+   OptionCheckBox* pFollowFileLinks = new OptionCheckBox( i18n("Follow file links"), false, "FollowFileLinks", &m_bDmFollowFileLinks, page, this );
    gbox->addMultiCellWidget( pFollowFileLinks, line, line, 0, 1 );
    QToolTip::add( pFollowFileLinks, i18n(
       "On: Compare the file the link points to.\n"
@@ -518,7 +559,7 @@
       ));
    ++line;
 
-   OptionCheckBox* pFollowDirLinks = new OptionCheckBox( i18n("Follow Directory Links"), false, "FollowDirLinks", &m_bDmFollowDirLinks, page, this );
+   OptionCheckBox* pFollowDirLinks = new OptionCheckBox( i18n("Follow directory links"), false, "FollowDirLinks", &m_bDmFollowDirLinks, page, this );
    gbox->addMultiCellWidget( pFollowDirLinks, line, line, 0, 1 );
    QToolTip::add( pFollowDirLinks,    i18n(
       "On: Compare the directory the link points to.\n"
@@ -532,14 +573,20 @@
                  "Files and directories without change will not appear in the list."));
    ++line;
 
-   OptionCheckBox* pTrustDate = new OptionCheckBox( i18n("Trust the modification date. (Unsafe)."), false, "TrustDate", &m_bDmTrustDate, page, this );
+   OptionCheckBox* pTrustDate = new OptionCheckBox( i18n("Trust the modification date (unsafe)"), false, "TrustDate", &m_bDmTrustDate, page, this );
    gbox->addMultiCellWidget( pTrustDate, line, line, 0, 1 );
    QToolTip::add( pTrustDate, i18n("Assume that files are equal if the modification date and file length are equal.\n"
                                      "Useful for big directories or slow networks.") );
    ++line;
 
+   OptionCheckBox* pTrustSize = new OptionCheckBox( i18n("Trust the size (unsafe)"), false, "TrustSize", &m_bDmTrustSize, page, this );
+   gbox->addMultiCellWidget( pTrustSize, line, line, 0, 1 );
+   QToolTip::add( pTrustSize, i18n("Assume that files are equal if their file lengths are equal.\n"
+                                   "Useful for big directories or slow networks when the date is modified during download.") );
+   ++line;
+
    // Some two Dir-options: Affects only the default actions.
-   OptionCheckBox* pSyncMode = new OptionCheckBox( i18n("Synchronize Directories."), false,"SyncMode", &m_bDmSyncMode, page, this );
+   OptionCheckBox* pSyncMode = new OptionCheckBox( i18n("Synchronize directories"), false,"SyncMode", &m_bDmSyncMode, page, this );
    gbox->addMultiCellWidget( pSyncMode, line, line, 0, 1 );
    QToolTip::add( pSyncMode, i18n(
                   "Offers to store files in both directories so that\n"
@@ -547,14 +594,14 @@
                   "Works only when comparing two directories without specifying a destination."  ) );
    ++line;
 
-   OptionCheckBox* pCopyNewer = new OptionCheckBox( i18n("Copy newer instead of merging. (Unsafe)."), false, "CopyNewer", &m_bDmCopyNewer, page, this );
+   OptionCheckBox* pCopyNewer = new OptionCheckBox( i18n("Copy newer instead of merging (unsafe)"), false, "CopyNewer", &m_bDmCopyNewer, page, this );
    gbox->addMultiCellWidget( pCopyNewer, line, line, 0, 1 );
    QToolTip::add( pCopyNewer, i18n(
                   "Don't look inside, just take the newer file.\n"
                   "(Use this only if you know what you are doing!)\n"
                   "Only effective when comparing two directories."  ) );
    ++line;
-                                               
+
    OptionCheckBox* pCreateBakFiles = new OptionCheckBox( i18n("Backup files (.orig)"), true, "CreateBakFiles", &m_bDmCreateBakFiles, page, this );
    gbox->addMultiCellWidget( pCreateBakFiles, line, line, 0, 1 );
    QToolTip::add( pCreateBakFiles, i18n(
@@ -590,8 +637,8 @@
          "Because this program doesn't handle variable width fonts\n"
          "correctly, you might experience problems while editing.\n\n"
          "Do you want to continue or do you want to select another font."),
-         i18n("Incompatible font."),
-         i18n("Continue at my own risk"), i18n("Select another font"));
+         i18n("Incompatible Font"),
+         i18n("Continue at Own Risk"), i18n("Select Another Font"));
       if (result==KMessageBox::No)
          return;
    }
@@ -637,11 +684,6 @@
 #else
    m_fontChooser->setFont( QFont("Courier", 10 ), true /*only fixed*/ );
 #endif
-
-   m_bAutoAdvance = false;
-   m_bShowWhiteSpace = true;
-   m_bShowLineNumbers = false;
-   m_bHorizDiffWindowSplitting = true;
 }
 
 /** Initialise the widgets using the values in the public varibles. */
@@ -671,11 +713,6 @@
    // FontConfigDlg
    config->writeEntry("Font",  m_font );
 
-   config->writeEntry("AutoAdvance", m_bAutoAdvance );
-   config->writeEntry("ShowWhiteSpace", m_bShowWhiteSpace );
-   config->writeEntry("ShowLineNumbers", m_bShowLineNumbers );
-   config->writeEntry("HorizDiffWindowSplitting", m_bHorizDiffWindowSplitting );
-
    // Recent files (selectable in the OpenDialog)
    config->writeEntry( "RecentAFiles", m_recentAFiles, '|' );
    config->writeEntry( "RecentBFiles", m_recentBFiles, '|' );
@@ -701,13 +738,6 @@
    // FontConfigDlg
    m_font = config->readFontEntry( "Font", &m_font);
 
-   // DiffConfigDlg
-
-   m_bAutoAdvance = config->readBoolEntry("AutoAdvance", m_bAutoAdvance );
-   m_bShowWhiteSpace = config->readBoolEntry("ShowWhiteSpace", m_bShowWhiteSpace );
-   m_bShowLineNumbers = config->readBoolEntry("ShowLineNumbers", m_bShowLineNumbers );
-   m_bHorizDiffWindowSplitting = config->readBoolEntry("HorizDiffWindowSplitting", m_bHorizDiffWindowSplitting);
-
    // Recent files (selectable in the OpenDialog)
    m_recentAFiles = config->readListEntry( "RecentAFiles", '|' );
    m_recentBFiles = config->readListEntry( "RecentBFiles", '|' );
--- a/kdiff3/src/optiondialog.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/optiondialog.h	Tue Dec 09 20:29:43 2003 +0000
@@ -18,13 +18,6 @@
  *
  */
 
-/***************************************************************************
- * $Log$
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- *                                                                   *
- ***************************************************************************/
-
 #ifndef OPTION_DIALOG_H
 #define OPTION_DIALOG_H
 
@@ -42,6 +35,7 @@
 class OptionItem;
 class KKeyDialog;
 
+
 class OptionDialog : public KDialogBase
 {
    Q_OBJECT
@@ -69,19 +63,20 @@
     bool m_bAutoIndentation;
     int  m_tabSize;
     bool m_bAutoCopySelection;
+    bool m_bStringEncoding;
 
-    bool m_bIgnoreTrivialMatches;
-    int  m_maxSearchLength;
     bool m_bPreserveCarriageReturn;
-    bool m_bUseExternalDiff;
     bool m_bTryHard;
+    bool m_bShowWhiteSpaceCharacters;
     bool m_bShowWhiteSpace;
     bool m_bShowLineNumbers;
     bool m_bHorizDiffWindowSplitting;
 
-    bool m_bIgnoreWhiteSpace;
+    int  m_whiteSpace2FileMergeDefault;
+    int  m_whiteSpace3FileMergeDefault;
     bool m_bUpCase;
     bool m_bIgnoreNumbers;
+    bool m_bIgnoreComments;
     QString m_PreProcessorCmd;
     QString m_LineMatchingPreProcessorCmd;
 
@@ -102,6 +97,7 @@
     bool m_bDmFindHidden;
     bool m_bDmCreateBakFiles;
     bool m_bDmTrustDate;
+    bool m_bDmTrustSize;
     bool m_bDmCopyNewer;
     bool m_bDmShowOnlyDeltas;
     bool m_bDmUseCvsIgnore;
@@ -124,9 +120,9 @@
 
 private:
     void resetToDefaults();
-    
+
     std::list<OptionItem*> m_optionItemList;
-    
+
     // FontConfigDlg
     KFontChooser *m_fontChooser;
 
@@ -137,6 +133,7 @@
     void setupDiffPage();
     void setupDirectoryMergePage();
     void setupKeysPage();
+    void setupOtherOptions();
 };
 
 
--- a/kdiff3/src/pdiff.cpp	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/pdiff.cpp	Tue Dec 09 20:29:43 2003 +0000
@@ -15,18 +15,6 @@
  *                                                                         *
  ***************************************************************************/
 
-/***************************************************************************
- * $Log$
- * Revision 1.3  2003/10/17 16:54:25  joachim99
- * Error-detection for diff-problems improved.
- *
- * Revision 1.2  2003/10/11 12:50:38  joachim99
- * KDiff3App::slotRefresh(): Call setFont() for subwindows
- *
- * Revision 1.1  2003/10/06 18:38:48  joachim99
- * KDiff3 version 0.9.70
- ***************************************************************************/
-
 #include "diff.h"
 #include "directorymergewindow.h"
 
@@ -67,6 +55,8 @@
 #include <unistd.h>
 #endif
 
+#include "gnudiff_diff.h"
+
 //using namespace std;
 
 int g_tabSize = 8;
@@ -111,8 +101,104 @@
 
 bool KDiff3App::runDiff( LineData* p1, int size1, LineData* p2, int size2, DiffList& diffList )
 {
+   g_pProgressDialog->setSubCurrent(0);
+
    diffList.clear();
-   //QString errorString;
+   if ( p1[0].pLine==0 || p2[0].pLine==0 )
+   {
+      Diff d( 0,0,0);
+      if ( p1[0].pLine==0 && p2[0].pLine==0 && size1 == size2 )
+         d.nofEquals = size1;
+      else if (p1[0].pLine!=0) d.diff1=size1;
+      else if (p2[0].pLine!=0) d.diff2=size2;
+
+      diffList.push_back(d);
+      return true;
+   }
+
+   GnuDiff::comparison comparisonInput;
+   memset( &comparisonInput, 0, sizeof(comparisonInput) );
+   comparisonInput.parent = 0;
+   comparisonInput.file[0].buffer = (word*)p1[0].pLine;//ptr to buffer
+   comparisonInput.file[0].buffered = p1[size1-1].pLine-p1[0].pLine+p1[size1-1].size; // size of buffer
+   comparisonInput.file[1].buffer = (word*)p2[0].pLine;//ptr to buffer
+   comparisonInput.file[1].buffered = p2[size2-1].pLine-p2[0].pLine+p2[size2-1].size; // size of buffer
+
+   GnuDiff::ignore_white_space = GnuDiff::IGNORE_ALL_SPACE;  // I think nobody needs anything else ...
+   GnuDiff::bIgnoreWhiteSpace = true;
+   GnuDiff::bIgnoreNumbers    = m_pOptionDialog->m_bIgnoreNumbers;
+   GnuDiff::minimal = m_pOptionDialog->m_bTryHard;
+   GnuDiff::ignore_case = false;  //  m_pOptionDialog->m_bUpCase is applied while reading.
+   GnuDiff::change* script = GnuDiff::diff_2_files( &comparisonInput );
+
+   int equalLinesAtStart =  comparisonInput.file[0].prefix_lines;
+   int currentLine1 = 0;
+   int currentLine2 = 0;
+   GnuDiff::change* p=0;
+   for (GnuDiff::change* e = script; e; e = p)
+   {
+      Diff d(0,0,0);
+      d.nofEquals = e->line0 - currentLine1;
+      assert( d.nofEquals == e->line1 - currentLine2 );
+      d.diff1 = e->deleted;
+      d.diff2 = e->inserted;
+      currentLine1 += d.nofEquals + d.diff1;
+      currentLine2 += d.nofEquals + d.diff2;
+      diffList.push_back(d);
+
+      p = e->link;
+      free (e);
+   }
+
+   if ( !diffList.empty() )
+   {
+      diffList.front().nofEquals += equalLinesAtStart;
+      currentLine1 += equalLinesAtStart;
+      currentLine2 += equalLinesAtStart;
+   }
+
+   if (size1-currentLine1==size2-currentLine2 )
+   {
+      Diff d( size1-currentLine1,0,0);
+      diffList.push_back(d);
+   }
+   else if ( !diffList.empty() )
+   {  // Only necessary for a files that end with a newline
+      int nofEquals = min2(size1-currentLine1,size2-currentLine2);
+      if ( nofEquals==0 )
+      {
+         diffList.back().diff1 += size1-currentLine1;
+         diffList.back().diff2 += size2-currentLine2;
+      }
+      else
+      {
+         Diff d( nofEquals,size1-currentLine1-nofEquals,size2-currentLine2-nofEquals);
+         diffList.push_back(d);
+      }
+   }
+
+#ifndef NDEBUG
+   // Verify difflist
+   {
+      int l1=0;
+      int l2=0;
+      DiffList::iterator i;
+      for( i = diffList.begin(); i!=diffList.end(); ++i )
+      {
+         l1+= i->nofEquals + i->diff1;
+         l2+= i->nofEquals + i->diff2;
+      }
+
+      //if( l1!=p1-p1start || l2!=p2-p2start )
+      if( l1!=size1 || l2!=size2 )
+         assert( false );
+   }
+#endif
+
+   g_pProgressDialog->setSubCurrent(1.0);
+
+   return true;
+#if 0
 
    if ( m_pOptionDialog->m_bUseExternalDiff )
    {
@@ -285,10 +371,10 @@
             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("KDiff3 Warning"));
+            i18n("Warning"));
          m_pOptionDialog->m_bUseExternalDiff = false;
       }
-      
+
       FileAccess::removeFile( fileName1 );
       FileAccess::removeFile( fileName2 );
       FileAccess::removeFile( fileNameOut );
@@ -314,6 +400,7 @@
       g_pProgressDialog->setSubCurrent(1.0);
    }
    return true;
+#endif
 }
 
 
@@ -327,12 +414,10 @@
       bPreserveCarriageReturn = false;
    }
 
-   g_bIgnoreWhiteSpace = m_pOptionDialog->m_bIgnoreWhiteSpace;
-   g_bIgnoreTrivialMatches = m_pOptionDialog->m_bIgnoreTrivialMatches;
-
    m_diff3LineList.clear();
 
-   bool bUseLineMatchingPP = !m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty();
+   bool bUseLineMatchingPP = !m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty() ||
+                             m_pOptionDialog->m_bIgnoreComments;
    bool bUpCase = m_pOptionDialog->m_bUpCase;
 
    if (m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed( false );
@@ -351,16 +436,15 @@
    // 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_sdlm1.readLMPPFile( &m_sd1, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
    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_sdlm2.readLMPPFile( &m_sd2, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
    g_pProgressDialog->step();
 
    m_sd3.m_bIsText = true;
-   int maxSearchLength = m_pOptionDialog->m_maxSearchLength;
    m_totalDiffStatus.reset();
    // Run the diff.
    if ( m_sd3.isEmpty() )
@@ -376,7 +460,7 @@
 
       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], maxSearchLength, m_totalDiffStatus.bTextAEqB );
+      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;
 
       g_pProgressDialog->step();
@@ -385,7 +469,7 @@
    {
       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_sdlm3.readLMPPFile( &m_sd3, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase, m_pOptionDialog->m_bIgnoreComments );
       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);
@@ -428,13 +512,13 @@
       debugLineCheck( m_diff3LineList, m_sd3.m_vSize, 3 );
 
       g_pProgressDialog->setInformation(i18n("Linediff: A <-> B"));
-      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], maxSearchLength, m_totalDiffStatus.bTextAEqB );
+      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], 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], maxSearchLength, m_totalDiffStatus.bTextBEqC );
+      fineDiff( m_diff3LineList, 2, &m_sd2.m_v[0], &m_sd3.m_v[0], 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], maxSearchLength, m_totalDiffStatus.bTextAEqC );
+      fineDiff( m_diff3LineList, 3, &m_sd3.m_v[0], &m_sd1.m_v[0], 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; }
@@ -522,7 +606,7 @@
          "Continue at your own risk.") );
 /*      QDialog d(this);
       QVBoxLayout* l = new QVBoxLayout(&d);
-      QVButtonGroup* bg = new QVButtonGroup(i18n("Some file(s) don't seem to be text files:"),&d);
+      QVButtonGroup* bg = new QVButtonGroup(i18n("Some File(s) Don't Seem to be Text Files"),&d);
       l->addWidget(bg);
       new QRadioButton("A: " + m_sd1.getAliasName(), bg);
       new QRadioButton("B: " + m_sd2.getAliasName(), bg);
@@ -532,7 +616,7 @@
       QPushButton* pSaveButton = new QPushButton( i18n("Save Selection"), &d );
       connect( pSaveButton, SIGNAL(clicked()), &d, SLOT(accept()));
       hbl->addWidget( pSaveButton );
-      QPushButton* pProceedButton = new QPushButton( i18n("Proceed with text-merge"), &d );
+      QPushButton* pProceedButton = new QPushButton( i18n("Proceed with Text-Merge"), &d );
       connect( pProceedButton, SIGNAL(clicked()), &d, SLOT(reject()));
       hbl->addWidget( pProceedButton );
 
@@ -928,15 +1012,15 @@
    QGridLayout* h = new QGridLayout( v, 5, 4, 5 );
    h->setColStretch( 1, 10 );
 
-   QLabel* label  = new QLabel( "A (Base):", this );
+   QLabel* label  = new QLabel( i18n("A (Base):"), this );
 
    m_lineA = new QComboBox( true, this );
    m_lineA->insertStringList( m_pOptions->m_recentAFiles );
    m_lineA->setEditText( KURL(n1).prettyURL() );
    m_lineA->setMinimumSize( 200, m_lineA->size().height() );
-   QPushButton * button = new QPushButton( "File...", this );
+   QPushButton * button = new QPushButton( i18n("File..."), this );
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileA() ) );
-   QPushButton * button2 = new QPushButton( "Dir...", this );
+   QPushButton * button2 = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirA() ) );
 
    h->addWidget( label,    0, 0 );
@@ -949,9 +1033,9 @@
    m_lineB->insertStringList( m_pOptions->m_recentBFiles );
    m_lineB->setEditText( KURL(n2).prettyURL() );
    m_lineB->setMinimumSize( 200, m_lineB->size().height() );
-   button   = new QPushButton( "File...", this );
+   button   = new QPushButton( i18n("File..."), this );
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileB() ) );
-   button2   = new QPushButton( "Dir...", this );
+   button2   = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirB() ) );
 
    h->addWidget( label,     1, 0 );
@@ -959,14 +1043,14 @@
    h->addWidget( button,    1, 2 );
    h->addWidget( button2,   1, 3 );
 
-   label  = new QLabel( "C (Optional):", this );
+   label  = new QLabel( i18n("C (Optional):"), this );
    m_lineC= new QComboBox( true, this );
    m_lineC->insertStringList( m_pOptions->m_recentCFiles );
    m_lineC->setEditText( KURL(n3).prettyURL() );
    m_lineC->setMinimumSize( 200, m_lineC->size().height() );
-   button = new QPushButton( "File...", this );
+   button = new QPushButton( i18n("File..."), this );
    connect( button, SIGNAL(clicked()), this, SLOT( selectFileC() ) );
-   button2   = new QPushButton( "Dir...", this );
+   button2   = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectDirC() ) );
 
    h->addWidget( label,     2, 0 );
@@ -974,17 +1058,17 @@
    h->addWidget( button,    2, 2 );
    h->addWidget( button2,   2, 3 );
 
-   m_pMerge = new QCheckBox( "Merge", this );
+   m_pMerge = new QCheckBox( i18n("Merge"), this );
    h->addWidget( m_pMerge, 3, 0 );
 
-   label  = new QLabel( "Output (Optional):", this );
+   label  = new QLabel( i18n("Output (optional):"), this );
    m_lineOut = new QComboBox( true, this );
    m_lineOut->insertStringList( m_pOptions->m_recentOutputFiles );
    m_lineOut->setEditText( KURL(outputName).prettyURL() );
    m_lineOut->setMinimumSize( 200, m_lineOut->size().height() );
-   button = new QPushButton( "File...", this );
+   button = new QPushButton( i18n("File..."), this );
    connect( button, SIGNAL(clicked()), this, SLOT( selectOutputName() ) );
-   button2   = new QPushButton( "Dir...", this );
+   button2   = new QPushButton( i18n("Dir..."), this );
    connect( button2, SIGNAL(clicked()), this, SLOT( selectOutputDir() ) );
    connect( m_pMerge, SIGNAL(stateChanged(int)), this, SLOT(internalSlot(int)) );
    connect( this, SIGNAL(internalSignal(bool)), m_lineOut, SLOT(setEnabled(bool)) );
@@ -1005,18 +1089,21 @@
    h->addColSpacing( 1, 200 );
 
    QHBoxLayout* l = new QHBoxLayout( v, 5 );
-   button = new QPushButton( "Ok", this );
+
+   button = new QPushButton( i18n("Configure..."), this );
+   connect( button, SIGNAL(clicked()), pParent, slotConfigure );
+   l->addWidget( button, 1 );
+
+   l->addStretch(1);
+
+   button = new QPushButton( i18n("&OK"), this );
    button->setDefault( true );
    connect( button, SIGNAL(clicked()), this, SLOT( accept() ) );
-   l->addWidget( button );
+   l->addWidget( button, 1 );
 
-   button = new QPushButton( "Cancel", this );
+   button = new QPushButton( i18n("&Cancel"), this );
    connect( button, SIGNAL(clicked()), this, SLOT( reject() ) );
-   l->addWidget( button );
-
-   button = new QPushButton( "Configure...", this );
-   connect( button, SIGNAL(clicked()), pParent, slotConfigure );
-   l->addWidget( button );
+   l->addWidget( button,1 );
 
    QSize sh = sizeHint();
    setFixedHeight( sh.height() );
@@ -1096,7 +1183,7 @@
    {
       int result = KMessageBox::warningYesNo(this,
          i18n("You are currently doing a directory merge. Are you sure, you want to abort?"),
-         i18n("Warning"), i18n("Yes - Abort"), i18n("No - Continue merging") );
+         i18n("Warning"), i18n("Abort"), i18n("Continue Merging") );
       if ( result!=KMessageBox::Yes )
          return;
    }
@@ -1345,14 +1432,16 @@
 {
    if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoNextDelta();
 }
+
+
 void KDiff3App::slotChooseA()
 {
-   if (m_pMergeResultWindow && ! m_bTimerBlock )  
+   if (m_pMergeResultWindow && ! m_bTimerBlock )
    {
-      m_pMergeResultWindow->slotChooseA();
+      m_pMergeResultWindow->choose(A);
       if ( autoAdvance->isChecked() )
       {
-         m_bTimerBlock = true;                  
+         m_bTimerBlock = true;
          QTimer::singleShot( m_pOptionDialog->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) );
       }
    }
@@ -1361,7 +1450,7 @@
 {
    if ( m_pMergeResultWindow && ! m_bTimerBlock )
    {
-      m_pMergeResultWindow->slotChooseB();
+      m_pMergeResultWindow->choose(B);
       if ( autoAdvance->isChecked()  )
       {
          m_bTimerBlock = true;
@@ -1371,9 +1460,9 @@
 }
 void KDiff3App::slotChooseC()
 {
-   if ( m_pMergeResultWindow && ! m_bTimerBlock )  
+   if ( m_pMergeResultWindow && ! m_bTimerBlock )
    {
-      m_pMergeResultWindow->slotChooseC();
+      m_pMergeResultWindow->choose(C);
       if ( autoAdvance->isChecked() )
       {
          m_bTimerBlock = true;
@@ -1381,31 +1470,27 @@
       }
    }
 }
-void KDiff3App::slotChooseAEverywhere()
+
+// bConflictsOnly automatically choose for conflicts only (true) or for everywhere
+static void mergeChooseGlobal( KDiff3App* pThis, MergeResultWindow* pMRW, int selector, bool bConflictsOnly, bool bWhiteSpaceOnly )
 {
-   if (m_pMergeResultWindow )
+   if ( pMRW )
    {
-      slotGoTop();
-      m_pMergeResultWindow->slotChooseAEverywhere();
-   }
-}
-void KDiff3App::slotChooseBEverywhere()
-{
-   if (m_pMergeResultWindow )
-   {
-      slotGoTop();
-      m_pMergeResultWindow->slotChooseBEverywhere();
+      pThis->slotGoTop();
+      pMRW->chooseGlobal(selector, bConflictsOnly, bWhiteSpaceOnly );
    }
 }
 
-void KDiff3App::slotChooseCEverywhere()
-{
-   if (m_pMergeResultWindow )
-   {
-      slotGoTop();
-      m_pMergeResultWindow->slotChooseCEverywhere();
-   }
-}
+void KDiff3App::slotChooseAEverywhere() {  mergeChooseGlobal( this, m_pMergeResultWindow, A, false, false ); }
+void KDiff3App::slotChooseBEverywhere() {  mergeChooseGlobal( this, m_pMergeResultWindow, B, false, false ); }
+void KDiff3App::slotChooseCEverywhere() {  mergeChooseGlobal( this, m_pMergeResultWindow, C, false, false ); }
+void KDiff3App::slotChooseAForUnsolvedConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, A, true, false ); }
+void KDiff3App::slotChooseBForUnsolvedConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, B, true, false ); }
+void KDiff3App::slotChooseCForUnsolvedConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, C, true, false ); }
+void KDiff3App::slotChooseAForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, A, true, true ); }
+void KDiff3App::slotChooseBForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, B, true, true ); }
+void KDiff3App::slotChooseCForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( this, m_pMergeResultWindow, C, true, true ); }
+
 
 void KDiff3App::slotAutoSolve()
 {
@@ -1445,32 +1530,27 @@
 void KDiff3App::slotRefresh()
 {
    g_tabSize = m_pOptionDialog->m_tabSize;
-   if (m_pDiffTextWindow1!=0)   
-   { 
-      m_pDiffTextWindow1->setFont(m_pOptionDialog->m_font); 
-      m_pDiffTextWindow1->update(); 
+   if (m_pDiffTextWindow1!=0)
+   {
+      m_pDiffTextWindow1->setFont(m_pOptionDialog->m_font);
+      m_pDiffTextWindow1->update();
    }
    if (m_pDiffTextWindow2!=0)
-   { 
-      m_pDiffTextWindow2->setFont(m_pOptionDialog->m_font); 
-      m_pDiffTextWindow2->update(); 
+   {
+      m_pDiffTextWindow2->setFont(m_pOptionDialog->m_font);
+      m_pDiffTextWindow2->update();
    }
    if (m_pDiffTextWindow3!=0)
-   { 
-      m_pDiffTextWindow3->setFont(m_pOptionDialog->m_font); 
-      m_pDiffTextWindow3->update(); 
+   {
+      m_pDiffTextWindow3->setFont(m_pOptionDialog->m_font);
+      m_pDiffTextWindow3->update();
    }
    if (m_pMergeResultWindow!=0)
-   { 
-      m_pMergeResultWindow->setFont(m_pOptionDialog->m_font); 
-      m_pMergeResultWindow->update(); 
+   {
+      m_pMergeResultWindow->setFont(m_pOptionDialog->m_font);
+      m_pMergeResultWindow->update();
    }
 
-
-   autoAdvance->setChecked( m_pOptionDialog->m_bAutoAdvance );
-   showWhiteSpace->setChecked( m_pOptionDialog->m_bShowWhiteSpace );
-   showLineNumbers->setChecked( m_pOptionDialog->m_bShowLineNumbers );
-
    if ( m_pDiffWindowSplitter!=0 )
    {
        m_pDiffWindowSplitter->setOrientation( m_pOptionDialog->m_bHorizDiffWindowSplitting ? Horizontal : Vertical );
@@ -1522,13 +1602,17 @@
 
 void KDiff3App::slotShowWhiteSpaceToggled()
 {
+   m_pOptionDialog->m_bShowWhiteSpaceCharacters = showWhiteSpaceCharacters->isChecked();
    m_pOptionDialog->m_bShowWhiteSpace = showWhiteSpace->isChecked();
+   showWhiteSpaceCharacters->setEnabled( showWhiteSpace->isChecked() );
    if ( m_pDiffTextWindow1!=0 )
       m_pDiffTextWindow1->update();
    if ( m_pDiffTextWindow2!=0 )
       m_pDiffTextWindow2->update();
    if ( m_pDiffTextWindow3!=0 )
       m_pDiffTextWindow3->update();
+   if ( m_pOverview!=0 )
+      m_pOverview->slotRedraw();
 }
 
 void KDiff3App::slotShowLineNumbersToggled()
@@ -1609,7 +1693,7 @@
    {
       int result = KMessageBox::warningYesNoCancel(this,
          i18n("The merge result hasn't been saved."),
-         i18n("Warning"), i18n("Save and continue"), i18n("Continue without saving") );
+         i18n("Warning"), i18n("Save && Continue"), i18n("Continue Without Saving") );
       if ( result==KMessageBox::Cancel )
          return false;
       else if ( result==KMessageBox::Yes )
@@ -1814,7 +1898,7 @@
       m_pFindDialog->currentPos = 0;
    }
 
-   KMessageBox::information(this,i18n("Search Complete."),i18n("KDiff3: Search Complete."));
+   KMessageBox::information(this,i18n("Search complete."),i18n("Search Complete"));
    m_pFindDialog->currentWindow = 1;
    m_pFindDialog->currentLine = 0;
    m_pFindDialog->currentPos = 0;
@@ -1918,6 +2002,8 @@
       m_pDiffWindowSplitter->setOrientation(
          m_pDiffWindowSplitter->orientation()==Vertical ? Horizontal : Vertical
          );
+
+      m_pOptionDialog->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation()==Horizontal;
    }
 }
 
@@ -1940,32 +2026,16 @@
    bool bDiffWindowVisible = m_pMainWidget != 0 && m_pMainWidget->isVisible();
    bool bMergeEditorVisible = m_pMergeWindowFrame !=0  &&  m_pMergeWindowFrame->isVisible();
 
-   dirStartOperation->setEnabled( m_bDirCompare );
-   dirFoldAll->setEnabled( m_bDirCompare );
-   dirUnfoldAll->setEnabled( m_bDirCompare );
-
-   dirCompareCurrent->setEnabled( m_bDirCompare  &&  m_pDirectoryMergeWindow->isVisible()  &&  m_pDirectoryMergeWindow->isFileSelected() );
-
-   dirMergeCurrent->setEnabled( m_bDirCompare  &&  m_pDirectoryMergeWindow->isVisible()  &&  m_pDirectoryMergeWindow->isFileSelected()
-                                || bDiffWindowVisible );
+   m_pDirectoryMergeWindow->updateAvailabilities( m_bDirCompare, bDiffWindowVisible );
 
    dirShowBoth->setEnabled( m_bDirCompare );
-
-   dirRescan->setEnabled( m_bDirCompare );
-
    dirViewToggle->setEnabled(
       m_bDirCompare &&
       (!m_pDirectoryMergeSplitter->isVisible()  &&  m_pMainWidget!=0 && m_pMainWidget->isVisible() ||
         m_pDirectoryMergeSplitter->isVisible()  &&  m_pMainWidget!=0 && !m_pMainWidget->isVisible() && bTextDataAvailable )
       );
 
-   dirAutoChoiceEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
-   dirDoNothingEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
-   dirChooseAEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
-   dirChooseBEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
-   dirChooseCEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
-
-   showWhiteSpace->setEnabled( bDiffWindowVisible );
+   showWhiteSpaceCharacters->setEnabled( bDiffWindowVisible );
    autoAdvance->setEnabled( bMergeEditorVisible );
    autoSolve->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
    unsolve->setEnabled( bMergeEditorVisible );
@@ -1975,6 +2045,12 @@
    chooseAEverywhere->setEnabled( bMergeEditorVisible );
    chooseBEverywhere->setEnabled( bMergeEditorVisible );
    chooseCEverywhere->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   chooseAForUnsolvedConflicts->setEnabled( bMergeEditorVisible );
+   chooseBForUnsolvedConflicts->setEnabled( bMergeEditorVisible );
+   chooseCForUnsolvedConflicts->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   chooseAForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible );
+   chooseBForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible );
+   chooseCForUnsolvedWhiteSpaceConflicts->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
    showWindowA->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow2->isVisible() || m_pDiffTextWindow3->isVisible() ) );
    showWindowB->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow3->isVisible() ));
    showWindowC->setEnabled( bDiffWindowVisible &&  m_bTripleDiff && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow2->isVisible() ) );
--- a/kdiff3/src/version.h	Fri Oct 17 16:54:25 2003 +0000
+++ b/kdiff3/src/version.h	Tue Dec 09 20:29:43 2003 +0000
@@ -1,2 +1,2 @@
 #undef VERSION
-#define VERSION "0.9.71"
+#define VERSION "0.9.80"