changeset 76:257ccb866dc3

KDiff3-0.9.91 (Qt3 based src)
author joachim99
date Sat, 04 Nov 2006 00:36:16 +0000
parents 08ea9b86c12c
children 1184fc843210
files kdiff3/src/.cvsignore kdiff3/src/Makefile.am kdiff3/src/Makefile.qt kdiff3/src/common.cpp kdiff3/src/common.h kdiff3/src/diff.cpp kdiff3/src/diff.h kdiff3/src/difftextwindow.cpp kdiff3/src/difftextwindow.h kdiff3/src/directorymergewindow.cpp kdiff3/src/directorymergewindow.h kdiff3/src/fileaccess.cpp kdiff3/src/fileaccess.h kdiff3/src/gnudiff_analyze.cpp kdiff3/src/gnudiff_diff.h kdiff3/src/gnudiff_io.cpp kdiff3/src/gnudiff_system.h kdiff3/src/gnudiff_xmalloc.cpp kdiff3/src/hi16-app-kdiff3.png kdiff3/src/hi32-app-kdiff3.png kdiff3/src/kdiff3.cpp kdiff3/src/kdiff3.desktop kdiff3/src/kdiff3.h kdiff3/src/kdiff3.ico kdiff3/src/kdiff3.lsm kdiff3/src/kdiff3.pro kdiff3/src/kdiff3.rc kdiff3/src/kdiff3_meta_unload.cpp kdiff3/src/kdiff3_part.cpp kdiff3/src/kdiff3_part.h kdiff3/src/kdiff3_part.rc kdiff3/src/kdiff3_shell.cpp kdiff3/src/kdiff3_shell.h kdiff3/src/kdiff3_shell.rc kdiff3/src/kdiff3part.desktop kdiff3/src/kreplacements/README kdiff3/src/kreplacements/ShellContextMenu.cpp kdiff3/src/kreplacements/ShellContextMenu.h kdiff3/src/kreplacements/diff.moc kdiff3/src/kreplacements/difftextwindow.moc kdiff3/src/kreplacements/directorymergewindow.moc kdiff3/src/kreplacements/fileaccess.moc kdiff3/src/kreplacements/kaboutdata.h kdiff3/src/kreplacements/kaccel.h kdiff3/src/kreplacements/kaction.h kdiff3/src/kreplacements/kapplication.h kdiff3/src/kreplacements/kcmdlineargs.h kdiff3/src/kreplacements/kcolorbtn.h kdiff3/src/kreplacements/kconfig.h kdiff3/src/kreplacements/kdialogbase.h kdiff3/src/kreplacements/kdiff3.moc kdiff3/src/kreplacements/kdiff3_part.moc kdiff3/src/kreplacements/kdiff3_shell.moc kdiff3/src/kreplacements/kedittoolbar.h kdiff3/src/kreplacements/kfiledialog.h kdiff3/src/kreplacements/kfontdialog.h kdiff3/src/kreplacements/kiconloader.h kdiff3/src/kreplacements/kinstance.h kdiff3/src/kreplacements/kio/global.h kdiff3/src/kreplacements/kio/job.h kdiff3/src/kreplacements/kio/jobclasses.h kdiff3/src/kreplacements/kkeydialog.h kdiff3/src/kreplacements/klibloader.h kdiff3/src/kreplacements/klocale.h kdiff3/src/kreplacements/kmainwindow.h kdiff3/src/kreplacements/kmenubar.h kdiff3/src/kreplacements/kmessagebox.h kdiff3/src/kreplacements/konq_popupmenu.h kdiff3/src/kreplacements/kparts/factory.h kdiff3/src/kreplacements/kparts/mainwindow.h kdiff3/src/kreplacements/kparts/part.h kdiff3/src/kreplacements/kpopupmenu.h kdiff3/src/kreplacements/kprinter.h kdiff3/src/kreplacements/kprogress.h kdiff3/src/kreplacements/kreplacements.cpp kdiff3/src/kreplacements/kreplacements.h kdiff3/src/kreplacements/kreplacements.moc kdiff3/src/kreplacements/kstandarddirs.h kdiff3/src/kreplacements/kstatusbar.h kdiff3/src/kreplacements/kstdaction.h kdiff3/src/kreplacements/ktempfile.h kdiff3/src/kreplacements/kunload.h kdiff3/src/kreplacements/kurl.h kdiff3/src/kreplacements/kurldrag.h kdiff3/src/kreplacements/mergeresultwindow.moc kdiff3/src/kreplacements/optiondialog.moc kdiff3/src/kreplacements/smalldialogs.moc kdiff3/src/lo16-app-kdiff3.png kdiff3/src/lo32-app-kdiff3.png kdiff3/src/main.cpp kdiff3/src/merger.cpp kdiff3/src/merger.h kdiff3/src/mergeresultwindow.cpp kdiff3/src/mergeresultwindow.h kdiff3/src/optiondialog.cpp kdiff3/src/optiondialog.h kdiff3/src/pdiff.cpp kdiff3/src/smalldialogs.cpp kdiff3/src/smalldialogs.h kdiff3/src/version.h kdiff3/src/xpm/autoadvance.xpm kdiff3/src/xpm/currentpos.xpm kdiff3/src/xpm/down1arrow.xpm kdiff3/src/xpm/down2arrow.xpm kdiff3/src/xpm/downend.xpm kdiff3/src/xpm/equal.xpm kdiff3/src/xpm/file.xpm kdiff3/src/xpm/filenew.xpm kdiff3/src/xpm/fileopen.xpm kdiff3/src/xpm/fileprint.xpm kdiff3/src/xpm/filesave.xpm kdiff3/src/xpm/folder.xpm kdiff3/src/xpm/iconA.xpm kdiff3/src/xpm/iconB.xpm kdiff3/src/xpm/iconC.xpm kdiff3/src/xpm/left1arrow.xpm kdiff3/src/xpm/left2arrow.xpm kdiff3/src/xpm/leftend.xpm kdiff3/src/xpm/link_arrow.xpm kdiff3/src/xpm/nextunsolved.xpm kdiff3/src/xpm/not_equal.xpm kdiff3/src/xpm/not_everywhere.xpm kdiff3/src/xpm/not_there.xpm kdiff3/src/xpm/prevunsolved.xpm kdiff3/src/xpm/reload.xpm kdiff3/src/xpm/right1arrow.xpm kdiff3/src/xpm/right2arrow.xpm kdiff3/src/xpm/rightend.xpm kdiff3/src/xpm/showequalfiles.xpm kdiff3/src/xpm/showfilesonlyina.xpm kdiff3/src/xpm/showfilesonlyinb.xpm kdiff3/src/xpm/showfilesonlyinc.xpm kdiff3/src/xpm/showlinenumbers.xpm kdiff3/src/xpm/showwhitespace.xpm kdiff3/src/xpm/showwhitespacechars.xpm kdiff3/src/xpm/startmerge.xpm kdiff3/src/xpm/up1arrow.xpm kdiff3/src/xpm/up2arrow.xpm kdiff3/src/xpm/upend.xpm
diffstat 128 files changed, 27091 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/.cvsignore	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/Makefile.am	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,58 @@
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# 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 version.h \
+	smalldialogs.h difftextwindow.h mergeresultwindow.h
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+	$(XGETTEXT) *.cpp -o $(podir)/kdiff3.pot
+
+KDE_ICON = kdiff3
+
+# this Makefile creates both a KPart application and a KPart
+#########################################################################
+# APPLICATION SECTION
+#########################################################################
+# this is the program that gets installed.  it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = kdiff3
+
+# the application source, library search path, and link libraries
+kdiff3_SOURCES = main.cpp kdiff3_shell.cpp
+kdiff3_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kdiff3_LDADD   = $(LIB_KPARTS)
+
+# this is where the desktop file will go
+shelldesktopdir   = $(kde_appsdir)/Development
+shelldesktop_DATA = kdiff3.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir   = $(kde_datadir)/kdiff3
+shellrc_DATA = kdiff3_shell.rc
+
+#########################################################################
+# KPART SECTION
+#########################################################################
+kde_module_LTLIBRARIES = libkdiff3part.la
+
+# 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 gnudiff_analyze.cpp gnudiff_io.cpp gnudiff_xmalloc.cpp \
+		common.cpp smalldialogs.cpp
+libkdiff3part_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libkdiff3part_la_LIBADD = $(LIB_KDEPRINT) $(LIB_KPARTS) $(LIB_KFILE)
+
+# this is where the desktop file will go
+partdesktopdir   = $(kde_servicesdir)
+partdesktop_DATA = kdiff3part.desktop
+
+# this is where the part's XML-GUI resource file goes
+partrcdir   = $(kde_datadir)/kdiff3part
+partrc_DATA = kdiff3_part.rc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/Makefile.qt	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,425 @@
+#############################################################################
+# Makefile for building: kdiff3
+# Generated by qmake (1.07a) (Qt 3.3.5) on: Sat Apr  8 20:11:51 2006
+# Project:  kdiff3.pro
+# Template: app
+# Command: $(QMAKE) -o Makefile kdiff3.pro
+#############################################################################
+
+####### Compiler, tools and options
+
+CC       = gcc
+CXX      = g++
+LEX      = flex
+YACC     = yacc
+CFLAGS   = -pipe -O2 -Wall -W -fPIC -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT -D__USE_STD_IOSTREAM
+CXXFLAGS = -pipe -O2 -Wall -W -fPIC -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -DQT_SHARED -DQT_TABLET_SUPPORT -D__USE_STD_IOSTREAM
+LEXFLAGS = 
+YACCFLAGS= -d
+INCPATH  = -I$(QTDIR)/mkspecs/default -I. -Ikreplacements -I/usr/include -I$(QTDIR)/include
+LINK     = g++
+LFLAGS   = 
+LIBS     = $(SUBLIBS) -L/usr/lib/ -L$(QTDIR)/lib/ -L/usr/X11R6/lib/ -lqt-mt -lXext -lX11 -lm -lpthread
+AR       = ar cqs
+RANLIB   = 
+MOC      = $(QTDIR)/bin/moc
+UIC      = $(QTDIR)/bin/uic
+QMAKE    = qmake
+TAR      = tar -cf
+GZIP     = gzip -9f
+COPY     = cp -f
+COPY_FILE= $(COPY)
+COPY_DIR = $(COPY) -r
+INSTALL_FILE= $(COPY_FILE)
+INSTALL_DIR = $(COPY_DIR)
+DEL_FILE = rm -f
+SYMLINK  = ln -sf
+DEL_DIR  = rmdir
+MOVE     = mv -f
+CHK_DIR_EXISTS= test -d
+MKDIR    = mkdir -p
+
+####### Output directory
+
+OBJECTS_DIR = ./
+
+####### Files
+
+HEADERS = version.h \
+		diff.h \
+		difftextwindow.h \
+		mergeresultwindow.h \
+		kdiff3.h \
+		merger.h \
+		optiondialog.h \
+		kreplacements/kreplacements.h \
+		directorymergewindow.h \
+		fileaccess.h \
+		kdiff3_shell.h \
+		kdiff3_part.h \
+		smalldialogs.h
+SOURCES = main.cpp \
+		diff.cpp \
+		difftextwindow.cpp \
+		kdiff3.cpp \
+		merger.cpp \
+		mergeresultwindow.cpp \
+		optiondialog.cpp \
+		pdiff.cpp \
+		directorymergewindow.cpp \
+		fileaccess.cpp \
+		smalldialogs.cpp \
+		kdiff3_shell.cpp \
+		kdiff3_part.cpp \
+		gnudiff_analyze.cpp \
+		gnudiff_io.cpp \
+		gnudiff_xmalloc.cpp \
+		common.cpp \
+		kreplacements/kreplacements.cpp \
+		kreplacements/ShellContextMenu.cpp
+OBJECTS = main.o \
+		diff.o \
+		difftextwindow.o \
+		kdiff3.o \
+		merger.o \
+		mergeresultwindow.o \
+		optiondialog.o \
+		pdiff.o \
+		directorymergewindow.o \
+		fileaccess.o \
+		smalldialogs.o \
+		kdiff3_shell.o \
+		kdiff3_part.o \
+		gnudiff_analyze.o \
+		gnudiff_io.o \
+		gnudiff_xmalloc.o \
+		common.o \
+		kreplacements.o \
+		ShellContextMenu.o
+FORMS = 
+UICDECLS = 
+UICIMPLS = 
+SRCMOC   = moc_difftextwindow.cpp \
+		moc_mergeresultwindow.cpp \
+		moc_kdiff3.cpp \
+		moc_optiondialog.cpp \
+		kreplacements/moc_kreplacements.cpp \
+		moc_directorymergewindow.cpp \
+		moc_fileaccess.cpp \
+		moc_kdiff3_shell.cpp \
+		moc_kdiff3_part.cpp \
+		moc_smalldialogs.cpp
+OBJMOC = moc_difftextwindow.o \
+		moc_mergeresultwindow.o \
+		moc_kdiff3.o \
+		moc_optiondialog.o \
+		moc_kreplacements.o \
+		moc_directorymergewindow.o \
+		moc_fileaccess.o \
+		moc_kdiff3_shell.o \
+		moc_kdiff3_part.o \
+		moc_smalldialogs.o
+DIST	   = kdiff3.pro
+QMAKE_TARGET = kdiff3
+DESTDIR  = 
+TARGET   = kdiff3
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .c .o .cpp .cc .cxx .C
+
+.cpp.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.cxx.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.C.o:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
+
+.c.o:
+	$(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
+
+####### Build rules
+
+all: $(TARGET)
+
+$(TARGET):  $(UICDECLS) $(OBJECTS) $(OBJMOC)  
+	$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJMOC) $(OBJCOMP) $(LIBS)
+
+mocables: $(SRCMOC)
+uicables: $(UICDECLS) $(UICIMPLS)
+
+$(MOC): 
+	( cd $(QTDIR)/src/moc && $(MAKE) )
+
+dist: 
+	@mkdir -p .tmp/kdiff3 && $(COPY_FILE) --parents $(SOURCES) $(HEADERS) $(FORMS) $(DIST) .tmp/kdiff3/ && ( cd `dirname .tmp/kdiff3` && $(TAR) kdiff3.tar kdiff3 && $(GZIP) kdiff3.tar ) && $(MOVE) `dirname .tmp/kdiff3`/kdiff3.tar.gz . && $(DEL_FILE) -r .tmp/kdiff3
+
+mocclean:
+	-$(DEL_FILE) $(OBJMOC)
+	-$(DEL_FILE) $(SRCMOC)
+
+uiclean:
+
+yaccclean:
+lexclean:
+clean: mocclean
+	-$(DEL_FILE) $(OBJECTS)
+	-$(DEL_FILE) *~ core *.core
+
+
+####### Sub-libraries
+
+distclean: clean
+	-$(DEL_FILE) $(TARGET) $(TARGET)
+
+
+FORCE:
+
+####### Compile
+
+main.o: main.cpp kdiff3_shell.h \
+		version.h \
+		optiondialog.h \
+		common.h
+
+diff.o: diff.cpp diff.h \
+		fileaccess.h \
+		optiondialog.h \
+		common.h
+
+difftextwindow.o: difftextwindow.cpp difftextwindow.h \
+		merger.h \
+		optiondialog.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+kdiff3.o: kdiff3.cpp difftextwindow.h \
+		mergeresultwindow.h \
+		kdiff3.h \
+		optiondialog.h \
+		fileaccess.h \
+		kdiff3_part.h \
+		directorymergewindow.h \
+		smalldialogs.h \
+		xpm/downend.xpm \
+		xpm/currentpos.xpm \
+		xpm/down1arrow.xpm \
+		xpm/down2arrow.xpm \
+		xpm/upend.xpm \
+		xpm/up1arrow.xpm \
+		xpm/up2arrow.xpm \
+		xpm/prevunsolved.xpm \
+		xpm/nextunsolved.xpm \
+		xpm/iconA.xpm \
+		xpm/iconB.xpm \
+		xpm/iconC.xpm \
+		xpm/autoadvance.xpm \
+		xpm/showwhitespace.xpm \
+		xpm/showwhitespacechars.xpm \
+		xpm/showlinenumbers.xpm \
+		diff.h \
+		common.h
+
+merger.o: merger.cpp merger.h \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+mergeresultwindow.o: mergeresultwindow.cpp mergeresultwindow.h \
+		optiondialog.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+optiondialog.o: optiondialog.cpp optiondialog.h \
+		diff.h \
+		smalldialogs.h \
+		common.h \
+		fileaccess.h
+
+pdiff.o: pdiff.cpp difftextwindow.h \
+		mergeresultwindow.h \
+		directorymergewindow.h \
+		smalldialogs.h \
+		kdiff3.h \
+		optiondialog.h \
+		fileaccess.h \
+		gnudiff_diff.h \
+		diff.h \
+		common.h \
+		gnudiff_system.h
+
+directorymergewindow.o: directorymergewindow.cpp directorymergewindow.h \
+		optiondialog.h \
+		xpm/link_arrow.xpm \
+		xpm/file.xpm \
+		xpm/folder.xpm \
+		xpm/startmerge.xpm \
+		xpm/showequalfiles.xpm \
+		xpm/showfilesonlyina.xpm \
+		xpm/showfilesonlyinb.xpm \
+		xpm/showfilesonlyinc.xpm \
+		common.h \
+		fileaccess.h \
+		diff.h
+
+fileaccess.o: fileaccess.cpp fileaccess.h \
+		optiondialog.h \
+		common.h
+
+smalldialogs.o: smalldialogs.cpp smalldialogs.h \
+		optiondialog.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+kdiff3_shell.o: kdiff3_shell.cpp kdiff3_shell.h \
+		kdiff3.h \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+kdiff3_part.o: kdiff3_part.cpp kdiff3_part.h \
+		kdiff3.h \
+		fileaccess.h \
+		version.h \
+		diff.h \
+		common.h \
+		optiondialog.h
+
+gnudiff_analyze.o: gnudiff_analyze.cpp gnudiff_diff.h \
+		gnudiff_system.h
+
+gnudiff_io.o: gnudiff_io.cpp gnudiff_diff.h \
+		gnudiff_system.h
+
+gnudiff_xmalloc.o: gnudiff_xmalloc.cpp gnudiff_diff.h \
+		gnudiff_system.h
+
+common.o: common.cpp common.h
+
+kreplacements.o: kreplacements/kreplacements.cpp kreplacements/kreplacements.h \
+		common.h \
+		xpm/fileopen.xpm \
+		xpm/filesave.xpm \
+		xpm/fileprint.xpm \
+		kreplacements/kreplacements.moc
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o kreplacements.o kreplacements/kreplacements.cpp
+
+ShellContextMenu.o: kreplacements/ShellContextMenu.cpp kreplacements/ShellContextMenu.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o ShellContextMenu.o kreplacements/ShellContextMenu.cpp
+
+moc_difftextwindow.o: moc_difftextwindow.cpp  difftextwindow.h diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+moc_mergeresultwindow.o: moc_mergeresultwindow.cpp  mergeresultwindow.h diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+moc_kdiff3.o: moc_kdiff3.cpp  kdiff3.h diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+moc_optiondialog.o: moc_optiondialog.cpp  optiondialog.h 
+
+moc_kreplacements.o: kreplacements/moc_kreplacements.cpp  kreplacements/kreplacements.h common.h
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_kreplacements.o kreplacements/moc_kreplacements.cpp
+
+moc_directorymergewindow.o: moc_directorymergewindow.cpp  directorymergewindow.h common.h \
+		fileaccess.h \
+		diff.h \
+		optiondialog.h
+
+moc_fileaccess.o: moc_fileaccess.cpp  fileaccess.h 
+
+moc_kdiff3_shell.o: moc_kdiff3_shell.cpp  kdiff3_shell.h 
+
+moc_kdiff3_part.o: moc_kdiff3_part.cpp  kdiff3_part.h 
+
+moc_smalldialogs.o: moc_smalldialogs.cpp  smalldialogs.h diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+moc_difftextwindow.cpp: $(MOC) difftextwindow.h
+	$(MOC) difftextwindow.h -o moc_difftextwindow.cpp
+
+moc_mergeresultwindow.cpp: $(MOC) mergeresultwindow.h
+	$(MOC) mergeresultwindow.h -o moc_mergeresultwindow.cpp
+
+moc_kdiff3.cpp: $(MOC) kdiff3.h
+	$(MOC) kdiff3.h -o moc_kdiff3.cpp
+
+moc_optiondialog.cpp: $(MOC) optiondialog.h
+	$(MOC) optiondialog.h -o moc_optiondialog.cpp
+
+kreplacements/moc_kreplacements.cpp: $(MOC) kreplacements/kreplacements.h
+	$(MOC) kreplacements/kreplacements.h -o kreplacements/moc_kreplacements.cpp
+
+moc_directorymergewindow.cpp: $(MOC) directorymergewindow.h
+	$(MOC) directorymergewindow.h -o moc_directorymergewindow.cpp
+
+moc_fileaccess.cpp: $(MOC) fileaccess.h
+	$(MOC) fileaccess.h -o moc_fileaccess.cpp
+
+moc_kdiff3_shell.cpp: $(MOC) kdiff3_shell.h
+	$(MOC) kdiff3_shell.h -o moc_kdiff3_shell.cpp
+
+moc_kdiff3_part.cpp: $(MOC) kdiff3_part.h
+	$(MOC) kdiff3_part.h -o moc_kdiff3_part.cpp
+
+moc_smalldialogs.cpp: $(MOC) smalldialogs.h
+	$(MOC) smalldialogs.h -o moc_smalldialogs.cpp
+
+####### Install
+
+install_documentation: all 
+	@$(CHK_DIR_EXISTS) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/" || $(MKDIR) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/da" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/de" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/en" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/et" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/fr" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/it" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/pt" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(INSTALL_DIR) "../doc/sv" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+
+
+uninstall_documentation: 
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/da"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/de"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/en"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/et"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/fr"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/it"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/pt"
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/sv"
+	-$(DEL_DIR) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+
+
+install_target: all 
+	@$(CHK_DIR_EXISTS) "$(INSTALL_ROOT)/usr/local/bin/" || $(MKDIR) "$(INSTALL_ROOT)/usr/local/bin/"
+	-$(INSTALL_FILE) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
+
+uninstall_target: 
+	-$(DEL_FILE) "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
+	-$(DEL_DIR) "$(INSTALL_ROOT)/usr/local/bin/"
+
+
+install: install_documentation install_target  
+
+uninstall: uninstall_documentation uninstall_target  
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/common.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,341 @@
+/***************************************************************************
+ *   Copyright (C) 2004-2006 by Joachim Eibl                               *
+ *   joachim.eibl at gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#include "common.h"
+#include <map>
+#include <qfont.h>
+#include <qcolor.h>
+#include <qsize.h>
+#include <qpoint.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+
+ValueMap::ValueMap()
+{
+}
+
+ValueMap::~ValueMap()
+{
+}
+
+void ValueMap::save( QTextStream& ts )
+{
+   std::map<QString,QString>::iterator i;
+   for( i=m_map.begin(); i!=m_map.end(); ++i)
+   {
+      QString key = i->first;
+      QString val = i->second;
+      ts << key << "=" << val << "\n";
+   }
+}
+
+QString ValueMap::getAsString()
+{
+   QString result;
+   std::map<QString,QString>::iterator i;
+   for( i=m_map.begin(); i!=m_map.end(); ++i)
+   {
+      QString key = i->first;
+      QString val = i->second;
+      result += key + "=" + val + "\n";
+   }
+   return result;
+}
+
+void ValueMap::load( QTextStream& ts )
+{
+   while ( !ts.eof() )
+   {                                 // until end of file...	   
+      QString s = ts.readLine();         // line of text excluding '\n'
+      int pos = s.find('=');
+      if( pos > 0 )                     // seems not to have a tag
+      {
+         QString key = s.left(pos);
+         QString val = s.mid(pos+1);
+         m_map[key] = val;
+      }
+   }
+}
+/*
+void ValueMap::load( const QString& s )
+{
+   int pos=0;
+   while ( pos<(int)s.length() )
+   {                                 // until end of file...
+      int pos2 = s.find('=', pos);
+      int pos3 = s.find('\n', pos2 );
+      if (pos3<0)
+         pos3=s.length();
+      if( pos2 > 0 )                     // seems not to have a tag
+      {
+         QString key = s.mid(pos, pos2-pos);
+         QString val = s.mid(pos2+1, pos3-pos2-1);
+         m_map[key] = val;
+      }
+      pos = pos3;
+   }
+}
+*/
+
+// safeStringJoin and safeStringSplit allow to convert a stringlist into a string and back
+// safely, even if the individual strings in the list contain the separator character.
+QString safeStringJoin(const QStringList& sl, char sepChar, char metaChar )
+{
+   // Join the strings in the list, using the separator ','
+   // If a string contains the separator character, it will be replaced with "\,".
+   // Any occurances of "\" (one backslash) will be replaced with "\\" (2 backslashes)
+   
+   assert(sepChar!=metaChar);
+   
+   QString sep;
+   sep += sepChar;
+   QString meta;
+   meta += metaChar;   
+   
+   QString safeString;
+   
+   QStringList::const_iterator i;
+   for (i=sl.begin(); i!=sl.end(); ++i)
+   {
+      QString s = *i;
+      s.replace(meta, meta+meta);   //  "\" -> "\\"
+      s.replace(sep, meta+sep);     //  "," -> "\,"
+      if ( i==sl.begin() )
+         safeString = s;
+      else
+         safeString += sep + s;
+   }
+   return safeString;
+}
+
+// Split a string that was joined with safeStringJoin
+QStringList safeStringSplit(const QString& s, char sepChar, char metaChar )
+{
+   assert(sepChar!=metaChar);
+   QStringList sl;
+   // Miniparser
+   int i=0;
+   int len=s.length();
+   QString b;
+   for(i=0;i<len;++i)
+   {
+      if      ( i+1<len && s[i]==metaChar && s[i+1]==metaChar ){ b+=metaChar; ++i; }
+      else if ( i+1<len && s[i]==metaChar && s[i+1]==sepChar ){ b+=sepChar; ++i; }
+      else if ( s[i]==sepChar )  // real separator
+      {
+         sl.push_back(b);
+         b="";
+      }
+      else { b+=s[i]; }
+   }
+   if ( !b.isEmpty() )
+      sl.push_back(b);
+
+   return sl;
+}
+
+
+
+static QString numStr(int n)
+{
+   QString s;
+   s.setNum( n );
+   return s;
+}
+
+static QString subSection( const QString& s, int idx, char sep )
+{
+   int pos=0;
+   while( idx>0 )
+   {
+      pos = s.find( sep, pos );
+      --idx;
+      if (pos<0) break;
+      ++pos;
+   }
+   if ( pos>=0 )
+   {
+      int pos2 = s.find( sep, pos );
+      if ( pos2>0 )
+         return s.mid(pos, pos2-pos);
+      else
+         return s.mid(pos);
+   }
+
+   return "";
+}
+
+static int num( QString& s, int idx )
+{
+   return subSection( s, idx, ',').toInt();
+}
+
+void ValueMap::writeEntry(const QString& k, const QFont& v )
+{
+   m_map[k] = v.family() + "," + QString::number(v.pointSize()) + "," + (v.bold() ? "bold" : "normal");
+}
+
+void ValueMap::writeEntry(const QString& k, const QColor& v )
+{
+   m_map[k] = numStr(v.red()) + "," + numStr(v.green()) + "," + numStr(v.blue());
+}
+
+void ValueMap::writeEntry(const QString& k, const QSize& v )
+{
+   m_map[k] = numStr(v.width()) + "," + numStr(v.height());
+}
+
+void ValueMap::writeEntry(const QString& k, const QPoint& v )
+{
+   m_map[k] = numStr(v.x()) + "," + numStr(v.y());
+}
+
+void ValueMap::writeEntry(const QString& k, int v )
+{
+   m_map[k] = numStr(v);
+}
+
+void ValueMap::writeEntry(const QString& k, bool v )
+{
+   m_map[k] = numStr(v);
+}
+
+void ValueMap::writeEntry(const QString& k, const QString& v )
+{
+   m_map[k] = v;
+}
+
+void ValueMap::writeEntry(const QString& k, const char* v )
+{
+   m_map[k] = v;
+}
+
+void ValueMap::writeEntry(const QString& k, const QStringList& v, char separator )
+{
+   m_map[k] = safeStringJoin(v, separator);
+}
+
+
+QFont ValueMap::readFontEntry(const QString& k, QFont* defaultVal )
+{
+   QFont f = *defaultVal;
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      f.setFamily( subSection( i->second, 0, ',' ) );
+      f.setPointSize( subSection( i->second, 1, ',' ).toInt() );
+      f.setBold( subSection( i->second, 2, ',' )=="bold" );
+      //f.fromString(i->second);
+   }
+
+   return f;
+}
+
+QColor ValueMap::readColorEntry(const QString& k, QColor* defaultVal )
+{
+   QColor c= *defaultVal;
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      QString s = i->second;
+      c = QColor( num(s,0),num(s,1),num(s,2) );
+   }
+
+   return c;
+}
+
+QSize ValueMap::readSizeEntry(const QString& k, QSize* defaultVal )
+{
+   QSize size = defaultVal ? *defaultVal : QSize(600,400);
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+
+      QString s = i->second;
+      size = QSize( num(s,0),num(s,1) );
+   }
+
+   return size;
+}
+
+QPoint ValueMap::readPointEntry(const QString& k, QPoint* defaultVal)
+{
+   QPoint point = defaultVal ? *defaultVal : QPoint(0,0);
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      QString s = i->second;
+      point = QPoint( num(s,0),num(s,1) );
+   }
+
+   return point;
+}
+
+bool ValueMap::readBoolEntry(const QString& k, bool bDefault )
+{
+   bool b = bDefault;
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      QString s = i->second;
+      b = (bool)num(s,0);
+   }
+
+   return b;
+}
+
+int ValueMap::readNumEntry(const QString& k, int iDefault )
+{
+   int ival = iDefault;
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      QString s = i->second;
+      ival = num(s,0);
+   }
+
+   return ival;
+}
+
+QString ValueMap::readEntry(const QString& k, const QString& sDefault )
+{
+   QString sval = sDefault;
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      sval = i->second;
+   }
+
+   return sval;
+}
+
+QStringList ValueMap::readListEntry(const QString& k, const QStringList& defaultVal, char separator )
+{
+   QStringList strList;
+
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      strList = safeStringSplit( i->second, separator );
+      return strList;
+   }
+   else
+      return defaultVal;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/common.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,113 @@
+/***************************************************************************
+                          common.h  -  Things that are needed often
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#include <assert.h>
+
+template< class T >
+T min2( T x, T y )
+{
+   return x<y ? x : y;
+}
+template< class T >
+T max2( T x, T y )
+{
+   return x>y ? x : y;
+}
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned int UINT32;
+
+
+template <class T>
+T min3( T d1, T d2, T d3 )
+{
+   if ( d1 < d2  &&  d1 < d3 ) return d1;
+   if ( d2 < d3 ) return d2;
+   return d3;
+}
+
+template <class T>
+T max3( T d1, T d2, T d3 )
+{
+
+   if ( d1 > d2  &&  d1 > d3 ) return d1;
+
+
+   if ( d2 > d3 ) return d2;
+   return d3;
+
+}
+
+template <class T>
+T minMaxLimiter( T d, T minimum, T maximum )
+{
+   assert(minimum<=maximum);
+   if ( d < minimum ) return minimum;
+   if ( d > maximum ) return maximum;
+   return d;
+}
+
+#include <map>
+#include <qstring.h>
+class QFont;
+class QColor;
+class QSize;
+class QPoint;
+class QStringList;
+class QTextStream;
+
+class ValueMap
+{
+private:
+   std::map<QString,QString> m_map;
+public:
+   ValueMap();
+   virtual ~ValueMap();
+
+   void save( QTextStream& ts );
+   void load( QTextStream& ts );
+   QString getAsString();
+   // void load( const QString& s );
+
+   virtual void writeEntry(const QString&, const QFont& );
+   virtual void writeEntry(const QString&, const QColor& );
+   virtual void writeEntry(const QString&, const QSize& );
+   virtual void writeEntry(const QString&, const QPoint& );
+   virtual void writeEntry(const QString&, int );
+   virtual void writeEntry(const QString&, bool );
+   virtual void writeEntry(const QString&, const QStringList&, char separator );
+   virtual void writeEntry(const QString&, const QString& );
+   virtual void writeEntry(const QString&, const char* );
+
+   virtual QFont       readFontEntry (const QString&, QFont* defaultVal );
+   virtual QColor      readColorEntry(const QString&, QColor* defaultVal );
+   virtual QSize       readSizeEntry (const QString&, QSize* defaultVal );
+   virtual QPoint      readPointEntry(const QString&, QPoint* defaultVal );
+   virtual bool        readBoolEntry (const QString&, bool bDefault );
+   virtual int         readNumEntry  (const QString&, int iDefault );
+   virtual QStringList readListEntry (const QString&, const QStringList& defaultVal, char separator );
+   virtual QString     readEntry     (const QString&, const QString& );
+};
+
+QStringList safeStringSplit(const QString& s, char sepChar=',', char metaChar='\\' );
+QString safeStringJoin(const QStringList& sl, char sepChar=',', char metaChar='\\' );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/diff.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1918 @@
+/***************************************************************************
+                          diff.cpp  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <iostream>
+
+#include "diff.h"
+#include "fileaccess.h"
+#include "optiondialog.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qtextcodec.h>
+
+#include <map>
+#include <assert.h>
+#include <ctype.h>
+//using namespace std;
+
+
+int LineData::width(int tabSize) const
+{
+   int w=0;
+   int j=0;
+   for( int i=0; i<size; ++i )
+   {
+      if ( pLine[i]=='\t' )
+      {
+         for(j %= tabSize; j<tabSize; ++j)
+            ++w;
+         j=0;
+      }
+      else
+      {
+         ++w;
+         ++j;
+      }
+   }
+   return w;
+}
+
+
+// The bStrict flag is true during the test where a nonmatching area ends.
+// Then the equal()-function requires that the match has more than 2 nonwhite characters.
+// This is to avoid matches on trivial lines (e.g. with white space only).
+// This choice is good for C/C++.
+bool equal( const LineData& l1, const LineData& l2, bool bStrict )
+{
+   if ( l1.pLine==0 || l2.pLine==0) return false;
+
+   if ( bStrict && g_bIgnoreTrivialMatches )//&& (l1.occurances>=5 || l2.occurances>=5) )
+      return false;
+
+   // Ignore white space diff
+   const QChar* p1 = l1.pLine;
+   const QChar* p1End = p1 + l1.size;
+
+   const QChar* p2 = l2.pLine;
+   const QChar* p2End = p2 + l2.size;
+
+   if ( g_bIgnoreWhiteSpace )
+   {
+      int nonWhite = 0;
+      for(;;)
+      {
+         while( isWhite( *p1 ) && p1!=p1End ) ++p1;
+         while( isWhite( *p2 ) && p2!=p2End ) ++p2;
+
+         if ( p1 == p1End  &&  p2 == p2End )
+         {
+            if ( bStrict && g_bIgnoreTrivialMatches )
+            {  // Then equality is not enough
+               return nonWhite>2;
+            }
+            else  // equality is enough
+               return true;
+         }
+         else if ( p1 == p1End || p2 == p2End )
+            return false;
+
+         if( *p1 != *p2 )
+            return false;
+         ++p1;
+         ++p2;
+         ++nonWhite;
+      }
+   }
+
+   else
+   {
+      if ( l1.size==l2.size && memcmp(p1, p2, l1.size)==0)
+         return true;
+      else
+         return false;
+   }
+}
+
+
+static bool isLineOrBufEnd( const QChar* p, int i, int size )
+{
+   return 
+      i>=size        // End of file
+      || p[i]=='\n'  // Normal end of line
+
+      // No support for Mac-end of line yet, because incompatible with GNU-diff-routines.      
+      // || ( p[i]=='\r' && (i>=size-1 || p[i+1]!='\n') 
+      //                 && (i==0        || p[i-1]!='\n') )  // Special case: '\r' without '\n'
+      ;
+}
+
+
+/* Features of class SourceData:
+- Read a file (from the given URL) or accept data via a string.
+- Allocate and free buffers as necessary.
+- Run a preprocessor, when specified.
+- Run the line-matching preprocessor, when specified.
+- Run other preprocessing steps: Uppercase, ignore comments,
+                                 remove carriage return, ignore numbers.
+
+Order of operation:
+ 1. If data was given via a string then save it to a temp file. (see setData())
+ 2. If the specified file is nonlocal (URL) copy it to a temp file.
+ 3. If a preprocessor was specified, run the input file through it.
+ 4. Read the output of the preprocessor.
+ 5. If Uppercase was specified: Turn the read data to uppercase.
+ 6. Write the result to a temp file.
+ 7. If a line-matching preprocessor was specified, run the temp file through it.
+ 8. Read the output of the line-matching preprocessor.
+ 9. If ignore numbers was specified, strip the LMPP-output of all numbers.
+10. If ignore comments was specified, strip the LMPP-output of comments.
+
+Optimizations: Skip unneeded steps.
+*/
+
+SourceData::SourceData()
+{
+   m_pOptionDialog = 0;
+   reset();
+}
+
+SourceData::~SourceData()
+{
+   reset();
+}
+
+void SourceData::reset()
+{
+   m_pEncoding = 0;
+   m_fileAccess = FileAccess();
+   m_normalData.reset();
+   m_lmppData.reset();
+   if ( !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+}
+
+void SourceData::setFilename( const QString& filename )
+{
+   if (filename.isEmpty())
+   {
+      reset();
+   }
+   else
+   {
+      FileAccess fa( filename );
+      setFileAccess( fa );
+   }
+}
+
+bool SourceData::isEmpty() 
+{ 
+   return getFilename().isEmpty(); 
+}
+
+bool SourceData::hasData() 
+{ 
+   return m_normalData.m_pBuf != 0;
+}
+
+bool SourceData::isValid()
+{
+   return isEmpty() || hasData();
+}
+
+void SourceData::setOptionDialog( OptionDialog* pOptionDialog )
+{
+   m_pOptionDialog = pOptionDialog;
+}
+
+QString SourceData::getFilename()
+{
+   return m_fileAccess.absFilePath();
+}
+
+QString SourceData::getAliasName()
+{
+   return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName;
+}
+
+void SourceData::setAliasName( const QString& name )
+{
+   m_aliasName = name;
+}
+
+void SourceData::setFileAccess( const FileAccess& fileAccess )
+{
+   m_fileAccess = fileAccess;
+   m_aliasName = QString();
+   if ( !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+}
+
+void SourceData::setData( const QString& data )
+{
+   // Create a temp file for preprocessing:
+   if ( m_tempInputFileName.isEmpty() )
+   {
+      m_tempInputFileName = FileAccess::tempFileName();
+   }
+
+   FileAccess f( m_tempInputFileName );
+   bool bSuccess = f.writeFile( QTextCodec::codecForName("UTF-8")->fromUnicode(data), data.length() );
+   if ( !bSuccess )
+   {
+      KMessageBox::error( m_pOptionDialog, i18n("Writing clipboard data to temp file failed.") );
+      return;
+   }
+
+   m_aliasName = i18n("From Clipboard");
+   m_fileAccess = FileAccess("");  // Effect: m_fileAccess.isValid() is false
+}
+
+const LineData* SourceData::getLineDataForDiff() const
+{
+   if ( m_lmppData.m_pBuf==0 )
+      return m_normalData.m_v.size()>0 ? &m_normalData.m_v[0] : 0;
+   else
+      return m_lmppData.m_v.size()>0   ? &m_lmppData.m_v[0]   : 0;
+}
+
+const LineData* SourceData::getLineDataForDisplay() const
+{
+   return m_normalData.m_v.size()>0 ? &m_normalData.m_v[0] : 0;
+}
+
+int  SourceData::getSizeLines() const
+{
+   return m_normalData.m_vSize;
+}
+
+int SourceData::getSizeBytes() const
+{
+   return m_normalData.m_size;
+}
+
+const char* SourceData::getBuf() const
+{
+   return m_normalData.m_pBuf;
+}
+
+bool SourceData::isText()
+{
+   return m_normalData.m_bIsText;
+}
+ 
+bool SourceData::isFromBuffer()
+{
+   return !m_fileAccess.isValid();
+}
+
+
+bool SourceData::isBinaryEqualWith( const SourceData& other ) const
+{
+   return getSizeBytes() == other.getSizeBytes() && 
+          ( getSizeBytes()==0 || memcmp( getBuf(), other.getBuf(), getSizeBytes() )==0 );
+}
+
+void SourceData::FileData::reset()
+{
+   delete[] (char*)m_pBuf;
+   m_pBuf = 0;
+   m_v.clear();
+   m_size = 0;
+   m_vSize = 0;
+   m_bIsText = true;
+}
+
+bool SourceData::FileData::readFile( const QString& filename )
+{
+   reset();
+   if ( filename.isEmpty() )   { return true; }
+
+   FileAccess fa( filename );
+   m_size = fa.sizeForReading();
+   char* pBuf;
+   m_pBuf = pBuf = new char[m_size+100];  // Alloc 100 byte extra: Savety hack, not nice but does no harm.
+                                // Some extra bytes at the end of the buffer are needed by
+                                // the diff algorithm. See also GnuDiff::diff_2_files().
+   bool bSuccess = fa.readFile( pBuf, m_size );
+   if ( !bSuccess )
+   {
+      delete pBuf;
+      m_pBuf = 0;
+      m_size = 0;
+   }
+   return bSuccess;
+}
+
+bool SourceData::saveNormalDataAs( const QString& fileName )
+{
+   return m_normalData.writeFile( fileName );
+}
+
+bool SourceData::FileData::writeFile( const QString& filename )
+{
+   if ( filename.isEmpty() )   { return true; }
+
+   FileAccess fa( filename );
+   bool bSuccess = fa.writeFile(m_pBuf, m_size);
+   return bSuccess;
+}
+
+void SourceData::FileData::copyBufFrom( const FileData& src )
+{
+   reset();
+   char* pBuf;
+   m_size = src.m_size;
+   m_pBuf = pBuf = new char[m_size+100];
+   memcpy( pBuf, src.m_pBuf, m_size );
+}
+
+// Convert the input file from input encoding to output encoding and write it to the output file.
+static bool convertFileEncoding( const QString& fileNameIn, QTextCodec* pCodecIn,
+                                 const QString& fileNameOut, QTextCodec* pCodecOut )
+{
+   QFile in( fileNameIn );
+   if ( ! in.open(IO_ReadOnly ) )
+      return false;
+   QTextStream inStream( &in );
+   inStream.setCodec( pCodecIn );
+   //inStream.setAutoDetectUnicode( false ); //not available in Qt3, will always detect UCS2
+
+   QFile out( fileNameOut );
+   if ( ! out.open( IO_WriteOnly ) )
+      return false;
+   QTextStream outStream( &out );
+   outStream.setCodec( pCodecOut );
+
+   QString data = inStream.read();
+   outStream << data;
+
+   return true;
+}
+
+static QTextCodec* detectEncoding( const char* buf, long size, long& skipBytes )
+{
+   if (size>=2)
+   {
+      skipBytes = 0; // In Qt3 UTF-16LE can only be used if autodetected.
+      if (buf[0]=='\xFF' && buf[1]=='\xFE' )
+         return QTextCodec::codecForName( "ISO-10646-UCS2" );// "UTF-16LE"
+
+      if (buf[0]=='\xFE' && buf[1]=='\xFF' )
+         return QTextCodec::codecForName( "ISO-10646-UCS2" );// "UTF-16BE". Qt3 autodetects the difference but has no name for it.
+   }
+   if (size>=3)
+   {
+      skipBytes = 3;
+      if (buf[0]=='\xEF' && buf[1]=='\xBB' && buf[2]=='\xBF' )
+         return QTextCodec::codecForName( "UTF-8-BOM" );
+   }
+   skipBytes = 0;
+   return 0;
+}
+
+QTextCodec* SourceData::detectEncoding( const QString& fileName, QTextCodec* pFallbackCodec )
+{
+   QFile f(fileName);
+   if ( f.open(IO_ReadOnly) )
+   {
+      char buf[4];
+      long size = f.readBlock( buf, sizeof(buf) );
+      long skipBytes = 0;
+      QTextCodec* pCodec = ::detectEncoding( buf, size, skipBytes );
+      if (pCodec)
+         return pCodec;
+   }
+   return pFallbackCodec;
+}
+
+void SourceData::readAndPreprocess( QTextCodec* pEncoding, bool bAutoDetectUnicode )
+{
+   m_pEncoding = pEncoding;
+   QString fileNameIn1;
+   QString fileNameOut1;
+   QString fileNameIn2;
+   QString fileNameOut2;
+
+   bool bTempFileFromClipboard = !m_fileAccess.isValid();
+
+   // Detect the input for the preprocessing operations
+   if ( !bTempFileFromClipboard )
+   {
+      if ( m_fileAccess.isLocal() )
+      {
+         fileNameIn1 = m_fileAccess.absFilePath();
+      }
+      else    // File is not local: create a temporary local copy:
+      {
+         if ( m_tempInputFileName.isEmpty() )  { m_tempInputFileName = FileAccess::tempFileName(); }
+
+         m_fileAccess.copyFile(m_tempInputFileName);
+         fileNameIn1 = m_tempInputFileName;
+      }
+      if ( bAutoDetectUnicode )
+      {
+         m_pEncoding = detectEncoding( fileNameIn1, pEncoding );
+      }
+   }
+   else // The input was set via setData(), probably from clipboard.
+   {
+      fileNameIn1 = m_tempInputFileName;
+      m_pEncoding = QTextCodec::codecForName("UTF-8");
+   }
+   QTextCodec* pEncoding1 = m_pEncoding;
+   QTextCodec* pEncoding2 = m_pEncoding;
+
+   m_normalData.reset();
+   m_lmppData.reset();
+
+   FileAccess faIn(fileNameIn1);
+   int fileInSize = faIn.size();
+
+   if ( faIn.exists() ) // fileInSize > 0 )
+   {
+
+#ifdef _WIN32
+      QString catCmd = "type";
+      fileNameIn1.replace( '/', "\\" );
+#else
+      QString catCmd = "cat";
+#endif
+
+      // Run the first preprocessor
+      if ( m_pOptionDialog->m_PreProcessorCmd.isEmpty() )
+      {
+         // No preprocessing: Read the file directly:
+         m_normalData.readFile( fileNameIn1 );
+      }
+      else
+      {
+         QString fileNameInPP = fileNameIn1;
+
+         if ( pEncoding1 != m_pOptionDialog->m_pEncodingPP )
+         {
+            // Before running the preprocessor convert to the format that the preprocessor expects.
+            fileNameInPP = FileAccess::tempFileName();
+            pEncoding1 = m_pOptionDialog->m_pEncodingPP;
+            convertFileEncoding( fileNameIn1, pEncoding, fileNameInPP, pEncoding1 );
+         }
+
+         QString ppCmd = m_pOptionDialog->m_PreProcessorCmd;
+         fileNameOut1 = FileAccess::tempFileName();
+         QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd  + " >\"" + fileNameOut1+"\"";
+         ::system( encodeString(cmd) );
+         bool bSuccess = m_normalData.readFile( fileNameOut1 );
+         if ( fileInSize >0 && ( !bSuccess || m_normalData.m_size==0 ) )
+         {
+            KMessageBox::error(m_pOptionDialog, 
+               i18n("Preprocessing possibly failed. Check this command:\n\n  %1"
+                  "\n\nThe preprocessing command will be disabled now."
+               ).arg(cmd) );
+            m_pOptionDialog->m_PreProcessorCmd = "";
+            m_normalData.readFile( fileNameIn1 );
+            pEncoding1 = m_pEncoding;
+         }
+         if (fileNameInPP != fileNameIn1)
+         {
+            FileAccess::removeTempFile( fileNameInPP );
+         }
+      }
+
+      // LineMatching Preprocessor
+      if ( ! m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty() )
+      {
+         fileNameIn2 = fileNameOut1.isEmpty() ? fileNameIn1 : fileNameOut1;
+         QString fileNameInPP = fileNameIn2;
+         pEncoding2 = pEncoding1;
+         if ( pEncoding2 != m_pOptionDialog->m_pEncodingPP )
+         {
+            // Before running the preprocessor convert to the format that the preprocessor expects.
+            fileNameInPP = FileAccess::tempFileName();
+            pEncoding2 = m_pOptionDialog->m_pEncodingPP;
+            convertFileEncoding( fileNameIn2, pEncoding1, fileNameInPP, pEncoding2 );
+         }
+
+         QString ppCmd = m_pOptionDialog->m_LineMatchingPreProcessorCmd;
+         fileNameOut2 = FileAccess::tempFileName();
+         QString cmd = catCmd + " \"" + fileNameInPP + "\" | " + ppCmd  + " >\"" + fileNameOut2 + "\"";
+         ::system( encodeString(cmd) );
+         bool bSuccess = m_lmppData.readFile( fileNameOut2 );
+         if ( FileAccess(fileNameIn2).size()>0 && ( !bSuccess || m_lmppData.m_size==0 ) )
+         {
+            KMessageBox::error(m_pOptionDialog, 
+               i18n("The line-matching-preprocessing possibly failed. Check this command:\n\n  %1"
+                    "\n\nThe line-matching-preprocessing command will be disabled now."
+                   ).arg(cmd) );
+            m_pOptionDialog->m_LineMatchingPreProcessorCmd = "";
+            m_lmppData.readFile( fileNameIn2 );
+         }
+         FileAccess::removeTempFile( fileNameOut2 );
+         if (fileNameInPP != fileNameIn2)
+         {
+            FileAccess::removeTempFile( fileNameInPP );
+         }
+      }
+      else if ( m_pOptionDialog->m_bIgnoreComments || m_pOptionDialog->m_bIgnoreCase )
+      {
+         // We need a copy of the normal data.
+         m_lmppData.copyBufFrom( m_normalData );
+      }
+      else
+      {  // We don't need any lmpp data at all.
+         m_lmppData.reset();
+      }
+   }
+
+   m_normalData.preprocess( m_pOptionDialog->m_bPreserveCarriageReturn, pEncoding1 );
+   m_lmppData.preprocess( false, pEncoding2 );
+
+   if ( m_lmppData.m_vSize < m_normalData.m_vSize )
+   {
+      // This probably is the fault of the LMPP-Command, but not worth reporting.
+      m_lmppData.m_v.resize( m_normalData.m_vSize );
+      for(int i=m_lmppData.m_vSize; i<m_normalData.m_vSize; ++i )
+      {  // Set all empty lines to point to the end of the buffer.
+         m_lmppData.m_v[i].pLine = m_lmppData.m_unicodeBuf.unicode()+m_lmppData.m_unicodeBuf.length();
+      }
+
+      m_lmppData.m_vSize = m_normalData.m_vSize;
+   }
+
+   // Internal Preprocessing: Uppercase-conversion   
+   if ( m_pOptionDialog->m_bIgnoreCase )
+   {
+      int i;
+      QChar* pBuf = const_cast<QChar*>(m_lmppData.m_unicodeBuf.unicode());
+      int ucSize = m_lmppData.m_unicodeBuf.length();
+      for(i=0; i<ucSize; ++i)
+      {
+         pBuf[i] = pBuf[i].upper();
+      }
+   }
+
+   // Ignore comments
+   if ( m_pOptionDialog->m_bIgnoreComments )
+   {
+      m_lmppData.removeComments();
+      int vSize = min2(m_normalData.m_vSize, m_lmppData.m_vSize);
+      for(int i=0; i<vSize; ++i )
+      {
+         m_normalData.m_v[i].bContainsPureComment = m_lmppData.m_v[i].bContainsPureComment;
+      }
+   }
+
+   // Remove unneeded temporary files. (A temp file from clipboard must not be deleted.)
+   if ( !bTempFileFromClipboard && !m_tempInputFileName.isEmpty() )
+   {
+      FileAccess::removeTempFile( m_tempInputFileName );
+      m_tempInputFileName = "";
+   }
+
+   if ( !fileNameOut1.isEmpty() )
+   {
+      FileAccess::removeTempFile( fileNameOut1 );
+      fileNameOut1="";
+   }
+}
+
+
+/** Prepare the linedata vector for every input line.*/
+void SourceData::FileData::preprocess( bool bPreserveCR, QTextCodec* pEncoding )
+{
+   //m_unicodeBuf = decodeString( m_pBuf, m_size, eEncoding );
+
+   long skipBytes = 0;
+   QTextCodec* pCodec = ::detectEncoding( m_pBuf, m_size, skipBytes );
+   if ( pCodec != pEncoding )
+      skipBytes=0;
+
+   QByteArray ba;
+   ba.setRawData( m_pBuf+skipBytes, m_size-skipBytes );
+   QTextStream ts( ba, IO_ReadOnly );
+   ts.setCodec( pEncoding);
+   //ts.setAutoDetectUnicode( false );
+   m_unicodeBuf = ts.read();
+   ba.resetRawData( m_pBuf+skipBytes, m_size-skipBytes );
+
+   int ucSize = m_unicodeBuf.length();
+   const QChar* p = m_unicodeBuf.unicode();
+
+   m_bIsText = true;
+   int lines = 1;
+   int i;
+   for( i=0; i<ucSize; ++i )
+   {
+      if ( isLineOrBufEnd(p,i,ucSize) )
+      {
+         ++lines;
+      }
+      if ( p[i]=='\0' )
+      {
+         m_bIsText = false;
+      }
+   }
+
+   m_v.resize( lines+5 );
+   int lineIdx=0;
+   int lineLength=0;
+   bool bNonWhiteFound = false;
+   int whiteLength = 0;
+   for( i=0; i<=ucSize; ++i )
+   {
+      if ( isLineOrBufEnd( p, i, ucSize ) )
+      {
+         m_v[lineIdx].pLine = &p[ i-lineLength ];
+         while ( !bPreserveCR  &&  lineLength>0  &&  m_v[lineIdx].pLine[lineLength-1]=='\r'  )
+         {
+            --lineLength;
+         }
+         m_v[lineIdx].pFirstNonWhiteChar = m_v[lineIdx].pLine + min2(whiteLength,lineLength);
+         m_v[lineIdx].size = lineLength;
+         lineLength = 0;
+         bNonWhiteFound = false;
+         whiteLength = 0;
+         ++lineIdx;
+      }
+      else
+      {
+         ++lineLength;
+
+         if ( ! bNonWhiteFound && isWhite( p[i] ) )
+            ++whiteLength;
+         else
+            bNonWhiteFound = true;
+      }
+   }
+   assert( lineIdx == lines );
+
+   m_vSize = lines;
+}
+
+
+// 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(
+   QChar* 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)
+   )
+{
+   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( ; !isLineOrBufEnd(p,i,size) && p[i]!='\''; ++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( ; !isLineOrBufEnd(p,i,size) && !(p[i]=='"' && p[i-1]!='\\'); ++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( ; !isLineOrBufEnd(p,i,size); ++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( ; !isLineOrBufEnd(p,i,size); ++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 ( isLineOrBufEnd(p,i,size) )
+      {
+         return;
+      }
+      else if ( !p[i].isSpace() )
+      {
+         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::FileData::removeComments()
+{
+   int line=0;
+   QChar* p = const_cast<QChar*>(m_unicodeBuf.unicode());
+   bool bWithinComment=false;
+   int size = m_unicodeBuf.length();
+   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( ; !isLineOrBufEnd(p,i,size); ++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( isLineOrBufEnd(p,i,size));
+      m_v[line].bContainsPureComment = bCommentInLine && bWhite;
+/*      std::cout << line << " : " <<
+       ( bCommentInLine ?  "c" : " " ) <<
+       ( bWhite ? "w " : "  ") <<
+       std::string(pLD[line].pLine, pLD[line].size) << std::endl;*/
+
+      ++line;
+   }
+}
+
+
+
+// First step
+void calcDiff3LineListUsingAB(
+   const DiffList* pDiffListAB,
+   Diff3LineList& d3ll
+   )
+{
+   // First make d3ll for AB (from pDiffListAB)
+
+   DiffList::const_iterator i=pDiffListAB->begin();
+   int lineA=0;
+   int lineB=0;
+   Diff d(0,0,0);
+
+   for(;;)
+   {
+      if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
+      {
+         if ( i!=pDiffListAB->end() )
+         {
+            d=*i;
+            ++i;
+         }
+         else
+            break;
+      }
+
+      Diff3Line d3l;
+      if( d.nofEquals>0 )
+      {
+         d3l.bAEqB = true;
+         d3l.lineA = lineA;
+         d3l.lineB = lineB;
+         --d.nofEquals;
+         ++lineA;
+         ++lineB;
+      }
+      else if ( d.diff1>0 && d.diff2>0 )
+      {
+         d3l.lineA = lineA;
+         d3l.lineB = lineB;
+         --d.diff1;
+         --d.diff2;
+         ++lineA;
+         ++lineB;
+      }
+      else if ( d.diff1>0 )
+      {
+         d3l.lineA = lineA;
+         --d.diff1;
+         ++lineA;
+      }
+      else if ( d.diff2>0 )
+      {
+         d3l.lineB = lineB;
+         --d.diff2;
+         ++lineB;
+      }
+
+      d3ll.push_back( d3l );
+   }
+}
+
+
+// Second step
+void calcDiff3LineListUsingAC(
+   const DiffList* pDiffListAC,
+   Diff3LineList& d3ll
+   )
+{
+   ////////////////
+   // Now insert data from C using pDiffListAC
+
+   DiffList::const_iterator i=pDiffListAC->begin();
+   Diff3LineList::iterator i3 = d3ll.begin();
+   int lineA=0;
+   int lineC=0;
+   Diff d(0,0,0);
+
+   for(;;)
+   {
+      if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
+      {
+         if ( i!=pDiffListAC->end() )
+         {
+            d=*i;
+            ++i;
+         }
+         else
+            break;
+      }
+
+      Diff3Line d3l;
+      if( d.nofEquals>0 )
+      {
+         // Find the corresponding lineA
+         while( (*i3).lineA!=lineA )
+            ++i3;
+
+         (*i3).lineC = lineC;
+         (*i3).bAEqC = true;
+         (*i3).bBEqC = (*i3).bAEqB;
+
+         --d.nofEquals;
+         ++lineA;
+         ++lineC;
+         ++i3;
+      }
+      else if ( d.diff1>0 && d.diff2>0 )
+      {
+         d3l.lineC = lineC;
+         d3ll.insert( i3, d3l );
+         --d.diff1;
+         --d.diff2;
+         ++lineA;
+         ++lineC;
+      }
+      else if ( d.diff1>0 )
+      {
+         --d.diff1;
+         ++lineA;
+      }
+      else if ( d.diff2>0 )
+      {
+         d3l.lineC = lineC;
+         d3ll.insert( i3, d3l );
+         --d.diff2;
+         ++lineC;
+      }
+   }
+}
+
+// Third step
+void calcDiff3LineListUsingBC(
+   const DiffList* pDiffListBC,
+   Diff3LineList& d3ll
+   )
+{
+   ////////////////
+   // Now improve the position of data from C using pDiffListBC
+   // If a line from C equals a line from A then it is in the
+   // same Diff3Line already.
+   // If a line from C equals a line from B but not A, this
+   // information will be used here.
+
+   DiffList::const_iterator i=pDiffListBC->begin();
+   Diff3LineList::iterator i3b = d3ll.begin();
+   Diff3LineList::iterator i3c = d3ll.begin();
+   int lineB=0;
+   int lineC=0;
+   Diff d(0,0,0);
+
+   for(;;)
+   {
+      if ( d.nofEquals==0 && d.diff1==0 && d.diff2==0 )
+      {
+         if ( i!=pDiffListBC->end() )
+         {
+            d=*i;
+            ++i;
+         }
+         else
+            break;
+      }
+
+      Diff3Line d3l;
+      if( d.nofEquals>0 )
+      {
+         // Find the corresponding lineB and lineC
+         while( i3b!=d3ll.end() && (*i3b).lineB!=lineB )
+            ++i3b;
+
+         while( i3c!=d3ll.end() && (*i3c).lineC!=lineC )
+            ++i3c;
+
+         assert(i3b!=d3ll.end());
+         assert(i3c!=d3ll.end());
+
+         if ( i3b==i3c )
+         {
+            assert( (*i3b).lineC == lineC );
+            (*i3b).bBEqC = true;
+         }
+         else
+         {
+            // Is it possible to move this line up?
+            // Test if no other B's are used between i3c and i3b
+
+            // First test which is before: i3c or i3b ?
+            Diff3LineList::iterator i3c1 = i3c;
+            Diff3LineList::iterator i3b1 = i3b;
+            while( i3c1!=i3b  &&  i3b1!=i3c )
+            {
+               assert(i3b1!=d3ll.end() || i3c1!=d3ll.end());
+               if( i3c1!=d3ll.end() ) ++i3c1;
+               if( i3b1!=d3ll.end() ) ++i3b1;
+            }
+
+            if( i3c1==i3b  &&  !(*i3b).bAEqB ) // i3c before i3b
+            {
+               Diff3LineList::iterator i3 = i3c;
+               int nofDisturbingLines = 0;
+               while( i3 != i3b && i3!=d3ll.end() )
+               {
+                  if ( (*i3).lineB != -1 )
+                     ++nofDisturbingLines;
+                  ++i3;
+               }
+
+               if ( nofDisturbingLines>0 )//&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 )
+               {
+                  // Move the disturbing lines up, out of sight.
+                  i3 = i3c;
+                  while( i3 != i3b )
+                  {
+                     if ( (*i3).lineB != -1 )
+                     {
+                        Diff3Line d3l;
+                        d3l.lineB = (*i3).lineB;
+                        (*i3).lineB = -1;
+                        (*i3).bAEqB = false;
+                        (*i3).bBEqC = false;
+                        d3ll.insert( i3c, d3l );
+                     }
+                     ++i3;
+                  }
+                  nofDisturbingLines=0;
+               }
+
+               if ( nofDisturbingLines == 0 )
+               {
+                  // Yes, the line from B can be moved.
+                  (*i3b).lineB = -1;   // This might leave an empty line: removed later.
+                  (*i3b).bAEqB = false;
+                  (*i3b).bAEqC = false;
+                  (*i3b).bBEqC = false;
+                  (*i3c).lineB = lineB;
+                  (*i3c).bBEqC = true;
+               }
+            }
+            else if( i3b1==i3c  &&  !(*i3c).bAEqC)
+            {
+               Diff3LineList::iterator i3 = i3b;
+               int nofDisturbingLines = 0;
+               while( i3 != i3c && i3!=d3ll.end() )
+               {
+                  if ( (*i3).lineC != -1 )
+                     ++nofDisturbingLines;
+                  ++i3;
+               }
+
+               if ( nofDisturbingLines>0 )//&& nofDisturbingLines < d.nofEquals*d.nofEquals+4 )
+               {
+                  // Move the disturbing lines up.
+                  i3 = i3b;
+                  while( i3 != i3c )
+                  {
+                     if ( (*i3).lineC != -1 )
+                     {
+                        Diff3Line d3l;
+                        d3l.lineC = (*i3).lineC;
+                        (*i3).lineC = -1;
+                        (*i3).bAEqC = false;
+                        (*i3).bBEqC = false;
+                        d3ll.insert( i3b, d3l );
+                     }
+                     ++i3;
+                  }
+                  nofDisturbingLines=0;
+               }
+
+               if ( nofDisturbingLines == 0 )
+               {
+                  // Yes, the line from C can be moved.
+                  (*i3c).lineC = -1;   // This might leave an empty line: removed later.
+                  (*i3c).bAEqC = false;
+                  (*i3c).bBEqC = false;
+                  (*i3b).lineC = lineC;
+                  (*i3b).bBEqC = true;
+               }
+            }
+         }
+
+         --d.nofEquals;
+         ++lineB;
+         ++lineC;
+         ++i3b;
+         ++i3c;
+      }
+      else if ( d.diff1>0 )
+      {
+         Diff3LineList::iterator i3 = i3b;
+         while( (*i3).lineB!=lineB )
+            ++i3;
+         if( i3 != i3b  &&  (*i3).bAEqB==false )
+         {
+            // Take B from this line and move it up as far as possible
+            d3l.lineB = lineB;
+            d3ll.insert( i3b, d3l );
+            (*i3).lineB = -1;
+         }
+         else
+         {
+            i3b=i3;
+         }
+         --d.diff1;
+         ++lineB;
+         ++i3b;
+
+         if( d.diff2>0 )
+         {
+            --d.diff2;
+            ++lineC;
+         }
+      }
+      else if ( d.diff2>0 )
+      {
+         --d.diff2;
+         ++lineC;
+      }
+   }
+/*
+   Diff3LineList::iterator it = d3ll.begin();
+   int li=0;
+   for( ; it!=d3ll.end(); ++it, ++li )
+   {
+      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",
+         li, (*it).lineA, (*it).lineB, (*it).lineC,
+         (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
+   }
+   printf("\n");*/
+}
+
+#ifdef _WIN32
+using ::equal;
+#endif
+
+// Test if the move would pass a barrier. Return true if not.
+static bool isValidMove( ManualDiffHelpList* pManualDiffHelpList, int line1, int line2, int winIdx1, int winIdx2 )
+{
+   if (line1>=0 && line2>=0)
+   {
+      ManualDiffHelpList::const_iterator i;
+      for( i = pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i )
+      {
+         const ManualDiffHelpEntry& mdhe = *i;
+
+         // Barrier
+         int l1 = winIdx1 == 1 ? mdhe.lineA1 : winIdx1==2 ? mdhe.lineB1 : mdhe.lineC1 ;
+         int l2 = winIdx2 == 1 ? mdhe.lineA1 : winIdx2==2 ? mdhe.lineB1 : mdhe.lineC1 ;
+
+         if ( l1>=0 && l2>=0 )
+         {
+            if ( line1>=l1 && line2<l2 || line1<l1 && line2>=l2 )
+               return false;
+            l1 = winIdx1 == 1 ? mdhe.lineA2 : winIdx1==2 ? mdhe.lineB2 : mdhe.lineC2 ;
+            l2 = winIdx2 == 1 ? mdhe.lineA2 : winIdx2==2 ? mdhe.lineB2 : mdhe.lineC2 ;
+            ++l1;
+            ++l2;
+            if ( line1>=l1 && line2<l2 || line1<l1 && line2>=l2 )
+               return false;
+         }
+      }
+   }
+   return true; // no barrier passed.
+}
+
+void correctManualDiffAlignment( Diff3LineList& d3ll, ManualDiffHelpList* pManualDiffHelpList )
+{
+   if ( pManualDiffHelpList->empty() )
+      return;
+
+   // If a line appears unaligned in comparison to the manual alignment, correct this.
+
+   ManualDiffHelpList::iterator iMDHL;
+   for( iMDHL =  pManualDiffHelpList->begin(); iMDHL != pManualDiffHelpList->end(); ++iMDHL )
+   {
+      Diff3LineList::iterator i3 = d3ll.begin();
+      int winIdxPreferred = 0;
+      int missingWinIdx = 0;
+      int alignedSum = (iMDHL->lineA1<0?0:1) + (iMDHL->lineB1<0?0:1) + (iMDHL->lineC1<0?0:1);
+      if (alignedSum==2)
+      {
+         // If only A & B are aligned then let C rather be aligned with A
+         // If only A & C are aligned then let B rather be aligned with A
+         // If only B & C are aligned then let A rather be aligned with B
+         missingWinIdx = iMDHL->lineA1<0 ? 1 : (iMDHL->lineB1<0 ? 2 : 3 );
+         winIdxPreferred = missingWinIdx == 1 ? 2 : 1; 
+      }
+      else if (alignedSum<=1)
+      {
+         return;
+      }
+
+      // At the first aligned line, move up the two other lines into new d3ls until the second input is aligned
+      // Then move up the third input until all three lines are aligned.
+      int wi=0;
+      for( ; i3!=d3ll.end(); ++i3 )
+      {
+         for ( wi=1; wi<=3; ++wi )
+         {
+            if ( i3->getLineInFile(wi) >= 0 && iMDHL->firstLine(wi) == i3->getLineInFile(wi) )
+               break;
+         }
+         if ( wi<=3 )
+            break;
+      }
+
+      if (wi>=1 && wi <= 3)
+      {
+         // Found manual alignment for one source
+         Diff3LineList::iterator iDest = i3;
+
+         // Move lines up until the next firstLine is found. Omit wi from move and search.
+         int wi2=0;
+         for( ; i3!=d3ll.end(); ++i3 )
+         {
+            for ( wi2=1; wi2<=3; ++wi2 )
+            {
+               if ( wi!=wi2 && i3->getLineInFile(wi2) >= 0 && iMDHL->firstLine(wi2) == i3->getLineInFile(wi2) )
+                  break;
+            }
+            if (wi2>3)
+            {  // Not yet found
+               // Move both others up
+               Diff3Line d3l;
+               // Move both up
+               if (wi==1) // Move B and C up
+               {
+                  d3l.bBEqC = i3->bBEqC;
+                  d3l.lineB = i3->lineB;
+                  d3l.lineC = i3->lineC;
+                  i3->lineB = -1;
+                  i3->lineC = -1;
+               }
+               if (wi==2) // Move A and C up
+               {
+                  d3l.bAEqC = i3->bAEqC;
+                  d3l.lineA = i3->lineA;
+                  d3l.lineC = i3->lineC;
+                  i3->lineA = -1;
+                  i3->lineC = -1;
+               }
+               if (wi==3) // Move A and B up
+               {
+                  d3l.bAEqB = i3->bAEqB;
+                  d3l.lineA = i3->lineA;
+                  d3l.lineB = i3->lineB;
+                  i3->lineA = -1;
+                  i3->lineB = -1;
+               }
+               i3->bAEqB = false;
+               i3->bAEqC = false;
+               i3->bBEqC = false;
+               d3ll.insert( iDest, d3l );
+            }
+            else 
+            {
+               // align the found line with the line we already have here
+               if ( i3 != iDest )
+               {
+                  if (wi2==1)
+                  {
+                     iDest->lineA = i3->lineA;
+                     i3->lineA = -1;
+                     i3->bAEqB = false;
+                     i3->bAEqC = false;                   
+                  }
+                  else if (wi2==2)
+                  {
+                     iDest->lineB = i3->lineB;
+                     i3->lineB = -1;
+                     i3->bAEqB = false;
+                     i3->bBEqC = false;                   
+                  }
+                  else if (wi2==3)
+                  {
+                     iDest->lineC = i3->lineC;
+                     i3->lineC = -1;
+                     i3->bBEqC = false;
+                     i3->bAEqC = false;                   
+                  }
+               }
+
+               if ( missingWinIdx!=0 )
+               {
+                  for( ; i3!=d3ll.end(); ++i3 )
+                  {
+                     int wi3 = missingWinIdx;
+                     if ( i3->getLineInFile(wi3) >= 0 )
+                     {
+                        // not found, move the line before iDest
+                        Diff3Line d3l;
+                        if ( wi3==1 )
+                        {
+                           if (i3->bAEqB)  // Stop moving lines up if one equal is found.
+                              break;
+                           d3l.lineA = i3->lineA;
+                           i3->lineA = -1;
+                           i3->bAEqB = false;
+                           i3->bAEqC = false;
+                        }
+                        if ( wi3==2 )
+                        {
+                           if (i3->bAEqB)
+                              break;
+                           d3l.lineB = i3->lineB;
+                           i3->lineB = -1;
+                           i3->bAEqB = false;
+                           i3->bBEqC = false;
+                        }
+                        if ( wi3==3 )
+                        {
+                           if (i3->bAEqC)
+                              break;
+                           d3l.lineC = i3->lineC;
+                           i3->lineC = -1;
+                           i3->bAEqC = false;
+                           i3->bBEqC = false;
+                        }
+                        d3ll.insert( iDest, d3l );
+                     }
+                  } // for(), searching for wi3
+               }
+               break;
+            }
+         } // for(), searching for wi2
+      } // if, wi found
+   } // for (iMDHL)
+}
+
+// Fourth step
+void calcDiff3LineListTrim(
+   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC, ManualDiffHelpList* pManualDiffHelpList
+   )
+{
+   const Diff3Line d3l_empty;
+   d3ll.remove( d3l_empty );
+
+   Diff3LineList::iterator i3 = d3ll.begin();
+   Diff3LineList::iterator i3A = d3ll.begin();
+   Diff3LineList::iterator i3B = d3ll.begin();
+   Diff3LineList::iterator i3C = d3ll.begin();
+
+   int line=0;  // diff3line counters
+   int lineA=0; // 
+   int lineB=0;
+   int lineC=0;
+
+   ManualDiffHelpList::iterator iMDHL = pManualDiffHelpList->begin();
+   // The iterator i3 and the variable line look ahead.
+   // The iterators i3A, i3B, i3C and corresponding lineA, lineB and lineC stop at empty lines, if found.
+   // If possible, then the texts from the look ahead will be moved back to the empty places.
+
+   for( ; i3!=d3ll.end(); ++i3, ++line )
+   {
+      if ( iMDHL!=pManualDiffHelpList->end() )
+      {
+         if ( i3->lineA >= 0 && i3->lineA==iMDHL->lineA1 || 
+              i3->lineB >= 0 && i3->lineB==iMDHL->lineB1 || 
+              i3->lineC >= 0 && i3->lineC==iMDHL->lineC1 )
+         {
+            i3A = i3;
+            i3B = i3;
+            i3C = i3;
+            lineA = line;
+            lineB = line;
+            lineC = line;
+            ++iMDHL;
+         }
+      }
+
+      if( line>lineA && (*i3).lineA != -1 && (*i3A).lineB!=-1 && (*i3A).bBEqC  &&
+          ::equal( pldA[(*i3).lineA], pldB[(*i3A).lineB], false ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3 ) )
+      {
+         // Empty space for A. A matches B and C in the empty line. Move it up.
+         (*i3A).lineA = (*i3).lineA;
+         (*i3A).bAEqB = true;
+         (*i3A).bAEqC = true;
+         (*i3).lineA = -1;
+         (*i3).bAEqB = false;
+         (*i3).bAEqC = false;
+         ++i3A;
+         ++lineA;
+      }
+
+      if( line>lineB && (*i3).lineB != -1 && (*i3B).lineA!=-1 && (*i3B).bAEqC  &&
+          ::equal( pldB[(*i3).lineB], pldA[(*i3B).lineA], false ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3 ) )
+      {
+         // Empty space for B. B matches A and C in the empty line. Move it up.
+         (*i3B).lineB = (*i3).lineB;
+         (*i3B).bAEqB = true;
+         (*i3B).bBEqC = true;
+         (*i3).lineB = -1;
+         (*i3).bAEqB = false;
+         (*i3).bBEqC = false;
+         ++i3B;
+         ++lineB;
+      }
+
+      if( line>lineC && (*i3).lineC != -1 && (*i3C).lineA!=-1 && (*i3C).bAEqB  &&
+          ::equal( pldC[(*i3).lineC], pldA[(*i3C).lineA], false )&&
+          isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2 ) )
+      {
+         // Empty space for C. C matches A and B in the empty line. Move it up.
+         (*i3C).lineC = (*i3).lineC;
+         (*i3C).bAEqC = true;
+         (*i3C).bBEqC = true;
+         (*i3).lineC = -1;
+         (*i3).bAEqC = false;
+         (*i3).bBEqC = false;
+         ++i3C;
+         ++lineC;
+      }
+
+      if( line>lineA && (*i3).lineA != -1 && !(*i3).bAEqB && !(*i3).bAEqC && 
+          isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineB, 1, 2 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineA, (*i3A).lineC, 1, 3 ) )      {
+         // Empty space for A. A doesn't match B or C. Move it up.
+         (*i3A).lineA = (*i3).lineA;
+         (*i3).lineA = -1;
+         ++i3A;
+         ++lineA;
+      }
+
+      if( line>lineB && (*i3).lineB != -1 && !(*i3).bAEqB && !(*i3).bBEqC  &&
+          isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineA, 2, 1 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineB, (*i3B).lineC, 2, 3 ) )
+      {
+         // Empty space for B. B matches neither A nor C. Move B up.
+         (*i3B).lineB = (*i3).lineB;
+         (*i3).lineB = -1;
+         ++i3B;
+         ++lineB;
+      }
+
+      if( line>lineC && (*i3).lineC != -1 && !(*i3).bAEqC && !(*i3).bBEqC &&
+          isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineA, 3, 1 ) &&
+          isValidMove( pManualDiffHelpList, (*i3).lineC, (*i3C).lineB, 3, 2 ) )
+      {
+         // Empty space for C. C matches neither A nor B. Move C up.
+         (*i3C).lineC = (*i3).lineC;
+         (*i3).lineC = -1;
+         ++i3C;
+         ++lineC;
+      }
+
+      if( line>lineA && line>lineB && (*i3).lineA != -1 && (*i3).bAEqB && !(*i3).bAEqC )
+      {
+         // Empty space for A and B. A matches B, but not C. Move A & B up.
+         Diff3LineList::iterator i = lineA > lineB ? i3A   : i3B;
+         int                     l = lineA > lineB ? lineA : lineB;
+
+         if ( isValidMove( pManualDiffHelpList, i->lineC, (*i3).lineA, 3, 1 ) &&
+              isValidMove( pManualDiffHelpList, i->lineC, (*i3).lineB, 3, 2 ) )
+         {
+            (*i).lineA = (*i3).lineA;
+            (*i).lineB = (*i3).lineB;
+            (*i).bAEqB = true;
+
+            (*i3).lineA = -1;
+            (*i3).lineB = -1;
+            (*i3).bAEqB = false;
+            i3A = i;
+            i3B = i;
+            ++i3A;
+            ++i3B;
+            lineA=l+1;
+            lineB=l+1;
+         }
+      }
+      else if( line>lineA && line>lineC && (*i3).lineA != -1 && (*i3).bAEqC && !(*i3).bAEqB )
+      {
+         // Empty space for A and C. A matches C, but not B. Move A & C up.
+         Diff3LineList::iterator i = lineA > lineC ? i3A   : i3C;
+         int                     l = lineA > lineC ? lineA : lineC;
+
+         if ( isValidMove( pManualDiffHelpList, i->lineB, (*i3).lineA, 2, 1 ) &&
+              isValidMove( pManualDiffHelpList, i->lineB, (*i3).lineC, 2, 3 ) )
+         {
+            (*i).lineA = (*i3).lineA;
+            (*i).lineC = (*i3).lineC;
+            (*i).bAEqC = true;
+
+            (*i3).lineA = -1;
+            (*i3).lineC = -1;
+            (*i3).bAEqC = false;
+            i3A = i;
+            i3C = i;
+            ++i3A;
+            ++i3C;
+            lineA=l+1;
+            lineC=l+1;
+         }
+      }
+      else if( line>lineB && line>lineC && (*i3).lineB != -1 && (*i3).bBEqC && !(*i3).bAEqC )
+      {
+         // Empty space for B and C. B matches C, but not A. Move B & C up.
+         Diff3LineList::iterator i = lineB > lineC ? i3B   : i3C;
+         int                     l = lineB > lineC ? lineB : lineC;
+
+         if ( isValidMove( pManualDiffHelpList, i->lineA, (*i3).lineB, 1, 2 ) &&
+              isValidMove( pManualDiffHelpList, i->lineA, (*i3).lineC, 1, 3 ) )
+         {
+            (*i).lineB = (*i3).lineB;
+            (*i).lineC = (*i3).lineC;
+            (*i).bBEqC = true;
+
+            (*i3).lineB = -1;
+            (*i3).lineC = -1;
+            (*i3).bBEqC = false;
+            i3B = i;
+            i3C = i;
+            ++i3B;
+            ++i3C;
+            lineB=l+1;
+            lineC=l+1;
+         }
+      }
+
+      if ( (*i3).lineA != -1 )
+      {
+         lineA = line+1;
+         i3A = i3;
+         ++i3A;
+      }
+      if ( (*i3).lineB != -1 )
+      {
+         lineB = line+1;
+         i3B = i3;
+         ++i3B;
+      }
+      if ( (*i3).lineC != -1 )
+      {
+         lineC = line+1;
+         i3C = i3;
+         ++i3C;
+      }
+   }
+
+   d3ll.remove( d3l_empty );
+
+/*
+
+   Diff3LineList::iterator it = d3ll.begin();
+   int li=0;
+   for( ; it!=d3ll.end(); ++it, ++li )
+   {
+      printf( "%4d %4d %4d %4d  A%c=B A%c=C B%c=C\n",
+         li, (*it).lineA, (*it).lineB, (*it).lineC,
+         (*it).bAEqB ? '=' : '!', (*it).bAEqC ? '=' : '!', (*it).bBEqC ? '=' : '!' );
+
+   }
+*/
+}
+
+void DiffBufferInfo::init( Diff3LineList* pD3ll, const Diff3LineVector* pD3lv,
+   const LineData* pldA, int sizeA, const LineData* pldB, int sizeB, const LineData* pldC, int sizeC )
+{
+   m_pDiff3LineList = pD3ll;
+   m_pDiff3LineVector = pD3lv;
+   m_pLineDataA = pldA;
+   m_pLineDataB = pldB;
+   m_pLineDataC = pldC;
+   m_sizeA = sizeA;
+   m_sizeB = sizeB;
+   m_sizeC = sizeC;
+   Diff3LineList::iterator i3 = pD3ll->begin();
+   for( ; i3!=pD3ll->end(); ++i3 )
+   {
+      i3->m_pDiffBufferInfo = this;
+   }
+}
+
+void calcWhiteDiff3Lines(
+   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC
+   )
+{
+   Diff3LineList::iterator i3 = d3ll.begin();
+
+   for( ; i3!=d3ll.end(); ++i3 )
+   {
+      i3->bWhiteLineA = ( (*i3).lineA == -1  ||  pldA==0 ||  pldA[(*i3).lineA].whiteLine() || pldA[(*i3).lineA].bContainsPureComment );
+      i3->bWhiteLineB = ( (*i3).lineB == -1  ||  pldB==0 ||  pldB[(*i3).lineB].whiteLine() || pldB[(*i3).lineB].bContainsPureComment );
+      i3->bWhiteLineC = ( (*i3).lineC == -1  ||  pldC==0 ||  pldC[(*i3).lineC].whiteLine() || pldC[(*i3).lineC].bContainsPureComment );
+   }
+}
+
+// Just make sure that all input lines are in the output too, exactly once.
+void debugLineCheck( Diff3LineList& d3ll, int size, int idx )
+{
+   Diff3LineList::iterator it = d3ll.begin();
+   int i=0;
+
+   for ( it = d3ll.begin(); it!= d3ll.end(); ++it )
+   {
+      int l=0;
+      if      (idx==1) l=(*it).lineA;
+      else if (idx==2) l=(*it).lineB;
+      else if (idx==3) l=(*it).lineC;
+      else assert(false);
+
+      if ( l!=-1 )
+      {
+         if( l!=i )
+         {
+            KMessageBox::error(0, i18n(
+               "Data loss error:\n"
+               "If it is reproducable please contact the author.\n"
+               ), i18n("Severe Internal Error") );
+            assert(false);
+            std::cerr << "Severe Internal Error.\n";
+            ::exit(-1);
+         }
+         ++i;
+      }
+   }
+
+   if( size!=i )
+   {
+      KMessageBox::error(0, i18n(
+         "Data loss error:\n"
+         "If it is reproducable please contact the author.\n"
+         ), i18n("Severe Internal Error") );
+      assert(false);
+      std::cerr << "Severe Internal Error.\n";
+      ::exit(-1);
+   }
+}
+
+inline bool equal( QChar c1, QChar 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,
+   const LineData* v1,
+   const LineData* v2,
+   bool& bTextsTotalEqual
+   )
+{
+   // Finetuning: Diff each line with deltas
+   ProgressProxy pp;
+   int maxSearchLength=500;
+   Diff3LineList::iterator i;
+   int k1=0;
+   int k2=0;
+   bTextsTotalEqual = true;
+   int listSize = diff3LineList.size();
+   int listIdx = 0;
+   for( i= diff3LineList.begin(); i!= diff3LineList.end(); ++i)
+   {
+      if      (selector==1){ k1=i->lineA; k2=i->lineB; }
+      else if (selector==2){ k1=i->lineB; k2=i->lineC; }
+      else if (selector==3){ k1=i->lineC; k2=i->lineA; }
+      else assert(false);
+      if( k1==-1 && k2!=-1  ||  k1!=-1 && k2==-1 ) bTextsTotalEqual=false;
+      if( k1!=-1 && k2!=-1 )
+      {
+         if ( v1[k1].size != v2[k2].size || memcmp( v1[k1].pLine, v2[k2].pLine, v1[k1].size<<1)!=0 )
+         {
+            bTextsTotalEqual = false;
+            DiffList* pDiffList = new DiffList;
+            calcDiff( v1[k1].pLine, v1[k1].size, v2[k2].pLine, v2[k2].size, *pDiffList, 2, maxSearchLength );
+
+            // Optimize the diff list.
+            DiffList::iterator dli;
+            bool bUsefulFineDiff = false;
+            for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
+            {
+               if( dli->nofEquals >= 4 )
+               {
+                  bUsefulFineDiff = true;
+                  break;
+               }
+            }
+
+            for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
+            {
+               if( dli->nofEquals < 4  &&  (dli->diff1>0 || dli->diff2>0) 
+                  && !( bUsefulFineDiff && dli==pDiffList->begin() )
+               )
+               {
+                  dli->diff1 += dli->nofEquals;
+                  dli->diff2 += dli->nofEquals;
+                  dli->nofEquals = 0;
+               }
+            }
+
+            if      (selector==1){ delete (*i).pFineAB; (*i).pFineAB = pDiffList; }
+            else if (selector==2){ delete (*i).pFineBC; (*i).pFineBC = pDiffList; }
+            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;
+      pp.setCurrent(double(listIdx)/listSize);
+   }
+}
+
+
+// Convert the list to a vector of pointers
+void calcDiff3LineVector( Diff3LineList& d3ll, Diff3LineVector& d3lv )
+{
+   d3lv.resize( d3ll.size() );
+   Diff3LineList::iterator i;
+   int j=0;
+   for( i= d3ll.begin(); i!= d3ll.end(); ++i, ++j)
+   {
+      d3lv[j] = &(*i);
+   }
+   assert( j==(int)d3lv.size() );
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/diff.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,462 @@
+/***************************************************************************
+                          diff.h  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef DIFF_H
+#define DIFF_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#include <qframe.h>
+#include <qtextstream.h>
+#include <qpainter.h>
+#include <list>
+#include <vector>
+#include <assert.h>
+#include "common.h"
+#include "fileaccess.h"
+
+class OptionDialog;
+
+// Each range with matching elements is followed by a range with differences on either side.
+// Then again range of matching elements should follow.
+struct Diff
+{
+   int nofEquals;
+
+   int diff1;
+   int diff2;
+
+   Diff(int eq, int d1, int d2){nofEquals=eq; diff1=d1; diff2=d2; }
+};
+
+typedef std::list<Diff> DiffList;
+
+struct LineData
+{
+   const QChar* pLine;
+   const QChar* pFirstNonWhiteChar;
+   int size;
+
+   LineData(){ pLine=0; pFirstNonWhiteChar=0; size=0; /*occurances=0;*/ bContainsPureComment=false; }
+   int width(int tabSize) const;  // Calcs width considering tabs.
+   //int occurances;
+   bool whiteLine() const { return pFirstNonWhiteChar-pLine == size; }
+   bool bContainsPureComment;
+};
+
+class Diff3LineList;
+class Diff3LineVector;
+
+struct DiffBufferInfo
+{
+   const LineData* m_pLineDataA;
+   const LineData* m_pLineDataB;
+   const LineData* m_pLineDataC;
+   int m_sizeA;
+   int m_sizeB;
+   int m_sizeC;
+   const Diff3LineList* m_pDiff3LineList;
+   const Diff3LineVector* m_pDiff3LineVector;
+   void init( Diff3LineList* d3ll, const Diff3LineVector* d3lv,
+      const LineData* pldA, int sizeA, const LineData* pldB, int sizeB, const LineData* pldC, int sizeC );
+};
+
+struct Diff3Line
+{
+   int lineA;
+   int lineB;
+   int lineC;
+
+   bool bAEqC : 1;             // These are true if equal or only white-space changes exist.
+   bool bBEqC : 1;
+   bool bAEqB : 1;
+
+   bool bWhiteLineA : 1;
+   bool bWhiteLineB : 1;
+   bool bWhiteLineC : 1;
+
+   DiffList* pFineAB;          // These are 0 only if completely equal or if either source doesn't exist.
+   DiffList* pFineBC;
+   DiffList* pFineCA;
+
+   int linesNeededForDisplay; // Due to wordwrap
+   int sumLinesNeededForDisplay; // For fast conversion to m_diff3WrapLineVector
+
+   DiffBufferInfo* m_pDiffBufferInfo; // For convenience
+
+   Diff3Line()
+   {
+      lineA=-1; lineB=-1; lineC=-1;
+      bAEqC=false; bAEqB=false; bBEqC=false;
+      pFineAB=0; pFineBC=0; pFineCA=0;
+      linesNeededForDisplay=1;
+      sumLinesNeededForDisplay=0;
+      bWhiteLineA=false; bWhiteLineB=false; bWhiteLineC=false;
+      m_pDiffBufferInfo=0;
+   }
+
+   ~Diff3Line()
+   {
+      if (pFineAB!=0) delete pFineAB;
+      if (pFineBC!=0) delete pFineBC;
+      if (pFineCA!=0) delete pFineCA;
+      pFineAB=0; pFineBC=0; pFineCA=0;
+   }
+
+   bool operator==( const Diff3Line& d3l )
+   {
+      return lineA == d3l.lineA  &&  lineB == d3l.lineB  &&  lineC == d3l.lineC  
+         && bAEqB == d3l.bAEqB  && bAEqC == d3l.bAEqC  && bBEqC == d3l.bBEqC;
+   }
+
+   const LineData* getLineData( int src ) const
+   {
+      assert( m_pDiffBufferInfo!=0 );
+      if ( src == 1 && lineA >= 0 ) return &m_pDiffBufferInfo->m_pLineDataA[lineA];
+      if ( src == 2 && lineB >= 0 ) return &m_pDiffBufferInfo->m_pLineDataB[lineB];
+      if ( src == 3 && lineC >= 0 ) return &m_pDiffBufferInfo->m_pLineDataC[lineC];
+      return 0;
+   }
+   QString getString( int src ) const
+   {
+      const LineData* pld = getLineData(src);
+      if ( pld )
+         return QString( pld->pLine, pld->size);
+      else
+         return QString();
+   }
+   int getLineInFile( int src ) const
+   {
+      if ( src == 1 ) return lineA;
+      if ( src == 2 ) return lineB;
+      if ( src == 3 ) return lineC;
+      return -1;
+   }
+};
+
+
+class Diff3LineList : public std::list<Diff3Line>
+{
+};
+class Diff3LineVector : public std::vector<Diff3Line*>
+{
+};
+
+class Diff3WrapLine
+{
+public:
+   Diff3Line* pD3L;
+   int diff3LineIndex;
+   int wrapLineOffset;
+   int wrapLineLength;
+};
+
+typedef std::vector<Diff3WrapLine> Diff3WrapLineVector;
+
+
+class TotalDiffStatus
+{
+public:
+   TotalDiffStatus(){ reset(); }
+   void reset() {bBinaryAEqC=false; bBinaryBEqC=false; bBinaryAEqB=false;
+                 bTextAEqC=false;   bTextBEqC=false;   bTextAEqB=false;
+                 nofUnsolvedConflicts=0; nofSolvedConflicts=0;
+                 nofWhitespaceConflicts=0;
+                }
+   bool bBinaryAEqC;
+   bool bBinaryBEqC;
+   bool bBinaryAEqB;
+
+   bool bTextAEqC;
+   bool bTextBEqC;
+   bool bTextAEqB;
+
+   int nofUnsolvedConflicts;
+   int nofSolvedConflicts;
+   int nofWhitespaceConflicts;
+};
+
+// Three corresponding ranges. (Minimum size of a valid range is one line.)
+class ManualDiffHelpEntry
+{
+public:
+   ManualDiffHelpEntry() { lineA1=-1; lineA2=-1; 
+                           lineB1=-1; lineB2=-1; 
+                           lineC1=-1; lineC2=-1; }
+   int lineA1;
+   int lineA2;
+   int lineB1;
+   int lineB2;
+   int lineC1;
+   int lineC2;
+   int& firstLine( int winIdx )
+   {
+      return winIdx==1 ? lineA1 : (winIdx==2 ? lineB1 : lineC1 );
+   }
+   int& lastLine( int winIdx )
+   {
+      return winIdx==1 ? lineA2 : (winIdx==2 ? lineB2 : lineC2 );
+   }
+   bool isLineInRange( int line, int winIdx )
+   {
+      return line>=0 && line>=firstLine(winIdx) && line<=lastLine(winIdx);
+   }
+   bool operator==(const ManualDiffHelpEntry& r) const
+   {
+      return lineA1 == r.lineA1   &&   lineB1 == r.lineB1   &&   lineC1 == r.lineC1  &&
+             lineA2 == r.lineA2   &&   lineB2 == r.lineB2   &&   lineC2 == r.lineC2;
+   }
+};
+
+// A list of corresponding ranges
+typedef std::list<ManualDiffHelpEntry> ManualDiffHelpList;
+
+void calcDiff3LineListUsingAB(
+   const DiffList* pDiffListAB,
+   Diff3LineList& d3ll
+   );
+
+void calcDiff3LineListUsingAC(
+   const DiffList* pDiffListBC,
+   Diff3LineList& d3ll
+   );
+
+void calcDiff3LineListUsingBC(
+   const DiffList* pDiffListBC,
+   Diff3LineList& d3ll
+   );
+
+void correctManualDiffAlignment( Diff3LineList& d3ll, ManualDiffHelpList* pManualDiffHelpList );
+
+class SourceData
+{
+public:
+   SourceData();
+   ~SourceData();
+
+   void setOptionDialog( OptionDialog* pOptionDialog );
+
+   int getSizeLines() const;
+   int getSizeBytes() const;
+   const char* getBuf() const;
+   const LineData* getLineDataForDisplay() const;
+   const LineData* getLineDataForDiff() const;
+
+   void setFilename(const QString& filename);
+   void setFileAccess( const FileAccess& fa );
+   //FileAccess& getFileAccess();
+   QString getFilename();
+   void setAliasName(const QString& a);
+   QString getAliasName();
+   bool isEmpty();  // File was set
+   bool hasData();  // Data was readable
+   bool isText();   // is it pure text (vs. binary data)
+   bool isFromBuffer();  // was it set via setData() (vs. setFileAccess() or setFilename())
+   void setData( const QString& data );
+   bool isValid(); // Either no file is specified or reading was successful
+
+   void readAndPreprocess(QTextCodec* pEncoding, bool bAutoDetectUnicode );
+   bool saveNormalDataAs( const QString& fileName );
+
+   bool isBinaryEqualWith( const SourceData& other ) const;
+
+   void reset();
+
+   QTextCodec* getEncoding() const { return m_pEncoding; }
+
+private:
+   QTextCodec* detectEncoding( const QString& fileName, QTextCodec* pFallbackCodec );
+   QString m_aliasName;
+   FileAccess m_fileAccess;
+   OptionDialog* m_pOptionDialog;
+   QString m_tempInputFileName;
+
+   struct FileData
+   {
+      FileData(){ m_pBuf=0; m_size=0; m_vSize=0; m_bIsText=false; }
+      ~FileData(){ reset(); }
+      const char* m_pBuf;
+      int m_size;
+      int m_vSize; // Nr of lines in m_pBuf1 and size of m_v1, m_dv12 and m_dv13
+      QString m_unicodeBuf;
+      std::vector<LineData> m_v;
+      bool m_bIsText;
+      bool readFile( const QString& filename );
+      bool writeFile( const QString& filename );
+      void preprocess(bool bPreserveCR, QTextCodec* pEncoding );
+      void reset();
+      void removeComments();
+      void copyBufFrom( const FileData& src );
+   };
+   FileData m_normalData;
+   FileData m_lmppData;  
+   QTextCodec* m_pEncoding; 
+};
+
+void calcDiff3LineListTrim( Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC, ManualDiffHelpList* pManualDiffHelpList );
+void calcWhiteDiff3Lines(   Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC );
+
+void calcDiff3LineVector( Diff3LineList& d3ll, Diff3LineVector& d3lv );
+
+void debugLineCheck( Diff3LineList& d3ll, int size, int idx );
+
+class QStatusBar;
+
+
+class Selection
+{
+public:
+   Selection(){ reset(); oldLastLine=-1; lastLine=-1; oldFirstLine=-1; }
+   int firstLine;
+   int firstPos;
+   int lastLine;
+   int lastPos;
+   int oldLastLine;
+   int oldFirstLine;
+   bool bSelectionContainsData;
+   bool isEmpty() { return firstLine==-1 || (firstLine==lastLine && firstPos==lastPos) || bSelectionContainsData==false;}
+   void reset(){
+      oldFirstLine=firstLine;
+      oldLastLine =lastLine;
+      firstLine=-1;
+      lastLine=-1;
+      bSelectionContainsData = false;
+   }
+   void start( int l, int p ) { firstLine = l; firstPos = p; }
+   void end( int l, int p )  {
+      if ( oldLastLine == -1 )
+         oldLastLine = lastLine;
+      lastLine  = l;
+      lastPos  = p;
+   }
+   bool within( int l, int p );
+
+   bool lineWithin( int l );
+   int firstPosInLine(int l);
+   int lastPosInLine(int l);
+   int beginLine(){ 
+      if (firstLine<0 && lastLine<0) return -1;
+      return max2(0,min2(firstLine,lastLine)); 
+   }
+   int endLine(){ 
+      if (firstLine<0 && lastLine<0) return -1;
+      return max2(firstLine,lastLine); 
+   }
+   int beginPos() { return firstLine==lastLine ? min2(firstPos,lastPos) :
+                           firstLine<lastLine ? (firstLine<0?0:firstPos) : (lastLine<0?0:lastPos);  }
+   int endPos()   { return firstLine==lastLine ? max2(firstPos,lastPos) :
+                           firstLine<lastLine ? lastPos : firstPos;      }
+};
+
+class OptionDialog;
+
+QCString encodeString( const QString& s );
+
+
+// Helper class that swaps left and right for some commands.
+class MyPainter : public QPainter
+{
+   int m_factor;
+   int m_xOffset;
+   int m_fontWidth;
+public:
+   MyPainter(const QPaintDevice* pd, bool bRTL, int width, int fontWidth) 
+   : QPainter(pd)
+   {
+      if (bRTL) 
+      {
+         m_fontWidth = fontWidth;
+         m_factor = -1;
+         m_xOffset = width-1;
+      }
+      else
+      {
+         m_fontWidth = 0;
+         m_factor = 1;
+         m_xOffset = 0;
+      }
+   }
+
+   void fillRect( int x, int y, int w, int h, const QBrush& b )
+   {
+      if (m_factor==1)
+         QPainter::fillRect( m_xOffset + x    , y, w, h, b );
+      else
+         QPainter::fillRect( m_xOffset - x - w, y, w, h, b );
+   }
+
+   void drawText( int x, int y, const QString& s, bool bAdapt=false )
+   {
+      TextDirection td = (m_factor==1 || bAdapt == false) ? LTR : RTL;
+      QPainter::drawText( m_xOffset-m_fontWidth*s.length() + m_factor*x, y, s, -1, td );
+   }
+
+   void drawLine( int x1, int y1, int x2, int y2 )
+   {
+      QPainter::drawLine( m_xOffset + m_factor*x1, y1, m_xOffset + m_factor*x2, y2 );
+   }
+};
+
+void fineDiff(
+   Diff3LineList& diff3LineList,
+   int selector,
+   const LineData* v1,
+   const LineData* v2,
+   bool& bTextsTotalEqual
+   );
+
+
+bool equal( const LineData& l1, const LineData& l2, bool bStrict );
+
+
+
+
+inline bool isWhite( QChar c )
+{
+   return c==' ' || c=='\t' ||  c=='\r';
+}
+
+/** Returns the number of equivalent spaces at position outPos.
+*/
+inline int tabber( int outPos, int tabSize )
+{
+   return tabSize - ( outPos % tabSize );
+}
+
+/** Returns a line number where the linerange [line, line+nofLines] can
+    be displayed best. If it fits into the currently visible range then
+    the returned value is the current firstLine.
+*/
+int getBestFirstLine( int line, int nofLines, int firstLine, int visibleLines );
+
+extern bool g_bIgnoreWhiteSpace;
+extern bool g_bIgnoreTrivialMatches;
+extern int g_bAutoSolve;
+
+// Cursor conversions that consider g_tabSize.
+int convertToPosInText( const QString& s, int posOnScreen, int tabSize );
+int convertToPosOnScreen( const QString& s, int posInText, int tabSize );
+
+enum e_CoordType { eFileCoords, eD3LLineCoords, eWrapCoords };
+
+void calcTokenPos( const QString&, int posOnScreen, int& pos1, int& pos2, int tabSize );
+
+QString calcHistorySortKey( const QString& keyOrder, QRegExp& matchedRegExpr, const QStringList& parenthesesGroupList );
+bool findParenthesesGroups( const QString& s, QStringList& sl );
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/difftextwindow.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1750 @@
+/***************************************************************************
+                          difftextwindow.cpp  -  description
+                             -------------------
+    begin                : Mon Apr 8 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "difftextwindow.h"
+#include "merger.h"
+#include <qpainter.h>
+#include <assert.h>
+#include <qpixmap.h>
+#include <qstatusbar.h>
+#include <qapplication.h>
+#include <qtooltip.h>
+#include <qfont.h>
+#include <qstringlist.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qtextcodec.h>
+#include <optiondialog.h>
+#include <math.h>
+#include <qdragobject.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+
+class DiffTextWindowData
+{
+public:
+   DiffTextWindowData( DiffTextWindow* p )
+   {
+      m_pDiffTextWindow = p;
+      m_bPaintingAllowed = false;
+      m_pLineData = 0;
+      m_size = 0;
+      m_bWordWrap = false;
+      m_delayedDrawTimer = 0;
+      m_pDiff3LineVector = 0;
+      m_pManualDiffHelpList = 0;
+      m_pOptionDialog = 0;
+      m_fastSelectorLine1 = 0;
+      m_fastSelectorNofLines = 0;
+      m_bTriple = 0;
+      m_winIdx = 0;
+      m_firstLine = 0;
+      m_oldFirstLine = 0;
+      m_oldFirstColumn = 0;
+      m_firstColumn = 0;
+      m_lineNumberWidth = 0;
+      m_pStatusBar = 0;
+      m_scrollDeltaX = 0;
+      m_scrollDeltaY = 0;
+      m_bMyUpdate = false;
+      m_bSelectionInProgress = false;
+   }
+   DiffTextWindow* m_pDiffTextWindow;
+   DiffTextWindowFrame* m_pDiffTextWindowFrame;
+
+   bool m_bPaintingAllowed;
+   const LineData* m_pLineData;
+   int m_size;
+   QString m_filename;
+   bool m_bWordWrap;
+   int m_delayedDrawTimer;
+
+   const Diff3LineVector* m_pDiff3LineVector;
+   Diff3WrapLineVector m_diff3WrapLineVector;
+   const ManualDiffHelpList* m_pManualDiffHelpList;
+
+   OptionDialog* m_pOptionDialog;
+   QColor m_cThis;
+   QColor m_cDiff1;
+   QColor m_cDiff2;
+   QColor m_cDiffBoth;
+
+   int m_fastSelectorLine1;
+   int m_fastSelectorNofLines;
+
+   bool m_bTriple;
+   int m_winIdx;
+   int m_firstLine;
+   int m_oldFirstLine;
+   int m_oldFirstColumn;
+   int m_firstColumn;
+   int m_lineNumberWidth;
+
+   void getLineInfo(
+           const Diff3Line& d,
+           int& lineIdx,
+           DiffList*& pFineDiff1, DiffList*& pFineDiff2,   // return values
+           int& changed, int& changed2  );
+
+   QString getString( int d3lIdx );
+   QString getLineString( int line );
+
+   void writeLine(
+         MyPainter& p, const LineData* pld,
+         const DiffList* pLineDiff1, const DiffList* pLineDiff2, int line,
+         int whatChanged, int whatChanged2, int srcLineIdx,
+         int wrapLineOffset, int wrapLineLength, bool bWrapLine, const QRect& invalidRect, int deviceWidth
+         );
+
+   void draw( MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine );
+
+   QStatusBar* m_pStatusBar;
+
+   Selection m_selection;
+
+   int m_scrollDeltaX;
+   int m_scrollDeltaY;
+
+   bool m_bMyUpdate;
+   void myUpdate(int afterMilliSecs );
+
+   int leftInfoWidth() { return 4+m_lineNumberWidth; }   // Nr of information columns on left side
+   int convertLineOnScreenToLineInSource( int lineOnScreen, e_CoordType coordType, bool bFirstLine );
+
+   bool m_bSelectionInProgress;
+   QPoint m_lastKnownMousePos;
+};
+
+DiffTextWindow::DiffTextWindow(
+   DiffTextWindowFrame* pParent,
+   QStatusBar* pStatusBar,
+   OptionDialog* pOptionDialog,
+   int winIdx
+   )
+   : QWidget(pParent, 0, Qt::WResizeNoErase | Qt::WRepaintNoErase)
+{
+   d = new DiffTextWindowData(this);
+   d->m_pDiffTextWindowFrame = pParent;
+   setFocusPolicy( ClickFocus );
+   setAcceptDrops( true );
+
+   d->m_pOptionDialog = pOptionDialog;
+   init( 0, 0, 0, 0, 0, false );
+
+   setMinimumSize(QSize(20,20));
+
+   d->m_pStatusBar = pStatusBar;
+   d->m_bPaintingAllowed = true;
+   d->m_bWordWrap = false;
+   d->m_winIdx = winIdx;
+
+   setFont(d->m_pOptionDialog->m_font);
+}
+
+DiffTextWindow::~DiffTextWindow()
+{
+   delete d;
+}
+
+void DiffTextWindow::init(
+   const QString& filename,
+   const LineData* pLineData,
+   int size,
+   const Diff3LineVector* pDiff3LineVector,
+   const ManualDiffHelpList* pManualDiffHelpList,
+   bool bTriple
+   )
+{
+   d->m_filename = filename;
+   d->m_pLineData = pLineData;
+   d->m_size = size;
+   d->m_pDiff3LineVector = pDiff3LineVector;
+   d->m_diff3WrapLineVector.clear();
+   d->m_pManualDiffHelpList = pManualDiffHelpList;
+
+   d->m_firstLine = 0;
+   d->m_oldFirstLine = -1;
+   d->m_firstColumn = 0;
+   d->m_oldFirstColumn = -1;
+   d->m_bTriple = bTriple;
+   d->m_scrollDeltaX=0;
+   d->m_scrollDeltaY=0;
+   d->m_bMyUpdate = false;
+   d->m_fastSelectorLine1 = 0;
+   d->m_fastSelectorNofLines = 0;
+   d->m_lineNumberWidth = 0;
+   d->m_selection.reset();
+   d->m_selection.oldFirstLine = -1; // reset is not enough here.
+   d->m_selection.oldLastLine = -1;
+   d->m_selection.lastLine = -1;
+
+   update();
+   d->m_pDiffTextWindowFrame->init();
+}
+
+void DiffTextWindow::reset()
+{
+   d->m_pLineData=0;
+   d->m_size=0;
+   d->m_pDiff3LineVector=0;
+   d->m_filename="";
+   d->m_diff3WrapLineVector.clear();
+}
+
+void DiffTextWindow::setPaintingAllowed( bool bAllowPainting )
+{
+   if (d->m_bPaintingAllowed != bAllowPainting)
+   {
+      d->m_bPaintingAllowed = bAllowPainting;
+      if ( d->m_bPaintingAllowed ) update();
+      else reset();
+   }
+}
+
+void DiffTextWindow::dragEnterEvent( QDragEnterEvent* e )
+{
+   e->accept( QUriDrag::canDecode(e) || QTextDrag::canDecode(e) );
+   // Note that the corresponding drop is handled in KDiff3App::eventFilter().
+}
+
+
+void DiffTextWindow::setFirstLine(int firstLine)
+{
+   int fontHeight = fontMetrics().height();
+
+   int newFirstLine = max2(0,firstLine);
+
+   int deltaY = fontHeight * ( d->m_firstLine - newFirstLine );
+
+   d->m_firstLine = newFirstLine;
+
+   if ( d->m_bSelectionInProgress && d->m_selection.firstLine != -1 )
+   {
+      int line, pos;
+      convertToLinePos( d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos );
+      d->m_selection.end( line, pos );
+      update();
+   }
+   else
+   {
+      QWidget::scroll( 0, deltaY );
+   }
+   d->m_pDiffTextWindowFrame->setFirstLine( d->m_firstLine );
+}
+
+int DiffTextWindow::getFirstLine()
+{
+   return d->m_firstLine;
+}
+
+void DiffTextWindow::setFirstColumn(int firstCol)
+{
+   int fontWidth = fontMetrics().width('W');
+   int xOffset = d->leftInfoWidth() * fontWidth;
+
+   int newFirstColumn = max2(0,firstCol);
+
+   int deltaX = fontWidth * ( d->m_firstColumn - newFirstColumn );
+
+   d->m_firstColumn = newFirstColumn;
+
+   QRect r( xOffset, 0, width()-xOffset, height() );
+
+   if ( d->m_pOptionDialog->m_bRightToLeftLanguage )
+   {
+      deltaX = -deltaX;
+      r = QRect( width()-1-xOffset, 0, -(width()-xOffset), height() ).normalize();
+   }
+
+   if ( d->m_bSelectionInProgress && d->m_selection.firstLine != -1 )
+   {
+      int line, pos;
+      convertToLinePos( d->m_lastKnownMousePos.x(), d->m_lastKnownMousePos.y(), line, pos );
+      d->m_selection.end( line, pos );
+      update();
+   }
+   else
+   {
+      QWidget::scroll( deltaX, 0, r );
+   }
+}
+
+int DiffTextWindow::getNofColumns()
+{
+   if (d->m_bWordWrap)
+   {
+      return getNofVisibleColumns();
+   }
+   else
+   {
+      int nofColumns = 0;
+      for( int i = 0; i< d->m_size; ++i )
+      {
+         if ( d->m_pLineData[i].width( d->m_pOptionDialog->m_tabSize ) > nofColumns )
+            nofColumns = d->m_pLineData[i].width( d->m_pOptionDialog->m_tabSize );
+      }
+      return nofColumns;
+   }
+}
+
+int DiffTextWindow::getNofLines()
+{
+   return d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : 
+                        d->m_pDiff3LineVector->size();
+}
+
+
+int DiffTextWindow::convertLineToDiff3LineIdx( int line )
+{
+   if ( d->m_bWordWrap && d->m_diff3WrapLineVector.size()>0 )
+      return d->m_diff3WrapLineVector[ min2( line, (int)d->m_diff3WrapLineVector.size()-1 ) ].diff3LineIndex;
+   else
+      return line;
+}
+
+int DiffTextWindow::convertDiff3LineIdxToLine( int d3lIdx )
+{
+   if ( d->m_bWordWrap && d->m_pDiff3LineVector!=0 && d->m_pDiff3LineVector->size()>0 )
+      return (*d->m_pDiff3LineVector)[ min2( d3lIdx, (int)d->m_pDiff3LineVector->size()-1 ) ]->sumLinesNeededForDisplay;
+   else
+      return d3lIdx;
+}
+
+/** Returns a line number where the linerange [line, line+nofLines] can
+    be displayed best. If it fits into the currently visible range then
+    the returned value is the current firstLine.
+*/
+int getBestFirstLine( int line, int nofLines, int firstLine, int visibleLines )
+{
+   int newFirstLine = firstLine;
+   if ( line < firstLine  ||  line + nofLines + 2 > firstLine + visibleLines )
+   {
+      if ( nofLines > visibleLines || nofLines <= ( 2*visibleLines / 3 - 1)  )
+         newFirstLine = line - visibleLines/3;
+      else
+         newFirstLine = line - (visibleLines - nofLines);
+   }
+
+   return newFirstLine;
+}
+
+
+void DiffTextWindow::setFastSelectorRange( int line1, int nofLines )
+{
+   d->m_fastSelectorLine1 = line1;
+   d->m_fastSelectorNofLines = nofLines;
+   if ( isVisible() )
+   {
+      int newFirstLine = getBestFirstLine( 
+         convertDiff3LineIdxToLine(d->m_fastSelectorLine1), 
+         convertDiff3LineIdxToLine(d->m_fastSelectorLine1+d->m_fastSelectorNofLines)-convertDiff3LineIdxToLine(d->m_fastSelectorLine1), 
+         d->m_firstLine, 
+         getNofVisibleLines() 
+         );
+      if ( newFirstLine != d->m_firstLine )
+      {
+         scroll( 0, newFirstLine - d->m_firstLine );
+      }
+
+      update();
+   }
+}
+
+
+void DiffTextWindow::showStatusLine(int line )
+{
+   int d3lIdx = convertLineToDiff3LineIdx( line );
+   if(d3lIdx >= 0 && d3lIdx<(int)d->m_pDiff3LineVector->size() )
+   {
+      const Diff3Line* pD3l = (*d->m_pDiff3LineVector)[d3lIdx];
+      if ( pD3l != 0 )
+      {
+         int l = pD3l->getLineInFile( d->m_winIdx );
+
+         QString s;
+         if ( l!=-1 )
+            s.sprintf("File %s: Line %d", d->m_filename.ascii(), l+1 );
+         else
+            s.sprintf("File %s: Line not available", d->m_filename.ascii() );
+         if (d->m_pStatusBar!=0) d->m_pStatusBar->message(s);
+
+         emit lineClicked( d->m_winIdx, l );
+      }
+   }
+}
+
+void DiffTextWindow::focusInEvent(QFocusEvent* e)
+{
+   emit gotFocus();
+   QWidget::focusInEvent(e);
+}
+
+void DiffTextWindow::mousePressEvent ( QMouseEvent* e )
+{
+   if ( e->button() == Qt::LeftButton )
+   {
+      int line;
+      int pos;
+      convertToLinePos( e->x(), e->y(), line, pos );
+      if ( pos < d->m_firstColumn )
+      {
+         emit setFastSelectorLine( convertLineToDiff3LineIdx(line) );
+         d->m_selection.firstLine = -1;     // Disable current d->m_selection
+      }
+      else
+      {  // Selection
+         resetSelection();
+         d->m_selection.start( line, pos );
+         d->m_selection.end( line, pos );
+         d->m_bSelectionInProgress = true;
+         d->m_lastKnownMousePos = e->pos();
+
+         showStatusLine( line );
+      }
+   }
+}
+
+bool isCTokenChar( QChar c )
+{
+   return (c=='_')  ||
+          ( c>='A' && c<='Z' ) || ( c>='a' && c<='z' ) ||
+          (c>='0' && c<='9');
+}
+
+/// Calculate where a token starts and ends, given the x-position on screen.
+void calcTokenPos( const QString& s, int posOnScreen, int& pos1, int& pos2, int tabSize )
+{
+   // Cursor conversions that consider g_tabSize
+   int pos = convertToPosInText( s, max2( 0, posOnScreen ), tabSize );
+   if ( pos>=(int)s.length() )
+   {
+      pos1=s.length();
+      pos2=s.length();
+      return;
+   }
+
+   pos1 = pos;
+   pos2 = pos+1;
+
+   if( isCTokenChar( s[pos1] ) )
+   {
+      while( pos1>=0 && isCTokenChar( s[pos1] ) )
+         --pos1;
+      ++pos1;
+
+      while( pos2<(int)s.length() && isCTokenChar( s[pos2] ) )
+         ++pos2;
+   }
+}
+
+void DiffTextWindow::mouseDoubleClickEvent( QMouseEvent* e )
+{
+   d->m_bSelectionInProgress = false;
+   d->m_lastKnownMousePos = e->pos();
+   if ( e->button() == Qt::LeftButton )
+   {
+      int line;
+      int pos;
+      convertToLinePos( e->x(), e->y(), line, pos );
+
+      // Get the string data of the current line
+      QString s;
+      if ( d->m_bWordWrap )
+      {
+         if ( line<0 || line >= (int)d->m_diff3WrapLineVector.size() )
+            return;
+         const Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[line];
+         s = d->getString( d3wl.diff3LineIndex ).mid( d3wl.wrapLineOffset, d3wl.wrapLineLength );
+      }
+      else
+      {
+         if ( line<0 || line >= (int)d->m_pDiff3LineVector->size() )
+            return;
+         s = d->getString( line );
+      }
+
+      if ( ! s.isEmpty() )
+      {
+         int pos1, pos2;
+         calcTokenPos( s, pos, pos1, pos2, d->m_pOptionDialog->m_tabSize );
+
+         resetSelection();
+         d->m_selection.start( line, convertToPosOnScreen( s, pos1, d->m_pOptionDialog->m_tabSize ) );
+         d->m_selection.end( line, convertToPosOnScreen( s, pos2, d->m_pOptionDialog->m_tabSize ) );
+         update();
+         // emit d->m_selectionEnd() happens in the mouseReleaseEvent.
+         showStatusLine( line );
+      }
+   }
+}
+
+void DiffTextWindow::mouseReleaseEvent ( QMouseEvent* e )
+{
+   d->m_bSelectionInProgress = false;
+   d->m_lastKnownMousePos = e->pos();
+   //if ( e->button() == LeftButton )
+   {
+      killTimer(d->m_delayedDrawTimer);
+      d->m_delayedDrawTimer = 0;
+      if (d->m_selection.firstLine != -1 )
+      {
+         emit selectionEnd();
+      }
+   }
+   d->m_scrollDeltaX=0;
+   d->m_scrollDeltaY=0;
+}
+
+inline int sqr(int x){return x*x;}
+
+void DiffTextWindow::mouseMoveEvent ( QMouseEvent * e )
+{
+   int line;
+   int pos;
+   convertToLinePos( e->x(), e->y(), line, pos );
+   d->m_lastKnownMousePos = e->pos();
+
+   if (d->m_selection.firstLine != -1 )
+   {
+      d->m_selection.end( line, pos );
+
+      showStatusLine( line );
+
+      // Scroll because mouse moved out of the window
+      const QFontMetrics& fm = fontMetrics();
+      int fontWidth = fm.width('W');
+      int deltaX=0;
+      int deltaY=0;
+      if ( ! d->m_pOptionDialog->m_bRightToLeftLanguage )
+      {
+         if ( e->x() < d->leftInfoWidth()*fontWidth )  deltaX = -1 - abs(e->x()-d->leftInfoWidth()*fontWidth)/fontWidth;
+         if ( e->x() > width()     )                   deltaX = +1 + abs(e->x()-width())/fontWidth;
+      }
+      else
+      {
+         if ( e->x() > width()-1-d->leftInfoWidth()*fontWidth ) deltaX=+1+ abs(e->x() - (width()-1-d->leftInfoWidth()*fontWidth)) / fontWidth;
+         if ( e->x() < fontWidth )                              deltaX=-1- abs(e->x()-fontWidth)/fontWidth;
+      }
+      if ( e->y() < 0 )          deltaY = -1 - sqr( e->y() ) / sqr(fm.height());
+      if ( e->y() > height() )   deltaY = +1 + sqr( e->y() - height() ) / sqr(fm.height());
+      if ( deltaX != 0 && d->m_scrollDeltaX!=deltaX || deltaY!= 0 && d->m_scrollDeltaY!=deltaY )
+      {
+         d->m_scrollDeltaX = deltaX;
+         d->m_scrollDeltaY = deltaY;
+         emit scroll( deltaX, deltaY );
+         killTimer( d->m_delayedDrawTimer );
+         d->m_delayedDrawTimer = startTimer(50);
+      }
+      else
+      {
+         d->m_scrollDeltaX = deltaX;
+         d->m_scrollDeltaY = deltaY;
+         d->myUpdate(0);
+      }
+   }
+}
+
+
+void DiffTextWindowData::myUpdate(int afterMilliSecs)
+{
+   m_pDiffTextWindow->killTimer( m_delayedDrawTimer );
+   m_bMyUpdate = true;
+   m_delayedDrawTimer = m_pDiffTextWindow->startTimer( afterMilliSecs );
+}
+
+void DiffTextWindow::timerEvent(QTimerEvent*)
+{
+   killTimer(d->m_delayedDrawTimer);
+   d->m_delayedDrawTimer = 0;
+
+   if ( d->m_bMyUpdate )
+   {
+      int fontHeight = fontMetrics().height();
+
+      if ( d->m_selection.oldLastLine != -1 )
+      {
+         int lastLine;
+         int firstLine;
+         if ( d->m_selection.oldFirstLine != -1 )
+         {
+            firstLine = min3( d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine );
+            lastLine = max3( d->m_selection.oldFirstLine, d->m_selection.lastLine, d->m_selection.oldLastLine );
+         }
+         else
+         {
+            firstLine = min2( d->m_selection.lastLine, d->m_selection.oldLastLine );
+            lastLine = max2( d->m_selection.lastLine, d->m_selection.oldLastLine );
+         }
+         int y1 = ( firstLine - d->m_firstLine ) * fontHeight;
+         int y2 = min2( height(), ( lastLine  - d->m_firstLine + 1 ) * fontHeight );
+
+         if ( y1<height() && y2>0 )
+         {
+            QRect invalidRect = QRect( 0, y1, width(), y2-y1 );
+            update( invalidRect );
+         }
+      }
+
+      d->m_bMyUpdate = false;
+   }
+
+   if ( d->m_scrollDeltaX != 0 || d->m_scrollDeltaY != 0 )
+   {
+      d->m_selection.end( d->m_selection.lastLine + d->m_scrollDeltaY, d->m_selection.lastPos +  d->m_scrollDeltaX );
+      emit scroll( d->m_scrollDeltaX, d->m_scrollDeltaY );
+      killTimer(d->m_delayedDrawTimer);
+      d->m_delayedDrawTimer = startTimer(50);
+   }
+}
+
+void DiffTextWindow::resetSelection()
+{
+   d->m_selection.reset();
+   update();
+}
+
+void DiffTextWindow::convertToLinePos( int x, int y, int& line, int& pos )
+{
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width('W');
+   int xOffset = ( d->leftInfoWidth() - d->m_firstColumn ) * fontWidth;
+
+   int yOffset = - d->m_firstLine * fontHeight;
+
+   line = ( y - yOffset ) / fontHeight;
+   if ( ! d->m_pOptionDialog->m_bRightToLeftLanguage )
+      pos  = ( x - xOffset ) / fontWidth;
+   else 
+      pos  = ( (width() - 1 - x) - xOffset ) / fontWidth;
+}
+
+int Selection::firstPosInLine(int l)
+{
+   assert( firstLine != -1 );
+
+   int l1 = firstLine;
+   int l2 = lastLine;
+   int p1 = firstPos;
+   int p2 = lastPos;
+   if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); }
+   if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); }
+
+   if ( l==l1 )
+      return p1;
+   return 0;
+}
+
+int Selection::lastPosInLine(int l)
+{
+   assert( firstLine != -1 );
+
+   int l1 = firstLine;
+   int l2 = lastLine;
+   int p1 = firstPos;
+   int p2 = lastPos;
+
+   if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); }
+   if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); }
+
+   if ( l==l2 )
+      return p2;
+   return INT_MAX;
+}
+
+bool Selection::within( int l, int p )
+{
+   if ( firstLine == -1 ) return false;
+   int l1 = firstLine;
+   int l2 = lastLine;
+   int p1 = firstPos;
+   int p2 = lastPos;
+   if ( l1>l2 ){ std::swap(l1,l2); std::swap(p1,p2); }
+   if ( l1==l2 && p1>p2 ){ std::swap(p1,p2); }
+   if( l1 <= l && l <= l2 )
+   {
+      if ( l1==l2 )
+         return p>=p1 && p<p2;
+      if ( l==l1 )
+         return p>=p1;
+      if ( l==l2 )
+         return p<p2;
+      return true;
+   }
+   return false;
+}
+
+bool Selection::lineWithin( int l )
+{
+   if ( firstLine == -1 ) return false;
+   int l1 = firstLine;
+   int l2 = lastLine;
+
+   if ( l1>l2 ){ std::swap(l1,l2); }
+
+   return ( l1 <= l && l <= l2 );
+}
+
+
+void DiffTextWindowData::writeLine(
+   MyPainter& p,
+   const LineData* pld,
+   const DiffList* pLineDiff1,
+   const DiffList* pLineDiff2,
+   int line,
+   int whatChanged,
+   int whatChanged2,
+   int srcLineIdx,
+   int wrapLineOffset,
+   int wrapLineLength,
+   bool bWrapLine,
+   const QRect& invalidRect,
+   int deviceWidth
+   )
+{
+   QFont normalFont = p.font();
+   QFont diffFont = normalFont;
+   diffFont.setItalic( m_pOptionDialog->m_bItalicForDeltas );
+   const QFontMetrics& fm = p.fontMetrics();
+   int fontHeight = fm.height();
+   int fontAscent = fm.ascent();
+   int fontDescent = fm.descent();
+   int fontWidth = fm.width('W');
+
+   int xOffset = (leftInfoWidth() - m_firstColumn)*fontWidth;
+   int yOffset = (line-m_firstLine) * fontHeight;
+
+   QRect lineRect( 0, yOffset, deviceWidth, fontHeight );
+   if ( ! invalidRect.intersects( lineRect ) )
+   {
+      return;
+   }
+
+   int fastSelectorLine1 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1);
+   int fastSelectorLine2 = m_pDiffTextWindow->convertDiff3LineIdxToLine(m_fastSelectorLine1+m_fastSelectorNofLines)-1;
+
+   bool bFastSelectionRange = (line>=fastSelectorLine1 && line<= fastSelectorLine2 );
+   QColor bgColor = m_pOptionDialog->m_bgColor;
+   QColor diffBgColor = m_pOptionDialog->m_diffBgColor;
+
+   if ( bFastSelectionRange )
+   {
+      bgColor = m_pOptionDialog->m_currentRangeBgColor;
+      diffBgColor = m_pOptionDialog->m_currentRangeDiffBgColor;
+   }
+
+   if ( yOffset+fontHeight<invalidRect.top()  ||  invalidRect.bottom() < yOffset-fontHeight )
+      return;
+
+   int changed = whatChanged;
+   if ( pLineDiff1 != 0 ) changed |= 1;
+   if ( pLineDiff2 != 0 ) changed |= 2;
+
+   QColor c = m_pOptionDialog->m_fgColor;
+   if ( changed == 2 ) {
+      c = m_cDiff2;
+   } else if ( changed == 1 ) {
+      c = m_cDiff1;
+   } else if ( changed == 3 ) {
+      c = m_cDiffBoth;
+   }
+
+   p.fillRect( leftInfoWidth()*fontWidth, yOffset, deviceWidth, fontHeight, bgColor );
+
+   if (pld!=0)
+   {
+      // First calculate the "changed" information for each character.
+      int i=0;
+      std::vector<UINT8> charChanged( pld->size );
+      if ( pLineDiff1!=0 || pLineDiff2 != 0 )
+      {
+         Merger merger( pLineDiff1, pLineDiff2 );
+         while( ! merger.isEndReached() &&  i<pld->size )
+         {
+            if ( i < pld->size )
+            {
+               charChanged[i] = merger.whatChanged();
+               ++i;
+            }
+            merger.next();
+         }
+      }
+
+      QString s=" ";
+      // Convert tabs
+      int outPos = 0;
+
+      QString lineString( pld->pLine, pld->size );
+      int lineLength = m_bWordWrap ? wrapLineOffset+wrapLineLength : lineString.length();
+
+      for( i=wrapLineOffset; i<lineLength; ++i )
+      {
+         int spaces = 1;
+
+         if ( lineString[i]=='\t' )
+         {
+            spaces = tabber( outPos, m_pOptionDialog->m_tabSize );
+            s[0] = ' ';
+         }
+         else
+         {
+            s[0] = lineString[i];
+         }
+
+         QColor c = m_pOptionDialog->m_fgColor;
+         int cchanged = charChanged[i] | whatChanged;
+
+         if ( cchanged == 2 ) {
+            c = m_cDiff2;
+         } else if ( cchanged == 1 ) {
+            c = m_cDiff1;
+         } else if ( cchanged == 3 ) {
+            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_pOptionDialog->m_bRightToLeftLanguage )
+            outRect = QRect( deviceWidth-1-(xOffset + fontWidth*outPos), yOffset, -fontWidth*spaces, fontHeight ).normalize();
+         if ( invalidRect.intersects( outRect ) )
+         {
+            if( !m_selection.within( line, outPos ) )
+            {
+
+               if( c!=m_pOptionDialog->m_fgColor )
+               {
+                  QColor lightc = diffBgColor;
+                  p.fillRect( xOffset + fontWidth*outPos, yOffset,
+                           fontWidth*spaces, fontHeight, lightc );
+                  p.setFont(diffFont);
+               }
+
+               p.setPen( c );
+               if ( s[0]==' '  &&  c!=m_pOptionDialog->m_fgColor  &&  charChanged[i]!=0 )
+               {
+                  if ( m_pOptionDialog->m_bShowWhiteSpaceCharacters && m_pOptionDialog->m_bShowWhiteSpace)
+                  {
+                     p.fillRect( xOffset + fontWidth*outPos, yOffset+fontAscent,
+                                 fontWidth*spaces-1, fontDescent, c );  // QT3
+                                 //fontWidth*spaces-1, fontDescent, c );  // QT4
+                  }
+               }
+               else
+               {
+                  p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, s );
+               }
+               p.setFont(normalFont);
+            }
+            else
+            {
+               p.fillRect( xOffset + fontWidth*outPos, yOffset,
+                           fontWidth*(spaces), fontHeight, m_pDiffTextWindow->colorGroup().highlight() );
+
+               p.setPen( m_pDiffTextWindow->colorGroup().highlightedText() );
+               p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, s );
+
+               m_selection.bSelectionContainsData = true;
+            }
+         }
+
+         outPos += spaces;
+      }
+
+      if( m_selection.lineWithin( line ) && m_selection.lineWithin( line+1 ) )
+      {
+         p.fillRect( xOffset + fontWidth*outPos, yOffset,
+                     deviceWidth, fontHeight, m_pDiffTextWindow->colorGroup().highlight() );
+      }
+   }
+
+   p.fillRect( 0, yOffset, leftInfoWidth()*fontWidth, fontHeight, m_pOptionDialog->m_bgColor );
+
+   xOffset = (m_lineNumberWidth+2)*fontWidth;
+   int xLeft =   m_lineNumberWidth*fontWidth;
+   p.setPen( m_pOptionDialog->m_fgColor );
+   if ( pld!=0 )
+   {
+      if ( m_pOptionDialog->m_bShowLineNumbers && !bWrapLine )
+      {
+         QString num;
+         num.sprintf( "%0*d", m_lineNumberWidth, srcLineIdx+1);
+         p.drawText( 0, yOffset + fontAscent, num );
+         //p.drawLine( xLeft -1, yOffset, xLeft -1, yOffset+fontHeight-1 );
+      }
+      if ( !bWrapLine || wrapLineLength>0 )
+      {
+         p.setPen( QPen( m_pOptionDialog->m_fgColor, 0, bWrapLine ? Qt::DotLine : Qt::SolidLine) );
+         p.drawLine( xOffset +1, yOffset, xOffset +1, yOffset+fontHeight-1 );
+         p.setPen( QPen( m_pOptionDialog->m_fgColor, 0, Qt::SolidLine) );
+      }
+   }
+   if ( c!=m_pOptionDialog->m_fgColor && whatChanged2==0 )//&& whatChanged==0 )
+   {
+      if ( m_pOptionDialog->m_bShowWhiteSpace )
+      {
+         p.setBrushOrigin(0,0);
+         p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Qt::Dense5Pattern) );
+      }
+   }
+   else
+   {
+      p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, c==m_pOptionDialog->m_fgColor ? bgColor : c );
+   }
+
+   if ( bFastSelectionRange )
+   {
+      p.fillRect( xOffset + fontWidth-1, yOffset, 3, fontHeight, m_pOptionDialog->m_fgColor );
+   }
+
+   // Check if line needs a manual diff help mark
+   ManualDiffHelpList::const_iterator ci;
+   for( ci = m_pManualDiffHelpList->begin(); ci!=m_pManualDiffHelpList->end(); ++ci)
+   {
+      const ManualDiffHelpEntry& mdhe=*ci;
+      int rangeLine1 = -1;
+      int rangeLine2 = -1;
+      if (m_winIdx==1 ) { rangeLine1 = mdhe.lineA1; rangeLine2= mdhe.lineA2; }
+      if (m_winIdx==2 ) { rangeLine1 = mdhe.lineB1; rangeLine2= mdhe.lineB2; }
+      if (m_winIdx==3 ) { rangeLine1 = mdhe.lineC1; rangeLine2= mdhe.lineC2; }
+      if ( rangeLine1>=0 && rangeLine2>=0 && srcLineIdx >= rangeLine1 && srcLineIdx <= rangeLine2 )
+      {
+         p.fillRect( xOffset - fontWidth, yOffset, fontWidth-1, fontHeight, m_pOptionDialog->m_manualHelpRangeColor );
+         break;
+      }
+   }
+}
+
+void DiffTextWindow::paintEvent( QPaintEvent* e )
+{
+   if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed ||
+        ( d->m_diff3WrapLineVector.empty() && d->m_bWordWrap ) ) 
+      return;
+
+   QRect invalidRect = e->rect();
+   if ( invalidRect.isEmpty() )
+      return;
+
+   bool bOldSelectionContainsData = d->m_selection.bSelectionContainsData;
+   d->m_selection.bSelectionContainsData = false;
+
+   int endLine = min2( d->m_firstLine + getNofVisibleLines()+2, getNofLines() );
+
+   //if ( invalidRect.size()==size() )
+   {  // double buffering, obsolete with Qt4
+      QPainter painter(this); // Remove for Qt4
+      QPixmap pixmap( invalidRect.size() );// Remove for Qt4
+
+      MyPainter p( &pixmap, d->m_pOptionDialog->m_bRightToLeftLanguage, width(), fontMetrics().width('W') ); // For Qt4 change pixmap to this
+
+      p.translate( -invalidRect.x(), -invalidRect.y() );// Remove for Qt4
+
+      p.setFont( font() );
+      p.QPainter::fillRect( invalidRect, d->m_pOptionDialog->m_bgColor );
+
+      d->draw( p, invalidRect, width(), d->m_firstLine, endLine );
+      // p.drawLine( m_invalidRect.x(), m_invalidRect.y(), m_invalidRect.right(), m_invalidRect.bottom() ); // For test only
+      p.end();
+
+      painter.drawPixmap( invalidRect.x(), invalidRect.y(), pixmap );// Remove for Qt4
+   }
+//    else
+//    {  // no double buffering
+//       MyPainter p( this, d->m_pOptionDialog->m_bRightToLeftLanguage, width(), fontMetrics().width('W') );
+//       p.setFont( font() );
+//       p.QPainter::fillRect( invalidRect, d->m_pOptionDialog->m_bgColor );
+//       d->draw( p, invalidRect, width(), d->m_firstLine, endLine );
+//    }
+
+
+   d->m_oldFirstLine = d->m_firstLine;
+   d->m_oldFirstColumn = d->m_firstColumn;
+   d->m_selection.oldLastLine = -1;
+   if ( d->m_selection.oldFirstLine !=-1 )
+      d->m_selection.oldFirstLine = -1;
+
+   if( !bOldSelectionContainsData  &&  d->m_selection.bSelectionContainsData )
+      emit newSelection();
+}
+
+void DiffTextWindow::print( MyPainter& p, const QRect&, int firstLine, int nofLinesPerPage )
+{
+   if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed ||
+        ( d->m_diff3WrapLineVector.empty() && d->m_bWordWrap ) ) 
+      return;
+   resetSelection();
+//   MyPainter p( this, d->m_pOptionDialog->m_bRightToLeftLanguage, width(), fontMetrics().width('W') );
+   int oldFirstLine = d->m_firstLine;
+   d->m_firstLine = firstLine;
+   QRect invalidRect = QRect(0,0,QCOORD_MAX,QCOORD_MAX);
+   QColor bgColor = d->m_pOptionDialog->m_bgColor;
+   d->m_pOptionDialog->m_bgColor = Qt::white;
+   d->draw( p, invalidRect, p.window().width(), firstLine, min2(firstLine+nofLinesPerPage,getNofLines()) );
+   d->m_pOptionDialog->m_bgColor = bgColor;
+   d->m_firstLine = oldFirstLine;
+}
+
+void DiffTextWindowData::draw( MyPainter& p, const QRect& invalidRect, int deviceWidth, int beginLine, int endLine )
+{
+   m_lineNumberWidth =  m_pOptionDialog->m_bShowLineNumbers ? (int)log10((double)m_size)+1 : 0;
+
+   if ( m_winIdx==1 )
+   {
+      m_cThis = m_pOptionDialog->m_colorA;
+      m_cDiff1 = m_pOptionDialog->m_colorB;
+      m_cDiff2 = m_pOptionDialog->m_colorC;
+   }
+   if ( m_winIdx==2 )
+   {
+      m_cThis = m_pOptionDialog->m_colorB;
+      m_cDiff1 = m_pOptionDialog->m_colorC;
+      m_cDiff2 = m_pOptionDialog->m_colorA;
+   }
+   if ( m_winIdx==3 )
+   {
+      m_cThis = m_pOptionDialog->m_colorC;
+      m_cDiff1 = m_pOptionDialog->m_colorA;
+      m_cDiff2 = m_pOptionDialog->m_colorB;
+   }
+   m_cDiffBoth = m_pOptionDialog->m_colorForConflict;  // Conflict color
+
+   p.setPen( m_cThis );
+
+   for ( int line = beginLine; line<endLine; ++line )
+   {
+      int wrapLineOffset=0;
+      int wrapLineLength=0;
+      const Diff3Line* d3l =0;
+      bool bWrapLine = false;
+      if (m_bWordWrap)
+      {
+         Diff3WrapLine& d3wl = m_diff3WrapLineVector[line];
+         wrapLineOffset = d3wl.wrapLineOffset;
+         wrapLineLength = d3wl.wrapLineLength;
+         d3l = d3wl.pD3L;
+         bWrapLine = line > 0 && m_diff3WrapLineVector[line-1].pD3L == d3l;
+      }
+      else
+      {
+         d3l = (*m_pDiff3LineVector)[line];
+      }
+      DiffList* pFineDiff1;
+      DiffList* pFineDiff2;
+      int changed=0;
+      int changed2=0;
+
+      int srcLineIdx=-1;
+      getLineInfo( *d3l, srcLineIdx, pFineDiff1, pFineDiff2, changed, changed2 );
+
+      writeLine(
+         p,                         // QPainter
+         srcLineIdx == -1 ? 0 : &m_pLineData[srcLineIdx],     // Text in this line
+         pFineDiff1,
+         pFineDiff2,
+         line,                      // Line on the screen
+         changed,
+         changed2,
+         srcLineIdx,
+         wrapLineOffset,
+         wrapLineLength,
+         bWrapLine,
+         invalidRect,
+         deviceWidth
+         );
+   }
+}
+
+QString DiffTextWindowData::getString( int d3lIdx )
+{
+   if ( d3lIdx<0 || d3lIdx>=(int)m_pDiff3LineVector->size() )
+      return QString();
+   const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx];
+   DiffList* pFineDiff1;
+   DiffList* pFineDiff2;
+   int changed=0;
+   int changed2=0;
+   int lineIdx;
+   getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 );
+
+   if (lineIdx==-1) return QString();
+   else
+   {
+      const LineData* ld = &m_pLineData[lineIdx];
+      return QString( ld->pLine, ld->size );
+   }
+   return QString();
+}
+
+QString DiffTextWindowData::getLineString( int line )
+{
+   if ( m_bWordWrap )
+   {
+      int d3LIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx(line);
+      return getString( d3LIdx ).mid( m_diff3WrapLineVector[line].wrapLineOffset, m_diff3WrapLineVector[line].wrapLineLength );
+   }
+   else
+   {
+      return getString( line );
+   }
+}
+
+void DiffTextWindowData::getLineInfo(
+   const Diff3Line& d3l,
+   int& lineIdx,
+   DiffList*& pFineDiff1, DiffList*& pFineDiff2,   // return values
+   int& changed, int& changed2
+   )
+{
+   changed=0;
+   changed2=0;
+   bool bAEqB = d3l.bAEqB || ( d3l.bWhiteLineA && d3l.bWhiteLineB );
+   bool bAEqC = d3l.bAEqC || ( d3l.bWhiteLineA && d3l.bWhiteLineC );
+   bool bBEqC = d3l.bBEqC || ( d3l.bWhiteLineB && d3l.bWhiteLineC );
+   if      ( m_winIdx == 1 ) {
+      lineIdx=d3l.lineA;
+      pFineDiff1=d3l.pFineAB;
+      pFineDiff2=d3l.pFineCA;
+      changed |= ((d3l.lineB==-1)!=(lineIdx==-1) ? 1 : 0) +
+                 ((d3l.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 2 : 0);
+      changed2 |= ( bAEqB ? 0 : 1 ) + (bAEqC || !m_bTriple ? 0 : 2);
+   }
+   else if ( m_winIdx == 2 ) {
+      lineIdx=d3l.lineB;
+      pFineDiff1=d3l.pFineBC;
+      pFineDiff2=d3l.pFineAB;
+      changed |= ((d3l.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 1 : 0) +
+                 ((d3l.lineA==-1)!=(lineIdx==-1) ? 2 : 0);
+      changed2 |= ( bBEqC || !m_bTriple ? 0 : 1 ) + (bAEqB ? 0 : 2);
+   }
+   else if ( m_winIdx == 3 ) {
+      lineIdx=d3l.lineC;
+      pFineDiff1=d3l.pFineCA;
+      pFineDiff2=d3l.pFineBC;
+      changed |= ((d3l.lineA==-1)!=(lineIdx==-1) ? 1 : 0) +
+                 ((d3l.lineB==-1)!=(lineIdx==-1) ? 2 : 0);
+      changed2 |= ( bAEqC ? 0 : 1 ) + (bBEqC ? 0 : 2);
+   }
+   else assert(false);
+}
+
+
+
+void DiffTextWindow::resizeEvent( QResizeEvent* e )
+{
+   QSize s = e->size();
+   QFontMetrics fm = fontMetrics();
+   int visibleLines = s.height()/fm.height()-2;
+   int visibleColumns = s.width()/fm.width('W') - d->leftInfoWidth();
+   emit resizeSignal( visibleColumns, visibleLines );
+   QWidget::resizeEvent(e);
+}
+
+int DiffTextWindow::getNofVisibleLines()
+{
+   QFontMetrics fm = fontMetrics();
+   int fmh = fm.height();
+   int h = height();
+   return h/fmh -1;//height()/fm.height()-2;
+}
+
+int DiffTextWindow::getNofVisibleColumns()
+{
+   QFontMetrics fm = fontMetrics();
+   return width()/fm.width('W') - d->leftInfoWidth();
+}
+
+QString DiffTextWindow::getSelection()
+{
+   QString selectionString;
+
+   int line=0;
+   int lineIdx=0;
+
+   int it;
+   int vectorSize = d->m_bWordWrap ? d->m_diff3WrapLineVector.size() : d->m_pDiff3LineVector->size();
+   for( it=0; it<vectorSize; ++it )
+   {
+      const Diff3Line* d3l = d->m_bWordWrap ? d->m_diff3WrapLineVector[it].pD3L : (*d->m_pDiff3LineVector)[it];
+      if      ( d->m_winIdx == 1 ) {    lineIdx=d3l->lineA;     }
+      else if ( d->m_winIdx == 2 ) {    lineIdx=d3l->lineB;     }
+      else if ( d->m_winIdx == 3 ) {    lineIdx=d3l->lineC;     }
+      else assert(false);
+
+      if( lineIdx != -1 )
+      {
+         const QChar* pLine = d->m_pLineData[lineIdx].pLine;
+         int size = d->m_pLineData[lineIdx].size;
+         QString lineString = QString( pLine, size );
+
+         if ( d->m_bWordWrap )
+         {
+            size = d->m_diff3WrapLineVector[it].wrapLineLength;
+            lineString = lineString.mid( d->m_diff3WrapLineVector[it].wrapLineOffset, size );
+         }
+
+         // Consider tabs
+         int outPos = 0;
+         for( int i=0; i<size; ++i )
+         {
+            int spaces = 1;
+            if ( lineString[i]=='\t' )
+            {
+               spaces = tabber( outPos, d->m_pOptionDialog->m_tabSize );
+            }
+
+            if( d->m_selection.within( line, outPos ) )
+            {
+               selectionString += lineString[i];
+            }
+
+            outPos += spaces;
+         }
+
+         if( d->m_selection.within( line, outPos ) &&
+            !( d->m_bWordWrap && it+1<vectorSize && d3l == d->m_diff3WrapLineVector[it+1].pD3L ) 
+           )
+         {
+            #ifdef _WIN32
+            selectionString += '\r';
+            #endif
+            selectionString += '\n';
+         }
+      }
+
+      ++line;
+   }
+
+   return selectionString;
+}
+
+bool DiffTextWindow::findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive )
+{
+   int it = d3vLine;
+   int endIt = bDirDown ? (int)d->m_pDiff3LineVector->size() : -1;
+   int step =  bDirDown ? 1 : -1;
+   int startPos = posInLine;
+
+   for( ; it!=endIt; it+=step )
+   {
+      QString line = d->getString( it );
+      if ( !line.isEmpty() )
+      {
+         int pos = line.find( s, startPos, bCaseSensitive );
+         if ( pos != -1 )
+         {
+            d3vLine = it;
+            posInLine = pos;
+            return true;
+         }
+
+         startPos = 0;
+      }
+   }
+   return false;
+}
+
+void DiffTextWindow::convertD3LCoordsToLineCoords( int d3LIdx, int d3LPos, int& line, int& pos )
+{
+   if( d->m_bWordWrap )
+   {
+      int wrapPos = d3LPos;
+      int wrapLine = convertDiff3LineIdxToLine(d3LIdx);
+      while ( wrapPos > d->m_diff3WrapLineVector[wrapLine].wrapLineLength )
+      {
+         wrapPos -= d->m_diff3WrapLineVector[wrapLine].wrapLineLength;
+         ++wrapLine;
+      }
+      pos = wrapPos;
+      line = wrapLine;
+   }
+   else
+   {
+      pos = d3LPos;
+      line = d3LIdx;
+   }
+}
+
+void DiffTextWindow::convertLineCoordsToD3LCoords( int line, int pos, int& d3LIdx, int& d3LPos )
+{
+   if( d->m_bWordWrap )
+   {
+      d3LPos = pos;
+      d3LIdx = convertLineToDiff3LineIdx( line );
+      int wrapLine = convertDiff3LineIdxToLine(d3LIdx); // First wrap line belonging to this d3LIdx
+      while ( wrapLine < line )
+      {
+         d3LPos += d->m_diff3WrapLineVector[wrapLine].wrapLineLength;
+         ++wrapLine;
+      }
+   }
+   else
+   {
+      d3LPos = pos;
+      d3LIdx = line;
+   }
+}
+
+
+void DiffTextWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos, int& l, int& p )
+{
+   d->m_selection.reset();
+   if ( lastLine >= getNofLines() )
+   {
+      lastLine = getNofLines()-1;
+
+      const Diff3Line* d3l = (*d->m_pDiff3LineVector)[convertLineToDiff3LineIdx(lastLine)];
+      int line = -1;
+      if ( d->m_winIdx==1 ) line = d3l->lineA;
+      if ( d->m_winIdx==2 ) line = d3l->lineB;
+      if ( d->m_winIdx==3 ) line = d3l->lineC;
+      if (line>=0)
+         endPos = d->m_pLineData[line].width( d->m_pOptionDialog->m_tabSize);
+   }
+
+   if ( d->m_bWordWrap && d->m_pDiff3LineVector!=0 )
+   {
+      QString s1 = d->getString(firstLine);
+      int firstWrapLine = convertDiff3LineIdxToLine(firstLine);
+      int wrapStartPos = startPos;
+      while ( wrapStartPos > d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength )
+      {
+         wrapStartPos -= d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength;
+         s1 = s1.mid(d->m_diff3WrapLineVector[firstWrapLine].wrapLineLength);
+         ++firstWrapLine;
+      }
+
+      QString s2 = d->getString(lastLine);
+      int lastWrapLine = convertDiff3LineIdxToLine(lastLine);
+      int wrapEndPos = endPos;
+      while ( wrapEndPos > d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength )
+      {
+         wrapEndPos -= d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength;
+         s2 = s2.mid(d->m_diff3WrapLineVector[lastWrapLine].wrapLineLength);
+         ++lastWrapLine;
+      }
+
+      d->m_selection.start( firstWrapLine, convertToPosOnScreen( s1, wrapStartPos, d->m_pOptionDialog->m_tabSize ) );
+      d->m_selection.end( lastWrapLine, convertToPosOnScreen( s2, wrapEndPos, d->m_pOptionDialog->m_tabSize ) );
+      l=firstWrapLine;
+      p=wrapStartPos;
+   }
+   else
+   {
+      d->m_selection.start( firstLine, convertToPosOnScreen( d->getString(firstLine), startPos, d->m_pOptionDialog->m_tabSize ) );
+      d->m_selection.end( lastLine, convertToPosOnScreen( d->getString(lastLine), endPos, d->m_pOptionDialog->m_tabSize ) );
+      l=firstLine;
+      p=startPos;
+   }
+   update();
+}
+
+int DiffTextWindowData::convertLineOnScreenToLineInSource( int lineOnScreen, e_CoordType coordType, bool bFirstLine )
+{
+   int line=-1;
+   if (lineOnScreen>=0)
+   {
+      if (coordType==eWrapCoords) return lineOnScreen;
+      int d3lIdx = m_pDiffTextWindow->convertLineToDiff3LineIdx( lineOnScreen );
+      if ( !bFirstLine && d3lIdx >= (int)m_pDiff3LineVector->size() )
+         d3lIdx = m_pDiff3LineVector->size()-1;
+      if (coordType==eD3LLineCoords) return d3lIdx;
+      while ( line<0 && d3lIdx<(int)m_pDiff3LineVector->size() && d3lIdx>=0 )
+      {
+         const Diff3Line* d3l = (*m_pDiff3LineVector)[d3lIdx];
+         if ( m_winIdx==1 ) line = d3l->lineA;
+         if ( m_winIdx==2 ) line = d3l->lineB;
+         if ( m_winIdx==3 ) line = d3l->lineC;
+         if ( bFirstLine )
+            ++d3lIdx;
+         else
+            --d3lIdx;
+      }
+      if (coordType==eFileCoords) return line;
+   }
+   return line;
+}
+
+
+void DiffTextWindow::getSelectionRange( int* pFirstLine, int* pLastLine, e_CoordType coordType )
+{
+   if (pFirstLine)
+      *pFirstLine = d->convertLineOnScreenToLineInSource( d->m_selection.beginLine(), coordType, true );
+   if (pLastLine)
+      *pLastLine = d->convertLineOnScreenToLineInSource( d->m_selection.endLine(), coordType, false );
+}
+
+// Returns the number of wrapped lines
+// if pWrappedLines != 0 then the stringlist will contain the wrapped lines.
+int wordWrap( const QString& origLine, int nofColumns, Diff3WrapLine* pDiff3WrapLine )
+{
+   if (nofColumns<=0)
+      nofColumns = 1;
+
+   int nofNeededLines = 0;
+   int length = origLine.length();
+
+   if (length==0)
+   {
+      nofNeededLines = 1;
+      if( pDiff3WrapLine )
+      {
+         pDiff3WrapLine->wrapLineOffset=0;
+         pDiff3WrapLine->wrapLineLength=0;
+      }
+   }
+   else
+   {
+      int pos = 0;
+
+      while ( pos < length )
+      {
+         int wrapPos = pos + nofColumns;
+
+         if ( length-pos <= nofColumns  )
+         {
+            wrapPos = length;
+         }
+         else
+         {
+            int wsPos = max2( origLine.findRev( ' ', wrapPos ), origLine.findRev( '\t', wrapPos ) );
+
+            if ( wsPos > pos )
+            {
+               // Wrap line at wsPos
+               wrapPos = wsPos;
+            }
+         }
+
+         if ( pDiff3WrapLine )
+         {
+            pDiff3WrapLine->wrapLineOffset = pos;
+            pDiff3WrapLine->wrapLineLength = wrapPos-pos;
+            ++pDiff3WrapLine;
+         }
+
+         pos = wrapPos;
+
+         ++nofNeededLines;
+      }
+   }
+   return nofNeededLines;
+}
+
+void DiffTextWindow::convertSelectionToD3LCoords()
+{
+   if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed || !isVisible() || d->m_selection.isEmpty() )
+   {
+      return;
+   }
+
+   // convert the d->m_selection to unwrapped coordinates: Later restore to new coords
+   int firstD3LIdx, firstD3LPos;
+   QString s = d->getLineString( d->m_selection.beginLine() );
+   int firstPosInText = convertToPosInText( s, d->m_selection.beginPos(), d->m_pOptionDialog->m_tabSize );
+   convertLineCoordsToD3LCoords( d->m_selection.beginLine(), firstPosInText, firstD3LIdx, firstD3LPos );
+
+   int lastD3LIdx, lastD3LPos;
+   s = d->getLineString( d->m_selection.endLine() );
+   int lastPosInText = convertToPosInText( s, d->m_selection.endPos(), d->m_pOptionDialog->m_tabSize );
+   convertLineCoordsToD3LCoords( d->m_selection.endLine(), lastPosInText, lastD3LIdx, lastD3LPos );
+
+   //d->m_selection.reset();
+   d->m_selection.start( firstD3LIdx, firstD3LPos );
+   d->m_selection.end( lastD3LIdx, lastD3LPos );
+}
+
+void DiffTextWindow::recalcWordWrap( bool bWordWrap, int wrapLineVectorSize, int nofVisibleColumns )
+{
+   if ( d->m_pDiff3LineVector==0 || ! d->m_bPaintingAllowed || !isVisible() )
+   {
+      d->m_bWordWrap = bWordWrap;
+      if (!bWordWrap)  d->m_diff3WrapLineVector.resize( 0 );
+      return;
+   }
+
+   d->m_bWordWrap = bWordWrap;
+
+   if ( bWordWrap )
+   {
+      d->m_diff3WrapLineVector.resize( wrapLineVectorSize );
+
+      if (nofVisibleColumns<0)
+         nofVisibleColumns = getNofVisibleColumns();
+      else
+         nofVisibleColumns-= d->leftInfoWidth();
+      int i;
+      int wrapLineIdx = 0;
+      int size = d->m_pDiff3LineVector->size();
+      for( i=0; i<size; ++i )
+      {
+         QString s = d->getString( i );
+         int linesNeeded = wordWrap( s, nofVisibleColumns, wrapLineVectorSize==0 ? 0 : &d->m_diff3WrapLineVector[wrapLineIdx] );
+         Diff3Line& d3l = *(*d->m_pDiff3LineVector)[i];
+         if ( d3l.linesNeededForDisplay<linesNeeded )
+         {
+            d3l.linesNeededForDisplay = linesNeeded;
+         }
+
+         if ( wrapLineVectorSize>0 )
+         {
+            int j;
+            for( j=0; j<d3l.linesNeededForDisplay; ++j, ++wrapLineIdx )
+            {
+               Diff3WrapLine& d3wl = d->m_diff3WrapLineVector[wrapLineIdx];
+               d3wl.diff3LineIndex = i;
+               d3wl.pD3L = (*d->m_pDiff3LineVector)[i];
+               if ( j>=linesNeeded )
+               {
+                  d3wl.wrapLineOffset=0;
+                  d3wl.wrapLineLength=0;
+               }
+            }
+         }
+      }
+
+      if ( wrapLineVectorSize>0 )
+      {
+         d->m_firstLine = min2( d->m_firstLine, wrapLineVectorSize-1 );
+         d->m_firstColumn = 0;
+         d->m_pDiffTextWindowFrame->setFirstLine( d->m_firstLine );
+      }
+   }
+   else
+   {
+      d->m_diff3WrapLineVector.resize( 0 );
+   }
+
+   if ( !d->m_selection.isEmpty() && ( !d->m_bWordWrap || wrapLineVectorSize>0 ) )
+   {
+      // Assume unwrapped coordinates 
+      //( Why? ->Conversion to unwrapped coords happened a few lines above in this method. 
+      //  Also see KDiff3App::recalcWordWrap() on the role of wrapLineVectorSize)
+
+      // Wrap them now.
+
+      // convert the d->m_selection to unwrapped coordinates.
+      int firstLine, firstPos;
+      convertD3LCoordsToLineCoords( d->m_selection.beginLine(), d->m_selection.beginPos(), firstLine, firstPos );
+
+      int lastLine, lastPos;
+      convertD3LCoordsToLineCoords( d->m_selection.endLine(), d->m_selection.endPos(), lastLine, lastPos );
+
+      //d->m_selection.reset();
+      d->m_selection.start( firstLine, convertToPosOnScreen( d->getLineString( firstLine ), firstPos, d->m_pOptionDialog->m_tabSize ) );
+      d->m_selection.end( lastLine, convertToPosOnScreen( d->getLineString( lastLine ),lastPos, d->m_pOptionDialog->m_tabSize ) );
+   }
+}
+
+
+class DiffTextWindowFrameData
+{
+public:
+   DiffTextWindow* m_pDiffTextWindow;
+   QLineEdit* m_pFileSelection;
+   QPushButton* m_pBrowseButton;
+   OptionDialog* m_pOptionDialog;
+   QLabel*       m_pLabel;
+   QLabel*       m_pTopLine;
+   QWidget*      m_pTopLineWidget;
+};
+
+DiffTextWindowFrame::DiffTextWindowFrame( QWidget* pParent, QStatusBar* pStatusBar, OptionDialog* pOptionDialog, int winIdx )
+   : QWidget( pParent )
+{
+   d = new DiffTextWindowFrameData;
+   d->m_pOptionDialog = pOptionDialog;
+   d->m_pTopLineWidget = new QWidget(this);
+   d->m_pFileSelection = new QLineEdit(d->m_pTopLineWidget);
+   d->m_pBrowseButton = new QPushButton( "...",d->m_pTopLineWidget );
+   d->m_pBrowseButton->setFixedWidth( 30 );
+   connect(d->m_pBrowseButton,SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked()));
+   connect(d->m_pFileSelection,SIGNAL(returnPressed()), this, SLOT(slotReturnPressed()));
+
+   d->m_pLabel = new QLabel("A:",d->m_pTopLineWidget);
+   d->m_pTopLine = new QLabel(d->m_pTopLineWidget);
+   d->m_pDiffTextWindow = 0;
+   d->m_pDiffTextWindow = new DiffTextWindow( this, pStatusBar, pOptionDialog, winIdx );
+   QHBoxLayout* pHL = new QHBoxLayout(d->m_pTopLineWidget);
+   pHL->setMargin(2);
+   pHL->setSpacing(2);
+
+   pHL->addWidget( d->m_pLabel, 0 );
+   pHL->addWidget( d->m_pFileSelection, 1 );
+   pHL->addWidget( d->m_pBrowseButton, 0 );
+   pHL->addWidget( d->m_pTopLine, 0 );
+
+   QVBoxLayout* pVL = new QVBoxLayout( this, 0, 0 );
+   pVL->addWidget( d->m_pTopLineWidget, 0 );
+   pVL->addWidget( d->m_pDiffTextWindow, 1 );
+
+   d->m_pDiffTextWindow->installEventFilter( this );
+   d->m_pFileSelection->installEventFilter( this );
+   d->m_pBrowseButton->installEventFilter( this );
+   init();
+}
+
+DiffTextWindowFrame::~DiffTextWindowFrame()
+{
+   delete d;
+}
+
+void DiffTextWindowFrame::init()
+{
+   DiffTextWindow* pDTW = d->m_pDiffTextWindow;
+   if ( pDTW )
+   {
+      QString s = pDTW->d->m_filename ;
+      d->m_pFileSelection->setText( s );
+      QString winId = pDTW->d->m_winIdx==1 ? 
+                             ( pDTW->d->m_bTriple?"A (Base)":"A") :
+                             ( pDTW->d->m_winIdx==2 ? "B" : "C" );
+      d->m_pLabel->setText( winId + ":" );
+   }
+}
+
+// Search for the first visible line (search loop needed when no line exist for this file.)
+int DiffTextWindow::calcTopLineInFile( int firstLine )
+{
+   int l=-1;
+   for ( int i = convertLineToDiff3LineIdx(firstLine); i<(int)d->m_pDiff3LineVector->size(); ++i )
+   {
+      const Diff3Line* d3l = (*d->m_pDiff3LineVector)[i];
+      l = d3l->getLineInFile(d->m_winIdx);
+      if (l!=-1) break;
+   }
+   return l;
+}
+
+void DiffTextWindowFrame::setFirstLine( int firstLine )
+{
+   DiffTextWindow* pDTW = d->m_pDiffTextWindow;
+   if ( pDTW && pDTW->d->m_pDiff3LineVector )
+   {
+      QString s= i18n("Top line");
+      int lineNumberWidth = (int)log10((double)pDTW->d->m_size)+1;
+
+      int l=pDTW->calcTopLineInFile(firstLine);
+
+      int w = d->m_pTopLine->fontMetrics().width(
+            s+" "+QString().fill('0',lineNumberWidth));
+      d->m_pTopLine->setMinimumWidth( w );
+
+      if (l==-1)
+         s = i18n("End");
+      else
+         s += " " + QString::number( l+1 );
+
+      d->m_pTopLine->setText( s );
+      d->m_pTopLine->repaint();
+   }
+}
+
+DiffTextWindow* DiffTextWindowFrame::getDiffTextWindow()
+{
+   return d->m_pDiffTextWindow;
+}
+
+bool DiffTextWindowFrame::eventFilter( QObject* o, QEvent* e )
+{
+   DiffTextWindow* pDTW = d->m_pDiffTextWindow;
+   if ( e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut )
+   {
+      QColor c1 = d->m_pOptionDialog->m_bgColor;
+      QColor c2 = pDTW->d->m_cThis;
+      QPalette p = d->m_pTopLineWidget->palette();
+      if ( e->type()==QEvent::FocusOut )
+         std::swap(c1,c2);
+
+      p.setColor(QColorGroup::Background, c2);
+      d->m_pTopLineWidget->setPalette( p );
+      d->m_pBrowseButton->setPalette( p );
+      d->m_pFileSelection->setPalette( p );
+
+      p.setColor(QColorGroup::Foreground, c1);
+      d->m_pLabel->setPalette( p );
+      d->m_pTopLine->setPalette( p );
+   }
+   if (o == d->m_pFileSelection && e->type()==QEvent::Drop)
+   {
+      QDropEvent* d = static_cast<QDropEvent*>(e);
+      
+      if ( QUriDrag::canDecode( d ) ) 
+      {
+         QStringList lst;
+         QUriDrag::decodeLocalFiles( d, lst );
+
+         if ( lst.count() > 0 )
+         {
+            static_cast<QLineEdit*>(o)->setText( lst[0] );
+            static_cast<QLineEdit*>(o)->setFocus();
+            emit fileNameChanged( lst[0], pDTW->d->m_winIdx );
+            return true;
+         }
+      }
+      /* The following lines work for Qt>4.1 but not for 4.0.x*/
+      /*if ( d->mimeData()->hasUrls() )
+      {
+         QList<QUrl> lst = d->mimeData()->urls();
+         if ( !lst.empty() )
+         {
+            static_cast<QLineEdit*>(o)->setText( lst[0].toLocalFile() );
+            static_cast<QLineEdit*>(o)->setFocus();
+            emit fileNameChanged( lst[0], pDTW->d->m_winIdx );
+            return true;
+         }
+      }*/
+   }
+   return false;
+}
+
+void DiffTextWindowFrame::slotReturnPressed()
+{
+   DiffTextWindow* pDTW = d->m_pDiffTextWindow;
+   if ( pDTW->d->m_filename != d->m_pFileSelection->text() )
+   {
+      emit fileNameChanged( d->m_pFileSelection->text(), pDTW->d->m_winIdx );
+   }
+}
+
+void DiffTextWindowFrame::slotBrowseButtonClicked()
+{
+   QString current = d->m_pFileSelection->text();
+
+   KURL newURL = KFileDialog::getOpenURL( current, 0, this);
+   if ( !newURL.isEmpty() )
+   {
+      DiffTextWindow* pDTW = d->m_pDiffTextWindow;
+      emit fileNameChanged( newURL.url(), pDTW->d->m_winIdx );
+   }
+}
+
+QCString encodeString( const QString& s )
+{
+   QTextCodec* c = QTextCodec::codecForLocale();
+   if (c!=0)
+      return c->fromUnicode( s );
+   else
+      return QCString( s.latin1() );
+}
+
+#include "difftextwindow.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/difftextwindow.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,135 @@
+/***************************************************************************
+                          difftextwindow.h  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002-2005 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef DIFFTEXTWINDOW_H
+#define DIFFTEXTWINDOW_H
+
+#include "diff.h"
+
+#include <qwidget.h>
+
+class QStatusBar;
+class OptionDialog;
+class DiffTextWindowData;
+class DiffTextWindowFrame;
+
+class DiffTextWindow : public QWidget
+{
+   Q_OBJECT
+public:
+   DiffTextWindow(
+      DiffTextWindowFrame* pParent,
+      QStatusBar* pStatusBar,
+      OptionDialog* pOptionDialog,
+      int winIdx
+      );
+   ~DiffTextWindow();
+   void init(
+      const QString& fileName,
+      const LineData* pLineData,
+      int size,
+      const Diff3LineVector* pDiff3LineVector,
+      const ManualDiffHelpList* pManualDiffHelpList,
+      bool bTriple
+      );
+   void reset();
+   void convertToLinePos( int x, int y, int& line, int& pos );
+
+   QString getSelection();
+   int getFirstLine();
+   int calcTopLineInFile( int firstLine );
+
+   int getNofColumns();
+   int getNofLines();
+   int getNofVisibleLines();
+   int getNofVisibleColumns();
+
+   int convertLineToDiff3LineIdx( int line );
+   int convertDiff3LineIdxToLine( int d3lIdx );
+
+   void convertD3LCoordsToLineCoords( int d3LIdx, int d3LPos, int& line, int& pos );
+   void convertLineCoordsToD3LCoords( int line, int pos, int& d3LIdx, int& d3LPos );
+
+   void convertSelectionToD3LCoords();
+
+   bool findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive );
+   void setSelection( int firstLine, int startPos, int lastLine, int endPos, int& l, int& p );
+   void getSelectionRange( int* firstLine, int* lastLine, e_CoordType coordType );
+
+   void setPaintingAllowed( bool bAllowPainting );
+   void recalcWordWrap( bool bWordWrap, int wrapLineVectorSize, int nofVisibleColumns );
+   void print( MyPainter& painter, const QRect& r, int firstLine, int nofLinesPerPage );
+signals:
+   void resizeSignal( int nofVisibleColumns, int nofVisibleLines );
+   void scroll( int deltaX, int deltaY );
+   void newSelection();
+   void selectionEnd();
+   void setFastSelectorLine( int line );
+   void gotFocus();
+   void lineClicked( int winIdx, int line );
+
+public slots:
+   void setFirstLine( int line );
+   void setFirstColumn( int col );
+   void resetSelection();
+   void setFastSelectorRange( int line1, int nofLines );
+
+protected:
+   virtual void mousePressEvent ( QMouseEvent * );
+   virtual void mouseReleaseEvent ( QMouseEvent * );
+   virtual void mouseMoveEvent ( QMouseEvent * );
+   virtual void mouseDoubleClickEvent ( QMouseEvent * e );
+
+   virtual void paintEvent( QPaintEvent*  );
+   virtual void dragEnterEvent( QDragEnterEvent* e );
+   virtual void focusInEvent( QFocusEvent* e );
+
+   virtual void resizeEvent( QResizeEvent* );
+   virtual void timerEvent(QTimerEvent*);
+
+private:
+   DiffTextWindowData* d;
+   void showStatusLine( int line );
+   friend class DiffTextWindowFrame;
+};
+
+
+class DiffTextWindowFrameData;
+
+class DiffTextWindowFrame : public QWidget
+{
+   Q_OBJECT
+public:
+   DiffTextWindowFrame( QWidget* pParent, QStatusBar* pStatusBar, OptionDialog* pOptionDialog, int winIdx );
+   ~DiffTextWindowFrame();
+   DiffTextWindow* getDiffTextWindow();
+   void init();
+   void setFirstLine(int firstLine);
+signals:
+   void fileNameChanged(const QString&, int);
+protected:
+   bool eventFilter( QObject*, QEvent* );
+private slots:
+   void slotReturnPressed();
+   void slotBrowseButtonClicked();
+private:
+   DiffTextWindowFrameData* d;
+};
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/directorymergewindow.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2982 @@
+/***************************************************************************
+                          directorymergewindow.cpp
+                             -----------------
+    begin                : Sat Oct 19 2002
+    copyright            : (C) 2002-2005 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "directorymergewindow.h"
+#include "optiondialog.h"
+#include <vector>
+#include <map>
+
+#include <qdir.h>
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <qregexp.h>
+#include <qmessagebox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtable.h>
+#include <qsplitter.h>
+#include <qtextedit.h>
+#include <qprogressdialog.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <iostream>
+#include <assert.h>
+//#include <konq_popupmenu.h>
+
+static bool conflictingFileTypes(MergeFileInfos& mfi);
+/*
+class StatusInfo : public QListView
+{
+public:
+   StatusInfo(QWidget* pParent) : QListView( pParent, "StatusInfo", Qt::WShowModal )
+   {
+      addColumn("");
+      setSorting(-1); //disable sorting
+   }
+
+   QListViewItem* m_pLast;
+   QListViewItem* last()
+   {
+      if (firstChild()==0) return 0;
+      else                 return m_pLast;
+   }
+
+   void addText(const QString& s )
+   {
+      if (firstChild()==0) m_pLast = new QListViewItem( this, s );
+      else                 m_pLast = new QListViewItem( this, last(), s );
+   }
+};
+*/
+class StatusInfo : public QTextEdit
+{
+public:
+   StatusInfo(QWidget* pParent) : QTextEdit( pParent, "StatusInfo" )
+   {
+      setWFlags(Qt::WShowModal);
+      setWordWrap(QTextEdit::NoWrap);
+      setReadOnly(true);
+      showMaximized();
+   }
+
+   bool isEmpty(){ return text().isEmpty(); }
+
+   void addText(const QString& s )
+   {
+      append(s);
+   }
+
+   void show()
+   {
+      scrollToBottom();
+      QTextEdit::show();
+   }
+};
+
+
+class TempRemover
+{
+public:
+   TempRemover( const QString& origName, FileAccess& fa );
+   ~TempRemover();
+   QString name() { return m_name; }
+   bool success() { return m_bSuccess; }
+private:
+   QString m_name;
+   bool m_bTemp;
+   bool m_bSuccess;
+};
+TempRemover::TempRemover(const QString& origName, FileAccess& fa)
+{
+   if ( fa.isLocal() )
+   {
+      m_name = origName;
+      m_bTemp = false;
+      m_bSuccess = true;
+   }
+   else
+   {
+      m_name = FileAccess::tempFileName();
+      m_bSuccess = fa.copyFile( m_name );
+      m_bTemp = m_bSuccess;
+   }
+}
+TempRemover::~TempRemover()
+{
+   if ( m_bTemp && ! m_name.isEmpty() )
+      FileAccess::removeTempFile(m_name);
+}
+
+void DirectoryMergeWindow::fastFileComparison(
+   FileAccess& fi1, FileAccess& fi2,
+   bool& bEqual, bool& bError, QString& status )
+{
+   ProgressProxy pp;
+   status = "";
+   bEqual = false;
+   bError = true;
+
+   if ( !m_bFollowFileLinks )
+   {
+      if ( fi1.isSymLink() != fi2.isSymLink() )
+      {
+         status = i18n("Mix of links and normal files.");
+         return;
+      }
+      else if ( fi1.isSymLink() && fi2.isSymLink() )
+      {
+         bError = false;
+         bEqual = fi1.readLink() == fi2.readLink();
+         status = i18n("Link: ");
+         return;
+      }
+   }
+
+   if ( fi1.size()!=fi2.size() )
+   {
+      bEqual = false;
+      status = i18n("Size. ");
+      return;
+   }
+   else if ( m_pOptions->m_bDmTrustSize )
+   {
+      bEqual = true;
+      return;
+   }
+
+   if ( m_pOptions->m_bDmTrustDate )
+   {
+      bEqual = ( fi1.lastModified() == fi2.lastModified()  &&  fi1.size()==fi2.size() );
+      bError = false;
+      status = i18n("Date & Size: ");
+      return;
+   }
+
+   QString fileName1 = fi1.absFilePath();
+   QString fileName2 = fi2.absFilePath();
+   TempRemover tr1( fileName1, fi1 );
+   if ( !tr1.success() )
+   {
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName1);
+      return;
+   }
+   TempRemover tr2( fileName2, fi2 );
+   if ( !tr2.success() )
+   {
+      status = i18n("Creating temp copy of %1 failed.").arg(fileName2);
+      return;
+   }
+
+   std::vector<char> buf1(100000);
+   std::vector<char> buf2(buf1.size());
+
+   QFile file1( tr1.name() );
+
+   if ( ! file1.open(IO_ReadOnly) )
+   {
+      status = i18n("Opening %1 failed.").arg(fileName1);
+      return;
+   }
+
+   QFile file2( tr2.name() );
+
+   if ( ! file2.open(IO_ReadOnly) )
+   {
+      status = i18n("Opening %1 failed.").arg(fileName2);
+      return;
+   }
+
+   pp.setInformation( i18n("Comparing file..."), 0, false );
+   typedef QFile::Offset t_FileSize;
+   t_FileSize fullSize = file1.size();
+   t_FileSize sizeLeft = fullSize;
+
+   while( sizeLeft>0 && ! pp.wasCancelled() )
+   {
+      int len = min2( sizeLeft, (t_FileSize)buf1.size() );
+      if( len != file1.readBlock( &buf1[0], len ) )
+      {
+         status = i18n("Error reading from %1").arg(fileName1);
+         return;
+      }
+
+      if( len != file2.readBlock( &buf2[0], len ) )
+      {
+         status = i18n("Error reading from %1").arg(fileName2);
+         return;
+      }
+
+      if ( memcmp( &buf1[0], &buf2[0], len ) != 0 )
+      {
+         bError = false;
+         return;
+      }
+      sizeLeft-=len;
+      pp.setCurrent(double(fullSize-sizeLeft)/fullSize, false );
+   }
+
+   // If the program really arrives here, then the files are really equal.
+   bError = false;
+   bEqual = true;
+}
+
+
+
+
+
+static int s_nameCol = 0;
+static int s_ACol = 1;
+static int s_BCol = 2;
+static int s_CCol = 3;
+static int s_OpCol = 4;
+static int s_OpStatusCol = 5;
+static int s_UnsolvedCol = 6;    // Nr of unsolved conflicts (for 3 input files)
+static int s_SolvedCol = 7;      // Nr of auto-solvable conflicts (for 3 input files)
+static int s_NonWhiteCol = 8;    // Nr of nonwhite deltas (for 2 input files)
+static int s_WhiteCol = 9;       // Nr of white deltas (for 2 input files)
+DirectoryMergeWindow::DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader )
+   : QListView( pParent )
+{
+   connect( this, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(onDoubleClick(QListViewItem*)));
+   connect( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(onDoubleClick(QListViewItem*)));
+   connect( this, SIGNAL( mouseButtonPressed(int,QListViewItem*,const QPoint&, int)),
+            this, SLOT(   onClick(int,QListViewItem*,const QPoint&, int))  );
+   connect( this, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint &,int)),
+            this, SLOT(   slotShowContextMenu(QListViewItem*,const QPoint &,int)));
+   connect( this, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(onSelectionChanged(QListViewItem*)));
+   m_pOptions = pOptions;
+   m_pIconLoader = pIconLoader;
+   m_pDirectoryMergeInfo = 0;
+   m_bAllowResizeEvents = true;
+   m_bSimulatedMergeStarted=false;
+   m_bRealMergeStarted=false;
+   m_bError = false;
+   m_bSyncMode = false;
+   m_pStatusInfo = new StatusInfo(0);
+   m_pStatusInfo->hide();
+   m_bScanning = false;
+   m_pSelection1Item = 0;
+   m_pSelection2Item = 0;
+   m_pSelection3Item = 0;
+   m_bCaseSensitive = true;
+
+   addColumn(i18n("Name"));
+   addColumn("A");
+   addColumn("B");
+   addColumn("C");
+   addColumn(i18n("Operation"));
+   addColumn(i18n("Status"));
+   addColumn(i18n("Unsolved"));
+   addColumn(i18n("Solved"));
+   addColumn(i18n("Nonwhite"));
+   addColumn(i18n("White"));
+
+   setColumnAlignment( s_UnsolvedCol, Qt::AlignRight );
+   setColumnAlignment( s_SolvedCol,   Qt::AlignRight );
+   setColumnAlignment( s_NonWhiteCol, Qt::AlignRight );
+   setColumnAlignment( s_WhiteCol,    Qt::AlignRight );
+}
+
+DirectoryMergeWindow::~DirectoryMergeWindow()
+{
+}
+
+
+int DirectoryMergeWindow::totalColumnWidth()
+{
+   int w=0;
+   for (int i=0; i<s_OpStatusCol; ++i)
+   {
+      w += columnWidth(i);
+   }
+   return w;
+}
+
+void DirectoryMergeWindow::reload()
+{
+   if ( isDirectoryMergeInProgress() )
+   {
+      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("Rescan"), i18n("Continue Merging") );
+      if ( result!=KMessageBox::Yes )
+         return;
+   }
+
+   init( m_dirA, m_dirB, m_dirC, m_dirDest, m_bDirectoryMerge );
+}
+
+// Copy pm2 onto pm1, but preserve the alpha value from pm1 where pm2 is transparent.
+static QPixmap pixCombiner( const QPixmap* pm1, const QPixmap* pm2 )
+{
+   QImage img1 = pm1->convertToImage().convertDepth(32);
+   QImage img2 = pm2->convertToImage().convertDepth(32);
+
+   for (int y = 0; y < img1.height(); y++)
+   {
+      Q_UINT32 *line1 = reinterpret_cast<Q_UINT32 *>(img1.scanLine(y));
+      Q_UINT32 *line2 = reinterpret_cast<Q_UINT32 *>(img2.scanLine(y));
+      for (int x = 0; x < img1.width();  x++)
+      {
+         if ( qAlpha( line2[x] ) >0 )
+            line1[x] = (line2[x] | 0xff000000);
+      }
+   }
+   QPixmap pix;
+   pix.convertFromImage(img1);
+   return pix;
+}
+
+// like pixCombiner but let the pm1 color shine through
+static QPixmap pixCombiner2( const QPixmap* pm1, const QPixmap* pm2 )
+{
+   QImage img1 = pm1->convertToImage().convertDepth(32);
+   QImage img2 = pm2->convertToImage().convertDepth(32);
+
+   for (int y = 0; y < img1.height(); y++)
+   {
+      Q_UINT32 *line1 = reinterpret_cast<Q_UINT32 *>(img1.scanLine(y));
+      Q_UINT32 *line2 = reinterpret_cast<Q_UINT32 *>(img2.scanLine(y));
+      for (int x = 0; x < img1.width();  x++)
+      {
+         if ( qAlpha( line2[x] ) >0 )
+         {
+            int r = ( qRed( line1[x] ) + qRed( line2[x] ))/2;
+            int g = ( qGreen( line1[x] ) + qGreen( line2[x] ))/2;
+            int b = ( qBlue( line1[x] ) + qBlue( line2[x] ))/2;
+            line1[x] = qRgba( r,g,b, 0xff );
+         }
+      }
+   }
+   QPixmap pix;
+   pix.convertFromImage(img1);
+   return pix;
+}
+
+static void calcDirStatus( bool bThreeDirs, DirMergeItem* i, int& nofFiles,
+                           int& nofDirs, int& nofEqualFiles, int& nofManualMerges )
+{
+   if ( i->m_pMFI->m_bDirA || i->m_pMFI->m_bDirB || i->m_pMFI->m_bDirC )
+   {
+      ++nofDirs;
+   }
+   else
+   {
+      ++nofFiles;
+      if ( i->m_pMFI->m_bEqualAB && (!bThreeDirs || i->m_pMFI->m_bEqualAC ))
+      {
+         ++nofEqualFiles;
+      }
+      else
+      {
+         if ( i->m_pMFI->m_eMergeOperation==eMergeABCToDest || i->m_pMFI->m_eMergeOperation==eMergeABToDest )
+            ++nofManualMerges;
+      }
+   }
+   for( QListViewItem* p = i->firstChild();  p!=0; p = p->nextSibling() )
+      calcDirStatus( bThreeDirs, static_cast<DirMergeItem*>(p), nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
+}
+
+static QString sortString(const QString& s, bool bCaseSensitive)
+{
+   if (bCaseSensitive)
+      return s;
+   else
+      return s.upper();
+}
+
+bool DirectoryMergeWindow::init
+   (
+   FileAccess& dirA,
+   FileAccess& dirB,
+   FileAccess& dirC,
+   FileAccess& dirDest,
+   bool bDirectoryMerge
+   )
+{
+   if ( m_pOptions->m_bDmFullAnalysis )
+   {
+      // A full analysis uses the same ressources that a normal text-diff/merge uses.
+      // So make sure that the user saves his data first.
+      bool bCanContinue=false;
+      checkIfCanContinue( &bCanContinue );
+      if ( !bCanContinue )
+         return false;
+      startDiffMerge("","","","","","","",0);  // hide main window
+   }
+
+   show();
+
+   ProgressProxy pp;
+   m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks;
+   m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks;
+   m_bSimulatedMergeStarted=false;
+   m_bRealMergeStarted=false;
+   m_bError=false;
+   m_bDirectoryMerge = bDirectoryMerge;
+   m_pSelection1Item = 0;
+   m_pSelection2Item = 0;
+   m_pSelection3Item = 0;
+   m_bCaseSensitive = m_pOptions->m_bDmCaseSensitiveFilenameComparison;
+
+   clear();
+
+   m_mergeItemList.clear();
+   m_currentItemForOperation = m_mergeItemList.end();
+
+   m_dirA = dirA;
+   m_dirB = dirB;
+   m_dirC = dirC;
+   m_dirDest = dirDest;
+
+   m_pDirShowIdenticalFiles->setChecked(true);
+   m_pDirShowDifferentFiles->setChecked(true);
+   m_pDirShowFilesOnlyInA->setChecked(true);
+   m_pDirShowFilesOnlyInB->setChecked(true);
+   m_pDirShowFilesOnlyInC->setChecked(true);
+
+   // Check if all input directories exist and are valid. The dest dir is not tested now.
+   // The test will happen only when we are going to write to it.
+   if ( !m_dirA.isDir() || !m_dirB.isDir() ||
+        (m_dirC.isValid() && !m_dirC.isDir()) )
+   {
+       QString text( i18n("Opening of directories failed:") );
+       text += "\n\n";
+       if ( !dirA.isDir() )
+       {  text += i18n("Dir A \"%1\" does not exist or is not a directory.\n").arg(m_dirA.prettyAbsPath()); }
+
+       if ( !dirB.isDir() )
+       {  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 += 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") );
+       return false;
+   }
+
+   if ( m_dirC.isValid() &&
+        (m_dirDest.prettyAbsPath() == m_dirA.prettyAbsPath()  ||  m_dirDest.prettyAbsPath()==m_dirB.prettyAbsPath() ) )
+   {
+      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."),
+         i18n("Parameter Warning"));
+      return false;
+   }
+
+   m_bScanning = true;
+   statusBarMessage(i18n("Scanning directories..."));
+
+   m_bSyncMode = m_pOptions->m_bDmSyncMode && !m_dirC.isValid() && !m_dirDest.isValid();
+
+   if ( m_dirDest.isValid() )
+      m_dirDestInternal = m_dirDest;
+   else
+      m_dirDestInternal = m_dirC.isValid() ? m_dirC : m_dirB;
+
+   QString origCurrentDirectory = QDir::currentDirPath();
+
+   m_fileMergeMap.clear();
+   t_DirectoryList::iterator i;
+
+   // calc how many directories will be read:
+   double nofScans = ( m_dirA.isValid() ? 1 : 0 )+( m_dirB.isValid() ? 1 : 0 )+( m_dirC.isValid() ? 1 : 0 );
+   int currentScan = 0;
+
+   setColumnWidthMode(s_UnsolvedCol, QListView::Manual);
+   setColumnWidthMode(s_SolvedCol,   QListView::Manual);
+   setColumnWidthMode(s_WhiteCol,    QListView::Manual);
+   setColumnWidthMode(s_NonWhiteCol, QListView::Manual);
+   if ( !m_pOptions->m_bDmFullAnalysis )
+   {
+      setColumnWidth( s_WhiteCol,    0 );
+      setColumnWidth( s_NonWhiteCol, 0 );
+      setColumnWidth( s_UnsolvedCol, 0 );
+      setColumnWidth( s_SolvedCol,   0 );
+   }
+   else if ( m_dirC.isValid() )
+   {
+      setColumnWidth(s_WhiteCol,    50 );
+      setColumnWidth(s_NonWhiteCol, 50 );
+      setColumnWidth(s_UnsolvedCol, 50 );
+      setColumnWidth(s_SolvedCol,   50 );
+   }
+   else
+   {
+      setColumnWidth(s_WhiteCol,    50 );
+      setColumnWidth(s_NonWhiteCol, 50 );
+      setColumnWidth(s_UnsolvedCol, 50 );
+      setColumnWidth(s_SolvedCol,    0 );
+   }
+
+   bool bListDirSuccessA = true;
+   bool bListDirSuccessB = true;
+   bool bListDirSuccessC = true;
+   if ( m_dirA.isValid() )
+   {
+      pp.setInformation(i18n("Reading Directory A"));
+      pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
+      ++currentScan;
+
+      t_DirectoryList dirListA;
+      bListDirSuccessA = m_dirA.listDir( &dirListA,
+         m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
+         m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
+         m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
+         m_pOptions->m_bDmUseCvsIgnore);
+
+      for (i=dirListA.begin(); i!=dirListA.end();++i )
+      {
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)];
+         //std::cout <<i->filePath()<<std::endl;
+         mfi.m_bExistsInA = true;
+         mfi.m_fileInfoA = *i;
+      }
+   }
+
+   if ( m_dirB.isValid() )
+   {
+      pp.setInformation(i18n("Reading Directory B"));
+      pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
+      ++currentScan;
+
+      t_DirectoryList dirListB;
+      bListDirSuccessB =  m_dirB.listDir( &dirListB,
+         m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
+         m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
+         m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
+         m_pOptions->m_bDmUseCvsIgnore);
+
+      for (i=dirListB.begin(); i!=dirListB.end();++i )
+      {
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(), m_bCaseSensitive)];
+         mfi.m_bExistsInB = true;
+         mfi.m_fileInfoB = *i;
+      }
+   }
+
+   e_MergeOperation eDefaultMergeOp;
+   if ( m_dirC.isValid() )
+   {
+      pp.setInformation(i18n("Reading Directory C"));
+      pp.setSubRangeTransformation(currentScan/nofScans, (currentScan+1)/nofScans);
+      ++currentScan;
+
+      t_DirectoryList dirListC;
+      bListDirSuccessC = m_dirC.listDir( &dirListC,
+         m_pOptions->m_bDmRecursiveDirs, m_pOptions->m_bDmFindHidden,
+         m_pOptions->m_DmFilePattern, m_pOptions->m_DmFileAntiPattern,
+         m_pOptions->m_DmDirAntiPattern, m_pOptions->m_bDmFollowDirLinks,
+         m_pOptions->m_bDmUseCvsIgnore);
+
+      for (i=dirListC.begin(); i!=dirListC.end();++i )
+      {
+         MergeFileInfos& mfi = m_fileMergeMap[sortString(i->filePath(),m_bCaseSensitive)];
+         mfi.m_bExistsInC = true;
+         mfi.m_fileInfoC = *i;
+      }
+
+      eDefaultMergeOp = eMergeABCToDest;
+   }
+   else
+      eDefaultMergeOp = m_bSyncMode ? eMergeToAB : eMergeABToDest;
+
+   bool bContinue = true;
+   if ( !bListDirSuccessA || !bListDirSuccessB || !bListDirSuccessC )
+   {
+      QString s = i18n("Some subdirectories were not readable in");
+      if ( !bListDirSuccessA )   s += "\nA: " + m_dirA.prettyAbsPath();
+      if ( !bListDirSuccessB )   s += "\nB: " + m_dirB.prettyAbsPath();
+      if ( !bListDirSuccessC )   s += "\nC: " + m_dirC.prettyAbsPath();
+      s+="\n";
+      s+= i18n("Check the permissions of the subdirectories.");
+      bContinue = KMessageBox::Continue == KMessageBox::warningContinueCancel( this, s );
+   }
+
+   if ( bContinue )
+   {
+      prepareListView(pp);
+
+      for( QListViewItem* p = firstChild();  p!=0; p = p->nextSibling() )
+      {
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
+         calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp );
+      }
+   }
+   else
+   {
+      setSelected( 0, true );
+   }
+
+   QDir::setCurrent(origCurrentDirectory);
+
+   // Try to improve the view a little bit.
+   QWidget* pParent = parentWidget();
+   QSplitter* pSplitter = static_cast<QSplitter*>(pParent);
+   if (pSplitter!=0)
+   {
+      QValueList<int> sizes = pSplitter->sizes();
+      int total = sizes[0] + sizes[1];
+      sizes[0]=total*6/10;
+      sizes[1]=total - sizes[0];
+      pSplitter->setSizes( sizes );
+   }
+
+   m_bScanning = false;
+   statusBarMessage(i18n("Ready."));
+
+   if ( bContinue )
+   {
+      // Generate a status report
+      int nofFiles=0;
+      int nofDirs=0;
+      int nofEqualFiles=0;
+      int nofManualMerges=0;
+      for( QListViewItem* p = firstChild();  p!=0; p = p->nextSibling() )
+         calcDirStatus( m_dirC.isValid(), static_cast<DirMergeItem*>(p),
+                        nofFiles, nofDirs, nofEqualFiles, nofManualMerges );
+
+      QString s;
+      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);
+
+      if ( m_dirC.isValid() )
+         s += "\n" + i18n("Number of manual merges:")   +" "+ QString::number(nofManualMerges);
+      KMessageBox::information( this, s );
+      setSelected( firstChild(), true );
+   }
+
+   return true;
+}
+
+
+
+void DirectoryMergeWindow::slotChooseAEverywhere(){ setAllMergeOperations( eCopyAToDest ); }
+
+void DirectoryMergeWindow::slotChooseBEverywhere(){ setAllMergeOperations( eCopyBToDest ); }
+
+void DirectoryMergeWindow::slotChooseCEverywhere(){ setAllMergeOperations( eCopyCToDest ); }
+
+void DirectoryMergeWindow::slotAutoChooseEverywhere()
+{
+   e_MergeOperation eDefaultMergeOp = m_dirC.isValid() ?  eMergeABCToDest :
+                                           m_bSyncMode ?  eMergeToAB      : eMergeABToDest;
+   setAllMergeOperations(eDefaultMergeOp );
+}
+
+void DirectoryMergeWindow::slotNoOpEverywhere(){ setAllMergeOperations(eNoOperation); }
+
+static void setListViewItemOpen( QListViewItem* p, bool bOpen )
+{
+   for( QListViewItem* pChild = p->firstChild();  pChild!=0; pChild = pChild->nextSibling() )
+      setListViewItemOpen( pChild, bOpen );
+
+   p->setOpen( bOpen );
+}
+
+void DirectoryMergeWindow::slotFoldAllSubdirs()
+{
+   for( QListViewItem* p = firstChild();  p!=0; p = p->nextSibling() )
+      setListViewItemOpen( p, false );
+}
+
+void DirectoryMergeWindow::slotUnfoldAllSubdirs()
+{
+   for( QListViewItem* p = firstChild();  p!=0; p = p->nextSibling() )
+      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(), m_bSyncMode ? eCopyAToB : eCopyAToDest ); }
+void DirectoryMergeWindow::slotCurrentChooseB()   { setMergeOperation(currentItem(), m_bSyncMode ? eCopyBToA : 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::focusInEvent(QFocusEvent*)
+{
+   updateAvailabilities();
+}
+void DirectoryMergeWindow::focusOutEvent(QFocusEvent*)
+{
+   updateAvailabilities();
+}
+
+void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
+{
+   if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
+        i18n("This affects all merge operations."),
+        i18n("Changing All Merge Operations"),i18n("C&ontinue"), i18n("&Cancel") ) )
+   {
+      for( QListViewItem* p = firstChild(); p!=0; p = p->nextSibling() )
+      {
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
+         calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation );
+      }
+   }
+}
+
+
+void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi )
+{
+   std::map<QDateTime,int> dateMap;
+
+   if( mfi.m_bExistsInA )
+   {
+      mfi.m_bLinkA = mfi.m_fileInfoA.isSymLink();
+      mfi.m_bDirA  = mfi.m_fileInfoA.isDir();
+      dateMap[ mfi.m_fileInfoA.lastModified() ] = 0;
+   }
+   if( mfi.m_bExistsInB )
+   {
+      mfi.m_bLinkB = mfi.m_fileInfoB.isSymLink();
+      mfi.m_bDirB  = mfi.m_fileInfoB.isDir();
+      dateMap[ mfi.m_fileInfoB.lastModified() ] = 1;
+   }
+   if( mfi.m_bExistsInC )
+   {
+      mfi.m_bLinkC = mfi.m_fileInfoC.isSymLink();
+      mfi.m_bDirC  = mfi.m_fileInfoC.isDir();
+      dateMap[ mfi.m_fileInfoC.lastModified() ] = 2;
+   }
+
+   if ( m_pOptions->m_bDmFullAnalysis )
+   {
+      if( mfi.m_bExistsInA && mfi.m_bDirA || mfi.m_bExistsInB && mfi.m_bDirB || mfi.m_bExistsInC && mfi.m_bDirC )
+      {
+         // If any input is a directory, don't start any comparison.
+         mfi.m_bEqualAB=mfi.m_bExistsInA && mfi.m_bExistsInB;
+         mfi.m_bEqualAC=mfi.m_bExistsInA && mfi.m_bExistsInC;
+         mfi.m_bEqualBC=mfi.m_bExistsInB && mfi.m_bExistsInC;
+      }
+      else
+      {
+         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(""),
+            "",
+            "","","",&mfi.m_totalDiffStatus
+            );
+         int nofNonwhiteConflicts = mfi.m_totalDiffStatus.nofUnsolvedConflicts + 
+            mfi.m_totalDiffStatus.nofSolvedConflicts - mfi.m_totalDiffStatus.nofWhitespaceConflicts;
+
+         if (m_pOptions->m_bDmWhiteSpaceEqual && nofNonwhiteConflicts == 0)
+         {
+            mfi.m_bEqualAB =  mfi.m_bEqualBC =  mfi.m_bEqualAC = true;
+         }
+         else
+         {
+            mfi.m_bEqualAB = mfi.m_totalDiffStatus.bBinaryAEqB;
+            mfi.m_bEqualBC = mfi.m_totalDiffStatus.bBinaryBEqC;
+            mfi.m_bEqualAC = mfi.m_totalDiffStatus.bBinaryAEqC;
+         }
+      }
+   }
+   else
+   {
+      bool bError;
+      QString eqStatus;
+      if( mfi.m_bExistsInA && mfi.m_bExistsInB )
+      {
+         if( mfi.m_bDirA ) mfi.m_bEqualAB=true;
+         else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoB, mfi.m_bEqualAB, bError, eqStatus );
+      }
+      if( mfi.m_bExistsInA && mfi.m_bExistsInC )
+      {
+         if( mfi.m_bDirA ) mfi.m_bEqualAC=true;
+         else fastFileComparison( mfi.m_fileInfoA, mfi.m_fileInfoC, mfi.m_bEqualAC, bError, eqStatus );
+      }
+      if( mfi.m_bExistsInB && mfi.m_bExistsInC )
+      {
+         if (mfi.m_bEqualAB && mfi.m_bEqualAC)
+            mfi.m_bEqualBC = true;
+         else
+         {
+            if( mfi.m_bDirB ) mfi.m_bEqualBC=true;
+            else fastFileComparison( mfi.m_fileInfoB, mfi.m_fileInfoC, mfi.m_bEqualBC, bError, eqStatus );
+         }
+      }
+   }
+
+   if (mfi.m_bLinkA!=mfi.m_bLinkB) mfi.m_bEqualAB=false;
+   if (mfi.m_bLinkA!=mfi.m_bLinkC) mfi.m_bEqualAC=false;
+   if (mfi.m_bLinkB!=mfi.m_bLinkC) mfi.m_bEqualBC=false;
+
+   if (mfi.m_bDirA!=mfi.m_bDirB) mfi.m_bEqualAB=false;
+   if (mfi.m_bDirA!=mfi.m_bDirC) mfi.m_bEqualAC=false;
+   if (mfi.m_bDirB!=mfi.m_bDirC) mfi.m_bEqualBC=false;
+
+   assert(eNew==0 && eMiddle==1 && eOld==2);
+
+   // The map automatically sorts the keys.
+   int age = eNew;
+   std::map<QDateTime,int>::reverse_iterator i;
+   for( i=dateMap.rbegin(); i!=dateMap.rend(); ++i )
+   {
+      int n = i->second;
+      if ( n==0 && mfi.m_ageA==eNotThere )
+      {
+         mfi.m_ageA = (e_Age)age; ++age;
+         if ( mfi.m_bEqualAB ) { mfi.m_ageB = mfi.m_ageA; ++age; }
+         if ( mfi.m_bEqualAC ) { mfi.m_ageC = mfi.m_ageA; ++age; }
+      }
+      else if  ( n==1 && mfi.m_ageB==eNotThere )
+      {
+         mfi.m_ageB = (e_Age)age; ++age;
+         if ( mfi.m_bEqualAB ) { mfi.m_ageA = mfi.m_ageB; ++age; }
+         if ( mfi.m_bEqualBC ) { mfi.m_ageC = mfi.m_ageB; ++age; }
+      }
+      else if  ( n==2 && mfi.m_ageC==eNotThere)
+      {
+         mfi.m_ageC = (e_Age)age; ++age;
+         if ( mfi.m_bEqualAC ) { mfi.m_ageA = mfi.m_ageC; ++age; }
+         if ( mfi.m_bEqualBC ) { mfi.m_ageB = mfi.m_ageC; ++age; }
+      }
+   }
+
+   // The checks below are necessary when the dates of the file are equal but the
+   // files are not. One wouldn't expect this to happen, yet it happens sometimes.
+   if ( mfi.m_bExistsInC && mfi.m_ageC==eNotThere )
+   {
+      mfi.m_ageC = (e_Age)age; ++age;
+      mfi.m_bConflictingAges = true;
+   }
+   if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
+   {
+      mfi.m_ageB = (e_Age)age; ++age;
+      mfi.m_bConflictingAges = true;
+   }
+   if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
+   {
+      mfi.m_ageA = (e_Age)age; ++age;
+      mfi.m_bConflictingAges = true;
+   }
+
+   if ( mfi.m_ageA != eOld  && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
+   {
+      if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
+      if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
+      if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
+   }
+}
+
+static QPixmap* s_pm_dir;
+static QPixmap* s_pm_file;
+
+static QPixmap* pmNotThere;
+static QPixmap* pmNew;
+static QPixmap* pmOld;
+static QPixmap* pmMiddle;
+
+static QPixmap* pmLink;
+
+static QPixmap* pmDirLink;
+static QPixmap* pmFileLink;
+
+static QPixmap* pmNewLink;
+static QPixmap* pmOldLink;
+static QPixmap* pmMiddleLink;
+
+static QPixmap* pmNewDir;
+static QPixmap* pmMiddleDir;
+static QPixmap* pmOldDir;
+
+static QPixmap* pmNewDirLink;
+static QPixmap* pmMiddleDirLink;
+static QPixmap* pmOldDirLink;
+
+
+static QPixmap colorToPixmap(QColor c)
+{
+   QPixmap pm(16,16);
+   QPainter p(&pm);
+   p.setPen( Qt::black );
+   p.setBrush( c );
+   p.drawRect(0,0,pm.width(),pm.height());
+   return pm;
+}
+
+static void initPixmaps( QColor newest, QColor oldest, QColor middle, QColor notThere )
+{
+   if (pmNew==0)
+   {
+      pmNotThere = new QPixmap;
+      pmNew = new QPixmap;
+      pmOld = new QPixmap;
+      pmMiddle = new QPixmap;
+
+      #include "xpm/link_arrow.xpm"
+      pmLink = new QPixmap(link_arrow);
+
+      pmDirLink = new QPixmap;
+      pmFileLink = new QPixmap;
+
+      pmNewLink = new QPixmap;
+      pmOldLink = new QPixmap;
+      pmMiddleLink = new QPixmap;
+
+      pmNewDir = new QPixmap;
+      pmMiddleDir = new QPixmap;
+      pmOldDir = new QPixmap;
+
+      pmNewDirLink = new QPixmap;
+      pmMiddleDirLink = new QPixmap;
+      pmOldDirLink = new QPixmap;
+   }
+
+
+   *pmNotThere = colorToPixmap(notThere);
+   *pmNew = colorToPixmap(newest);
+   *pmOld = colorToPixmap(oldest);
+   *pmMiddle = colorToPixmap(middle);
+
+   *pmDirLink = pixCombiner( s_pm_dir, pmLink);
+   *pmFileLink = pixCombiner( s_pm_file, pmLink );
+
+   *pmNewLink = pixCombiner( pmNew, pmLink);
+   *pmOldLink = pixCombiner( pmOld, pmLink);
+   *pmMiddleLink = pixCombiner( pmMiddle, pmLink);
+
+   *pmNewDir = pixCombiner2( pmNew, s_pm_dir);
+   *pmMiddleDir = pixCombiner2( pmMiddle, s_pm_dir);
+   *pmOldDir = pixCombiner2( pmOld, s_pm_dir);
+
+   *pmNewDirLink = pixCombiner( pmNewDir, pmLink);
+   *pmMiddleDirLink = pixCombiner( pmMiddleDir, pmLink);
+   *pmOldDirLink = pixCombiner( pmOldDir, pmLink);
+}
+
+
+static void setOnePixmap( QListViewItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir )
+{
+   static QPixmap* ageToPm[]=       { pmNew,     pmMiddle,     pmOld,     pmNotThere, s_pm_file  };
+   static QPixmap* ageToPmLink[]=   { pmNewLink, pmMiddleLink, pmOldLink, pmNotThere, pmFileLink };
+   static QPixmap* ageToPmDir[]=    { pmNewDir,  pmMiddleDir,  pmOldDir,  pmNotThere, s_pm_dir   };
+   static QPixmap* ageToPmDirLink[]={ pmNewDirLink, pmMiddleDirLink, pmOldDirLink, pmNotThere, pmDirLink };
+
+   QPixmap** ppPm = bDir ? ( bLink ? ageToPmDirLink : ageToPmDir ):
+                           ( bLink ? ageToPmLink    : ageToPm    );
+
+   pLVI->setPixmap( col, *ppPm[eAge] );
+}
+
+static void setPixmaps( MergeFileInfos& mfi, bool bCheckC )
+{
+   setOnePixmap( mfi.m_pDMI, s_nameCol, eAgeEnd,
+      mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC,
+      mfi.m_bDirA  || mfi.m_bDirB  || mfi.m_bDirC
+      );
+
+   if ( mfi.m_bDirA  || mfi.m_bDirB  || mfi.m_bDirC )
+   {
+      mfi.m_ageA=eNotThere;
+      mfi.m_ageB=eNotThere;
+      mfi.m_ageC=eNotThere;
+      int age = eNew;
+      if ( mfi.m_bExistsInC )
+      {
+         mfi.m_ageC = (e_Age)age;
+         if (mfi.m_bEqualAC) mfi.m_ageA = (e_Age)age;
+         if (mfi.m_bEqualBC) mfi.m_ageB = (e_Age)age;
+         ++age;
+      }
+      if ( mfi.m_bExistsInB && mfi.m_ageB==eNotThere )
+      {
+         mfi.m_ageB = (e_Age)age;
+         if (mfi.m_bEqualAB) mfi.m_ageA = (e_Age)age;
+         ++age;
+      }
+      if ( mfi.m_bExistsInA && mfi.m_ageA==eNotThere )
+      {
+         mfi.m_ageA = (e_Age)age;
+      }
+      if ( mfi.m_ageA != eOld  && mfi.m_ageB != eOld && mfi.m_ageC != eOld )
+      {
+         if (mfi.m_ageA == eMiddle) mfi.m_ageA = eOld;
+         if (mfi.m_ageB == eMiddle) mfi.m_ageB = eOld;
+         if (mfi.m_ageC == eMiddle) mfi.m_ageC = eOld;
+      }
+   }
+
+   setOnePixmap( mfi.m_pDMI, s_ACol, mfi.m_ageA, mfi.m_bLinkA, mfi.m_bDirA );
+   setOnePixmap( mfi.m_pDMI, s_BCol, mfi.m_ageB, mfi.m_bLinkB, mfi.m_bDirB );
+   if ( bCheckC )
+      setOnePixmap( mfi.m_pDMI, s_CCol, mfi.m_ageC, mfi.m_bLinkC, mfi.m_bDirC );
+}
+
+// Iterate through the complete tree. Start by specifying QListView::firstChild().
+static QListViewItem* treeIterator( QListViewItem* p, bool bVisitChildren=true, bool bFindInvisible=false )
+{
+   if( p!=0 )
+   {
+      do
+      {
+         if ( bVisitChildren && p->firstChild() != 0 )      p = p->firstChild();
+         else if ( p->nextSibling() !=0 ) p = p->nextSibling();
+         else
+         {
+            p = p->parent();
+            while ( p!=0 )
+            {
+               if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
+               else                      { p = p->parent();             }
+            }
+         }
+      }
+      while( p && !(p->isVisible() || bFindInvisible) );
+   }
+   return p;
+}
+
+void DirectoryMergeWindow::prepareListView( ProgressProxy& pp )
+{
+   static bool bFirstTime = true;
+   if (bFirstTime)
+   {
+      #include "xpm/file.xpm"
+      #include "xpm/folder.xpm"
+      s_pm_dir = new QPixmap( m_pIconLoader->loadIcon("folder", KIcon::Small ) );
+      if (s_pm_dir->size()!=QSize(16,16))
+      {
+         delete s_pm_dir;
+         s_pm_dir = new QPixmap( folder_pm );
+      }
+      s_pm_file= new QPixmap( file_pm );
+      bFirstTime=false;
+   }
+
+   clear();
+   initPixmaps( m_pOptions->m_newestFileColor, m_pOptions->m_oldestFileColor,
+                m_pOptions->m_midAgeFileColor, m_pOptions->m_missingFileColor );
+
+   setRootIsDecorated( true );
+
+   bool bCheckC = m_dirC.isValid();
+
+   std::map<QString, MergeFileInfos>::iterator j;
+   int nrOfFiles = m_fileMergeMap.size();
+   int currentIdx = 1;
+   QTime t;
+   t.start();
+   for( j=m_fileMergeMap.begin(); j!=m_fileMergeMap.end(); ++j )
+   {
+      MergeFileInfos& mfi = j->second;
+
+      mfi.m_subPath = mfi.m_fileInfoA.exists() ? mfi.m_fileInfoA.filePath() :
+                      mfi.m_fileInfoB.exists() ? mfi.m_fileInfoB.filePath() :
+                      mfi.m_fileInfoC.exists() ? mfi.m_fileInfoC.filePath() :
+                      QString("");
+
+      // const QString& fileName = j->first;
+      const QString& fileName = mfi.m_subPath;
+
+      pp.setInformation(
+         i18n("Processing ") + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
+         +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
+      if ( pp.wasCancelled() ) break;
+      ++currentIdx;
+
+
+      // The comparisons and calculations for each file take place here.
+      compareFilesAndCalcAges( mfi );
+
+      bool bEqual = bCheckC ? mfi.m_bEqualAB && mfi.m_bEqualAC : mfi.m_bEqualAB;
+      //bool bDir = mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC;
+
+      //if ( m_pOptions->m_bDmShowOnlyDeltas && !bDir && bEqual )
+      //   continue;
+
+      // Get dirname from fileName: Search for "/" from end:
+      int pos = fileName.findRev('/');
+      QString dirPart;
+      QString filePart;
+      if (pos==-1)
+      {
+         // Top dir
+         filePart = fileName;
+      }
+      else
+      {
+         dirPart = fileName.left(pos);
+         filePart = fileName.mid(pos+1);
+      }
+
+      if ( dirPart.isEmpty() ) // Top level
+      {
+         new DirMergeItem( this, filePart, &mfi );
+      }
+      else
+      {
+         MergeFileInfos& dirMfi = m_fileMergeMap[sortString(dirPart, m_bCaseSensitive)]; // parent
+         assert(dirMfi.m_pDMI!=0);
+         new DirMergeItem( dirMfi.m_pDMI, filePart, &mfi );
+         mfi.m_pParent = &dirMfi;
+
+         if ( !bEqual )  // Set all parents to "not equal"
+         {
+            MergeFileInfos* p = mfi.m_pParent;
+            while(p!=0)
+            {
+               bool bChange = false;
+               if ( !mfi.m_bEqualAB && p->m_bEqualAB ){ p->m_bEqualAB = false; bChange=true; }
+               if ( !mfi.m_bEqualAC && p->m_bEqualAC ){ p->m_bEqualAC = false; bChange=true; }
+               if ( !mfi.m_bEqualBC && p->m_bEqualBC ){ p->m_bEqualBC = false; bChange=true; }
+
+               if ( bChange )
+                  setPixmaps( *p, bCheckC );
+               else
+                  break;
+
+               p = p->m_pParent;
+            }
+         }
+      }
+
+      setPixmaps( mfi, bCheckC );
+   }
+
+   /*if ( m_pOptions->m_bDmShowOnlyDeltas )
+   {
+      // Remove all equals. (Search tree depth first)
+      QListViewItem* p = firstChild();
+      while( p!=0 && firstChild() != 0 )
+      {
+         QListViewItem* pParent = p->parent();
+         QListViewItem* pNextSibling = p->nextSibling();
+
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+         bool bDirEqual = bCheckC ? pDMI->m_pMFI->m_bEqualAB && pDMI->m_pMFI->m_bEqualAC
+                                  : pDMI->m_pMFI->m_bEqualAB;
+         if ( pDMI!=0  && pDMI->m_pMFI->m_bDirA && bDirEqual )
+         {
+            delete p;
+            p=0;
+         }
+
+         if ( p!=0 && p->firstChild() != 0 )    p = p->firstChild();
+         else if ( pNextSibling!=0 )            p = pNextSibling;
+         else
+         {
+            p=pParent;
+            while ( p!=0 )
+            {
+               if( p->nextSibling()!=0 ) { p = p->nextSibling(); break; }
+               else                      { p = p->parent();             }
+            }
+         }
+      }
+   }*/
+}
+
+static bool conflictingFileTypes(MergeFileInfos& mfi)
+{
+   // Now check if file/dir-types fit.
+   if ( mfi.m_bLinkA || mfi.m_bLinkB || mfi.m_bLinkC )
+   {
+      if ( mfi.m_bExistsInA && ! mfi.m_bLinkA  ||
+           mfi.m_bExistsInB && ! mfi.m_bLinkB  ||
+           mfi.m_bExistsInC && ! mfi.m_bLinkC )
+      {
+         return true;
+      }
+   }
+
+   if ( mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC )
+   {
+      if ( mfi.m_bExistsInA && ! mfi.m_bDirA  ||
+           mfi.m_bExistsInB && ! mfi.m_bDirB  ||
+           mfi.m_bExistsInC && ! mfi.m_bDirC )
+      {
+         return true;
+      }
+   }
+   return false;
+}
+
+void DirectoryMergeWindow::calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultMergeOp )
+{
+   bool bCheckC = m_dirC.isValid();
+   bool bCopyNewer = m_pOptions->m_bDmCopyNewer;
+   bool bOtherDest = !( m_dirDestInternal.absFilePath() == m_dirA.absFilePath() ||
+                        m_dirDestInternal.absFilePath() == m_dirB.absFilePath() ||
+                        bCheckC && m_dirDestInternal.absFilePath() == m_dirC.absFilePath() );
+
+   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 )
+         {
+            mfi.setMergeOperation( bOtherDest ? eCopyBToDest : eNoOperation );
+         }
+         else if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
+         {
+            if ( !bCopyNewer || mfi.m_bDirA )
+               mfi.setMergeOperation( eDefaultMergeOp );
+            else if (  bCopyNewer && mfi.m_bConflictingAges )
+            {
+               mfi.setMergeOperation( eConflictingAges );
+            }
+            else
+            {
+               if ( mfi.m_ageA == eNew )
+                  mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ?  eCopyAToB : eCopyAToDest );
+               else
+                  mfi.setMergeOperation( eDefaultMergeOp == eMergeToAB ?  eCopyBToA : eCopyBToDest );
+            }
+         }
+         else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB )
+         {
+            if ( eDefaultMergeOp==eMergeABToDest  ) mfi.setMergeOperation( eCopyBToDest );
+            else if ( eDefaultMergeOp==eMergeToB )  mfi.setMergeOperation( eNoOperation );
+            else                                    mfi.setMergeOperation( eCopyBToA );
+         }
+         else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB )
+         {
+            if ( eDefaultMergeOp==eMergeABToDest  ) mfi.setMergeOperation( eCopyAToDest );
+            else if ( eDefaultMergeOp==eMergeToA )  mfi.setMergeOperation( eNoOperation );
+            else                                    mfi.setMergeOperation( eCopyAToB );
+         }
+         else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB )
+         {
+            mfi.setMergeOperation( eNoOperation ); assert(false);
+         }
+      }
+      else
+      {
+         if ( mfi.m_bEqualAB && mfi.m_bEqualAC )
+         {
+            mfi.setMergeOperation( bOtherDest ? eCopyCToDest : eNoOperation );
+         }
+         else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC)
+         {
+            if ( mfi.m_bEqualAB )
+               mfi.setMergeOperation( eCopyCToDest );
+            else if ( mfi.m_bEqualAC )
+               mfi.setMergeOperation( eCopyBToDest );
+            else if ( mfi.m_bEqualBC )
+               mfi.setMergeOperation( eCopyCToDest );
+            else
+               mfi.setMergeOperation( eMergeABCToDest );
+         }
+         else if ( mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
+         {
+            if ( mfi.m_bEqualAB )
+               mfi.setMergeOperation( eDeleteFromDest );
+            else
+               mfi.setMergeOperation( eCopyBToDest );
+         }
+         else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
+         {
+            if ( mfi.m_bEqualAC )
+               mfi.setMergeOperation( eDeleteFromDest );
+            else
+               mfi.setMergeOperation( eCopyCToDest );
+         }
+         else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && mfi.m_bExistsInC )
+         {
+            if ( mfi.m_bEqualBC )
+               mfi.setMergeOperation( eCopyCToDest );
+            else
+               mfi.setMergeOperation( eMergeABCToDest );
+         }
+         else if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && mfi.m_bExistsInC )
+         {
+            mfi.setMergeOperation( eCopyCToDest );
+         }
+         else if ( !mfi.m_bExistsInA && mfi.m_bExistsInB && !mfi.m_bExistsInC )
+         {
+            mfi.setMergeOperation( eCopyBToDest );
+         }
+         else if ( mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC)
+         {
+            mfi.setMergeOperation( eDeleteFromDest );
+         }
+         else //if ( !mfi.m_bExistsInA && !mfi.m_bExistsInB && !mfi.m_bExistsInC )
+         {
+            mfi.setMergeOperation( eNoOperation ); assert(false);
+         }
+      }
+
+      // Now check if file/dir-types fit.
+      if ( conflictingFileTypes(mfi) )
+      {
+         mfi.setMergeOperation( eConflictingFileTypes );
+      }
+   }
+   else
+   {
+      e_MergeOperation eMO = eDefaultMergeOp;
+      switch ( eDefaultMergeOp )
+      {
+      case eConflictingFileTypes:
+      case eConflictingAges:
+      case eDeleteA:
+      case eDeleteB:
+      case eDeleteAB:
+      case eDeleteFromDest:
+      case eNoOperation: break;
+      case eCopyAToB:    if ( !mfi.m_bExistsInA ) { eMO = eDeleteB; }        break;
+      case eCopyBToA:    if ( !mfi.m_bExistsInB ) { eMO = eDeleteA; }        break;
+      case eCopyAToDest: if ( !mfi.m_bExistsInA ) { eMO = eDeleteFromDest; } break;
+      case eCopyBToDest: if ( !mfi.m_bExistsInB ) { eMO = eDeleteFromDest; } break;
+      case eCopyCToDest: if ( !mfi.m_bExistsInC ) { eMO = eDeleteFromDest; } break;
+
+      case eMergeToA:
+      case eMergeToB:
+      case eMergeToAB:
+      case eMergeABCToDest:
+      case eMergeABToDest:
+      default:
+         assert(false);
+      }
+      mfi.setMergeOperation( eMO );
+   }
+}
+
+void DirectoryMergeWindow::onDoubleClick( QListViewItem* lvi )
+{
+   if (lvi==0) return;
+
+   if ( m_bDirectoryMerge )
+      mergeCurrentFile();
+   else
+      compareCurrentFile();
+}
+
+void DirectoryMergeWindow::onSelectionChanged( QListViewItem* lvi )
+{
+   if ( lvi==0 ) return;
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
+
+   MergeFileInfos& mfi = *pDMI->m_pMFI;
+   assert( mfi.m_pDMI==pDMI );
+
+   m_pDirectoryMergeInfo->setInfo( m_dirA, m_dirB, m_dirC, m_dirDestInternal, mfi );
+}
+
+void DirectoryMergeWindow::onClick( int button, QListViewItem* lvi, const QPoint& p, int c )
+{
+   if ( lvi==0 ) return;
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
+
+   MergeFileInfos& mfi = *pDMI->m_pMFI;
+   assert( mfi.m_pDMI==pDMI );
+
+   if ( c==s_OpCol )
+   {
+      bool bThreeDirs = m_dirC.isValid();
+
+      KPopupMenu m(this);
+      if ( bThreeDirs )
+      {
+         m_pDirCurrentDoNothing->plug(&m);
+         int count=0;
+         if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); ++count;  }
+         if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); ++count;  }
+         if ( mfi.m_bExistsInC ) { m_pDirCurrentChooseC->plug(&m); ++count;  }
+         if ( !conflictingFileTypes(mfi) && count>1 ) m_pDirCurrentMerge->plug(&m);
+         m_pDirCurrentDelete->plug(&m);
+      }
+      else if ( m_bSyncMode )
+      {
+         m_pDirCurrentSyncDoNothing->plug(&m);
+         if ( mfi.m_bExistsInA ) m_pDirCurrentSyncCopyAToB->plug(&m);
+         if ( mfi.m_bExistsInB ) m_pDirCurrentSyncCopyBToA->plug(&m);
+         if ( mfi.m_bExistsInA ) m_pDirCurrentSyncDeleteA->plug(&m);
+         if ( mfi.m_bExistsInB ) m_pDirCurrentSyncDeleteB->plug(&m);
+         if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
+         {
+            m_pDirCurrentSyncDeleteAAndB->plug(&m);
+            if ( !conflictingFileTypes(mfi))
+            {
+               m_pDirCurrentSyncMergeToA->plug(&m);
+               m_pDirCurrentSyncMergeToB->plug(&m);
+               m_pDirCurrentSyncMergeToAAndB->plug(&m);
+            }
+         }
+      }
+      else
+      {
+         m_pDirCurrentDoNothing->plug(&m);
+         if ( mfi.m_bExistsInA ) { m_pDirCurrentChooseA->plug(&m); }
+         if ( mfi.m_bExistsInB ) { m_pDirCurrentChooseB->plug(&m); }
+         if ( !conflictingFileTypes(mfi) && mfi.m_bExistsInA  &&  mfi.m_bExistsInB ) m_pDirCurrentMerge->plug(&m);
+         m_pDirCurrentDelete->plug(&m);
+      }
+
+      m.exec( p );
+   }
+   else if ( c == s_ACol || c==s_BCol || c==s_CCol )
+   {
+      QString itemPath;
+      if      ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); }
+      else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); }
+      else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); }
+
+      if (!itemPath.isEmpty())
+      {
+         selectItemAndColumn( pDMI, c, button==Qt::RightButton );
+      }
+   }
+}
+
+void DirectoryMergeWindow::slotShowContextMenu(QListViewItem* lvi,const QPoint & p,int c)
+{
+   if ( lvi==0 ) return;
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(lvi);
+
+   MergeFileInfos& mfi = *pDMI->m_pMFI;
+   assert( mfi.m_pDMI==pDMI );
+   if ( c == s_ACol || c==s_BCol || c==s_CCol )
+   {
+      QString itemPath;
+      if      ( c == s_ACol && mfi.m_bExistsInA ){ itemPath = fullNameA(mfi); }
+      else if ( c == s_BCol && mfi.m_bExistsInB ){ itemPath = fullNameB(mfi); }
+      else if ( c == s_CCol && mfi.m_bExistsInC ){ itemPath = fullNameC(mfi); }
+
+      if (!itemPath.isEmpty())
+      {
+         selectItemAndColumn(pDMI, c, true);
+         KPopupMenu m(this);
+         m_pDirCompareExplicit->plug(&m);
+         m_pDirMergeExplicit->plug(&m);
+
+#ifndef _WIN32
+         m.exec( p );
+#else
+         void showShellContextMenu( const QString&, QPoint, QWidget*, QPopupMenu* );
+         showShellContextMenu( itemPath, p, this, &m );
+#endif
+      }
+   }
+}
+
+static QString getFileName( DirMergeItem* pDMI, int column )
+{
+   if ( pDMI != 0 )
+   {
+      MergeFileInfos& mfi = *pDMI->m_pMFI;
+      return column == s_ACol ? mfi.m_fileInfoA.absFilePath() :
+             column == s_BCol ? mfi.m_fileInfoB.absFilePath() :
+             column == s_CCol ? mfi.m_fileInfoC.absFilePath() :
+             QString("");
+   }
+   return "";
+}
+
+static bool isDir( DirMergeItem* pDMI, int column )
+{
+   if ( pDMI != 0 )
+   {
+      MergeFileInfos& mfi = *pDMI->m_pMFI;
+      return column == s_ACol ? mfi.m_bDirA :
+             column == s_BCol ? mfi.m_bDirB :
+                                mfi.m_bDirC;
+   }
+   return false;
+}
+
+
+void DirectoryMergeWindow::selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu)
+{
+   if ( bContextMenu && (
+        pDMI==m_pSelection1Item && c==m_selection1Column && m_pSelection2Item==0 ||
+        pDMI==m_pSelection2Item && c==m_selection2Column && m_pSelection3Item==0 ||
+        pDMI==m_pSelection3Item && c==m_selection3Column ) )
+      return;
+
+   DirMergeItem* pOld1=m_pSelection1Item;
+   DirMergeItem* pOld2=m_pSelection2Item;
+   DirMergeItem* pOld3=m_pSelection3Item;
+
+   bool bReset = false;
+
+   if ( m_pSelection1Item )
+   {
+      if (isDir( m_pSelection1Item, m_selection1Column )!=isDir( pDMI, c ))
+         bReset = true;
+   }
+
+   if ( bReset || m_pSelection3Item!=0 ||
+        pDMI==m_pSelection1Item && c==m_selection1Column ||
+        pDMI==m_pSelection2Item && c==m_selection2Column ||
+        pDMI==m_pSelection3Item && c==m_selection3Column)
+   {
+      m_pSelection1Item = 0;
+      m_pSelection2Item = 0;
+      m_pSelection3Item = 0;
+   }
+   else if ( m_pSelection1Item==0 )
+   {
+      m_pSelection1Item = pDMI;
+      m_selection1Column = c;
+      m_pSelection2Item = 0;
+      m_pSelection3Item = 0;
+   }
+   else if ( m_pSelection2Item==0 )
+   {
+      m_pSelection2Item = pDMI;
+      m_selection2Column = c;
+      m_pSelection3Item = 0;
+   }
+   else if ( m_pSelection3Item==0 )
+   {
+      m_pSelection3Item = pDMI;
+      m_selection3Column = c;
+   }
+   if (pOld1) repaintItem( pOld1 );
+   if (pOld2) repaintItem( pOld2 );
+   if (pOld3) repaintItem( pOld3 );
+   if (m_pSelection1Item) repaintItem( m_pSelection1Item );
+   if (m_pSelection2Item) repaintItem( m_pSelection2Item );
+   if (m_pSelection3Item) repaintItem( m_pSelection3Item );
+   emit updateAvailabilities();
+}
+
+// Since Qt 2.3.0 doesn't allow the specification of a compare operator, this trick emulates it.
+#if QT_VERSION==230
+#define DIRSORT(x) ( pMFI->m_bDirA ? " " : "" )+x
+#else
+#define DIRSORT(x) x
+#endif
+
+DirMergeItem::DirMergeItem( QListView* pParent, const QString& fileName, MergeFileInfos* pMFI )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do."), "" )
+{
+   init(pMFI);
+}
+
+DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", i18n("To do."), "" )
+{
+   init(pMFI);
+}
+
+
+void DirMergeItem::init(MergeFileInfos* pMFI)
+{
+   pMFI->m_pDMI = this;
+   m_pMFI = pMFI;
+   TotalDiffStatus& tds = pMFI->m_totalDiffStatus;
+   if ( m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC )
+   {
+   }
+   else
+   {
+      setText( s_UnsolvedCol, QString::number( tds.nofUnsolvedConflicts ) );
+      setText( s_SolvedCol,   QString::number( tds.nofSolvedConflicts ) );
+      setText( s_NonWhiteCol, QString::number( tds.nofUnsolvedConflicts + tds.nofSolvedConflicts - tds.nofWhitespaceConflicts ) );
+      setText( s_WhiteCol,    QString::number( tds.nofWhitespaceConflicts ) );
+   }
+}
+
+int DirMergeItem::compare(QListViewItem *i, int col, bool ascending) const
+{
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>(i);
+   bool bDir1 =  m_pMFI->m_bDirA || m_pMFI->m_bDirB || m_pMFI->m_bDirC;
+   bool bDir2 =  pDMI->m_pMFI->m_bDirA || pDMI->m_pMFI->m_bDirB || pDMI->m_pMFI->m_bDirC;
+   if ( m_pMFI==0 || pDMI->m_pMFI==0 || bDir1 == bDir2 )
+   {
+      if(col==s_UnsolvedCol || col==s_SolvedCol || col==s_NonWhiteCol || col==s_WhiteCol)
+         return key(col,ascending).toInt() > i->key(col,ascending).toInt() ? -1 : 1;
+      else
+         return QListViewItem::compare( i, col, ascending );
+   }
+   else
+      return bDir1 ? -1 : 1;
+}
+
+void DirMergeItem::paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align )
+{
+   if (column == s_ACol || column == s_BCol || column == s_CCol )
+   {
+      const QPixmap* icon = pixmap(column);
+      if ( icon )
+      {
+         int yOffset = (height() - icon->height()) / 2;
+         p->fillRect( 0, 0, width, height(), cg.base() );
+         p->drawPixmap( 2, yOffset, *icon );
+         if ( listView() )
+         {
+            DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>(listView());
+            int i = this==pDMW->m_pSelection1Item && column == pDMW->m_selection1Column ? 1 :
+                    this==pDMW->m_pSelection2Item && column == pDMW->m_selection2Column ? 2 :
+                    this==pDMW->m_pSelection3Item && column == pDMW->m_selection3Column ? 3 :
+                    0;
+            if ( i!=0 )
+            {
+               OptionDialog* pOD = pDMW->m_pOptions;
+               QColor c ( i==1 ? pOD->m_colorA : i==2 ? pOD->m_colorB : pOD->m_colorC );
+               p->setPen( c );// highlight() );
+               p->drawRect( 2, yOffset, icon->width(), icon->height());
+               p->setPen( QPen( c, 0, Qt::DotLine) );
+               p->drawRect( 1, yOffset-1, icon->width()+2, icon->height()+2);
+               p->setPen( cg.background() );
+               QString s( QChar('A'+i-1) );
+               p->drawText( 2 + (icon->width() - p->fontMetrics().width(s))/2,
+                            yOffset + (icon->height() + p->fontMetrics().ascent())/2-1,
+                            s );
+            }
+            else
+            {
+               p->setPen( cg.background() );
+               p->drawRect( 1, yOffset-1, icon->width()+2, icon->height()+2);
+            }
+         }
+         return;
+      }
+   }
+   QListViewItem::paintCell(p,cg,column,width,align);
+}
+
+DirMergeItem::~DirMergeItem()
+{
+   m_pMFI->m_pDMI = 0;
+}
+
+void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp )
+{
+   if ( eMOp != m_eMergeOperation )
+   {
+      m_bOperationComplete = false;
+      m_pDMI->setText( s_OpStatusCol, "" );
+   }
+
+   m_eMergeOperation = eMOp;
+   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=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=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);
+
+      e_MergeOperation eChildrenMergeOp = m_eMergeOperation;
+      if ( eChildrenMergeOp == eConflictingFileTypes ) eChildrenMergeOp = eMergeABCToDest;
+      QListViewItem* p = m_pDMI->firstChild();
+      while ( p!=0 )
+      {
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
+         DirectoryMergeWindow* pDMW = static_cast<DirectoryMergeWindow*>( p->listView() );
+         pDMW->calcSuggestedOperation( *pDMI->m_pMFI, eChildrenMergeOp );
+         p = p->nextSibling();
+      }
+   }
+}
+
+void DirectoryMergeWindow::compareCurrentFile()
+{
+   if (!canContinue()) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
+      return;
+   }
+
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
+   if ( pDMI != 0 )
+   {
+      MergeFileInfos& mfi = *pDMI->m_pMFI;
+      if ( !(mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC) )
+      {
+         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(""),
+            "",
+            "","","",0
+            );
+      }
+   }
+   emit updateAvailabilities();
+}
+
+
+void DirectoryMergeWindow::slotCompareExplicitlySelectedFiles()
+{
+   if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
+      return;
+   }
+
+   emit startDiffMerge(
+      getFileName( m_pSelection1Item, m_selection1Column ),
+      getFileName( m_pSelection2Item, m_selection2Column ),
+      getFileName( m_pSelection3Item, m_selection3Column ),
+      "",
+      "","","",0
+      );
+   m_pSelection1Item=0;
+   m_pSelection2Item=0;
+   m_pSelection3Item=0;
+
+   emit updateAvailabilities();
+   triggerUpdate();
+}
+
+void DirectoryMergeWindow::slotMergeExplicitlySelectedFiles()
+{
+   if ( ! isDir(m_pSelection1Item,m_selection1Column) && !canContinue() ) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,i18n("This operation is currently not possible."),i18n("Operation Not Possible"));
+      return;
+   }
+
+   QString fn1 = getFileName( m_pSelection1Item, m_selection1Column );
+   QString fn2 = getFileName( m_pSelection2Item, m_selection2Column );
+   QString fn3 = getFileName( m_pSelection3Item, m_selection3Column );
+
+   emit startDiffMerge( fn1, fn2, fn3, 
+      fn3.isEmpty() ? fn2 : fn3,
+      "","","",0
+      );
+   m_pSelection1Item=0;
+   m_pSelection2Item=0;
+   m_pSelection3Item=0;
+
+   emit updateAvailabilities();
+   triggerUpdate();
+}
+
+bool DirectoryMergeWindow::isFileSelected()
+{
+   DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
+   if ( pDMI != 0 )
+   {
+      MergeFileInfos& mfi = *pDMI->m_pMFI;
+      return ! (mfi.m_bDirA || mfi.m_bDirB || mfi.m_bDirC || conflictingFileTypes(mfi) );
+   }
+   return false;
+}
+
+void DirectoryMergeWindow::mergeResultSaved(const QString& fileName)
+{
+   DirMergeItem* pCurrentItemForOperation = (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() )
+                                               ? 0
+                                               : *m_currentItemForOperation;
+
+   if ( pCurrentItemForOperation!=0 && pCurrentItemForOperation->m_pMFI==0 )
+   {
+      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 ( pCurrentItemForOperation!=0 && fileName == fullNameDest(*pCurrentItemForOperation->m_pMFI) )
+   {
+      if ( pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
+      {
+         MergeFileInfos& mfi = *pCurrentItemForOperation->m_pMFI;
+         bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
+         if (!bSuccess)
+         {
+            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;
+            pCurrentItemForOperation->setText( s_OpStatusCol, i18n("Error.") );
+            mfi.m_eMergeOperation = eCopyBToA;
+            return;
+         }
+      }
+      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();
+}
+
+bool DirectoryMergeWindow::canContinue()
+{
+   bool bCanContinue=false;
+   checkIfCanContinue( &bCanContinue );
+   if ( bCanContinue && !m_bError )
+   {
+      DirMergeItem* pCurrentItemForOperation =
+         (m_mergeItemList.empty() || m_currentItemForOperation==m_mergeItemList.end() ) ? 0 : *m_currentItemForOperation;
+
+      if ( pCurrentItemForOperation!=0  && ! pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+      {
+         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;
+}
+
+bool DirectoryMergeWindow::executeMergeOperation( MergeFileInfos& mfi, bool& bSingleFileMerge )
+{
+   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);
+   }
+
+   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);
+   }
+
+   return bSuccess;
+}
+
+
+// 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 )
+   {
+      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 && ! pDMI->m_pMFI->m_bOperationComplete )
+      {
+         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."), 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."), i18n("Error"));
+            m_mergeItemList.clear();
+            m_bRealMergeStarted=false;
+            return;
+         }
+      }
+   }
+
+   m_currentItemForOperation = m_mergeItemList.begin();
+   return;
+}
+
+void DirectoryMergeWindow::slotRunOperationForCurrentItem()
+{
+   if ( ! canContinue() ) return;
+
+   bool bVerbose = false;
+   if ( m_mergeItemList.empty() )
+   {
+      QListViewItem* pBegin = currentItem();
+      QListViewItem* pEnd = treeIterator(pBegin,false,false); // find next visible sibling (no children)
+
+      prepareMergeStart( pBegin, pEnd, 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 directory merge is currently running."),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)
+{
+   ProgressProxy pp;
+   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 = *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 ( !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("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;
+   }
+
+   bool bSuccess = true;
+   bool bSingleFileMerge = false;
+   bool bSim = m_bSimulatedMergeStarted;
+   while( bSuccess )
+   {
+      if ( pCurrentItemForOperation==0 )
+      {
+         m_mergeItemList.clear();
+         m_bRealMergeStarted=false;
+         break;
+      }
+
+      if ( pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
+      {
+         if ( bSim )
+         {
+            if( pCurrentItemForOperation->firstChild()==0 )
+            {
+               pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
+            }
+         }
+         else
+         {
+            if( pCurrentItemForOperation->firstChild()==0 )
+            {
+               if( !pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+               {
+                  pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? i18n("Skipped.") : i18n("Done.") );
+                  pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+                  bSkipItem = false;
+               }
+            }
+            else
+            {
+               pCurrentItemForOperation->setText( s_OpStatusCol, i18n("In progress...") );
+            }
+         }
+      }
+
+      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 )
+         {
+            // Check if the parent may be set to "Done"
+            QListViewItem* pParent = pPrevItem->parent();
+            bool bDone = true;
+            while ( bDone && pParent!=0 )
+            {
+               for( QListViewItem* p = pParent->firstChild(); p!=0; p=p->nextSibling() )
+               {
+                  DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+                  if ( !bSim && ! pDMI->m_pMFI->m_bOperationComplete   ||  bSim && pDMI->m_pMFI->m_bSimOpComplete )
+                  {
+                     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();
+            }
+         }
+      }
+
+      if ( pCurrentItemForOperation == 0 ) // end?
+      {
+         if ( m_bRealMergeStarted )
+         {
+            if (bVerbose)
+            {
+               KMessageBox::information( this, i18n("Merge operation complete."), i18n("Merge Complete") );
+            }
+            m_bRealMergeStarted = false;
+            m_pStatusInfo->setCaption(i18n("Merge Complete"));
+         }
+         if ( m_bSimulatedMergeStarted )
+         {
+            m_bSimulatedMergeStarted = false;
+            for( QListViewItem* p=firstChild(); p!=0; p=treeIterator(p) )
+            {
+               static_cast<DirMergeItem*>(p)->m_pMFI->m_bSimOpComplete = false;
+            }
+            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 = *pCurrentItemForOperation->m_pMFI;
+
+      pp.setInformation( mfi.m_subPath,
+         bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
+         false // bRedrawUpdate
+         );
+      //g_pProgressDialog->show();
+
+      bSuccess = executeMergeOperation( mfi, bSingleFileMerge );  // Here the real operation happens.
+
+      if ( bSuccess )
+      {
+         if(bSim) ++nrOfCompletedSimItems;
+         else     ++nrOfCompletedItems;
+         bContinueWithCurrentItem = false;
+      }
+
+      if( pp.wasCancelled() )
+         break;
+   }  // end while
+
+   //g_pProgressDialog->hide();
+
+   setCurrentItem( pCurrentItemForOperation );
+   ensureItemVisible( pCurrentItemForOperation );
+   if ( !bSuccess &&  !bSingleFileMerge )
+   {
+      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;
+      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 )
+{
+   m_bAllowResizeEvents = bAllowResizeEvents;
+}
+
+void DirectoryMergeWindow::resizeEvent( QResizeEvent* e )
+{
+   if (m_bAllowResizeEvents)
+      QListView::resizeEvent(e);
+}
+
+bool DirectoryMergeWindow::deleteFLD( const QString& name, bool bCreateBackup )
+{
+   FileAccess fi(name, true);
+   if ( !fi.exists() )
+      return true;
+
+   if ( bCreateBackup )
+   {
+      bool bSuccess = renameFLD( name, name+".orig" );
+      if (!bSuccess)
+      {
+         m_pStatusInfo->addText( i18n("Error: While deleting %1: Creating backup failed.").arg(name) );
+         return false;
+      }
+   }
+   else
+   {
+      if ( fi.isDir() && !fi.isSymLink() )
+         m_pStatusInfo->addText(i18n("delete directory recursively( %1 )").arg(name));
+      else
+         m_pStatusInfo->addText(i18n("delete( %1 )").arg(name));
+
+      if ( m_bSimulatedMergeStarted )
+      {
+         return true;
+      }
+
+      if ( fi.isDir() && !fi.isSymLink() )// recursive directory delete only for real dirs, not symlinks
+      {
+         t_DirectoryList dirList;
+         bool bSuccess = fi.listDir( &dirList, false, true, "*", "", "", false, false );  // not recursive, find hidden files
+
+         if ( !bSuccess )
+         {
+             // No Permission to read directory or other error.
+             m_pStatusInfo->addText( i18n("Error: delete dir operation failed while trying to read the directory.") );
+             return false;
+         }
+
+         t_DirectoryList::iterator it;      // create list iterator
+
+         for ( it=dirList.begin(); it!=dirList.end(); ++it )       // for each file...
+         {
+            FileAccess& fi2 = *it;
+            if ( fi2.fileName() == "." ||  fi2.fileName()==".." )
+               continue;
+            bSuccess = deleteFLD( fi2.absFilePath(), false );
+            if (!bSuccess) break;
+         }
+         if (bSuccess)
+         {
+            bSuccess = FileAccess::removeDir( name );
+            if ( !bSuccess )
+            {
+               m_pStatusInfo->addText( i18n("Error: rmdir( %1 ) operation failed.").arg(name));
+               return false;
+            }
+         }
+      }
+      else
+      {
+         bool bSuccess = FileAccess::removeFile( name );
+         if ( !bSuccess )
+         {
+            m_pStatusInfo->addText( i18n("Error: delete operation failed.") );
+            return false;
+         }
+      }
+   }
+   return true;
+}
+
+bool DirectoryMergeWindow::mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,const QString& nameDest, bool& bSingleFileMerge )
+{
+   FileAccess fi(nameA);
+   if (fi.isDir())
+   {
+      return makeDir(nameDest);
+   }
+
+   // Make sure that the dir exists, into which we will save the file later.
+   int pos=nameDest.findRev('/');
+   if ( pos>0 )
+   {
+      QString parentName = nameDest.left(pos);
+      bool bSuccess = makeDir(parentName, true /*quiet*/);
+      if (!bSuccess)
+         return false;
+   }
+
+   m_pStatusInfo->addText(i18n("manual merge( %1, %2, %3 -> %4)").arg(nameA).arg(nameB).arg(nameC).arg(nameDest));
+   if ( m_bSimulatedMergeStarted )
+   {
+      m_pStatusInfo->addText(i18n("     Note: After a manual merge the user should continue by pressing F7.") );
+      return true;
+   }
+
+   bSingleFileMerge = true;
+   (*m_currentItemForOperation)->setText( s_OpStatusCol, i18n("In progress...") );
+   ensureItemVisible( *m_currentItemForOperation );
+
+   emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","",0 );
+
+   return false;
+}
+
+bool DirectoryMergeWindow::copyFLD( const QString& srcName, const QString& destName )
+{
+   if ( srcName == destName )
+      return true;
+
+   if ( FileAccess(destName, true).exists() )
+   {
+      bool bSuccess = deleteFLD( destName, m_pOptions->m_bDmCreateBakFiles );
+      if ( !bSuccess )
+      {
+         m_pStatusInfo->addText(i18n("Error: copy( %1 -> %2 ) failed."
+            "Deleting existing destination failed.").arg(srcName).arg(destName));
+         return false;
+      }
+   }
+
+   FileAccess fi( srcName );
+
+   if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks  ||  !fi.isDir() && !m_bFollowFileLinks) )
+   {
+      m_pStatusInfo->addText(i18n("copyLink( %1 -> %2 )").arg(srcName).arg(destName));
+#ifdef _WIN32
+      // What are links?
+#else
+      if ( m_bSimulatedMergeStarted )
+      {
+         return true;
+      }
+      FileAccess destFi(destName);
+      if ( !destFi.isLocal() || !fi.isLocal() )
+      {
+         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(i18n("Error: copyLink failed."));
+      return bSuccess;
+#endif
+   }
+
+   if ( fi.isDir() )
+   {
+      bool bSuccess = makeDir( destName );
+      return bSuccess;
+   }
+
+   int pos=destName.findRev('/');
+   if ( pos>0 )
+   {
+      QString parentName = destName.left(pos);
+      bool bSuccess = makeDir(parentName, true /*quiet*/);
+      if (!bSuccess)
+         return false;
+   }
+
+   m_pStatusInfo->addText(i18n("copy( %1 -> %2 )").arg(srcName).arg(destName));
+
+   if ( m_bSimulatedMergeStarted )
+   {
+      return true;
+   }
+
+   FileAccess faSrc ( srcName );
+   bool bSuccess = faSrc.copyFile( destName );
+   if (! bSuccess ) m_pStatusInfo->addText( faSrc.getStatusText() );
+   return bSuccess;
+}
+
+// Rename is not an operation that can be selected by the user.
+// It will only be used to create backups.
+// Hence it will delete an existing destination without making a backup (of the old backup.)
+bool DirectoryMergeWindow::renameFLD( const QString& srcName, const QString& destName )
+{
+   if ( srcName == destName )
+      return true;
+
+   if ( FileAccess(destName, true).exists() )
+   {
+      bool bSuccess = deleteFLD( destName, false /*no backup*/ );
+      if (!bSuccess)
+      {
+         m_pStatusInfo->addText( i18n("Error during rename( %1 -> %2 ): "
+                             "Cannot delete existing destination." ).arg(srcName).arg(destName));
+         return false;
+      }
+   }
+
+   m_pStatusInfo->addText(i18n("rename( %1 -> %2 )").arg(srcName).arg(destName));
+   if ( m_bSimulatedMergeStarted )
+   {
+      return true;
+   }
+
+   bool bSuccess = FileAccess( srcName ).rename( destName );
+   if (!bSuccess)
+   {
+      m_pStatusInfo->addText( i18n("Error: Rename failed.") );
+      return false;
+   }
+
+   return true;
+}
+
+bool DirectoryMergeWindow::makeDir( const QString& name, bool bQuiet )
+{
+   FileAccess fi(name, true);
+   if( fi.exists() && fi.isDir() )
+      return true;
+
+   if( fi.exists() && !fi.isDir() )
+   {
+      bool bSuccess = deleteFLD( name, true );
+      if (!bSuccess)
+      {
+         m_pStatusInfo->addText( i18n("Error during makeDir of %1. "
+                             "Cannot delete existing file." ).arg(name));
+         return false;
+      }
+   }
+
+   int pos=name.findRev('/');
+   if ( pos>0 )
+   {
+      QString parentName = name.left(pos);
+      bool bSuccess = makeDir(parentName,true);
+      if (!bSuccess)
+         return false;
+   }
+
+   if ( ! bQuiet )
+      m_pStatusInfo->addText(i18n("makeDir( %1 )").arg(name));
+
+   if ( m_bSimulatedMergeStarted )
+   {
+      return true;
+   }
+
+   bool bSuccess = FileAccess::makeDir( name );
+   if ( bSuccess == false )
+   {
+      m_pStatusInfo->addText( i18n("Error while creating directory.") );
+      return false;
+   }
+   return true;
+}
+
+
+DirectoryMergeInfo::DirectoryMergeInfo( QWidget* pParent )
+: QFrame(pParent)
+{
+   QVBoxLayout *topLayout = new QVBoxLayout( this );
+
+   QGridLayout *grid = new QGridLayout( topLayout );
+   grid->setColStretch(1,10);
+
+   int line=0;
+
+   m_pA = new QLabel("A",this);        grid->addWidget( m_pA,line, 0 );
+   m_pInfoA = new QLabel(this);        grid->addWidget( m_pInfoA,line,1 ); ++line;
+   m_pB = new QLabel("B",this);        grid->addWidget( m_pB,line, 0 );
+   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(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(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 );
+
+   m_pInfoList->installEventFilter(this);
+}
+
+bool DirectoryMergeInfo::eventFilter(QObject*o, QEvent* e)
+{
+   if ( e->type()==QEvent::FocusIn && o==m_pInfoList )
+      emit gotFocus();
+   return false;
+}
+
+static void addListViewItem( QListView* pListView, const QString& dir,
+   const QString& basePath, FileAccess& fi )
+{
+   if ( basePath.isEmpty() )
+   {
+      return;
+   }
+   else
+   {
+      if ( fi.exists() )
+      {
+#if QT_VERSION==230
+         QString dateString = fi.lastModified().toString();
+#else
+         QString dateString = fi.lastModified().toString("yyyy-MM-dd hh:mm:ss");
+#endif
+
+         new QListViewItem(
+            pListView,
+            dir,
+            QString( fi.isDir() ? i18n("Dir") : i18n("File") ) + (fi.isSymLink() ? "-Link" : ""),
+            QString::number(fi.size()),
+            QString(fi.isReadable() ? "r" : " ") + (fi.isWritable()?"w" : " ")
+#ifdef _WIN32
+            /*Future: Use GetFileAttributes()*/,
+#else
+            + (fi.isExecutable()?"x" : " "),
+#endif
+            dateString,
+            QString(fi.isSymLink() ? (" -> " + fi.readLink()) : QString(""))
+            );
+      }
+      else
+      {
+         new QListViewItem(
+            pListView,
+            dir,
+            i18n("not available"),
+            "",
+            "",
+            "",
+            ""
+            );
+      }
+   }
+}
+
+void DirectoryMergeInfo::setInfo(
+   const FileAccess& dirA,
+   const FileAccess& dirB,
+   const FileAccess& dirC,
+   const FileAccess& dirDest,
+   MergeFileInfos& mfi )
+{
+   bool bHideDest = false;
+   if ( dirA.absFilePath()==dirDest.absFilePath() )
+   {
+      m_pA->setText( i18n("A (Dest): ") );  bHideDest=true;
+   }
+   else
+      m_pA->setText( !dirC.isValid() ? QString("A:    ") : i18n("A (Base): "));
+
+   m_pInfoA->setText( dirA.prettyAbsPath() );
+
+   if ( dirB.absFilePath()==dirDest.absFilePath() )
+   {
+      m_pB->setText( i18n("B (Dest): ") );  bHideDest=true;
+   }
+   else
+      m_pB->setText( "B:    " );
+   m_pInfoB->setText( dirB.prettyAbsPath() );
+
+   if ( dirC.absFilePath()==dirDest.absFilePath() )
+   {
+      m_pC->setText( i18n("C (Dest): ") );  bHideDest=true;
+   }
+   else
+      m_pC->setText( "C:    " );
+   m_pInfoC->setText( dirC.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();   }
+
+   if (!dirDest.isValid()||bHideDest) { m_pDest->hide(); m_pInfoDest->hide(); }
+   else                                { m_pDest->show(); m_pInfoDest->show(); }
+
+   m_pInfoList->clear();
+   addListViewItem( m_pInfoList, "A", dirA.prettyAbsPath(), mfi.m_fileInfoA );
+   addListViewItem( m_pInfoList, "B", dirB.prettyAbsPath(), mfi.m_fileInfoB );
+   addListViewItem( m_pInfoList, "C", dirC.prettyAbsPath(), mfi.m_fileInfoC );
+   if (!bHideDest)
+   {
+      FileAccess fiDest( dirDest.prettyAbsPath() + "/" + mfi.m_subPath, true );
+      addListViewItem( m_pInfoList, i18n("Dest"), dirDest.prettyAbsPath(), fiDest );
+   }
+}
+
+QTextStream& operator<<( QTextStream& ts, MergeFileInfos& mfi )
+{
+   ts << "{\n";
+   ValueMap vm;
+   vm.writeEntry( "SubPath", mfi.m_subPath );
+   vm.writeEntry( "ExistsInA", mfi.m_bExistsInA );
+   vm.writeEntry( "ExistsInB",  mfi.m_bExistsInB );
+   vm.writeEntry( "ExistsInC",  mfi.m_bExistsInC );
+   vm.writeEntry( "EqualAB",  mfi.m_bEqualAB );
+   vm.writeEntry( "EqualAC",  mfi.m_bEqualAC );
+   vm.writeEntry( "EqualBC",  mfi.m_bEqualBC );
+   //DirMergeItem* m_pDMI;
+   //MergeFileInfos* m_pParent;
+   vm.writeEntry( "MergeOperation", (int) mfi.m_eMergeOperation );
+   vm.writeEntry( "DirA",  mfi.m_bDirA );
+   vm.writeEntry( "DirB",  mfi.m_bDirB );
+   vm.writeEntry( "DirC",  mfi.m_bDirC );
+   vm.writeEntry( "LinkA",  mfi.m_bLinkA );
+   vm.writeEntry( "LinkB",  mfi.m_bLinkB );
+   vm.writeEntry( "LinkC",  mfi.m_bLinkC );
+   vm.writeEntry( "OperationComplete", mfi.m_bOperationComplete );
+   //bool m_bSimOpComplete );
+
+   vm.writeEntry( "AgeA", (int) mfi.m_ageA );
+   vm.writeEntry( "AgeB", (int) mfi.m_ageB );
+   vm.writeEntry( "AgeC", (int) mfi.m_ageC );
+   vm.writeEntry( "ConflictingAges", mfi.m_bConflictingAges );       // Equal age but files are not!
+
+   //FileAccess m_fileInfoA;
+   //FileAccess m_fileInfoB;
+   //FileAccess m_fileInfoC;
+
+   //TotalDiffStatus m_totalDiffStatus;
+   
+   vm.save(ts);
+   
+   ts << "}\n";
+
+   return ts;
+}
+
+void DirectoryMergeWindow::slotSaveMergeState()
+{
+   //slotStatusMsg(i18n("Saving Directory Merge State ..."));
+
+   //QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save As...") ).url();
+   QString s = KFileDialog::getSaveFileName( QDir::currentDirPath(), 0, this, i18n("Save Directory Merge State As...") );
+   if(!s.isEmpty())
+   {
+      m_dirMergeStateFilename = s;
+
+
+      QFile file(m_dirMergeStateFilename);
+      bool bSuccess = file.open( IO_WriteOnly );
+      if ( bSuccess )
+      {
+         QTextStream ts( &file );
+
+         QListViewItemIterator it( this );
+         while ( it.current() ) {
+            DirMergeItem* item = static_cast<DirMergeItem*>(it.current());
+            MergeFileInfos* pMFI = item->m_pMFI;
+            ts << *pMFI;
+            ++it;
+         }
+      }
+   }
+
+   //slotStatusMsg(i18n("Ready."));
+
+}
+
+void DirectoryMergeWindow::slotLoadMergeState()
+{
+}
+
+void DirectoryMergeWindow::updateFileVisibilities()
+{
+   bool bShowIdentical = m_pDirShowIdenticalFiles->isChecked();
+   bool bShowDifferent = m_pDirShowDifferentFiles->isChecked();
+   bool bShowOnlyInA   = m_pDirShowFilesOnlyInA->isChecked();
+   bool bShowOnlyInB   = m_pDirShowFilesOnlyInB->isChecked();
+   bool bShowOnlyInC   = m_pDirShowFilesOnlyInC->isChecked();
+   bool bThreeDirs = m_dirC.isValid();
+   m_pSelection1Item = 0;
+   m_pSelection2Item = 0;
+   m_pSelection3Item = 0;
+
+   QListViewItem* p = firstChild();
+   while(p)
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+      MergeFileInfos* pMFI = pDMI->m_pMFI;
+      bool bDir = pMFI->m_bDirA || pMFI->m_bDirB || pMFI->m_bDirC;
+      bool bExistsEverywhere = pMFI->m_bExistsInA && pMFI->m_bExistsInB && (pMFI->m_bExistsInC || !bThreeDirs);
+      int existCount = int(pMFI->m_bExistsInA) + int(pMFI->m_bExistsInB) + int(pMFI->m_bExistsInC);
+      bool bVisible =
+               ( bShowIdentical && bExistsEverywhere && pMFI->m_bEqualAB && (pMFI->m_bEqualAC || !bThreeDirs) )
+            || ( (bShowDifferent||bDir) && existCount>=2 && (!pMFI->m_bEqualAB || !(pMFI->m_bEqualAC || !bThreeDirs)))
+            || ( bShowOnlyInA &&  pMFI->m_bExistsInA && !pMFI->m_bExistsInB && !pMFI->m_bExistsInC )
+            || ( bShowOnlyInB && !pMFI->m_bExistsInA &&  pMFI->m_bExistsInB && !pMFI->m_bExistsInC )
+            || ( bShowOnlyInC && !pMFI->m_bExistsInA && !pMFI->m_bExistsInB &&  pMFI->m_bExistsInC );
+
+      QString fileName = pMFI->m_subPath.section( '/', -1 );
+      bVisible = bVisible && (
+            bDir && ! wildcardMultiMatch( m_pOptions->m_DmDirAntiPattern, fileName, m_bCaseSensitive )
+            || wildcardMultiMatch( m_pOptions->m_DmFilePattern, fileName, m_bCaseSensitive )
+               && !wildcardMultiMatch( m_pOptions->m_DmFileAntiPattern, fileName, m_bCaseSensitive ) );
+
+      p->setVisible(bVisible);
+      p = treeIterator( p, true, true );
+   }
+}
+
+void DirectoryMergeWindow::slotShowIdenticalFiles() { m_pOptions->m_bDmShowIdenticalFiles=m_pDirShowIdenticalFiles->isChecked();
+                                                      updateFileVisibilities(); }
+void DirectoryMergeWindow::slotShowDifferentFiles() { updateFileVisibilities(); }
+void DirectoryMergeWindow::slotShowFilesOnlyInA()   { updateFileVisibilities(); }
+void DirectoryMergeWindow::slotShowFilesOnlyInB()   { updateFileVisibilities(); }
+void DirectoryMergeWindow::slotShowFilesOnlyInC()   { updateFileVisibilities(); }
+
+void DirectoryMergeWindow::slotSynchronizeDirectories()   {  }
+void DirectoryMergeWindow::slotChooseNewerFiles()   {  }
+
+void DirectoryMergeWindow::initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac )
+{
+#include "xpm/startmerge.xpm"
+#include "xpm/showequalfiles.xpm"
+#include "xpm/showfilesonlyina.xpm"
+#include "xpm/showfilesonlyinb.xpm"
+#include "xpm/showfilesonlyinc.xpm"
+   DirectoryMergeWindow* p = this;
+
+   m_pDirStartOperation = new KAction(i18n("Start/Continue Directory Merge"), Qt::Key_F7, p, SLOT(slotRunOperationForAllItems()), ac, "dir_start_operation");
+   m_pDirRunOperationForCurrentItem = new KAction(i18n("Run Operation for Current Item"), Qt::Key_F6, p, SLOT(slotRunOperationForCurrentItem()), ac, "dir_run_operation_for_current_item");
+   m_pDirCompareCurrent = new KAction(i18n("Compare Selected File"), 0, p, SLOT(compareCurrentFile()), ac, "dir_compare_current");
+   m_pDirMergeCurrent = new KAction(i18n("Merge Current File"), QIconSet(QPixmap(startmerge)), 0, pKDiff3App, SLOT(slotMergeCurrentFile()), ac, "merge_current");
+   m_pDirFoldAll = new KAction(i18n("Fold All Subdirs"), 0, p, SLOT(slotFoldAllSubdirs()), ac, "dir_fold_all");
+   m_pDirUnfoldAll = new KAction(i18n("Unfold All Subdirs"), 0, p, SLOT(slotUnfoldAllSubdirs()), ac, "dir_unfold_all");
+   m_pDirRescan = new KAction(i18n("Rescan"), Qt::SHIFT+Qt::Key_F5, p, SLOT(reload()), ac, "dir_rescan");
+   m_pDirSaveMergeState = 0; //new KAction(i18n("Save Directory Merge State ..."), 0, p, SLOT(slotSaveMergeState()), ac, "dir_save_merge_state");
+   m_pDirLoadMergeState = 0; //new KAction(i18n("Load Directory Merge State ..."), 0, p, SLOT(slotLoadMergeState()), ac, "dir_load_merge_state");
+   m_pDirChooseAEverywhere = new KAction(i18n("Choose A for All Items"), 0, p, SLOT(slotChooseAEverywhere()), ac, "dir_choose_a_everywhere");
+   m_pDirChooseBEverywhere = new KAction(i18n("Choose B for All Items"), 0, p, SLOT(slotChooseBEverywhere()), ac, "dir_choose_b_everywhere");
+   m_pDirChooseCEverywhere = new KAction(i18n("Choose C for All Items"), 0, p, SLOT(slotChooseCEverywhere()), ac, "dir_choose_c_everywhere");
+   m_pDirAutoChoiceEverywhere = new KAction(i18n("Auto-Choose Operation for All Items"), 0, p, SLOT(slotAutoChooseEverywhere()), ac, "dir_autochoose_everywhere");
+   m_pDirDoNothingEverywhere = new KAction(i18n("No Operation for All Items"), 0, p, SLOT(slotNoOpEverywhere()), ac, "dir_nothing_everywhere");
+
+//   m_pDirSynchronizeDirectories = new KToggleAction(i18n("Synchronize Directories"), 0, this, SLOT(slotSynchronizeDirectories()), ac, "dir_synchronize_directories");
+//   m_pDirChooseNewerFiles = new KToggleAction(i18n("Copy Newer Files Instead of Merging"), 0, this, SLOT(slotChooseNewerFiles()), ac, "dir_choose_newer_files");
+
+   m_pDirShowIdenticalFiles = new KToggleAction(i18n("Show Identical Files"), QIconSet(QPixmap(showequalfiles)), 0, this, SLOT(slotShowIdenticalFiles()), ac, "dir_show_identical_files");
+   m_pDirShowDifferentFiles = new KToggleAction(i18n("Show Different Files"), 0, this, SLOT(slotShowDifferentFiles()), ac, "dir_show_different_files");
+   m_pDirShowFilesOnlyInA   = new KToggleAction(i18n("Show Files only in A"), QIconSet(QPixmap(showfilesonlyina)), 0, this, SLOT(slotShowFilesOnlyInA()), ac, "dir_show_files_only_in_a");
+   m_pDirShowFilesOnlyInB   = new KToggleAction(i18n("Show Files only in B"), QIconSet(QPixmap(showfilesonlyinb)), 0, this, SLOT(slotShowFilesOnlyInB()), ac, "dir_show_files_only_in_b");
+   m_pDirShowFilesOnlyInC   = new KToggleAction(i18n("Show Files only in C"), QIconSet(QPixmap(showfilesonlyinc)), 0, this, SLOT(slotShowFilesOnlyInC()), ac, "dir_show_files_only_in_c");
+
+   m_pDirShowIdenticalFiles->setChecked( m_pOptions->m_bDmShowIdenticalFiles );
+
+   m_pDirCompareExplicit = new KAction(i18n("Compare Explicitly Selected Files"), 0, p, SLOT(slotCompareExplicitlySelectedFiles()), ac, "dir_compare_explicitly_selected_files");
+   m_pDirMergeExplicit = new KAction(i18n("Merge Explicitly Selected Files"), 0, p, SLOT(slotMergeExplicitlySelectedFiles()), ac, "dir_merge_explicitly_selected_files");
+
+   m_pDirCurrentDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_do_nothing");
+   m_pDirCurrentChooseA = new KAction(i18n("A"), 0, p, SLOT(slotCurrentChooseA()), ac, "dir_current_choose_a");
+   m_pDirCurrentChooseB = new KAction(i18n("B"), 0, p, SLOT(slotCurrentChooseB()), ac, "dir_current_choose_b");
+   m_pDirCurrentChooseC = new KAction(i18n("C"), 0, p, SLOT(slotCurrentChooseC()), ac, "dir_current_choose_c");
+   m_pDirCurrentMerge   = new KAction(i18n("Merge"), 0, p, SLOT(slotCurrentMerge()), ac, "dir_current_merge");
+   m_pDirCurrentDelete  = new KAction(i18n("Delete (if exists)"), 0, p, SLOT(slotCurrentDelete()), ac, "dir_current_delete");
+
+   m_pDirCurrentSyncDoNothing = new KAction(i18n("Do Nothing"), 0, p, SLOT(slotCurrentDoNothing()), ac, "dir_current_sync_do_nothing");
+   m_pDirCurrentSyncCopyAToB = new KAction(i18n("Copy A to B"), 0, p, SLOT(slotCurrentCopyAToB()), ac, "dir_current_sync_copy_a_to_b" );
+   m_pDirCurrentSyncCopyBToA = new KAction(i18n("Copy B to A"), 0, p, SLOT(slotCurrentCopyBToA()), ac, "dir_current_sync_copy_b_to_a" );
+   m_pDirCurrentSyncDeleteA  = new KAction(i18n("Delete A"), 0, p, SLOT(slotCurrentDeleteA()), ac,"dir_current_sync_delete_a");
+   m_pDirCurrentSyncDeleteB  = new KAction(i18n("Delete B"), 0, p, SLOT(slotCurrentDeleteB()), ac,"dir_current_sync_delete_b");
+   m_pDirCurrentSyncDeleteAAndB  = new KAction(i18n("Delete A && B"), 0, p, SLOT(slotCurrentDeleteAAndB()), ac,"dir_current_sync_delete_a_and_b");
+   m_pDirCurrentSyncMergeToA   = new KAction(i18n("Merge to A"), 0, p, SLOT(slotCurrentMergeToA()), ac,"dir_current_sync_merge_to_a");
+   m_pDirCurrentSyncMergeToB   = new KAction(i18n("Merge to B"), 0, p, SLOT(slotCurrentMergeToB()), ac,"dir_current_sync_merge_to_b");
+   m_pDirCurrentSyncMergeToAAndB   = new KAction(i18n("Merge to A && B"), 0, p, SLOT(slotCurrentMergeToAAndB()), ac,"dir_current_sync_merge_to_a_and_b");
+   
+   
+}
+
+
+void DirectoryMergeWindow::updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible,
+   KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC )
+{
+   m_pDirStartOperation->setEnabled( bDirCompare );
+   m_pDirRunOperationForCurrentItem->setEnabled( bDirCompare );
+   m_pDirFoldAll->setEnabled( bDirCompare );
+   m_pDirUnfoldAll->setEnabled( bDirCompare );
+
+   m_pDirCompareCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected() );
+
+   m_pDirMergeCurrent->setEnabled( bDirCompare  &&  isVisible()  &&  isFileSelected()
+                                || bDiffWindowVisible );
+
+   m_pDirRescan->setEnabled( bDirCompare );
+
+   m_pDirAutoChoiceEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirDoNothingEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirChooseAEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirChooseBEverywhere->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirChooseCEverywhere->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);
+
+   bool bDirWindowHasFocus = isVisible() && hasFocus();
+
+   m_pDirShowIdenticalFiles->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirShowDifferentFiles->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirShowFilesOnlyInA->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirShowFilesOnlyInB->setEnabled( bDirCompare &&  isVisible() );
+   m_pDirShowFilesOnlyInC->setEnabled( bDirCompare &&  isVisible() && bThreeDirs );
+
+   m_pDirCompareExplicit->setEnabled( bDirCompare &&  isVisible() && m_pSelection2Item!=0 );
+   m_pDirMergeExplicit->setEnabled( bDirCompare &&  isVisible() && m_pSelection2Item!=0 );
+
+   m_pDirCurrentDoNothing->setEnabled( bItemActive && bMergeMode );
+   m_pDirCurrentChooseA->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInA );
+   m_pDirCurrentChooseB->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInB );
+   m_pDirCurrentChooseC->setEnabled( bItemActive && bMergeMode && pMFI->m_bExistsInC );
+   m_pDirCurrentMerge->setEnabled( bItemActive && bMergeMode && !bFTConflict );
+   m_pDirCurrentDelete->setEnabled( bItemActive && bMergeMode );
+   if ( bDirWindowHasFocus )
+   {
+      chooseA->setEnabled( bItemActive && pMFI->m_bExistsInA );
+      chooseB->setEnabled( bItemActive && pMFI->m_bExistsInB );
+      chooseC->setEnabled( bItemActive && pMFI->m_bExistsInC );
+      chooseA->setChecked( false );
+      chooseB->setChecked( false );
+      chooseC->setChecked( false );
+   }
+
+   m_pDirCurrentSyncDoNothing->setEnabled( bItemActive && !bMergeMode );
+   m_pDirCurrentSyncCopyAToB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   m_pDirCurrentSyncCopyBToA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   m_pDirCurrentSyncDeleteA->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInA );
+   m_pDirCurrentSyncDeleteB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB );
+   m_pDirCurrentSyncDeleteAAndB->setEnabled( bItemActive && !bMergeMode && pMFI->m_bExistsInB && pMFI->m_bExistsInB );
+   m_pDirCurrentSyncMergeToA->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   m_pDirCurrentSyncMergeToB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+   m_pDirCurrentSyncMergeToAAndB->setEnabled( bItemActive && !bMergeMode && !bFTConflict );
+}
+
+
+#include "directorymergewindow.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/directorymergewindow.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,353 @@
+/***************************************************************************
+                          directorymergewindow.h
+                             -------------------
+    begin                : Sat Oct 19 2002
+    copyright            : (C) 2002-2005 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef DIRECTORY_MERGE_WINDOW_H
+#define DIRECTORY_MERGE_WINDOW_H
+
+#include <qfileinfo.h>
+#include <qlistview.h>
+#include <qtimer.h>
+#include <qdir.h>
+#include <list>
+#include <map>
+#include "common.h"
+#include "fileaccess.h"
+#include "diff.h" //TotalDiffStatus
+
+class OptionDialog;
+class KIconLoader;
+class StatusInfo;
+class DirectoryMergeInfo;
+class OneDirectoryInfo;
+class QLabel;
+class KAction;
+class KToggleAction;
+class KActionCollection;
+class TotalDiffStatus;
+
+enum e_MergeOperation
+{
+   eTitleId,
+   eNoOperation,
+   // Operations in sync mode (with only two directories):
+   eCopyAToB, eCopyBToA, eDeleteA, eDeleteB, eDeleteAB, eMergeToA, eMergeToB, eMergeToAB,
+
+   // Operations in merge mode (with two or three directories)
+   eCopyAToDest, eCopyBToDest, eCopyCToDest, eDeleteFromDest, eMergeABCToDest,
+   eMergeABToDest,
+   eConflictingFileTypes, // Error
+   eConflictingAges       // Equal age but files are not!
+};
+
+class DirMergeItem;
+
+enum e_Age { eNew, eMiddle, eOld, eNotThere, eAgeEnd };
+
+class MergeFileInfos
+{
+public:
+   MergeFileInfos(){ m_bEqualAB=false; m_bEqualAC=false; m_bEqualBC=false;
+                     m_pDMI=0; m_pParent=0;
+                     m_bExistsInA=false;m_bExistsInB=false;m_bExistsInC=false;
+                     m_bDirA=false;  m_bDirB=false;  m_bDirC=false;
+                     m_bLinkA=false; m_bLinkB=false; m_bLinkC=false;
+                     m_bOperationComplete=false; m_bSimOpComplete = false;
+                     m_eMergeOperation=eNoOperation;
+                     m_ageA = eNotThere; m_ageB=eNotThere; m_ageC=eNotThere;
+                     m_bConflictingAges=false; }
+   bool operator>( const MergeFileInfos& );
+   QString m_subPath;
+
+   bool m_bExistsInA;
+   bool m_bExistsInB;
+   bool m_bExistsInC;
+   bool m_bEqualAB;
+   bool m_bEqualAC;
+   bool m_bEqualBC;
+   DirMergeItem* m_pDMI;
+   MergeFileInfos* m_pParent;
+   e_MergeOperation m_eMergeOperation;
+   void setMergeOperation( e_MergeOperation eMOp );
+   bool m_bDirA;
+   bool m_bDirB;
+   bool m_bDirC;
+   bool m_bLinkA;
+   bool m_bLinkB;
+   bool m_bLinkC;
+   bool m_bOperationComplete;
+   bool m_bSimOpComplete;
+   e_Age m_ageA;
+   e_Age m_ageB;
+   e_Age m_ageC;
+   bool m_bConflictingAges;       // Equal age but files are not!
+
+   FileAccess m_fileInfoA;
+   FileAccess m_fileInfoB;
+   FileAccess m_fileInfoC;
+
+   TotalDiffStatus m_totalDiffStatus;   
+};
+
+class DirMergeItem : public QListViewItem
+{
+public:
+   DirMergeItem( QListView* pParent, const QString&, MergeFileInfos*);
+   DirMergeItem( DirMergeItem* pParent, const QString&, MergeFileInfos*);
+   ~DirMergeItem();
+   MergeFileInfos* m_pMFI;
+   virtual int compare(QListViewItem *i, int col, bool ascending) const;
+   virtual void paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align );
+   void init(MergeFileInfos* pMFI);
+};
+
+class DirectoryMergeWindow : public QListView
+{
+   Q_OBJECT
+public:
+   DirectoryMergeWindow( QWidget* pParent, OptionDialog* pOptions, KIconLoader* pIconLoader );
+   ~DirectoryMergeWindow();
+   void setDirectoryMergeInfo(DirectoryMergeInfo* p){ m_pDirectoryMergeInfo=p; }
+   bool init(
+      FileAccess& dirA,
+      FileAccess& dirB,
+      FileAccess& dirC,
+      FileAccess& dirDest,
+      bool bDirectoryMerge
+   );
+   bool isFileSelected();
+   void allowResizeEvents(bool bAllowResizeEvents);
+   bool isDirectoryMergeInProgress() { return m_bRealMergeStarted; }
+   int totalColumnWidth();
+   bool isSyncMode() { return m_bSyncMode; }
+   bool isScanning() { return m_bScanning; }
+   void initDirectoryMergeActions( QObject* pKDiff3App, KActionCollection* ac );
+   void updateAvailabilities( bool bDirCompare, bool bDiffWindowVisible,
+      KToggleAction* chooseA, KToggleAction* chooseB, KToggleAction* chooseC );
+   void updateFileVisibilities();
+
+   virtual void keyPressEvent( QKeyEvent* e );
+   virtual void focusInEvent( QFocusEvent* e );
+   virtual void focusOutEvent( QFocusEvent* e );
+
+public slots:
+   void reload();
+   void mergeCurrentFile();
+   void compareCurrentFile();
+   void slotRunOperationForAllItems();
+   void slotRunOperationForCurrentItem();
+   void mergeResultSaved(const QString& fileName);
+   void slotChooseAEverywhere();
+   void slotChooseBEverywhere();
+   void slotChooseCEverywhere();
+   void slotAutoChooseEverywhere();
+   void slotNoOpEverywhere();
+   void slotFoldAllSubdirs();
+   void slotUnfoldAllSubdirs();
+   void slotShowIdenticalFiles();
+   void slotShowDifferentFiles();
+   void slotShowFilesOnlyInA();
+   void slotShowFilesOnlyInB();
+   void slotShowFilesOnlyInC();
+
+   void slotSynchronizeDirectories();
+   void slotChooseNewerFiles();
+
+   void slotCompareExplicitlySelectedFiles();
+   void slotMergeExplicitlySelectedFiles();
+
+   // 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();
+
+   void slotSaveMergeState();
+   void slotLoadMergeState();
+
+protected:
+   void mergeContinue( bool bStart, bool bVerbose );
+   void resizeEvent(QResizeEvent* e);
+   bool m_bAllowResizeEvents;
+
+   void prepareListView(ProgressProxy& pp);
+   void calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultOperation );
+   void setAllMergeOperations( e_MergeOperation eDefaultOperation );
+   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 );
+   void fastFileComparison( FileAccess& fi1, FileAccess& fi2,
+                            bool& bEqual, bool& bError, QString& status );
+   void compareFilesAndCalcAges( MergeFileInfos& mfi );
+
+   QString fullNameA( const MergeFileInfos& mfi )
+   { return m_dirA.absFilePath() + "/" + mfi.m_subPath; }
+   QString fullNameB( const MergeFileInfos& mfi )
+   { return m_dirB.absFilePath() + "/" + mfi.m_subPath; }
+   QString fullNameC( const MergeFileInfos& mfi )
+   { return m_dirC.absFilePath() + "/" + mfi.m_subPath; }
+   QString fullNameDest( const MergeFileInfos& mfi )
+   { return m_dirDestInternal.absFilePath() + "/" + mfi.m_subPath; }
+
+   bool copyFLD( const QString& srcName, const QString& destName );
+   bool deleteFLD( const QString& name, bool bCreateBackup );
+   bool makeDir( const QString& name, bool bQuiet=false );
+   bool renameFLD( const QString& srcName, const QString& destName );
+   bool mergeFLD( const QString& nameA,const QString& nameB,const QString& nameC,
+                  const QString& nameDest, bool& bSingleFileMerge );
+
+   FileAccess m_dirA;
+   FileAccess m_dirB;
+   FileAccess m_dirC;
+   FileAccess m_dirDest;
+   FileAccess m_dirDestInternal;
+
+   QString m_dirMergeStateFilename;
+
+   std::map<QString, MergeFileInfos> m_fileMergeMap;
+
+   bool m_bFollowDirLinks;
+   bool m_bFollowFileLinks;
+   bool m_bSimulatedMergeStarted;
+   bool m_bRealMergeStarted;
+   bool m_bError;
+   bool m_bSyncMode;
+   bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff.
+   bool m_bCaseSensitive;
+   
+   bool m_bScanning; // true while in init()
+
+   OptionDialog* m_pOptions;
+   KIconLoader* m_pIconLoader;
+   DirectoryMergeInfo* m_pDirectoryMergeInfo;
+   StatusInfo* m_pStatusInfo;
+
+   typedef std::list<DirMergeItem*> MergeItemList;
+   MergeItemList m_mergeItemList;
+   MergeItemList::iterator m_currentItemForOperation;
+
+   DirMergeItem* m_pSelection1Item;
+   int m_selection1Column;
+   DirMergeItem* m_pSelection2Item;
+   int m_selection2Column;
+   DirMergeItem* m_pSelection3Item;
+   int m_selection3Column;
+   void selectItemAndColumn(DirMergeItem* pDMI, int c, bool bContextMenu);
+   friend class DirMergeItem;
+
+   KAction* m_pDirStartOperation;
+   KAction* m_pDirRunOperationForCurrentItem;
+   KAction* m_pDirCompareCurrent;
+   KAction* m_pDirMergeCurrent;
+   KAction* m_pDirRescan;
+   KAction* m_pDirChooseAEverywhere;
+   KAction* m_pDirChooseBEverywhere;
+   KAction* m_pDirChooseCEverywhere;
+   KAction* m_pDirAutoChoiceEverywhere;
+   KAction* m_pDirDoNothingEverywhere;
+   KAction* m_pDirFoldAll;
+   KAction* m_pDirUnfoldAll;
+
+   KToggleAction* m_pDirShowIdenticalFiles;
+   KToggleAction* m_pDirShowDifferentFiles;
+   KToggleAction* m_pDirShowFilesOnlyInA;
+   KToggleAction* m_pDirShowFilesOnlyInB;
+   KToggleAction* m_pDirShowFilesOnlyInC;
+
+   KToggleAction* m_pDirSynchronizeDirectories;
+   KToggleAction* m_pDirChooseNewerFiles;
+
+   KAction* m_pDirCompareExplicit;
+   KAction* m_pDirMergeExplicit;
+
+   KAction* m_pDirCurrentDoNothing;
+   KAction* m_pDirCurrentChooseA;
+   KAction* m_pDirCurrentChooseB;
+   KAction* m_pDirCurrentChooseC;
+   KAction* m_pDirCurrentMerge;
+   KAction* m_pDirCurrentDelete;
+
+   KAction* m_pDirCurrentSyncDoNothing;
+   KAction* m_pDirCurrentSyncCopyAToB;
+   KAction* m_pDirCurrentSyncCopyBToA;
+   KAction* m_pDirCurrentSyncDeleteA;
+   KAction* m_pDirCurrentSyncDeleteB;
+   KAction* m_pDirCurrentSyncDeleteAAndB;
+   KAction* m_pDirCurrentSyncMergeToA;
+   KAction* m_pDirCurrentSyncMergeToB;
+   KAction* m_pDirCurrentSyncMergeToAAndB;
+
+   KAction* m_pDirSaveMergeState;
+   KAction* m_pDirLoadMergeState;
+signals:
+   void startDiffMerge(QString fn1,QString fn2, QString fn3, QString ofn, QString,QString,QString,TotalDiffStatus*);
+   void checkIfCanContinue( bool* pbContinue );
+   void updateAvailabilities();
+   void statusBarMessage( const QString& msg );
+protected slots:
+   void onDoubleClick( QListViewItem* lvi );
+   void onClick( int button, QListViewItem* lvi, const QPoint&, int c );
+   void slotShowContextMenu(QListViewItem* lvi,const QPoint &,int c);
+   void onSelectionChanged(QListViewItem* lvi);
+};
+
+class DirectoryMergeInfo : public QFrame
+{
+   Q_OBJECT
+public:
+   DirectoryMergeInfo( QWidget* pParent );
+   void setInfo(
+      const FileAccess& APath,
+      const FileAccess& BPath,
+      const FileAccess& CPath,
+      const FileAccess& DestPath,
+      MergeFileInfos& mfi );
+   QListView* getInfoList() {return m_pInfoList;}
+   virtual bool eventFilter( QObject* o, QEvent* e );
+signals:
+   void gotFocus();
+private:
+   QLabel* m_pInfoA;
+   QLabel* m_pInfoB;
+   QLabel* m_pInfoC;
+   QLabel* m_pInfoDest;
+
+   QLabel* m_pA;
+   QLabel* m_pB;
+   QLabel* m_pC;
+   QLabel* m_pDest;
+
+   QListView* m_pInfoList;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/fileaccess.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1793 @@
+/***************************************************************************
+ *   Copyright (C) 2003 by Joachim Eibl                                    *
+ *   joachim.eibl at gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
+#include "fileaccess.h"
+#include <iostream>
+#include <kio/global.h>
+#include <kmessagebox.h>
+#include "optiondialog.h"
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qapplication.h>
+#include <qpushbutton.h>
+
+#include <qeventloop.h>
+
+#include "common.h"
+#include <ktempfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+#include <vector>
+#include <klocale.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <sys/utime.h>
+#include <io.h>
+#include <windows.h>
+#else
+#include <unistd.h>          // Needed for creating symbolic links via symlink().
+#include <utime.h>
+#endif
+
+
+ProgressDialog* g_pProgressDialog=0;
+
+
+FileAccess::FileAccess( const QString& name, bool bWantToWrite )
+{
+   setFile( name, bWantToWrite );
+}
+
+FileAccess::FileAccess()
+{
+   m_bValidData = false;
+   m_size = 0;
+   m_creationTime = QDateTime();
+   m_accessTime = QDateTime();
+   m_modificationTime = QDateTime();
+   m_bReadable = false;
+   m_bWritable = false;
+   m_bExecutable = false;
+   m_bLocal = false;
+   m_bHidden = false;
+   m_bExists = false;
+   m_bFile = false;
+   m_bDir  = false;
+   m_bSymLink = false;
+}
+
+FileAccess::~FileAccess()
+{
+   if( !m_localCopy.isEmpty() )
+   {
+      removeTempFile( m_localCopy );
+   }
+}
+
+void FileAccess::setFile( const QString& name, bool bWantToWrite )
+{
+   m_url = KURL::fromPathOrURL( name );
+   m_bValidData = false;
+
+   m_size = 0;
+   m_creationTime = QDateTime();
+   m_accessTime = QDateTime();
+   m_modificationTime = QDateTime();
+   m_bReadable = false;
+   m_bWritable = false;
+   m_bExecutable = false;
+   m_bHidden = false;
+   m_bExists = false;
+   m_bFile = false;
+   m_bDir  = false;
+   m_bSymLink = false;
+   m_linkTarget = "";
+   m_fileType = -1;
+   m_bLocal = true;
+
+   // Note: Checking if the filename-string is empty is necessary for Win95/98/ME.
+   //       The isFile() / isDir() queries would cause the program to crash.
+   //       (This is a Win95-bug which has been corrected only in WinNT/2000/XP.)
+   if ( !name.isEmpty() )
+   {
+      // 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 ( !bExistsLocal && m_url.isLocalFile() && name.left(5).lower()=="file:" )
+         {
+            localName = m_url.path(); // I want the path without preceding "file:"
+         }
+         QFileInfo fi( localName );
+#if defined(Q_WS_WIN)
+         // On some windows machines in a network this takes very long.
+         // and it's not so important anyway.
+         m_bReadable    = true;
+         m_bWritable    = true; // in certain situations this might become a problem though
+         m_bExecutable  = false;
+#else
+         m_bReadable    = fi.isReadable();
+         m_bWritable    = fi.isWritable();
+         m_bExecutable  = fi.isExecutable();
+#endif
+         m_creationTime = fi.created();
+         m_bHidden    = fi.isHidden();
+         m_modificationTime = fi.lastModified();
+         m_accessTime = fi.lastRead();
+         m_size       = fi.size();
+         m_bSymLink   = fi.isSymLink();
+         m_bFile      = fi.isFile();
+         m_bDir       = fi.isDir();
+         m_bExists    = fi.exists();
+         m_name       = fi.fileName();
+         m_path       = fi.filePath();
+         m_absFilePath= fi.absFilePath();
+         if ( m_bSymLink ) m_linkTarget = fi.readLink();
+         m_bLocal = true;
+         m_bValidData = true;
+         if ( ! m_url.isValid() )
+         {
+            m_url.setPath( m_absFilePath );
+         }
+
+         if ( !m_bExists  && m_absFilePath.contains("@@") )
+         {
+            // Try reading a clearcase file
+            m_localCopy = FileAccess::tempFileName();
+            QString cmd = "cleartool get -to \"" + m_localCopy + "\"  \"" + m_absFilePath + "\"";
+            ::system( cmd.local8Bit() );
+
+            QFileInfo fi( m_localCopy );
+#if defined(Q_WS_WIN)
+            m_bReadable    = true;//fi.isReadable();
+            m_bWritable    = true;//fi.isWritable();
+            m_bExecutable  = false;//fi.isExecutable();
+#else
+            m_bReadable    = fi.isReadable();
+            m_bWritable    = fi.isWritable();
+            m_bExecutable  = fi.isExecutable();
+#endif
+            m_creationTime = fi.created();
+            m_bHidden    = fi.isHidden();
+            m_modificationTime = fi.lastModified();
+            m_accessTime = fi.lastRead();
+            m_size       = fi.size();
+            m_bSymLink   = fi.isSymLink();
+            m_bFile      = fi.isFile();
+            m_bDir       = fi.isDir();
+            m_bExists    = fi.exists();
+         }
+      }
+      else
+      {
+         m_absFilePath = name;
+         m_name   = m_url.fileName();
+         m_bLocal = false;
+
+         FileAccessJobHandler jh( this ); // A friend, which writes to the parameters of this class!
+         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 )
+{
+   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:
+       S_IFMT     0170000   bitmask for the file type bitfields
+       S_IFSOCK   0140000   socket
+       S_IFLNK    0120000   symbolic link
+       S_IFREG    0100000   regular file
+       S_IFBLK    0060000   block device
+       S_IFDIR    0040000   directory
+       S_IFCHR    0020000   character device
+       S_IFIFO    0010000   fifo
+       S_ISUID    0004000   set UID bit
+       S_ISGID    0002000   set GID bit (see below)
+       S_ISVTX    0001000   sticky bit (see below)
+
+       Access:
+       S_IRWXU    00700     mask for file owner permissions
+       S_IRUSR    00400     owner has read permission
+       S_IWUSR    00200     owner has write permission
+       S_IXUSR    00100     owner has execute permission
+       S_IRWXG    00070     mask for group permissions
+       S_IRGRP    00040     group has read permission
+       S_IWGRP    00020     group has write permission
+       S_IXGRP    00010     group has execute permission
+       S_IRWXO    00007     mask for permissions for others (not in group)
+       S_IROTH    00004     others have read permission
+       S_IWOTH    00002     others have write permisson
+       S_IXOTH    00001     others have execute permission
+*/
+
+#ifdef KREPLACEMENTS_H
+void FileAccess::setUdsEntry( const KIO::UDSEntry& ){}  // not needed if KDE is not available
+#else
+void FileAccess::setUdsEntry( const KIO::UDSEntry& e )
+{
+   KIO::UDSEntry::const_iterator ei;
+   long acc = 0;
+   long fileType = 0;
+   for( ei=e.begin(); ei!=e.end(); ++ei )
+   {
+      const KIO::UDSAtom& a = *ei;
+      switch( a.m_uds )
+      {
+         case KIO::UDS_SIZE :              m_size   = a.m_long;   break;
+         case KIO::UDS_USER :              m_user   = a.m_str;    break;
+         case KIO::UDS_GROUP :             m_group  = a.m_str;    break;
+         case KIO::UDS_NAME :              m_path   = a.m_str;    break;  // During listDir the relative path is given here.
+         case KIO::UDS_MODIFICATION_TIME : m_modificationTime.setTime_t( a.m_long ); break;
+         case KIO::UDS_ACCESS_TIME :       m_accessTime.setTime_t( a.m_long ); break;
+         case KIO::UDS_CREATION_TIME :     m_creationTime.setTime_t( a.m_long ); break;
+         case KIO::UDS_LINK_DEST :         m_linkTarget       = a.m_str; break;
+         case KIO::UDS_ACCESS :
+         {
+            acc = a.m_long;
+            m_bReadable   = (acc & S_IRUSR)!=0;
+            m_bWritable   = (acc & S_IWUSR)!=0;
+            m_bExecutable = (acc & S_IXUSR)!=0;
+            break;
+         }
+         case KIO::UDS_FILE_TYPE :
+         {
+            fileType = a.m_long;
+            m_bDir     = ( fileType & S_IFMT ) == S_IFDIR;
+            m_bFile    = ( fileType & S_IFMT ) == S_IFREG;
+            m_bSymLink = ( fileType & S_IFMT ) == S_IFLNK;
+            m_bExists  = fileType != 0;
+            m_fileType = fileType;
+            break;
+         }
+
+         case KIO::UDS_URL :               // m_url = KURL( a.str );
+                                           break;
+         case KIO::UDS_MIME_TYPE :         break;
+         case KIO::UDS_GUESSED_MIME_TYPE : break;
+         case KIO::UDS_XML_PROPERTIES :    break;
+         default: break;
+      }
+   }
+
+   m_bExists = acc!=0 || fileType!=0;
+
+   m_bLocal = false;
+   m_bValidData = true;
+   m_bSymLink = !m_linkTarget.isEmpty();
+   if ( m_name.isEmpty() )
+   {
+      int pos = m_path.findRev('/') + 1;
+      m_name = m_path.mid( pos );
+   }
+   m_bHidden = m_name[0]=='.';
+}
+#endif
+
+
+bool FileAccess::isValid() const       {   return m_bValidData;  }
+bool FileAccess::isFile() const        {   return m_bFile;       }
+bool FileAccess::isDir() const         {   return m_bDir;        }
+bool FileAccess::isSymLink() const     {   return m_bSymLink;    }
+bool FileAccess::exists() const        {   return m_bExists;     }
+long FileAccess::size() const          {   return m_size;        }
+KURL FileAccess::url() const           {   return m_url;         }
+bool FileAccess::isLocal() const       {   return m_bLocal;      }
+bool FileAccess::isReadable() const    {   return m_bReadable;   }
+bool FileAccess::isWritable() const    {   return m_bWritable;   }
+bool FileAccess::isExecutable() const  {   return m_bExecutable; }
+bool FileAccess::isHidden() const      {   return m_bHidden;     }
+QString FileAccess::readLink() const   {   return m_linkTarget;  }
+QString FileAccess::absFilePath() const{   return m_absFilePath; }  // Full abs path
+QString FileAccess::fileName() const   {   return m_name;        }  // Just the name-part of the path, without parent directories
+QString FileAccess::filePath() const   {   return m_path;        }  // The path-string that was used during construction
+QString FileAccess::prettyAbsPath() const { return isLocal() ? m_absFilePath : m_url.prettyURL(); }
+
+QDateTime FileAccess::created() const
+{
+   return ( m_creationTime.isValid() ?  m_creationTime : m_modificationTime );
+}
+
+QDateTime FileAccess::lastModified() const
+{
+   return m_modificationTime;
+}
+
+QDateTime FileAccess::lastRead() const
+{
+   return ( m_accessTime.isValid() ?  m_accessTime : m_modificationTime );
+}
+
+static bool interruptableReadFile( QFile& f, void* pDestBuffer, unsigned long maxLength )
+{
+   ProgressProxy pp;
+   const unsigned long maxChunkSize = 100000;
+   unsigned long i=0;
+   while( i<maxLength )
+   {
+      unsigned long nextLength = min2( maxLength-i, maxChunkSize );
+      unsigned long reallyRead = f.readBlock( (char*)pDestBuffer+i, nextLength );
+      if ( reallyRead != nextLength )
+      {
+         return false;
+      }
+      i+=reallyRead;
+
+      pp.setCurrent( double(i)/maxLength );
+      if ( pp.wasCancelled() ) return false;
+   }
+   return true;
+}
+
+bool FileAccess::readFile( void* pDestBuffer, unsigned long maxLength )
+{
+   if ( !m_localCopy.isEmpty() )
+   {
+      QFile f( m_localCopy );
+      if ( f.open( IO_ReadOnly ) )
+         return interruptableReadFile(f, pDestBuffer, maxLength);// maxLength == f.readBlock( (char*)pDestBuffer, maxLength );
+   }
+   else if (m_bLocal)
+   {
+      QFile f( filePath() );
+
+      if ( f.open( IO_ReadOnly ) )
+         return interruptableReadFile(f, pDestBuffer, maxLength); //maxLength == f.readBlock( (char*)pDestBuffer, maxLength );
+   }
+   else
+   {
+      FileAccessJobHandler jh( this );
+      return jh.get( pDestBuffer, maxLength );
+   }
+   return false;
+}
+
+bool FileAccess::writeFile( const void* pSrcBuffer, unsigned long length )
+{
+   ProgressProxy pp;
+   if (m_bLocal)
+   {
+      QFile f( filePath() );
+      if ( f.open( IO_WriteOnly ) )
+      {
+         const unsigned long maxChunkSize = 100000;
+         unsigned long i=0;
+         while( i<length )
+         {
+            unsigned long nextLength = min2( length-i, maxChunkSize );
+            unsigned long reallyWritten = f.writeBlock( (char*)pSrcBuffer+i, nextLength );
+            if ( reallyWritten != nextLength )
+            {
+               return false;
+            }
+            i+=reallyWritten;
+
+            pp.setCurrent( double(i)/length );
+            if ( pp.wasCancelled() ) return false;
+         }
+         f.close();
+#ifndef _WIN32
+         if ( isExecutable() )  // value is true if the old file was executable
+         {
+            // Preserve attributes
+            struct stat srcFileStatus;
+            int statResult = ::stat( filePath().ascii(), &srcFileStatus );
+            if (statResult==0)
+            {
+               ::chmod ( filePath().ascii(), srcFileStatus.st_mode | S_IXUSR );
+            }
+         }
+#endif
+
+         return true;
+      }
+   }
+   else
+   {
+      FileAccessJobHandler jh( this );
+      return jh.put( pSrcBuffer, length, true /*overwrite*/ );
+   }
+   return false;
+}
+
+bool FileAccess::copyFile( const QString& dest )
+{
+   FileAccessJobHandler jh( this );
+   return jh.copyFile( dest );   // Handles local and remote copying.
+}
+
+bool FileAccess::rename( const QString& dest )
+{
+   FileAccessJobHandler jh( this );
+   return jh.rename( dest );
+}
+
+bool FileAccess::removeFile()
+{
+   if ( isLocal() )
+   {
+      return QDir().remove( absFilePath() );
+   }
+   else
+   {
+      FileAccessJobHandler jh( this );
+      return jh.removeFile( absFilePath() );
+   }
+}
+
+bool FileAccess::removeFile( const QString& name ) // static
+{
+   return FileAccess(name).removeFile();
+}
+
+bool FileAccess::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
+   const QString& filePattern, const QString& fileAntiPattern, const QString& dirAntiPattern,
+   bool bFollowDirLinks, bool bUseCvsIgnore )
+{
+   FileAccessJobHandler jh( this );
+   return jh.listDir( pDirList, bRecursive, bFindHidden, filePattern, fileAntiPattern,
+                      dirAntiPattern, bFollowDirLinks, bUseCvsIgnore );
+}
+
+QString FileAccess::tempFileName()
+{
+   #ifdef KREPLACEMENTS_H
+
+      QString fileName;
+      #ifdef _WIN32
+         QString tmpDir = getenv("TEMP");
+      #else
+         QString tmpDir = "/tmp";
+      #endif
+      for(int i=0; ;++i)
+      {
+         // short filenames for WIN98 because for system() the command must not exceed 120 characters.
+         #ifdef _WIN32
+         if ( QApplication::winVersion() & Qt::WV_DOS_based ) // Win95, 98, ME
+            fileName = tmpDir + "\\" + QString::number(i);
+         else
+         #endif
+            fileName = tmpDir + "/kdiff3_" + QString::number(i) +".tmp";
+         if ( ! FileAccess::exists(fileName) && 
+              QFile(fileName).open(IO_WriteOnly) ) // open, truncate and close the file, true if successful
+         {
+            break;
+         }
+      }
+      return QDir::convertSeparators(fileName+".2");
+
+   #else  // using KDE
+
+      KTempFile tmpFile;
+      //tmpFile.setAutoDelete( true );  // We only want the name. Delete the precreated file immediately.
+      tmpFile.close();
+      return tmpFile.name()+".2";
+
+   #endif
+}
+
+bool FileAccess::removeTempFile( const QString& name ) // static
+{
+   if (name.endsWith(".2"))
+      FileAccess(name.left(name.length()-2)).removeFile();
+   return FileAccess(name).removeFile();
+}
+
+
+bool FileAccess::makeDir( const QString& dirName )
+{
+   FileAccessJobHandler fh(0);
+   return fh.mkDir( dirName );
+}
+
+bool FileAccess::removeDir( const QString& dirName )
+{
+   FileAccessJobHandler fh(0);
+   return fh.rmDir( dirName );
+}
+
+bool FileAccess::symLink( const QString& linkTarget, const QString& linkLocation )
+{
+#ifdef _WIN32
+   return false;
+#else
+   return 0==::symlink( linkTarget.ascii(), linkLocation.ascii() );
+   //FileAccessJobHandler fh(0);
+   //return fh.symLink( linkTarget, linkLocation );
+#endif
+}
+
+bool FileAccess::exists( const QString& name )
+{
+   FileAccess fa( name );
+   return fa.exists();
+}
+
+// If the size couldn't be determined by stat() then the file is copied to a local temp file.
+long FileAccess::sizeForReading()
+{
+   if ( m_size == 0 && !isLocal() )
+   {
+      // Size couldn't be determined. Copy the file to a local temp place.
+      QString localCopy = tempFileName();
+      bool bSuccess = copyFile( localCopy );
+      if ( bSuccess )
+      {
+         QFileInfo fi( localCopy );
+         m_size = fi.size();
+         m_localCopy = localCopy;
+         return m_size;
+      }
+      else
+      {
+         return 0;
+      }
+   }
+   else
+      return m_size;
+}
+
+QString FileAccess::getStatusText()
+{
+   return m_statusText;
+}
+
+QString FileAccess::cleanDirPath( const QString& path ) // static
+{
+   KURL url(path);
+   if ( url.isLocalFile() || ! url.isValid() )
+   {
+      return QDir().cleanDirPath( path );
+   }
+   else
+   {
+      return path;
+   }
+}
+
+bool FileAccess::createBackup( const QString& bakExtension )
+{
+   if ( exists() )
+   {
+      // First rename the existing file to the bak-file. If a bak-file file exists, delete that.
+      QString bakName = absFilePath() + bakExtension;
+      FileAccess bakFile( bakName, true /*bWantToWrite*/ );
+      if ( bakFile.exists() )
+      {
+         bool bSuccess = bakFile.removeFile();
+         if ( !bSuccess )
+         {
+            m_statusText = i18n("While trying to make a backup, deleting an older backup failed. \nFilename: ") + bakName;
+            return false;
+         }
+      }
+      bool bSuccess = rename( bakName );
+      if (!bSuccess)
+      {
+         m_statusText = i18n("While trying to make a backup, renaming failed. \nFilenames: ") +
+               absFilePath() + " -> " + bakName;
+         return false;
+      }
+   }
+   return true;
+}
+
+FileAccessJobHandler::FileAccessJobHandler( FileAccess* pFileAccess )
+{
+   m_pFileAccess = pFileAccess;
+   m_bSuccess = false;
+}
+
+bool FileAccessJobHandler::stat( int detail, bool bWantToWrite )
+{
+   m_bSuccess = false;
+   m_pFileAccess->m_statusText = QString();
+   KIO::StatJob* pStatJob = KIO::stat( m_pFileAccess->m_url, ! bWantToWrite, detail, false );
+
+   connect( pStatJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotStatResult(KIO::Job*)));
+
+   g_pProgressDialog->enterEventLoop( pStatJob, i18n("Getting file status: %1").arg(m_pFileAccess->prettyAbsPath()) );
+
+   return m_bSuccess;
+}
+
+void FileAccessJobHandler::slotStatResult(KIO::Job* pJob)
+{
+   if ( pJob->error() )
+   {
+      //pJob->showErrorDialog(g_pProgressDialog);
+      m_pFileAccess->m_bExists = false;
+      m_bSuccess = true;
+   }
+   else
+   {
+      m_bSuccess = true;
+
+      m_pFileAccess->m_bValidData = true;
+      const KIO::UDSEntry e = static_cast<KIO::StatJob*>(pJob)->statResult();
+
+      m_pFileAccess->setUdsEntry( e );
+   }
+
+   g_pProgressDialog->exitEventLoop();
+}
+
+
+bool FileAccessJobHandler::get(void* pDestBuffer, long maxLength )
+{
+   ProgressProxy pp; // Implicitly used in slotPercent()
+   if ( maxLength>0 && !pp.wasCancelled() )
+   {
+      KIO::TransferJob* pJob = KIO::get( m_pFileAccess->m_url, false /*reload*/, false );
+      m_transferredBytes = 0;
+      m_pTransferBuffer = (char*)pDestBuffer;
+      m_maxLength = maxLength;
+      m_bSuccess = false;
+      m_pFileAccess->m_statusText = QString();
+
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+      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( pJob, i18n("Reading file: %1").arg(m_pFileAccess->prettyAbsPath()) );
+      return m_bSuccess;
+   }
+   else
+      return true;
+}
+
+void FileAccessJobHandler::slotGetData( KIO::Job* pJob, const QByteArray& newData )
+{
+   if ( pJob->error() )
+   {
+      pJob->showErrorDialog(g_pProgressDialog);
+   }
+   else
+   {
+      long length = min2( long(newData.size()), m_maxLength - m_transferredBytes );
+      ::memcpy( m_pTransferBuffer + m_transferredBytes, newData.data(), newData.size() );
+      m_transferredBytes += length;
+   }
+}
+
+bool FileAccessJobHandler::put(const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume, int permissions )
+{
+   if ( maxLength>0 )
+   {
+      KIO::TransferJob* pJob = KIO::put( m_pFileAccess->m_url, permissions, bOverwrite, bResume, false );
+      m_transferredBytes = 0;
+      m_pTransferBuffer = (char*)pSrcBuffer;
+      m_maxLength = maxLength;
+      m_bSuccess = false;
+      m_pFileAccess->m_statusText = QString();
+
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotPutJobResult(KIO::Job*)));
+      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( pJob, i18n("Writing file: %1").arg(m_pFileAccess->prettyAbsPath()) );
+      return m_bSuccess;
+   }
+   else
+      return true;
+}
+
+void FileAccessJobHandler::slotPutData( KIO::Job* pJob, QByteArray& data )
+{
+   if ( pJob->error() )
+   {
+      pJob->showErrorDialog(g_pProgressDialog);
+   }
+   else
+   {
+      long maxChunkSize = 100000;
+      long length = min2( maxChunkSize, m_maxLength - m_transferredBytes );
+      bool bSuccess = data.resize( length );
+      if ( bSuccess )
+      {
+         if ( length>0 )
+         {
+            ::memcpy( data.data(), m_pTransferBuffer + m_transferredBytes, data.size() );
+            m_transferredBytes += length;
+         }
+      }
+      else
+      {
+         KMessageBox::error( g_pProgressDialog, i18n("Out of memory") );
+         data.resize(0);
+         m_bSuccess = false;
+      }
+   }
+}
+
+void FileAccessJobHandler::slotPutJobResult(KIO::Job* pJob)
+{
+   if ( pJob->error() )
+   {
+      pJob->showErrorDialog(g_pProgressDialog);
+   }
+   else
+   {
+      m_bSuccess = (m_transferredBytes == m_maxLength); // Special success condition
+   }
+   g_pProgressDialog->exitEventLoop();  // Close the dialog, return from exec()
+}
+
+bool FileAccessJobHandler::mkDir( const QString& dirName )
+{
+   KURL dirURL = KURL::fromPathOrURL( dirName );
+   if ( dirName.isEmpty() )
+      return false;
+   else if ( dirURL.isLocalFile() )
+   {
+      return QDir().mkdir( dirURL.path() );
+   }
+   else
+   {
+      m_bSuccess = false;
+      KIO::SimpleJob* pJob = KIO::mkdir( dirURL );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Making directory: %1").arg(dirName) );
+      return m_bSuccess;
+   }
+}
+
+bool FileAccessJobHandler::rmDir( const QString& dirName )
+{
+   KURL dirURL = KURL::fromPathOrURL( dirName );
+   if ( dirName.isEmpty() )
+      return false;
+   else if ( dirURL.isLocalFile() )
+   {
+      return QDir().rmdir( dirURL.path() );
+   }
+   else
+   {
+      m_bSuccess = false;
+      KIO::SimpleJob* pJob = KIO::rmdir( dirURL );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop(pJob, i18n("Removing directory: %1").arg(dirName));
+      return m_bSuccess;
+   }
+}
+
+bool FileAccessJobHandler::removeFile( const QString& fileName )
+{
+   if ( fileName.isEmpty() )
+      return false;
+   else
+   {
+      m_bSuccess = false;
+      KIO::SimpleJob* pJob = KIO::file_delete( KURL::fromPathOrURL(fileName), false );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop( pJob, i18n("Removing file: %1").arg(fileName) );
+      return m_bSuccess;
+   }
+}
+
+bool FileAccessJobHandler::symLink( const QString& linkTarget, const QString& linkLocation )
+{
+   if ( linkTarget.isEmpty() || linkLocation.isEmpty() )
+      return false;
+   else
+   {
+      m_bSuccess = false;
+      KIO::CopyJob* pJob = KIO::link( KURL::fromPathOrURL(linkTarget), KURL::fromPathOrURL(linkLocation), false );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop( pJob,
+         i18n("Creating symbolic link: %1 -> %2").arg(linkLocation).arg(linkTarget) );
+      return m_bSuccess;
+   }
+}
+
+bool FileAccessJobHandler::rename( const QString& dest )
+{
+   KURL kurl = KURL::fromPathOrURL( dest );
+   if ( dest.isEmpty() )
+      return false;
+   else if ( m_pFileAccess->isLocal() && kurl.isLocalFile() )
+   {
+      return QDir().rename( m_pFileAccess->absFilePath(), kurl.path() );
+   }
+   else
+   {
+      bool bOverwrite = false;
+      bool bResume = false;
+      bool bShowProgress = false;
+      int permissions=-1;
+      m_bSuccess = false;
+      KIO::FileCopyJob* pJob = KIO::file_move( m_pFileAccess->m_url, kurl, 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( pJob,
+         i18n("Renaming file: %1 -> %2").arg(m_pFileAccess->prettyAbsPath()).arg(dest) );
+      return m_bSuccess;
+   }
+}
+
+void FileAccessJobHandler::slotSimpleJobResult(KIO::Job* pJob)
+{
+   if ( pJob->error() )
+   {
+      pJob->showErrorDialog(g_pProgressDialog);
+   }
+   else
+   {
+      m_bSuccess = true;
+   }
+   g_pProgressDialog->exitEventLoop();  // Close the dialog, return from exec()
+}
+
+
+// Copy local or remote files.
+bool FileAccessJobHandler::copyFile( const QString& dest )
+{
+   ProgressProxy pp;
+   KURL destUrl = KURL::fromPathOrURL( dest );
+   m_pFileAccess->m_statusText = QString();
+   if ( ! m_pFileAccess->isLocal() || ! destUrl.isLocalFile() ) // if either url is nonlocal
+   {
+      bool bOverwrite = false;
+      bool bResume = false;
+      bool bShowProgress = false;
+      int permissions = (m_pFileAccess->isExecutable()?0111:0)+(m_pFileAccess->isWritable()?0222:0)+(m_pFileAccess->isReadable()?0444:0);
+      m_bSuccess = false;
+      KIO::FileCopyJob* pJob = KIO::file_copy ( m_pFileAccess->m_url, destUrl, 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( 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.
+   }
+
+   // Both files are local:
+   QString srcName = m_pFileAccess->absFilePath();
+   QString destName = dest;
+   QFile srcFile( srcName );
+   QFile destFile( destName );
+   bool bReadSuccess = srcFile.open( IO_ReadOnly );
+   if ( bReadSuccess == false )
+   {
+      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 = i18n("Error during file copy operation: Opening file for writing failed. Filename: %1").arg(destName);
+      return false;
+   }
+
+#if QT_VERSION==230
+   typedef long Q_LONG;
+#endif
+   std::vector<char> buffer(100000);
+   Q_LONG bufSize = buffer.size();
+   Q_LONG srcSize = srcFile.size();
+   while ( srcSize > 0 && !pp.wasCancelled() )
+   {
+      Q_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) );
+      if ( readSize==-1 || readSize==0 )
+      {
+         m_pFileAccess->m_statusText = i18n("Error during file copy operation: Reading failed. Filename: %1").arg(srcName);
+         return false;
+      }
+      srcSize -= readSize;
+      while ( readSize > 0 )
+      {
+         Q_LONG writeSize = destFile.writeBlock( &buffer[0], readSize );
+         if ( writeSize==-1 || writeSize==0 )
+         {
+            m_pFileAccess->m_statusText = i18n("Error during file copy operation: Writing failed. Filename: %1").arg(destName);
+            return false;
+         }
+         readSize -= writeSize;
+      }
+      destFile.flush();
+      pp.setCurrent( (double)(srcFile.size()-srcSize)/srcFile.size(), false );
+   }
+   srcFile.close();
+   destFile.close();
+
+   // Update the times of the destFile
+#ifdef _WIN32
+   struct _stat srcFileStatus;
+   int statResult = ::_stat( srcName.ascii(), &srcFileStatus );
+   if (statResult==0)
+   {
+      _utimbuf destTimes;
+      destTimes.actime = srcFileStatus.st_atime;/* time of last access */
+      destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */
+
+      _utime ( destName.ascii(), &destTimes );
+      _chmod ( destName.ascii(), srcFileStatus.st_mode );
+   }
+#else
+   struct stat srcFileStatus;
+   int statResult = ::stat( srcName.ascii(), &srcFileStatus );
+   if (statResult==0)
+   {
+      utimbuf destTimes;
+      destTimes.actime = srcFileStatus.st_atime;/* time of last access */
+      destTimes.modtime = srcFileStatus.st_mtime;/* time of last modification */
+
+      utime ( destName.ascii(), &destTimes );
+      chmod ( destName.ascii(), srcFileStatus.st_mode );
+   }
+#endif
+   return true;
+}
+
+bool wildcardMultiMatch( const QString& wildcard, const QString& testString, bool bCaseSensitive )
+{
+   QStringList sl = QStringList::split( ";", wildcard );
+
+   for ( QStringList::Iterator it = sl.begin(); it != sl.end(); ++it )
+   {
+      QRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/);
+      if ( pattern.exactMatch( testString ) )
+         return true;
+   }
+
+   return false;
+}
+
+
+// class CvsIgnoreList from Cervisia cvsdir.cpp
+//    Copyright (C) 1999-2002 Bernd Gehrmann <bernd at mail.berlios.de>
+// with elements from class StringMatcher
+//    Copyright (c) 2003 Andr�Woebeking <Woebbeking at web.de>
+// Modifications for KDiff3 by Joachim Eibl
+class CvsIgnoreList
+{
+public:
+    CvsIgnoreList(){}
+    void init(FileAccess& dir, bool bUseLocalCvsIgnore );
+    bool matches(const QString& fileName, bool bCaseSensitive ) const;
+
+private:
+    void addEntriesFromString(const QString& str);
+    void addEntriesFromFile(const QString& name);
+    void addEntry(const QString& entry);
+
+    QStringList m_exactPatterns;
+    QStringList m_startPatterns;
+    QStringList m_endPatterns;
+    QStringList m_generalPatterns;
+};
+
+
+void CvsIgnoreList::init( FileAccess& dir, bool bUseLocalCvsIgnore )
+{
+   static const char *ignorestr = ". .. core RCSLOG tags TAGS RCS SCCS .make.state "
+           ".nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj "
+           "*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
+
+   addEntriesFromString(QString::fromLatin1(ignorestr));
+   addEntriesFromFile(QDir::homeDirPath() + "/.cvsignore");
+   addEntriesFromString(QString::fromLocal8Bit(::getenv("CVSIGNORE")));
+
+   if (bUseLocalCvsIgnore)
+   {
+      FileAccess file(dir);
+      file.addPath( ".cvsignore" );
+      int size = file.exists() ? file.sizeForReading() : 0;
+      if ( size>0 )
+      {
+         char* buf=new char[size];
+         if (buf!=0)
+         {
+            file.readFile( buf, size );
+            int pos1 = 0;
+            for ( int pos = 0; pos<=size; ++pos )
+            {
+               if( pos==size || buf[pos]==' ' || buf[pos]=='\t' || buf[pos]=='\n' || buf[pos]=='\r' )
+               {
+                  if (pos>pos1)
+                  {
+                     addEntry( QString::fromLatin1( &buf[pos1], pos-pos1 ) );
+                  }
+                  ++pos1;
+               }
+            }
+            delete buf;
+         }
+      }
+   }
+}
+
+
+void CvsIgnoreList::addEntriesFromString(const QString& str)
+{
+    int posLast(0);
+    int pos;
+    while ((pos = str.find(' ', posLast)) >= 0)
+    {
+        if (pos > posLast)
+            addEntry(str.mid(posLast, pos - posLast));
+        posLast = pos + 1;
+    }
+
+    if (posLast < static_cast<int>(str.length()))
+        addEntry(str.mid(posLast));
+}
+
+
+void CvsIgnoreList::addEntriesFromFile(const QString &name)
+{
+    QFile file(name);
+
+    if( file.open(IO_ReadOnly) )
+    {
+        QTextStream stream(&file);
+        while( !stream.eof() )
+        {
+            addEntriesFromString(stream.readLine());
+        }
+    }
+}
+
+void CvsIgnoreList::addEntry(const QString& pattern)
+{
+   if (pattern != QString("!"))
+   {
+      if (pattern.isEmpty())    return;
+
+      // The general match is general but slow.
+      // Special tests for '*' and '?' at the beginning or end of a pattern
+      // allow fast checks.
+
+      // Count number of '*' and '?'
+      unsigned int nofMetaCharacters = 0;
+
+      const QChar* pos;
+      pos = pattern.unicode();
+      const QChar* posEnd;
+      posEnd=pos + pattern.length();
+      while (pos < posEnd)
+      {
+         if( *pos==QChar('*') || *pos==QChar('?') )  ++nofMetaCharacters;
+         ++pos;
+      }
+
+      if ( nofMetaCharacters==0 )
+      {
+         m_exactPatterns.append(pattern);
+      }
+      else if ( nofMetaCharacters==1 )
+      {
+         if ( pattern.constref(0) == QChar('*') )
+         {
+            m_endPatterns.append( pattern.right( pattern.length() - 1) );
+         }
+         else if (pattern.constref(pattern.length() - 1) == QChar('*'))
+         {
+            m_startPatterns.append( pattern.left( pattern.length() - 1) );
+         }
+         else
+         {
+            m_generalPatterns.append(pattern.local8Bit());
+         }
+      }
+      else
+      {
+         m_generalPatterns.append(pattern.local8Bit());
+      }
+   }
+   else
+   {
+      m_exactPatterns.clear();
+      m_startPatterns.clear();
+      m_endPatterns.clear();
+      m_generalPatterns.clear();
+   }
+}
+
+bool CvsIgnoreList::matches(const QString& text, bool bCaseSensitive ) const
+{
+    if (m_exactPatterns.find(text) != m_exactPatterns.end())
+    {
+        return true;
+    }
+
+    QStringList::ConstIterator it;
+    QStringList::ConstIterator itEnd;
+    for ( it=m_startPatterns.begin(), itEnd=m_startPatterns.end(); it != itEnd; ++it)
+    {
+        if (text.startsWith(*it))
+        {
+            return true;
+        }
+    }
+
+    for ( it = m_endPatterns.begin(), itEnd=m_endPatterns.end(); it != itEnd; ++it)
+    {
+        if (text.mid( text.length() - (*it).length() )==*it)  //(text.endsWith(*it))
+        {
+            return true;
+        }
+    }
+
+    /*
+    for (QValueList<QCString>::const_iterator it(m_generalPatterns.begin()),
+                                              itEnd(m_generalPatterns.end());
+         it != itEnd; ++it)
+    {
+        if (::fnmatch(*it, text.local8Bit(), FNM_PATHNAME) == 0)
+        {
+            return true;
+        }
+    }
+    */
+
+
+   for ( it = m_generalPatterns.begin(); it != m_generalPatterns.end(); ++it )
+   {
+      QRegExp pattern( *it, bCaseSensitive, true /*wildcard mode*/);
+#if QT_VERSION==230
+      int len=0;
+      if ( pattern.match( text, 0, &len )!=-1 && len==text.length())
+         return true;
+#else
+      if ( pattern.exactMatch( text ) )
+         return true;
+#endif
+   }
+
+   return false;
+}
+
+static QString nicePath( const QFileInfo& fi )
+{
+   QString fp = fi.filePath();
+   if ( fp.length()>2 && fp[0] == '.' && fp[1] == '/' )
+   {
+      return fp.mid(2);
+   }
+   return fp;
+}
+
+static bool cvsIgnoreExists( t_DirectoryList* pDirList )
+{
+   t_DirectoryList::iterator i;
+   for( i = pDirList->begin(); i!=pDirList->end(); ++i )
+   {
+      if ( i->fileName()==".cvsignore" )
+         return true;
+   }
+   return false;
+}
+
+bool FileAccessJobHandler::listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden, const QString& filePattern,
+   const QString& fileAntiPattern, const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore )
+{
+   ProgressProxy pp;
+   m_pDirList = pDirList;
+   m_pDirList->clear();
+   m_bFindHidden = bFindHidden;
+   m_bRecursive = bRecursive;
+   m_bFollowDirLinks = bFollowDirLinks;  // Only relevant if bRecursive==true.
+   m_fileAntiPattern = fileAntiPattern;
+   m_filePattern = filePattern;
+   m_dirAntiPattern = dirAntiPattern;
+
+   if ( pp.wasCancelled() )
+      return true; // Cancelled is not an error.
+
+   pp.setInformation( i18n("Reading directory: ") + m_pFileAccess->absFilePath(), 0, false );
+
+   if( m_pFileAccess->isLocal() )
+   {
+      QString currentPath = QDir::currentDirPath();
+      m_bSuccess = QDir::setCurrent( m_pFileAccess->absFilePath() );
+      if ( m_bSuccess )
+      {
+#ifndef _WIN32
+         m_bSuccess = true;
+         QDir dir( "." );
+
+         dir.setSorting( QDir::Name | QDir::DirsFirst );
+         dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
+         dir.setMatchAllDirs( true );
+
+         const QFileInfoList *fiList = dir.entryInfoList();
+         if ( fiList == 0 )
+         {
+            // No Permission to read directory or other error.
+            m_bSuccess = false;
+         }
+         else
+         {
+            QFileInfoListIterator it( *fiList );      // create list iterator
+            for ( ; it.current() != 0; ++it )       // for each file...
+            {
+               QFileInfo* fi = it.current();
+               if ( fi->fileName() == "." ||  fi->fileName()==".." )
+                  continue;
+
+               pDirList->push_back( FileAccess( nicePath(*fi) ) );
+            }
+         }
+#else
+         QString pattern ="*.*";
+         WIN32_FIND_DATA findData;
+         WIN32_FIND_DATAA& findDataA=*(WIN32_FIND_DATAA*)&findData;  // Needed for Win95
+
+         HANDLE searchHandle = QT_WA_INLINE(
+                 FindFirstFile( (TCHAR*)pattern.ucs2(), &findData ),
+                 FindFirstFileA( pattern.local8Bit(), &findDataA )
+              );
+
+         if ( searchHandle != INVALID_HANDLE_VALUE )
+         {
+            QString absPath = m_pFileAccess->absFilePath();
+            QString relPath = m_pFileAccess->filePath();
+            bool bFirst=true;
+            while( ! pp.wasCancelled() )
+            {
+               if (!bFirst)
+               {
+                  if ( ! QT_WA_INLINE(
+                            FindNextFile(searchHandle,&findData),
+                            FindNextFileA(searchHandle,&findDataA)) )
+                     break;
+               }
+               bFirst = false;
+               FileAccess fa;
+               fa.m_size = findData.nFileSizeLow ;//+ findData.nFileSizeHigh;
+
+               FILETIME ft;
+               SYSTEMTIME t;
+               FileTimeToLocalFileTime( &findData.ftLastWriteTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_modificationTime = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+               FileTimeToLocalFileTime( &findData.ftLastAccessTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_accessTime       = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+               FileTimeToLocalFileTime( &findData.ftCreationTime, &ft ); FileTimeToSystemTime(&ft,&t);
+               fa.m_creationTime     = QDateTime( QDate(t.wYear, t.wMonth, t.wDay), QTime(t.wHour, t.wMinute, t.wSecond) );
+
+               int  a = findData.dwFileAttributes;
+               fa.m_bWritable   = ( a & FILE_ATTRIBUTE_READONLY) == 0;
+               fa.m_bDir        = ( a & FILE_ATTRIBUTE_DIRECTORY ) != 0;
+               fa.m_bFile       = !fa.m_bDir;
+               fa.m_bHidden     = ( a & FILE_ATTRIBUTE_HIDDEN) != 0;
+
+               fa.m_bExecutable = false; // Useless on windows
+               fa.m_bExists     = true;
+               fa.m_bReadable   = true;
+               fa.m_bLocal      = true;
+               fa.m_bValidData  = true;
+               fa.m_bSymLink    = false;
+               fa.m_fileType    = 0;
+
+               fa.m_name = QT_WA_INLINE(
+                  QString::fromUcs2((const ushort*)findData.cFileName),
+                  QString::fromLocal8Bit(findDataA.cFileName)
+                  );
+
+               fa.m_path = fa.m_name;
+               fa.m_absFilePath = absPath + "/" + fa.m_name;
+               fa.m_url.setPath( fa.m_absFilePath );
+               if ( fa.m_name!="." && fa.m_name!=".." )
+                  pDirList->push_back( fa );
+            }
+            FindClose( searchHandle );
+         }
+         else
+         {
+            QDir::setCurrent( currentPath ); // restore current path
+            return false;
+         }
+#endif
+      }
+      QDir::setCurrent( currentPath ); // restore current path
+   }
+   else
+   {
+      bool bShowProgress = false;
+
+      KIO::ListJob* pListJob=0;
+      pListJob = KIO::listDir( m_pFileAccess->m_url, bShowProgress, true /*bFindHidden*/ );
+
+      m_bSuccess = false;
+      if ( pListJob!=0 )
+      {
+         connect( pListJob, SIGNAL( entries( KIO::Job *, const KIO::UDSEntryList& ) ),
+                  this,     SLOT( slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& )) );
+         connect( pListJob, SIGNAL( result( KIO::Job* )),
+                  this,     SLOT( slotSimpleJobResult(KIO::Job*) ) );
+
+         connect( pListJob, SIGNAL( infoMessage(KIO::Job*, const QString&)),
+                  this,     SLOT( slotListDirInfoMessage(KIO::Job*, const QString&) ));
+
+         // 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( pListJob,
+            i18n("Listing directory: %1").arg(m_pFileAccess->prettyAbsPath()) );
+      }
+   }
+
+   CvsIgnoreList cvsIgnoreList;
+   if ( bUseCvsIgnore )
+   {
+      cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) );
+   }
+#ifdef _WIN32
+   bool bCaseSensitive = false;
+#else
+   bool bCaseSensitive = true;
+#endif
+
+   // Now remove all entries that don't match:
+   t_DirectoryList::iterator i;
+   for( i = pDirList->begin(); i!=pDirList->end();  )
+   {
+      t_DirectoryList::iterator i2=i;
+      ++i2;
+      QString fn = i->fileName();
+      if (  (!bFindHidden && i->isHidden() )
+            ||
+            (i->isFile() &&
+               ( !wildcardMultiMatch( filePattern, i->fileName(), bCaseSensitive ) ||
+                 wildcardMultiMatch( fileAntiPattern, i->fileName(), bCaseSensitive ) ) )
+            ||
+            (i->isDir() && wildcardMultiMatch( dirAntiPattern, i->fileName(), bCaseSensitive ) )
+            ||
+            cvsIgnoreList.matches( i->fileName(), bCaseSensitive )
+         )
+      {
+         // Remove it
+         pDirList->erase( i );
+         i = i2;
+      }
+      else
+      {
+         ++i;
+      }
+   }
+
+   if ( bRecursive )
+   {
+      t_DirectoryList subDirsList;
+
+      t_DirectoryList::iterator i;
+      for( i = m_pDirList->begin(); i!=m_pDirList->end(); ++i )
+      {
+         if  ( i->isDir() && (!i->isSymLink() || m_bFollowDirLinks))
+         {
+            t_DirectoryList dirList;
+            i->listDir( &dirList, bRecursive, bFindHidden,
+               filePattern, fileAntiPattern, dirAntiPattern, bFollowDirLinks, bUseCvsIgnore );
+
+            t_DirectoryList::iterator j;
+            for( j = dirList.begin(); j!=dirList.end(); ++j )
+            {
+               j->m_path = i->fileName() + "/" + j->m_path;
+            }
+
+            // append data onto the main list
+            subDirsList.splice( subDirsList.end(), dirList );
+         }
+      }
+
+      m_pDirList->splice( m_pDirList->end(), subDirsList );
+   }
+
+   return m_bSuccess;
+}
+
+
+void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l )
+{
+   KURL parentUrl( m_pFileAccess->m_absFilePath );
+
+   KIO::UDSEntryList::ConstIterator i;
+   for ( i=l.begin(); i!=l.end(); ++i )
+   {
+      const KIO::UDSEntry& e = *i;
+      FileAccess fa;
+      fa.setUdsEntry( e );
+
+      if ( fa.filePath() != "." && fa.filePath() != ".." )
+      {
+         fa.m_url = parentUrl;
+         fa.m_url.addPath( fa.filePath() );
+         fa.m_absFilePath = fa.m_url.url();
+         m_pDirList->push_back( fa );
+      }
+   }
+}
+
+void FileAccessJobHandler::slotListDirInfoMessage( KIO::Job*, const QString& msg )
+{
+   g_pProgressDialog->setInformation( msg, 0.0 );
+}
+
+void FileAccessJobHandler::slotPercent( KIO::Job*, unsigned long percent )
+{
+   g_pProgressDialog->setCurrent( percent/100.0 );
+}
+
+
+ProgressDialog::ProgressDialog( QWidget* pParent )
+: QDialog( pParent, 0, true )
+{
+   QVBoxLayout* layout = new QVBoxLayout(this);
+
+   m_pInformation = new QLabel( " ", this );
+   layout->addWidget( m_pInformation );
+
+   m_pProgressBar = new KProgress(1000, this);
+   layout->addWidget( m_pProgressBar );
+
+   m_pSubInformation = new QLabel( " ", this);
+   layout->addWidget( m_pSubInformation );
+
+   m_pSubProgressBar = new KProgress(1000, this);
+   layout->addWidget( m_pSubProgressBar );
+
+   m_pSlowJobInfo = new QLabel( " ", this);
+   layout->addWidget( m_pSlowJobInfo );
+
+   QHBoxLayout* hlayout = new QHBoxLayout( layout );
+   hlayout->addStretch(1);
+   m_pAbortButton = new QPushButton( i18n("&Cancel"), this);
+   hlayout->addWidget( m_pAbortButton );
+   connect( m_pAbortButton, SIGNAL(clicked()), this, SLOT(slotAbort()) );
+
+   m_progressDelayTimer = 0;
+   resize( 400, 100 );
+   m_t1.start();
+   m_t2.start();
+   m_bWasCancelled = false;
+   m_pJob = 0;
+}
+
+void ProgressDialog::push()
+{
+   ProgressLevelData pld;
+   if ( !m_progressStack.empty() )
+   {
+      pld.m_dRangeMax = m_progressStack.back().m_dSubRangeMax;
+      pld.m_dRangeMin = m_progressStack.back().m_dSubRangeMin;
+   }
+   else
+   {
+      m_bWasCancelled = false;
+      m_t1.restart();
+      m_t2.restart();
+      show();
+   }
+
+   m_progressStack.push_back( pld );
+}
+
+void ProgressDialog::pop( bool bRedrawUpdate )
+{
+   if ( !m_progressStack.empty() )
+   {
+      m_progressStack.pop_back();
+      if ( m_progressStack.empty() )
+         hide();
+      else
+         recalc(bRedrawUpdate);
+   }
+}
+
+void ProgressDialog::setInformation(const QString& info, double dCurrent, bool bRedrawUpdate )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_dCurrent = dCurrent;
+   int level = m_progressStack.size();
+   if ( level==1 )
+   {
+      m_pInformation->setText( info );
+      m_pSubInformation->setText("");
+   }
+   else if ( level==2 )
+   {
+      m_pSubInformation->setText( info );
+   }
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setInformation(const QString& info, bool bRedrawUpdate )
+{
+   if ( m_progressStack.empty() )
+      return;
+   //ProgressLevelData& pld = m_progressStack.back();
+   int level = m_progressStack.size();
+   if ( level==1 )
+   {
+      m_pInformation->setText( info );
+      m_pSubInformation->setText( "" );
+   }
+   else if ( level==2 )
+   {
+      m_pSubInformation->setText( info );
+   }
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setMaxNofSteps( int maxNofSteps )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_maxNofSteps = maxNofSteps;
+   pld.m_dCurrent = 0;
+}
+
+void ProgressDialog::step( bool bRedrawUpdate )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_dCurrent += 1.0/pld.m_maxNofSteps;
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setCurrent( double dSubCurrent, bool bRedrawUpdate )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_dCurrent = dSubCurrent;
+   recalc( bRedrawUpdate );
+}
+
+// The progressbar goes from 0 to 1 usually.
+// By supplying a subrange transformation the subCurrent-values
+// 0 to 1 will be transformed to dMin to dMax instead.
+// Requirement: 0 < dMin < dMax < 1
+void ProgressDialog::setRangeTransformation( double dMin, double dMax )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_dRangeMin = dMin;
+   pld.m_dRangeMax = dMax;
+   pld.m_dCurrent = 0;
+}
+
+void ProgressDialog::setSubRangeTransformation( double dMin, double dMax )
+{
+   if ( m_progressStack.empty() )
+      return;
+   ProgressLevelData& pld = m_progressStack.back();
+   pld.m_dSubRangeMin = dMin;
+   pld.m_dSubRangeMax = dMax;
+}
+
+void qt_enter_modal(QWidget*);
+void qt_leave_modal(QWidget*);
+
+void ProgressDialog::enterEventLoop( KIO::Job* pJob, const QString& jobInfo )
+{
+   m_pJob = pJob;
+   m_pSlowJobInfo->setText("");
+   m_currentJobInfo = jobInfo;
+   killTimer( m_progressDelayTimer );
+   m_progressDelayTimer = 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();
+#else
+   qt_enter_modal(this);
+   qApp->eventLoop()->enterLoop();
+   qt_leave_modal(this);
+#endif
+}
+
+void ProgressDialog::exitEventLoop()
+{
+   killTimer( m_progressDelayTimer );
+   m_progressDelayTimer = 0;
+   m_pJob = 0;
+   qApp->eventLoop()->exitLoop();
+}
+
+void ProgressDialog::recalc( bool bUpdate )
+{
+   killTimer( m_progressDelayTimer );
+   m_progressDelayTimer = startTimer( 3000 ); /* 3 s delay */
+
+   int level = m_progressStack.size();
+   if( ( bUpdate && level==1) || m_t1.elapsed()>200 )
+   {
+      if (m_progressStack.empty() )
+      {
+         m_pProgressBar->setProgress( 0 );
+         m_pSubProgressBar->setProgress( 0 );
+      }
+      else
+      {
+         std::list<ProgressLevelData>::iterator i = m_progressStack.begin();
+         m_pProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) );
+         ++i;
+         if ( i!=m_progressStack.end() )
+            m_pSubProgressBar->setProgress( int( 1000.0 * ( i->m_dCurrent * (i->m_dRangeMax - i->m_dRangeMin) + i->m_dRangeMin ) ) );
+         else
+            m_pSubProgressBar->setProgress( int( 1000.0 * m_progressStack.front().m_dSubRangeMin ) );
+      }
+
+      if ( !isVisible() ) show();
+      qApp->processEvents();
+      m_t1.restart();
+   }
+}
+
+
+#include <qtimer.h>
+void ProgressDialog::show()
+{
+   killTimer( m_progressDelayTimer );
+   m_progressDelayTimer = 0;
+   if ( !isVisible() && (parentWidget()==0 || parentWidget()->isVisible()) )
+   {
+#if QT_VERSION==230
+      QWidget::show();
+#else
+      QDialog::show();
+#endif
+   }
+}
+
+void ProgressDialog::hide()
+{
+   killTimer( m_progressDelayTimer );
+   m_progressDelayTimer = 0;
+   // 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_progressStack.clear();
+
+   m_pProgressBar->setProgress( 0 );
+   m_pSubProgressBar->setProgress( 0 );
+   m_pSubInformation->setText("");
+   m_pSlowJobInfo->setText("");
+}
+
+void ProgressDialog::reject()
+{
+   m_bWasCancelled = true;
+   QDialog::reject();
+}
+
+void ProgressDialog::slotAbort()
+{
+   reject();
+}
+
+bool ProgressDialog::wasCancelled()
+{
+   if( m_t2.elapsed()>100 )
+   {
+      qApp->processEvents();
+      m_t2.restart();
+   }
+   return m_bWasCancelled;
+}
+
+
+void ProgressDialog::timerEvent(QTimerEvent*)
+{
+   if( !isVisible() )
+   {
+      show();
+   }
+   m_pSlowJobInfo->setText( m_currentJobInfo );
+}
+
+
+ProgressProxy::ProgressProxy()
+{
+   g_pProgressDialog->push();
+}
+
+ProgressProxy::~ProgressProxy()
+{
+   g_pProgressDialog->pop(false);
+}
+
+void ProgressProxy::setInformation( const QString& info, bool bRedrawUpdate )
+{
+   g_pProgressDialog->setInformation( info, bRedrawUpdate );
+}
+
+void ProgressProxy::setInformation( const QString& info, double dCurrent, bool bRedrawUpdate )
+{
+   g_pProgressDialog->setInformation( info, dCurrent, bRedrawUpdate );
+}
+
+void ProgressProxy::setCurrent( double dCurrent, bool bRedrawUpdate  )
+{
+   g_pProgressDialog->setCurrent( dCurrent, bRedrawUpdate );
+}
+
+void ProgressProxy::step( bool bRedrawUpdate )
+{
+   g_pProgressDialog->step( bRedrawUpdate );
+}
+
+void ProgressProxy::setMaxNofSteps( int maxNofSteps )
+{
+   g_pProgressDialog->setMaxNofSteps( maxNofSteps );
+}
+
+bool ProgressProxy::wasCancelled()
+{
+   return g_pProgressDialog->wasCancelled();
+}
+
+void ProgressProxy::setRangeTransformation( double dMin, double dMax )
+{
+   g_pProgressDialog->setRangeTransformation( dMin, dMax );
+}
+
+void ProgressProxy::setSubRangeTransformation( double dMin, double dMax )
+{
+   g_pProgressDialog->setSubRangeTransformation( dMin, dMax );
+}
+
+
+
+
+
+#include "fileaccess.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/fileaccess.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,263 @@
+/***************************************************************************
+ *   Copyright (C) 2003-2006 by Joachim Eibl                               *
+ *   joachim.eibl at gmx.de                                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ ***************************************************************************/
+
+#ifndef FILEACCESS_H
+#define FILEACCESS_H
+
+#include <qdialog.h>
+#include <qfileinfo.h>
+#include <kprogress.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kurldrag.h>
+#include <list>
+#include <qstring.h>
+#include <qdatetime.h>
+
+bool wildcardMultiMatch( const QString& wildcard, const QString& testString, bool bCaseSensitive );
+
+class t_DirectoryList;
+
+class FileAccess
+{
+public:
+   FileAccess();
+   ~FileAccess();
+   FileAccess( const QString& name, bool bWantToWrite=false ); // name: local file or dirname or url (when supported)
+   void setFile( const QString& name, bool bWantToWrite=false );
+
+   bool isValid() const;
+   bool isFile() const;
+   bool isDir() const;
+   bool isSymLink() const;
+   bool exists() const;
+   long size() const;            // Size as returned by stat().
+   long sizeForReading();  // If the size can't be determined by stat() then the file is copied to a local temp file.
+   bool isReadable() const;
+   bool isWritable() const;
+   bool isExecutable() const;
+   bool isHidden() const;
+   QString readLink() const;
+
+   QDateTime   created()       const;
+   QDateTime   lastModified()  const;
+   QDateTime   lastRead()      const;
+
+   QString fileName() const; // Just the name-part of the path, without parent directories
+   QString filePath() const; // The path-string that was used during construction
+   QString prettyAbsPath() const;
+   KURL url() const;
+   QString absFilePath() const;
+
+   bool isLocal() const;
+
+   bool readFile(void* pDestBuffer, unsigned long maxLength );
+   bool writeFile(const void* pSrcBuffer, unsigned long length );
+   bool listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
+                 const QString& filePattern, const QString& fileAntiPattern,
+                 const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore );
+   bool copyFile( const QString& destUrl );
+   bool createBackup( const QString& bakExtension );
+
+   static QString tempFileName();
+   static bool removeTempFile( const QString& );
+   bool removeFile();
+   static bool removeFile( const QString& );
+   static bool makeDir( const QString& );
+   static bool removeDir( const QString& );
+   static bool exists( const QString& );
+   static QString cleanDirPath( const QString& );
+
+   //bool chmod( const QString& );
+   bool rename( const QString& );
+   static bool symLink( const QString& linkTarget, const QString& linkLocation );
+
+   void addPath( const QString& txt );
+   QString getStatusText();
+private:
+   void setUdsEntry( const KIO::UDSEntry& e );
+   KURL m_url;
+   bool m_bLocal;
+   bool m_bValidData;
+
+   unsigned long m_size;
+   QDateTime m_modificationTime;
+   QDateTime m_accessTime;
+   QDateTime m_creationTime;
+   bool m_bReadable;
+   bool m_bWritable;
+   bool m_bExecutable;
+   bool m_bExists;
+   bool m_bFile;
+   bool m_bDir;
+   bool m_bSymLink;
+   bool m_bHidden;
+   long m_fileType; // for testing only
+
+   QString m_linkTarget;
+   QString m_user;
+   QString m_group;
+   QString m_name;
+   QString m_path;
+   QString m_absFilePath;
+   QString m_localCopy;
+   QString m_statusText;  // Might contain an error string, when the last operation didn't succeed.
+
+   friend class FileAccessJobHandler;
+};
+
+class t_DirectoryList : public std::list<FileAccess>
+{};
+
+
+class FileAccessJobHandler : public QObject
+{
+   Q_OBJECT
+public:
+   FileAccessJobHandler( FileAccess* pFileAccess );
+
+   bool get( void* pDestBuffer, long maxLength );
+   bool put( const void* pSrcBuffer, long maxLength, bool bOverwrite, bool bResume=false, int permissions=-1 );
+   bool stat(int detailLevel=2, bool bWantToWrite=false );
+   bool copyFile( const QString& dest );
+   bool rename( const QString& dest );
+   bool listDir( t_DirectoryList* pDirList, bool bRecursive, bool bFindHidden,
+                 const QString& filePattern, const QString& fileAntiPattern,
+                 const QString& dirAntiPattern, bool bFollowDirLinks, bool bUseCvsIgnore );
+   bool mkDir( const QString& dirName );
+   bool rmDir( const QString& dirName );
+   bool removeFile( const QString& dirName );
+   bool symLink( const QString& linkTarget, const QString& linkLocation );
+
+private:
+   FileAccess* m_pFileAccess;
+   bool m_bSuccess;
+
+   // Data needed during Job
+   long m_transferredBytes;
+   char* m_pTransferBuffer;  // Needed during get or put
+   long m_maxLength;
+
+   QString m_filePattern;
+   QString m_fileAntiPattern;
+   QString m_dirAntiPattern;
+   t_DirectoryList* m_pDirList;
+   bool m_bFindHidden;
+   bool m_bRecursive;
+   bool m_bFollowDirLinks;
+
+   bool scanLocalDirectory( const QString& dirName, t_DirectoryList* dirList );
+
+private slots:
+   void slotStatResult( KIO::Job* );
+   void slotSimpleJobResult( KIO::Job* pJob );
+   void slotPutJobResult( KIO::Job* pJob );
+
+   void slotGetData(KIO::Job*,const QByteArray&);
+   void slotPutData(KIO::Job*, QByteArray&);
+
+   void slotListDirInfoMessage( KIO::Job*, const QString& msg );
+   void slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l );
+
+   void slotPercent( KIO::Job* pJob, unsigned long percent );
+};
+
+class ProgressDialog : public QDialog
+{
+   Q_OBJECT
+public:
+   ProgressDialog( QWidget* pParent );
+
+   void setInformation( const QString& info, bool bRedrawUpdate=true );
+   void setInformation( const QString& info, double dCurrent, bool bRedrawUpdate=true );
+   void setCurrent( double dCurrent, bool bRedrawUpdate=true  );
+   void step( bool bRedrawUpdate=true );
+   void setMaxNofSteps( int dMaxNofSteps );
+   void push();
+   void pop(bool bRedrawUpdate=true);
+
+   // The progressbar goes from 0 to 1 usually.
+   // By supplying a subrange transformation the subCurrent-values
+   // 0 to 1 will be transformed to dMin to dMax instead.
+   // Requirement: 0 < dMin < dMax < 1
+   void setRangeTransformation( double dMin, double dMax );
+   void setSubRangeTransformation( double dMin, double dMax );
+
+   void exitEventLoop();
+   void enterEventLoop( KIO::Job* pJob, const QString& jobInfo );
+
+   bool wasCancelled();
+   void show();
+   void hide();
+   
+   virtual void timerEvent(QTimerEvent*);
+private:
+
+   struct ProgressLevelData
+   {
+      ProgressLevelData()
+      {
+         m_dCurrent=0; m_maxNofSteps=1; m_dRangeMin=0; m_dRangeMax=1; 
+         m_dSubRangeMin = 0; m_dSubRangeMax = 1;
+      }
+      double m_dCurrent;
+      int    m_maxNofSteps;     // when step() is used.
+      double m_dRangeMax;
+      double m_dRangeMin;
+      double m_dSubRangeMax;
+      double m_dSubRangeMin;
+   };
+   std::list<ProgressLevelData> m_progressStack;
+   
+   int m_progressDelayTimer;
+
+   KProgress* m_pProgressBar;
+   KProgress* m_pSubProgressBar;
+   QLabel* m_pInformation;
+   QLabel* m_pSubInformation;
+   QLabel* m_pSlowJobInfo;
+   QPushButton* m_pAbortButton;
+   void recalc(bool bRedrawUpdate);
+   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();
+};
+
+// When using the ProgressProxy you need not take care of the push and pop, except when explicit.
+class ProgressProxy
+{
+public:
+   ProgressProxy();
+   ~ProgressProxy();
+   
+   void setInformation( const QString& info, bool bRedrawUpdate=true );
+   void setInformation( const QString& info, double dCurrent, bool bRedrawUpdate=true );
+   void setCurrent( double dCurrent, bool bRedrawUpdate=true  );
+   void step( bool bRedrawUpdate=true );
+   void setMaxNofSteps( int dMaxNofSteps );
+   bool wasCancelled();
+   void setRangeTransformation( double dMin, double dMax );
+   void setSubRangeTransformation( double dMin, double dMax );
+private:
+};
+
+extern ProgressDialog* g_pProgressDialog;
+
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/gnudiff_analyze.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,873 @@
+/* Analyze file differences for GNU DIFF.
+
+   Modified for KDiff3 by Joachim Eibl 2003.
+   The original file was part of GNU DIFF.
+
+   Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002
+   Free Software Foundation, Inc.
+
+   GNU DIFF is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU DIFF is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* The basic algorithm is described in:
+   "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+   Algorithmica Vol. 1 No. 2, 1986, pp. 251-266;
+   see especially section 4.2, which describes the variation used below.
+   Unless the --minimal option is specified, this code uses the TOO_EXPENSIVE
+   heuristic, by Paul Eggert, to limit the cost to O(N**1.5 log N)
+   at the price of producing suboptimal output for large inputs with
+   many differences.
+
+   The basic algorithm was independently discovered as described in:
+   "Algorithms for Approximate String Matching", E. Ukkonen,
+   Information and Control Vol. 64, 1985, pp. 100-118.  */
+
+#define GDIFF_MAIN
+
+#include "gnudiff_diff.h"
+//#include <error.h>
+#include <stdlib.h>
+
+static lin *xvec, *yvec;	/* Vectors being compared. */
+static lin *fdiag;		/* Vector, indexed by diagonal, containing
+				   1 + the X coordinate of the point furthest
+				   along the given diagonal in the forward
+				   search of the edit matrix. */
+static lin *bdiag;		/* Vector, indexed by diagonal, containing
+				   the X coordinate of the point furthest
+				   along the given diagonal in the backward
+				   search of the edit matrix. */
+static lin too_expensive;	/* Edit scripts longer than this are too
+				   expensive to compute.  */
+
+#define SNAKE_LIMIT 20	/* Snakes bigger than this are considered `big'.  */
+
+
+struct partition
+{
+  lin xmid, ymid;	/* Midpoints of this partition.  */
+  bool lo_minimal;	/* Nonzero if low half will be analyzed minimally.  */
+  bool hi_minimal;	/* Likewise for high half.  */
+};
+
+/* Find the midpoint of the shortest edit script for a specified
+   portion of the two files.
+
+   Scan from the beginnings of the files, and simultaneously from the ends,
+   doing a breadth-first search through the space of edit-sequence.
+   When the two searches meet, we have found the midpoint of the shortest
+   edit sequence.
+
+   If FIND_MINIMAL is nonzero, find the minimal edit script regardless
+   of expense.  Otherwise, if the search is too expensive, use
+   heuristics to stop the search and report a suboptimal answer.
+
+   Set PART->(xmid,ymid) to the midpoint (XMID,YMID).  The diagonal number
+   XMID - YMID equals the number of inserted lines minus the number
+   of deleted lines (counting only lines before the midpoint).
+   Return the approximate edit cost; this is the total number of
+   lines inserted or deleted (counting only lines before the midpoint),
+   unless a heuristic is used to terminate the search prematurely.
+
+   Set PART->lo_minimal to true iff the minimal edit script for the
+   left half of the partition is known; similarly for PART->hi_minimal.
+
+   This function assumes that the first lines of the specified portions
+   of the two files do not match, and likewise that the last lines do not
+   match.  The caller must trim matching lines from the beginning and end
+   of the portions it is going to specify.
+
+   If we return the "wrong" partitions,
+   the worst this can do is cause suboptimal diff output.
+   It cannot cause incorrect diff output.  */
+
+lin
+GnuDiff::diag (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal,
+      struct partition *part)
+{
+  lin *const fd = fdiag;	/* Give the compiler a chance. */
+  lin *const bd = bdiag;	/* Additional help for the compiler. */
+  lin const *const xv = xvec;	/* Still more help for the compiler. */
+  lin const *const yv = yvec;	/* And more and more . . . */
+  lin const dmin = xoff - ylim;	/* Minimum valid diagonal. */
+  lin const dmax = xlim - yoff;	/* Maximum valid diagonal. */
+  lin const fmid = xoff - yoff;	/* Center diagonal of top-down search. */
+  lin const bmid = xlim - ylim;	/* Center diagonal of bottom-up search. */
+  lin fmin = fmid, fmax = fmid;	/* Limits of top-down search. */
+  lin bmin = bmid, bmax = bmid;	/* Limits of bottom-up search. */
+  lin c;			/* Cost. */
+  bool odd = (fmid - bmid) & 1;	/* True if southeast corner is on an odd
+				   diagonal with respect to the northwest. */
+
+  fd[fmid] = xoff;
+  bd[bmid] = xlim;
+
+  for (c = 1;; ++c)
+    {
+      lin d;			/* Active diagonal. */
+      bool big_snake = 0;
+
+      /* Extend the top-down search by an edit step in each diagonal. */
+      fmin > dmin ? fd[--fmin - 1] = -1 : ++fmin;
+      fmax < dmax ? fd[++fmax + 1] = -1 : --fmax;
+      for (d = fmax; d >= fmin; d -= 2)
+	{
+	  lin x, y, oldx, tlo = fd[d - 1], thi = fd[d + 1];
+
+	  if (tlo >= thi)
+	    x = tlo + 1;
+	  else
+	    x = thi;
+	  oldx = x;
+	  y = x - d;
+	  while (x < xlim && y < ylim && xv[x] == yv[y])
+	    ++x, ++y;
+	  if (x - oldx > SNAKE_LIMIT)
+	    big_snake = 1;
+	  fd[d] = x;
+	  if (odd && bmin <= d && d <= bmax && bd[d] <= x)
+	    {
+	      part->xmid = x;
+	      part->ymid = y;
+	      part->lo_minimal = part->hi_minimal = 1;
+	      return 2 * c - 1;
+	    }
+	}
+
+      /* Similarly extend the bottom-up search.  */
+      bmin > dmin ? bd[--bmin - 1] = LIN_MAX : ++bmin;
+      bmax < dmax ? bd[++bmax + 1] = LIN_MAX : --bmax;
+      for (d = bmax; d >= bmin; d -= 2)
+	{
+	  lin x, y, oldx, tlo = bd[d - 1], thi = bd[d + 1];
+
+	  if (tlo < thi)
+	    x = tlo;
+	  else
+	    x = thi - 1;
+	  oldx = x;
+	  y = x - d;
+	  while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1])
+	    --x, --y;
+	  if (oldx - x > SNAKE_LIMIT)
+	    big_snake = 1;
+	  bd[d] = x;
+	  if (!odd && fmin <= d && d <= fmax && x <= fd[d])
+	    {
+	      part->xmid = x;
+	      part->ymid = y;
+	      part->lo_minimal = part->hi_minimal = 1;
+	      return 2 * c;
+	    }
+	}
+
+      if (find_minimal)
+	continue;
+
+      /* Heuristic: check occasionally for a diagonal that has made
+	 lots of progress compared with the edit distance.
+	 If we have any such, find the one that has made the most
+	 progress and return it as if it had succeeded.
+
+	 With this heuristic, for files with a constant small density
+	 of changes, the algorithm is linear in the file size.  */
+
+      if (200 < c && big_snake && speed_large_files)
+	{
+	  lin best;
+
+	  best = 0;
+	  for (d = fmax; d >= fmin; d -= 2)
+	    {
+	      lin dd = d - fmid;
+	      lin x = fd[d];
+	      lin y = x - d;
+	      lin v = (x - xoff) * 2 - dd;
+	      if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+		{
+		  if (v > best
+		      && xoff + SNAKE_LIMIT <= x && x < xlim
+		      && yoff + SNAKE_LIMIT <= y && y < ylim)
+		    {
+		      /* We have a good enough best diagonal;
+			 now insist that it end with a significant snake.  */
+		      int k;
+
+		      for (k = 1; xv[x - k] == yv[y - k]; k++)
+			if (k == SNAKE_LIMIT)
+			  {
+			    best = v;
+			    part->xmid = x;
+			    part->ymid = y;
+			    break;
+			  }
+		    }
+		}
+	    }
+	  if (best > 0)
+	    {
+	      part->lo_minimal = 1;
+	      part->hi_minimal = 0;
+	      return 2 * c - 1;
+	    }
+
+	  best = 0;
+	  for (d = bmax; d >= bmin; d -= 2)
+	    {
+	      lin dd = d - bmid;
+	      lin x = bd[d];
+	      lin y = x - d;
+	      lin v = (xlim - x) * 2 + dd;
+	      if (v > 12 * (c + (dd < 0 ? -dd : dd)))
+		{
+		  if (v > best
+		      && xoff < x && x <= xlim - SNAKE_LIMIT
+		      && yoff < y && y <= ylim - SNAKE_LIMIT)
+		    {
+		      /* We have a good enough best diagonal;
+			 now insist that it end with a significant snake.  */
+		      int k;
+
+		      for (k = 0; xv[x + k] == yv[y + k]; k++)
+			if (k == SNAKE_LIMIT - 1)
+			  {
+			    best = v;
+			    part->xmid = x;
+			    part->ymid = y;
+			    break;
+			  }
+		    }
+		}
+	    }
+	  if (best > 0)
+	    {
+	      part->lo_minimal = 0;
+	      part->hi_minimal = 1;
+	      return 2 * c - 1;
+	    }
+	}
+
+      /* Heuristic: if we've gone well beyond the call of duty,
+	 give up and report halfway between our best results so far.  */
+      if (c >= too_expensive)
+	{
+	  lin fxybest, fxbest;
+	  lin bxybest, bxbest;
+
+	  fxbest = bxbest = 0;  /* Pacify `gcc -Wall'.  */
+
+	  /* Find forward diagonal that maximizes X + Y.  */
+	  fxybest = -1;
+	  for (d = fmax; d >= fmin; d -= 2)
+	    {
+	      lin x = MIN (fd[d], xlim);
+	      lin y = x - d;
+	      if (ylim < y)
+		x = ylim + d, y = ylim;
+	      if (fxybest < x + y)
+		{
+		  fxybest = x + y;
+		  fxbest = x;
+		}
+	    }
+
+	  /* Find backward diagonal that minimizes X + Y.  */
+	  bxybest = LIN_MAX;
+	  for (d = bmax; d >= bmin; d -= 2)
+	    {
+	      lin x = MAX (xoff, bd[d]);
+	      lin y = x - d;
+	      if (y < yoff)
+		x = yoff + d, y = yoff;
+	      if (x + y < bxybest)
+		{
+		  bxybest = x + y;
+		  bxbest = x;
+		}
+	    }
+
+	  /* Use the better of the two diagonals.  */
+	  if ((xlim + ylim) - bxybest < fxybest - (xoff + yoff))
+	    {
+	      part->xmid = fxbest;
+	      part->ymid = fxybest - fxbest;
+	      part->lo_minimal = 1;
+	      part->hi_minimal = 0;
+	    }
+	  else
+	    {
+	      part->xmid = bxbest;
+	      part->ymid = bxybest - bxbest;
+	      part->lo_minimal = 0;
+	      part->hi_minimal = 1;
+	    }
+	  return 2 * c - 1;
+	}
+    }
+}
+
+/* Compare in detail contiguous subsequences of the two files
+   which are known, as a whole, to match each other.
+
+   The results are recorded in the vectors files[N].changed, by
+   storing 1 in the element for each line that is an insertion or deletion.
+
+   The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+
+   Note that XLIM, YLIM are exclusive bounds.
+   All line numbers are origin-0 and discarded lines are not counted.
+
+   If FIND_MINIMAL, find a minimal difference no matter how
+   expensive it is.  */
+
+void GnuDiff::compareseq (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal)
+{
+  lin * const xv = xvec; /* Help the compiler.  */
+  lin * const yv = yvec;
+
+  /* Slide down the bottom initial diagonal. */
+  while (xoff < xlim && yoff < ylim && xv[xoff] == yv[yoff])
+    ++xoff, ++yoff;
+  /* Slide up the top initial diagonal. */
+  while (xlim > xoff && ylim > yoff && xv[xlim - 1] == yv[ylim - 1])
+    --xlim, --ylim;
+
+  /* Handle simple cases. */
+  if (xoff == xlim)
+    while (yoff < ylim)
+      files[1].changed[files[1].realindexes[yoff++]] = 1;
+  else if (yoff == ylim)
+    while (xoff < xlim)
+      files[0].changed[files[0].realindexes[xoff++]] = 1;
+  else
+    {
+      lin c;
+      struct partition part;
+
+      /* Find a point of correspondence in the middle of the files.  */
+
+      c = diag (xoff, xlim, yoff, ylim, find_minimal, &part);
+
+      if (c == 1)
+	{
+	  /* This should be impossible, because it implies that
+	     one of the two subsequences is empty,
+	     and that case was handled above without calling `diag'.
+	     Let's verify that this is true.  */
+	  abort ();
+#if 0
+	  /* The two subsequences differ by a single insert or delete;
+	     record it and we are done.  */
+	  if (part.xmid - part.ymid < xoff - yoff)
+	    files[1].changed[files[1].realindexes[part.ymid - 1]] = 1;
+	  else
+	    files[0].changed[files[0].realindexes[part.xmid]] = 1;
+#endif
+	}
+      else
+	{
+	  /* Use the partitions to split this problem into subproblems.  */
+	  compareseq (xoff, part.xmid, yoff, part.ymid, part.lo_minimal);
+	  compareseq (part.xmid, xlim, part.ymid, ylim, part.hi_minimal);
+	}
+    }
+}
+
+/* Discard lines from one file that have no matches in the other file.
+
+   A line which is discarded will not be considered by the actual
+   comparison algorithm; it will be as if that line were not in the file.
+   The file's `realindexes' table maps virtual line numbers
+   (which don't count the discarded lines) into real line numbers;
+   this is how the actual comparison algorithm produces results
+   that are comprehensible when the discarded lines are counted.
+
+   When we discard a line, we also mark it as a deletion or insertion
+   so that it will be printed in the output.  */
+
+void GnuDiff::discard_confusing_lines (struct file_data filevec[])
+{
+  int f;
+  lin i;
+  char *discarded[2];
+  lin *equiv_count[2];
+  lin *p;
+
+  /* Allocate our results.  */
+  p = (lin*)xmalloc ((filevec[0].buffered_lines + filevec[1].buffered_lines)
+	       * (2 * sizeof *p));
+  for (f = 0; f < 2; f++)
+    {
+      filevec[f].undiscarded = p;  p += filevec[f].buffered_lines;
+      filevec[f].realindexes = p;  p += filevec[f].buffered_lines;
+    }
+
+  /* Set up equiv_count[F][I] as the number of lines in file F
+     that fall in equivalence class I.  */
+
+  p = (lin*)zalloc (filevec[0].equiv_max * (2 * sizeof *p));
+  equiv_count[0] = p;
+  equiv_count[1] = p + filevec[0].equiv_max;
+
+  for (i = 0; i < filevec[0].buffered_lines; ++i)
+    ++equiv_count[0][filevec[0].equivs[i]];
+  for (i = 0; i < filevec[1].buffered_lines; ++i)
+    ++equiv_count[1][filevec[1].equivs[i]];
+
+  /* Set up tables of which lines are going to be discarded.  */
+
+  discarded[0] = (char*)zalloc (filevec[0].buffered_lines
+			 + filevec[1].buffered_lines);
+  discarded[1] = discarded[0] + filevec[0].buffered_lines;
+
+  /* Mark to be discarded each line that matches no line of the other file.
+     If a line matches many lines, mark it as provisionally discardable.  */
+
+  for (f = 0; f < 2; f++)
+    {
+      size_t end = filevec[f].buffered_lines;
+      char *discards = discarded[f];
+      lin *counts = equiv_count[1 - f];
+      lin *equivs = filevec[f].equivs;
+      size_t many = 5;
+      size_t tem = end / 64;
+
+      /* Multiply MANY by approximate square root of number of lines.
+	 That is the threshold for provisionally discardable lines.  */
+      while ((tem = tem >> 2) > 0)
+	many *= 2;
+
+      for (i = 0; i < (lin)end; i++)
+	{
+	  lin nmatch;
+	  if (equivs[i] == 0)
+	    continue;
+	  nmatch = counts[equivs[i]];
+	  if (nmatch == 0)
+	    discards[i] = 1;
+	  else if (nmatch > (lin)many)
+	    discards[i] = 2;
+	}
+    }
+
+  /* Don't really discard the provisional lines except when they occur
+     in a run of discardables, with nonprovisionals at the beginning
+     and end.  */
+
+  for (f = 0; f < 2; f++)
+    {
+      lin end = filevec[f].buffered_lines;
+      register char *discards = discarded[f];
+
+      for (i = 0; i < end; i++)
+	{
+	  /* Cancel provisional discards not in middle of run of discards.  */
+	  if (discards[i] == 2)
+	    discards[i] = 0;
+	  else if (discards[i] != 0)
+	    {
+	      /* We have found a nonprovisional discard.  */
+	      register lin j;
+	      lin length;
+	      lin provisional = 0;
+
+	      /* Find end of this run of discardable lines.
+		 Count how many are provisionally discardable.  */
+	      for (j = i; j < end; j++)
+		{
+		  if (discards[j] == 0)
+		    break;
+		  if (discards[j] == 2)
+		    ++provisional;
+		}
+
+	      /* Cancel provisional discards at end, and shrink the run.  */
+	      while (j > i && discards[j - 1] == 2)
+		discards[--j] = 0, --provisional;
+
+	      /* Now we have the length of a run of discardable lines
+		 whose first and last are not provisional.  */
+	      length = j - i;
+
+	      /* If 1/4 of the lines in the run are provisional,
+		 cancel discarding of all provisional lines in the run.  */
+	      if (provisional * 4 > length)
+		{
+		  while (j > i)
+		    if (discards[--j] == 2)
+		      discards[j] = 0;
+		}
+	      else
+		{
+		  register lin consec;
+		  lin minimum = 1;
+		  lin tem = length >> 2;
+
+		  /* MINIMUM is approximate square root of LENGTH/4.
+		     A subrun of two or more provisionals can stand
+		     when LENGTH is at least 16.
+		     A subrun of 4 or more can stand when LENGTH >= 64.  */
+		  while (0 < (tem >>= 2))
+		    minimum <<= 1;
+		  minimum++;
+
+		  /* Cancel any subrun of MINIMUM or more provisionals
+		     within the larger run.  */
+		  for (j = 0, consec = 0; j < length; j++)
+		    if (discards[i + j] != 2)
+		      consec = 0;
+		    else if (minimum == ++consec)
+		      /* Back up to start of subrun, to cancel it all.  */
+		      j -= consec;
+		    else if (minimum < consec)
+		      discards[i + j] = 0;
+
+		  /* Scan from beginning of run
+		     until we find 3 or more nonprovisionals in a row
+		     or until the first nonprovisional at least 8 lines in.
+		     Until that point, cancel any provisionals.  */
+		  for (j = 0, consec = 0; j < length; j++)
+		    {
+		      if (j >= 8 && discards[i + j] == 1)
+			break;
+		      if (discards[i + j] == 2)
+			consec = 0, discards[i + j] = 0;
+		      else if (discards[i + j] == 0)
+			consec = 0;
+		      else
+			consec++;
+		      if (consec == 3)
+			break;
+		    }
+
+		  /* I advances to the last line of the run.  */
+		  i += length - 1;
+
+		  /* Same thing, from end.  */
+		  for (j = 0, consec = 0; j < length; j++)
+		    {
+		      if (j >= 8 && discards[i - j] == 1)
+			break;
+		      if (discards[i - j] == 2)
+			consec = 0, discards[i - j] = 0;
+		      else if (discards[i - j] == 0)
+			consec = 0;
+		      else
+			consec++;
+		      if (consec == 3)
+			break;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Actually discard the lines. */
+  for (f = 0; f < 2; f++)
+    {
+      char *discards = discarded[f];
+      lin end = filevec[f].buffered_lines;
+      lin j = 0;
+      for (i = 0; i < end; ++i)
+	if (minimal || discards[i] == 0)
+	  {
+	    filevec[f].undiscarded[j] = filevec[f].equivs[i];
+	    filevec[f].realindexes[j++] = i;
+	  }
+	else
+	  filevec[f].changed[i] = 1;
+      filevec[f].nondiscarded_lines = j;
+    }
+
+  free (discarded[0]);
+  free (equiv_count[0]);
+}
+
+/* Adjust inserts/deletes of identical lines to join changes
+   as much as possible.
+
+   We do something when a run of changed lines include a
+   line at one end and have an excluded, identical line at the other.
+   We are free to choose which identical line is included.
+   `compareseq' usually chooses the one at the beginning,
+   but usually it is cleaner to consider the following identical line
+   to be the "change".  */
+
+void GnuDiff::shift_boundaries (struct file_data filevec[])
+{
+  int f;
+
+  for (f = 0; f < 2; f++)
+    {
+      bool *changed = filevec[f].changed;
+      bool const *other_changed = filevec[1 - f].changed;
+      lin const *equivs = filevec[f].equivs;
+      lin i = 0;
+      lin j = 0;
+      lin i_end = filevec[f].buffered_lines;
+
+      while (1)
+	{
+	  lin runlength, start, corresponding;
+
+	  /* Scan forwards to find beginning of another run of changes.
+	     Also keep track of the corresponding point in the other file.  */
+
+	  while (i < i_end && !changed[i])
+	    {
+	      while (other_changed[j++])
+		continue;
+	      i++;
+	    }
+
+	  if (i == i_end)
+	    break;
+
+	  start = i;
+
+	  /* Find the end of this run of changes.  */
+
+	  while (changed[++i])
+	    continue;
+	  while (other_changed[j])
+	    j++;
+
+	  do
+	    {
+	      /* Record the length of this run of changes, so that
+		 we can later determine whether the run has grown.  */
+	      runlength = i - start;
+
+	      /* Move the changed region back, so long as the
+		 previous unchanged line matches the last changed one.
+		 This merges with previous changed regions.  */
+
+	      while (start && equivs[start - 1] == equivs[i - 1])
+		{
+		  changed[--start] = 1;
+		  changed[--i] = 0;
+		  while (changed[start - 1])
+		    start--;
+		  while (other_changed[--j])
+		    continue;
+		}
+
+	      /* Set CORRESPONDING to the end of the changed run, at the last
+		 point where it corresponds to a changed run in the other file.
+		 CORRESPONDING == I_END means no such point has been found.  */
+	      corresponding = other_changed[j - 1] ? i : i_end;
+
+	      /* Move the changed region forward, so long as the
+		 first changed line matches the following unchanged one.
+		 This merges with following changed regions.
+		 Do this second, so that if there are no merges,
+		 the changed region is moved forward as far as possible.  */
+
+	      while (i != i_end && equivs[start] == equivs[i])
+		{
+		  changed[start++] = 0;
+		  changed[i++] = 1;
+		  while (changed[i])
+		    i++;
+		  while (other_changed[++j])
+		    corresponding = i;
+		}
+	    }
+	  while (runlength != i - start);
+
+	  /* If possible, move the fully-merged run of changes
+	     back to a corresponding run in the other file.  */
+
+	  while (corresponding < i)
+	    {
+	      changed[--start] = 1;
+	      changed[--i] = 0;
+	      while (other_changed[--j])
+		continue;
+	    }
+	}
+    }
+}
+
+/* Cons an additional entry onto the front of an edit script OLD.
+   LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+   DELETED is the number of lines deleted here from file 0.
+   INSERTED is the number of lines inserted here in file 1.
+
+   If DELETED is 0 then LINE0 is the number of the line before
+   which the insertion was done; vice versa for INSERTED and LINE1.  */
+
+GnuDiff::change* GnuDiff::add_change (lin line0, lin line1, lin deleted, lin inserted, struct change *old)
+{
+  struct change *newChange = (change*) xmalloc (sizeof *newChange);
+
+  newChange->line0 = line0;
+  newChange->line1 = line1;
+  newChange->inserted = inserted;
+  newChange->deleted = deleted;
+  newChange->link = old;
+  return newChange;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+   producing an edit script in reverse order.  */
+
+GnuDiff::change* GnuDiff::build_reverse_script (struct file_data const filevec[])
+{
+  struct change *script = 0;
+  bool *changed0 = filevec[0].changed;
+  bool *changed1 = filevec[1].changed;
+  lin len0 = filevec[0].buffered_lines;
+  lin len1 = filevec[1].buffered_lines;
+
+  /* Note that changedN[len0] does exist, and is 0.  */
+
+  lin i0 = 0, i1 = 0;
+
+  while (i0 < len0 || i1 < len1)
+    {
+      if (changed0[i0] | changed1[i1])
+	{
+	  lin line0 = i0, line1 = i1;
+
+	  /* Find # lines changed here in each file.  */
+	  while (changed0[i0]) ++i0;
+	  while (changed1[i1]) ++i1;
+
+	  /* Record this change.  */
+	  script = add_change (line0, line1, i0 - line0, i1 - line1, script);
+	}
+
+      /* We have reached lines in the two files that match each other.  */
+      i0++, i1++;
+    }
+
+  return script;
+}
+
+/* Scan the tables of which lines are inserted and deleted,
+   producing an edit script in forward order.  */
+
+GnuDiff::change* GnuDiff::build_script (struct file_data const filevec[])
+{
+  struct change *script = 0;
+  bool *changed0 = filevec[0].changed;
+  bool *changed1 = filevec[1].changed;
+  lin i0 = filevec[0].buffered_lines, i1 = filevec[1].buffered_lines;
+
+  /* Note that changedN[-1] does exist, and is 0.  */
+
+  while (i0 >= 0 || i1 >= 0)
+    {
+      if (changed0[i0 - 1] | changed1[i1 - 1])
+	{
+	  lin line0 = i0, line1 = i1;
+
+	  /* Find # lines changed here in each file.  */
+	  while (changed0[i0 - 1]) --i0;
+	  while (changed1[i1 - 1]) --i1;
+
+	  /* Record this change.  */
+	  script = add_change (i0, i1, line0 - i0, line1 - i1, script);
+	}
+
+      /* We have reached lines in the two files that match each other.  */
+      i0--, i1--;
+    }
+
+  return script;
+}
+
+
+/* Report the differences of two files.  */
+GnuDiff::change* GnuDiff::diff_2_files (struct comparison *cmp)
+{
+  lin diags;
+  int f;
+  //struct change *e, *p;
+  struct change *script;
+  int changes;
+
+  read_files (cmp->file, files_can_be_treated_as_binary);
+
+    {
+      /* Allocate vectors for the results of comparison:
+	 a flag for each line of each file, saying whether that line
+	 is an insertion or deletion.
+	 Allocate an extra element, always 0, at each end of each vector.  */
+
+      size_t s = cmp->file[0].buffered_lines + cmp->file[1].buffered_lines + 4;
+      bool *flag_space = (bool*)zalloc (s * sizeof(*flag_space));
+      cmp->file[0].changed = flag_space + 1;
+      cmp->file[1].changed = flag_space + cmp->file[0].buffered_lines + 3;
+
+      /* Some lines are obviously insertions or deletions
+	 because they don't match anything.  Detect them now, and
+	 avoid even thinking about them in the main comparison algorithm.  */
+
+      discard_confusing_lines (cmp->file);
+
+      /* Now do the main comparison algorithm, considering just the
+	 undiscarded lines.  */
+
+      xvec = cmp->file[0].undiscarded;
+      yvec = cmp->file[1].undiscarded;
+      diags = (cmp->file[0].nondiscarded_lines
+	       + cmp->file[1].nondiscarded_lines + 3);
+      fdiag = (lin*)xmalloc (diags * (2 * sizeof *fdiag));
+      bdiag = fdiag + diags;
+      fdiag += cmp->file[1].nondiscarded_lines + 1;
+      bdiag += cmp->file[1].nondiscarded_lines + 1;
+
+      /* Set TOO_EXPENSIVE to be approximate square root of input size,
+	 bounded below by 256.  */
+      too_expensive = 1;
+      for (;  diags != 0;  diags >>= 2)
+	too_expensive <<= 1;
+      too_expensive = MAX (256, too_expensive);
+
+      files[0] = cmp->file[0];
+      files[1] = cmp->file[1];
+
+      compareseq (0, cmp->file[0].nondiscarded_lines,
+		  0, cmp->file[1].nondiscarded_lines, minimal);
+
+      free (fdiag - (cmp->file[1].nondiscarded_lines + 1));
+
+      /* Modify the results slightly to make them prettier
+	 in cases where that can validly be done.  */
+
+      shift_boundaries (cmp->file);
+
+      /* Get the results of comparison in the form of a chain
+         of `struct change's -- an edit script.  */
+
+      script = build_script (cmp->file);
+
+      changes = (script != 0);
+
+      free (cmp->file[0].undiscarded);
+
+      free (flag_space);
+
+      for (f = 0; f < 2; f++)
+	{
+	  free (cmp->file[f].equivs);
+	  free (cmp->file[f].linbuf + cmp->file[f].linbuf_base);
+	}
+    }
+
+  return script;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/gnudiff_diff.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,355 @@
+/* Shared definitions for GNU DIFF
+
+   Modified for KDiff3 by Joachim Eibl 2003, 2004, 2005.
+   The original file was part of GNU DIFF.
+
+   Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1998, 2001,
+   2002 Free Software Foundation, Inc.
+
+   GNU DIFF is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU DIFF is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef GNUDIFF_DIFF_H
+#define GNUDIFF_DIFF_H
+
+#include "gnudiff_system.h"
+
+#include <stdio.h>
+#include <qstring.h>
+
+#define TAB_WIDTH 8
+
+class GnuDiff
+{
+public:
+/* What kind of changes a hunk contains.  */
+enum changes
+{
+  /* No changes: lines common to both files.  */
+  UNCHANGED,
+
+  /* Deletes only: lines taken from just the first file.  */
+  OLD,
+
+  /* Inserts only: lines taken from just the second file.  */
+  NEW,
+
+  /* Both deletes and inserts: a hunk containing both old and new lines.  */
+  CHANGED
+};
+
+/* Variables for command line options */
+
+/* Nonzero if output cannot be generated for identical files.  */
+bool no_diff_means_no_output;
+
+/* Number of lines of context to show in each set of diffs.
+   This is zero when context is not to be shown.  */
+lin context;
+
+/* Consider all files as text files (-a).
+   Don't interpret codes over 0177 as implying a "binary file".  */
+bool text;
+
+/* The significance of white space during comparisons.  */
+enum
+{
+  /* All white space is significant (the default).  */
+  IGNORE_NO_WHITE_SPACE,
+
+  /* Ignore changes due to tab expansion (-E).  */
+  IGNORE_TAB_EXPANSION,
+
+  /* Ignore changes in horizontal white space (-b).  */
+  IGNORE_SPACE_CHANGE,
+
+  /* Ignore all horizontal white space (-w).  */
+  IGNORE_ALL_SPACE
+} ignore_white_space;
+
+/* Ignore changes that affect only blank lines (-B).  */
+bool ignore_blank_lines;
+
+/* Ignore changes that affect only numbers. (J. Eibl)  */
+bool bIgnoreNumbers;
+bool bIgnoreWhiteSpace;
+
+/* Files can be compared byte-by-byte, as if they were binary.
+   This depends on various options.  */
+bool files_can_be_treated_as_binary;
+
+/* Ignore differences in case of letters (-i).  */
+bool ignore_case;
+
+/* Ignore differences in case of letters in file names.  */
+bool ignore_file_name_case;
+
+/* Regexp to identify function-header lines (-F).  */
+//struct re_pattern_buffer function_regexp;
+
+/* Ignore changes that affect only lines matching this regexp (-I).  */
+//struct re_pattern_buffer ignore_regexp;
+
+/* Say only whether files differ, not how (-q).  */
+bool brief;
+
+/* Expand tabs in the output so the text lines up properly
+   despite the characters added to the front of each line (-t).  */
+bool expand_tabs;
+
+/* Use a tab in the output, rather than a space, before the text of an
+   input line, so as to keep the proper alignment in the input line
+   without changing the characters in it (-T).  */
+bool initial_tab;
+
+/* In directory comparison, specify file to start with (-S).
+   This is used for resuming an aborted comparison.
+   All file names less than this name are ignored.  */
+const QChar *starting_file;
+
+/* Pipe each file's output through pr (-l).  */
+bool paginate;
+
+/* Line group formats for unchanged, old, new, and changed groups.  */
+const QChar *group_format[CHANGED + 1];
+
+/* Line formats for unchanged, old, and new lines.  */
+const QChar *line_format[NEW + 1];
+
+/* If using OUTPUT_SDIFF print extra information to help the sdiff filter.  */
+bool sdiff_merge_assist;
+
+/* Tell OUTPUT_SDIFF to show only the left version of common lines.  */
+bool left_column;
+
+/* Tell OUTPUT_SDIFF to not show common lines.  */
+bool suppress_common_lines;
+
+/* The half line width and column 2 offset for OUTPUT_SDIFF.  */
+unsigned int sdiff_half_width;
+unsigned int sdiff_column2_offset;
+
+/* Use heuristics for better speed with large files with a small
+   density of changes.  */
+bool speed_large_files;
+
+/* Patterns that match file names to be excluded.  */
+struct exclude *excluded;
+
+/* Don't discard lines.  This makes things slower (sometimes much
+   slower) but will find a guaranteed minimal set of changes.  */
+bool minimal;
+
+
+/* The result of comparison is an "edit script": a chain of `struct change'.
+   Each `struct change' represents one place where some lines are deleted
+   and some are inserted.
+
+   LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+   DELETED is the number of lines deleted here from file 0.
+   INSERTED is the number of lines inserted here in file 1.
+
+   If DELETED is 0 then LINE0 is the number of the line before
+   which the insertion was done; vice versa for INSERTED and LINE1.  */
+
+struct change
+{
+  struct change *link;		/* Previous or next edit command  */
+  lin inserted;			/* # lines of file 1 changed here.  */
+  lin deleted;			/* # lines of file 0 changed here.  */
+  lin line0;			/* Line number of 1st deleted line.  */
+  lin line1;			/* Line number of 1st inserted line.  */
+  bool ignore;			/* Flag used in context.c.  */
+};
+
+/* Structures that describe the input files.  */
+
+/* Data on one input file being compared.  */
+
+struct file_data {
+    /* Buffer in which text of file is read.  */
+    const QChar* buffer;
+
+    /* Allocated size of buffer, in QChars.  Always a multiple of
+       sizeof *buffer.  */
+    size_t bufsize;
+
+    /* Number of valid bytes now in the buffer.  */
+    size_t buffered;
+
+    /* Array of pointers to lines in the file.  */
+    const QChar **linbuf;
+
+    /* linbuf_base <= buffered_lines <= valid_lines <= alloc_lines.
+       linebuf[linbuf_base ... buffered_lines - 1] are possibly differing.
+       linebuf[linbuf_base ... valid_lines - 1] contain valid data.
+       linebuf[linbuf_base ... alloc_lines - 1] are allocated.  */
+    lin linbuf_base, buffered_lines, valid_lines, alloc_lines;
+
+    /* Pointer to end of prefix of this file to ignore when hashing.  */
+    const QChar *prefix_end;
+
+    /* Count of lines in the prefix.
+       There are this many lines in the file before linbuf[0].  */
+    lin prefix_lines;
+
+    /* Pointer to start of suffix of this file to ignore when hashing.  */
+    const QChar *suffix_begin;
+
+    /* Vector, indexed by line number, containing an equivalence code for
+       each line.  It is this vector that is actually compared with that
+       of another file to generate differences.  */
+    lin *equivs;
+
+    /* Vector, like the previous one except that
+       the elements for discarded lines have been squeezed out.  */
+    lin *undiscarded;
+
+    /* Vector mapping virtual line numbers (not counting discarded lines)
+       to real ones (counting those lines).  Both are origin-0.  */
+    lin *realindexes;
+
+    /* Total number of nondiscarded lines.  */
+    lin nondiscarded_lines;
+
+    /* Vector, indexed by real origin-0 line number,
+       containing TRUE for a line that is an insertion or a deletion.
+       The results of comparison are stored here.  */
+    bool *changed;
+
+    /* 1 if at end of file.  */
+    bool eof;
+
+    /* 1 more than the maximum equivalence value used for this or its
+       sibling file.  */
+    lin equiv_max;
+};
+
+/* Data on two input files being compared.  */
+
+struct comparison
+  {
+    struct file_data file[2];
+    struct comparison const *parent;  /* parent, if a recursive comparison */
+  };
+
+/* Describe the two files currently being compared.  */
+
+struct file_data files[2];
+
+/* Stdio stream to output diffs to.  */
+
+FILE *outfile;
+
+/* Declare various functions.  */
+
+/* analyze.c */
+struct change* diff_2_files (struct comparison *);
+
+/* context.c */
+void print_context_header (struct file_data[], bool);
+void print_context_script (struct change *, bool);
+
+/* dir.c */
+int diff_dirs (struct comparison const *, int (*) (struct comparison const *, const QChar *, const QChar *));
+
+/* ed.c */
+void print_ed_script (struct change *);
+void pr_forward_ed_script (struct change *);
+
+/* ifdef.c */
+void print_ifdef_script (struct change *);
+
+/* io.c */
+void file_block_read (struct file_data *, size_t);
+bool read_files (struct file_data[], bool);
+
+/* normal.c */
+void print_normal_script (struct change *);
+
+/* rcs.c */
+void print_rcs_script (struct change *);
+
+/* side.c */
+void print_sdiff_script (struct change *);
+
+/* util.c */
+QChar *concat (const QChar *, const QChar *, const QChar *);
+bool lines_differ ( const QChar *, size_t, const QChar *, size_t );
+lin translate_line_number (struct file_data const *, lin);
+struct change *find_change (struct change *);
+struct change *find_reverse_change (struct change *);
+void *zalloc (size_t);
+enum changes analyze_hunk (struct change *, lin *, lin *, lin *, lin *);
+void begin_output (void);
+void debug_script (struct change *);
+void finish_output (void);
+void message (const QChar *, const QChar *, const QChar *);
+void message5 (const QChar *, const QChar *, const QChar *, const QChar *, const QChar *);
+void output_1_line (const QChar *, const QChar *, const QChar *, const QChar *);
+void perror_with_name (const QChar *);
+void setup_output (const QChar *, const QChar *, bool);
+void translate_range (struct file_data const *, lin, lin, long *, long *);
+
+/* version.c */
+//extern const QChar version_string[];
+
+private:
+   // gnudiff_analyze.cpp
+   lin diag (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal, struct partition *part);
+   void compareseq (lin xoff, lin xlim, lin yoff, lin ylim, bool find_minimal);
+   void discard_confusing_lines (struct file_data filevec[]);
+   void shift_boundaries (struct file_data filevec[]);
+   struct change * add_change (lin line0, lin line1, lin deleted, lin inserted, struct change *old);
+   struct change * build_reverse_script (struct file_data const filevec[]);
+   struct change* build_script (struct file_data const filevec[]);
+
+   // gnudiff_io.cpp
+   void find_and_hash_each_line (struct file_data *current);
+   void find_identical_ends (struct file_data filevec[]);
+
+   // gnudiff_xmalloc.cpp
+   void *xmalloc (size_t n);
+   void *xrealloc(void *p, size_t n);
+   void xalloc_die (void);
+
+   inline bool isWhite( QChar c )
+   {
+      return c==' ' || c=='\t' ||  c=='\r';
+   }
+}; // class GnuDiff
+
+# define XMALLOC(Type, N_items) ((Type *) xmalloc (sizeof (Type) * (N_items)))
+# define XREALLOC(Ptr, Type, N_items) \
+  ((Type *) xrealloc ((void *) (Ptr), sizeof (Type) * (N_items)))
+
+/* Declare and alloc memory for VAR of type TYPE. */
+# define NEW(Type, Var)  Type *(Var) = XMALLOC (Type, 1)
+
+/* Free VAR only if non NULL. */
+# define XFREE(Var)	\
+   do {                 \
+      if (Var)          \
+        free (Var);     \
+   } while (0)
+
+/* Return a pointer to a malloc'ed copy of the array SRC of NUM elements. */
+# define CCLONE(Src, Num) \
+  (memcpy (xmalloc (sizeof (*Src) * (Num)), (Src), sizeof (*Src) * (Num)))
+
+/* Return a malloc'ed copy of SRC. */
+# define CLONE(Src) CCLONE (Src, 1)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/gnudiff_io.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,559 @@
+/* File I/O for GNU DIFF.
+
+   Modified for KDiff3 by Joachim Eibl 2003, 2004, 2005.
+   The original file was part of GNU DIFF.
+
+   Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002
+   Free Software Foundation, Inc.
+
+   GNU DIFF is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU DIFF is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include "gnudiff_diff.h"
+#include <stdlib.h>
+
+/* Rotate an unsigned value to the left.  */
+#define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n)))
+
+/* Given a hash value and a new character, return a new hash value.  */
+#define HASH(h, c) ((c) + ROL (h, 7))
+
+/* The type of a hash value.  */
+typedef size_t hash_value;
+verify (hash_value_is_unsigned, ! TYPE_SIGNED (hash_value));
+
+/* Lines are put into equivalence classes of lines that match in lines_differ.
+   Each equivalence class is represented by one of these structures,
+   but only while the classes are being computed.
+   Afterward, each class is represented by a number.  */
+struct equivclass
+{
+  lin next;		/* Next item in this bucket.  */
+  hash_value hash;	/* Hash of lines in this class.  */
+  const QChar *line;	/* A line that fits this class.  */
+  size_t length;	/* That line's length, not counting its newline.  */
+};
+
+/* Hash-table: array of buckets, each being a chain of equivalence classes.
+   buckets[-1] is reserved for incomplete lines.  */
+static lin *buckets;
+
+/* Number of buckets in the hash table array, not counting buckets[-1].  */
+static size_t nbuckets;
+
+/* Array in which the equivalence classes are allocated.
+   The bucket-chains go through the elements in this array.
+   The number of an equivalence class is its index in this array.  */
+static struct equivclass *equivs;
+
+/* Index of first free element in the array `equivs'.  */
+static lin equivs_index;
+
+/* Number of elements allocated in the array `equivs'.  */
+static lin equivs_alloc;
+
+
+/* Check for binary files and compare them for exact identity.  */
+
+/* Return 1 if BUF contains a non text character.
+   SIZE is the number of characters in BUF.  */
+
+#define binary_file_p(buf, size) (memchr (buf, 0, size) != 0)
+
+/* Compare two lines (typically one from each input file)
+   according to the command line options.
+   For efficiency, this is invoked only when the lines do not match exactly
+   but an option like -i might cause us to ignore the difference.
+   Return nonzero if the lines differ.  */
+
+bool GnuDiff::lines_differ (const QChar *s1, size_t len1, const QChar *s2, size_t len2 )
+{
+   const QChar *t1 = s1;
+   const QChar *t2 = s2;
+   const QChar *s1end = s1+len1;
+   const QChar *s2end = s2+len2;
+
+   for ( ; ; ++t1, ++t2 )
+   {
+      /* Test for exact char equality first, since it's a common case.  */
+      if ( t1!=s1end && t2!=s2end && *t1==*t2 )
+         continue;
+      else
+      {
+         while ( t1!=s1end &&
+                 ( bIgnoreWhiteSpace && isWhite( *t1 )  ||
+                   bIgnoreNumbers    && (t1->isDigit() || *t1=='-' || *t1=='.' )))
+         {
+            ++t1;
+         }
+
+         while ( t2 != s2end &&
+                 ( bIgnoreWhiteSpace && isWhite( *t2 )  ||
+                   bIgnoreNumbers    && (t2->isDigit() || *t2=='-' || *t2=='.' )))
+         {
+            ++t2;
+         }
+
+         if ( t1!=s1end && t2!=s2end )
+         {
+            if (ignore_case)
+            {  /* Lowercase comparison. */
+               if ( t1->lower() == t2->lower() )
+                  continue;
+            }
+            else if ( *t1 == *t2 )
+               continue;
+            else
+               return true;
+         }
+         else if ( t1==s1end && t2==s2end )
+            return false;
+         else
+            return true;
+      }
+   }
+   return false;
+}
+
+
+/* Split the file into lines, simultaneously computing the equivalence
+   class for each line.  */
+
+void GnuDiff::find_and_hash_each_line (struct file_data *current)
+{
+  hash_value h;
+  const QChar *p = current->prefix_end;
+  QChar c;
+  lin i, *bucket;
+  size_t length;
+
+  /* Cache often-used quantities in local variables to help the compiler.  */
+  const QChar **linbuf = current->linbuf;
+  lin alloc_lines = current->alloc_lines;
+  lin line = 0;
+  lin linbuf_base = current->linbuf_base;
+  lin *cureqs = (lin*)xmalloc (alloc_lines * sizeof *cureqs);
+  struct equivclass *eqs = equivs;
+  lin eqs_index = equivs_index;
+  lin eqs_alloc = equivs_alloc;
+  const QChar *suffix_begin = current->suffix_begin;
+  const QChar *bufend = current->buffer + current->buffered;
+  bool diff_length_compare_anyway =
+    ignore_white_space != IGNORE_NO_WHITE_SPACE || bIgnoreNumbers;
+  bool same_length_diff_contents_compare_anyway =
+    diff_length_compare_anyway | ignore_case;
+
+  while ( p < suffix_begin)
+    {
+      const QChar *ip = p;
+
+      h = 0;
+
+      /* Hash this line until we find a newline or bufend is reached.  */
+      if (ignore_case)
+	switch (ignore_white_space)
+	  {
+	  case IGNORE_ALL_SPACE:
+	    while ( p<bufend && (c = *p) != '\n' )
+            {
+	      if (! (isWhite(c) || bIgnoreNumbers && (c.isDigit() || c=='-' || c=='.' ) ))
+                  h = HASH (h, c.lower().unicode());
+              ++p;
+            }            
+	    break;
+
+	  default:
+	    while ( p<bufend && (c = *p) != '\n' )
+            {
+               h = HASH (h, c.lower().unicode());
+               ++p;
+            }
+	    break;
+	  }
+      else
+	switch (ignore_white_space)
+	  {
+	  case IGNORE_ALL_SPACE:
+	    while ( p<bufend && (c = *p) != '\n')
+            {
+	      if (! (isWhite(c)|| bIgnoreNumbers && (c.isDigit() || c=='-' || c=='.' ) ))
+                 h = HASH (h, c.unicode());
+              ++p;
+            }
+	    break;
+
+	  default:
+	    while ( p<bufend && (c = *p) != '\n')
+            {
+               h = HASH (h, c.unicode());
+               ++p;
+            }
+	    break;
+	  }
+
+      bucket = &buckets[h % nbuckets];
+      length = p - ip;
+      ++p;
+
+      for (i = *bucket;  ;  i = eqs[i].next)
+	if (!i)
+	  {
+	    /* Create a new equivalence class in this bucket.  */
+	    i = eqs_index++;
+	    if (i == eqs_alloc)
+	      {
+		if ((lin)(PTRDIFF_MAX / (2 * sizeof *eqs)) <= eqs_alloc)
+		  xalloc_die ();
+		eqs_alloc *= 2;
+		eqs = (equivclass*)xrealloc (eqs, eqs_alloc * sizeof *eqs);
+	      }
+	    eqs[i].next = *bucket;
+	    eqs[i].hash = h;
+	    eqs[i].line = ip;
+	    eqs[i].length = length;
+	    *bucket = i;
+	    break;
+	  }
+	else if (eqs[i].hash == h)
+	  {
+	    const QChar *eqline = eqs[i].line;
+
+	    /* Reuse existing class if lines_differ reports the lines
+               equal.  */
+	    if (eqs[i].length == length)
+	      {
+		/* Reuse existing equivalence class if the lines are identical.
+		   This detects the common case of exact identity
+		   faster than lines_differ would.  */
+		if (memcmp (eqline, ip, length*sizeof(QChar)) == 0)
+		  break;
+		if (!same_length_diff_contents_compare_anyway)
+		  continue;
+	      }
+	    else if (!diff_length_compare_anyway)
+	      continue;
+
+	    if (! lines_differ (eqline, eqs[i].length, ip, length))
+	      break;
+	  }
+
+      /* Maybe increase the size of the line table.  */
+      if (line == alloc_lines)
+	{
+	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
+	  if ((lin)(PTRDIFF_MAX / 3) <= alloc_lines
+	      || (lin)(PTRDIFF_MAX / sizeof *cureqs) <= 2 * alloc_lines - linbuf_base
+	      || (lin)(PTRDIFF_MAX / sizeof *linbuf) <= alloc_lines - linbuf_base)
+	    xalloc_die ();
+	  alloc_lines = 2 * alloc_lines - linbuf_base;
+	  cureqs =(lin*) xrealloc (cureqs, alloc_lines * sizeof *cureqs);
+	  linbuf += linbuf_base;
+	  linbuf = (const QChar**) xrealloc (linbuf,
+			     (alloc_lines - linbuf_base) * sizeof *linbuf);
+	  linbuf -= linbuf_base;
+	}
+      linbuf[line] = ip;
+      cureqs[line] = i;
+      ++line;
+    }
+
+  current->buffered_lines = line;
+
+  for (i = 0;  ;  i++)
+    {
+      /* Record the line start for lines in the suffix that we care about.
+	 Record one more line start than lines,
+	 so that we can compute the length of any buffered line.  */
+      if (line == alloc_lines)
+	{
+	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
+	  if ((lin)(PTRDIFF_MAX / 3) <= alloc_lines
+	      || (lin)(PTRDIFF_MAX / sizeof *cureqs) <= 2 * alloc_lines - linbuf_base
+	      || (lin)(PTRDIFF_MAX / sizeof *linbuf) <= alloc_lines - linbuf_base)
+	    xalloc_die ();
+	  alloc_lines = 2 * alloc_lines - linbuf_base;
+	  linbuf += linbuf_base;
+	  linbuf = (const QChar**)xrealloc (linbuf,
+			     (alloc_lines - linbuf_base) * sizeof *linbuf);
+	  linbuf -= linbuf_base;
+	}
+      linbuf[line] = p;
+
+      if ( p >= bufend)
+	break;
+
+      if (context <= i && no_diff_means_no_output)
+	break;
+
+      line++;
+
+      while (p<bufend && *p++ != '\n')
+        continue;
+    }
+
+  /* Done with cache in local variables.  */
+  current->linbuf = linbuf;
+  current->valid_lines = line;
+  current->alloc_lines = alloc_lines;
+  current->equivs = cureqs;
+  equivs = eqs;
+  equivs_alloc = eqs_alloc;
+  equivs_index = eqs_index;
+}
+
+/* We have found N lines in a buffer of size S; guess the
+   proportionate number of lines that will be found in a buffer of
+   size T.  However, do not guess a number of lines so large that the
+   resulting line table might cause overflow in size calculations.  */
+static lin
+guess_lines (lin n, size_t s, size_t t)
+{
+  size_t guessed_bytes_per_line = n < 10 ? 32 : s / (n - 1);
+  lin guessed_lines = MAX (1, t / guessed_bytes_per_line);
+  return MIN (guessed_lines, (lin)(PTRDIFF_MAX / (2 * sizeof (QChar *) + 1) - 5)) + 5;
+}
+
+/* Given a vector of two file_data objects, find the identical
+   prefixes and suffixes of each object.  */
+
+void GnuDiff::find_identical_ends (struct file_data filevec[])
+{
+  /* Find identical prefix.  */
+  const QChar *p0, *p1, *buffer0, *buffer1;
+  p0 = buffer0 = filevec[0].buffer;
+  p1 = buffer1 = filevec[1].buffer;
+  size_t n0, n1;
+  n0 = filevec[0].buffered;
+  n1 = filevec[1].buffered;
+  const QChar* const pEnd0 = p0 + n0;
+  const QChar* const pEnd1 = p1 + n1;
+
+  if (p0 == p1)
+    /* The buffers are the same; sentinels won't work.  */
+    p0 = p1 += n1;
+  else
+    {
+      /* Loop until first mismatch, or end. */
+      while ( p0!=pEnd0  &&  p1!=pEnd1  &&  *p0 == *p1 )
+      {
+         p0++;
+         p1++;
+      }
+    }
+
+  /* Now P0 and P1 point at the first nonmatching characters.  */
+
+  /* Skip back to last line-beginning in the prefix. */
+  while (p0 != buffer0 && (p0[-1] != '\n' ))
+    p0--, p1--;
+
+  /* Record the prefix.  */
+  filevec[0].prefix_end = p0;
+  filevec[1].prefix_end = p1;
+
+  /* Find identical suffix.  */
+
+  /* P0 and P1 point beyond the last chars not yet compared.  */
+  p0 = buffer0 + n0;
+  p1 = buffer1 + n1;
+
+   const QChar *end0, *beg0;
+   end0 = p0; /* Addr of last char in file 0.  */
+
+   /* Get value of P0 at which we should stop scanning backward:
+      this is when either P0 or P1 points just past the last char
+      of the identical prefix.  */
+   beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
+
+   /* Scan back until chars don't match or we reach that point.  */
+   for (; p0 != beg0; p0--, p1--)
+   {
+      if (*p0 != *p1)
+      {
+         /* Point at the first char of the matching suffix.  */
+         beg0 = p0;
+         break;
+      }
+   }
+
+   // Go to the next line (skip last line with a difference)
+   if ( p0 != end0 )
+   {
+      if (*p0 != *p1)
+         ++p0;
+      while ( p0<pEnd0 && *p0++ != '\n')
+         continue;
+   }
+
+   p1 += p0 - beg0;
+
+  /* Record the suffix.  */
+  filevec[0].suffix_begin = p0;
+  filevec[1].suffix_begin = p1;
+
+  /* Calculate number of lines of prefix to save.
+
+     prefix_count == 0 means save the whole prefix;
+     we need this for options like -D that output the whole file,
+     or for enormous contexts (to avoid worrying about arithmetic overflow).
+     We also need it for options like -F that output some preceding line;
+     at least we will need to find the last few lines,
+     but since we don't know how many, it's easiest to find them all.
+
+     Otherwise, prefix_count != 0.  Save just prefix_count lines at start
+     of the line buffer; they'll be moved to the proper location later.
+     Handle 1 more line than the context says (because we count 1 too many),
+     rounded up to the next power of 2 to speed index computation.  */
+
+  const QChar **linbuf0, **linbuf1;
+  lin alloc_lines0, alloc_lines1;
+  lin buffered_prefix, prefix_count, prefix_mask;
+  lin middle_guess, suffix_guess;
+  if (no_diff_means_no_output
+      && context < (lin)(LIN_MAX / 4) && context < (lin)(n0))
+    {
+      middle_guess = guess_lines (0, 0, p0 - filevec[0].prefix_end);
+      suffix_guess = guess_lines (0, 0, buffer0 + n0 - p0);
+      for (prefix_count = 1;  prefix_count <= context;  prefix_count *= 2)
+	continue;
+      alloc_lines0 = (prefix_count + middle_guess
+		      + MIN (context, suffix_guess));
+    }
+  else
+    {
+      prefix_count = 0;
+      alloc_lines0 = guess_lines (0, 0, n0);
+    }
+
+  prefix_mask = prefix_count - 1;
+  lin lines = 0;
+  linbuf0 = (const QChar**) xmalloc (alloc_lines0 * sizeof(*linbuf0));
+  p0 = buffer0;
+
+  /* If the prefix is needed, find the prefix lines.  */
+  if (! (no_diff_means_no_output
+	 && filevec[0].prefix_end == p0
+	 && filevec[1].prefix_end == p1))
+    {
+      end0 = filevec[0].prefix_end;
+      while (p0 != end0)
+	{
+	  lin l = lines++ & prefix_mask;
+	  if (l == alloc_lines0)
+	    {
+	      if ((lin)(PTRDIFF_MAX / (2 * sizeof *linbuf0)) <= alloc_lines0)
+		xalloc_die ();
+	      alloc_lines0 *= 2;
+              linbuf0 = (const QChar**) xrealloc (linbuf0, alloc_lines0 * sizeof(*linbuf0));
+	    }
+	  linbuf0[l] = p0;
+	  while ( p0<pEnd0 && *p0++ != '\n' )
+	    continue;
+	}
+    }
+  buffered_prefix = prefix_count && context < lines ? context : lines;
+
+  /* Allocate line buffer 1.  */
+
+  middle_guess = guess_lines (lines, p0 - buffer0, p1 - filevec[1].prefix_end);
+  suffix_guess = guess_lines (lines, p0 - buffer0, buffer1 + n1 - p1);
+  alloc_lines1 = buffered_prefix + middle_guess + MIN (context, suffix_guess);
+  if (alloc_lines1 < buffered_prefix
+      || (lin)(PTRDIFF_MAX / sizeof *linbuf1) <= alloc_lines1)
+    xalloc_die ();
+  linbuf1 = (const QChar**)xmalloc (alloc_lines1 * sizeof(*linbuf1));
+
+  lin i;
+  if (buffered_prefix != lines)
+  {
+      /* Rotate prefix lines to proper location.  */
+      for (i = 0;  i < buffered_prefix;  i++)
+	linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
+      for (i = 0;  i < buffered_prefix;  i++)
+	linbuf0[i] = linbuf1[i];
+  }
+
+  /* Initialize line buffer 1 from line buffer 0.  */
+  for (i = 0; i < buffered_prefix; i++)
+    linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
+
+  /* Record the line buffer, adjusted so that
+     linbuf[0] points at the first differing line.  */
+  filevec[0].linbuf = linbuf0 + buffered_prefix;
+  filevec[1].linbuf = linbuf1 + buffered_prefix;
+  filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
+  filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
+  filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
+  filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
+}
+
+/* If 1 < k, then (2**k - prime_offset[k]) is the largest prime less
+   than 2**k.  This table is derived from Chris K. Caldwell's list
+   <http://www.utm.edu/research/primes/lists/2small/>.  */
+
+static unsigned char const prime_offset[] =
+{
+  0, 0, 1, 1, 3, 1, 3, 1, 5, 3, 3, 9, 3, 1, 3, 19, 15, 1, 5, 1, 3, 9, 3,
+  15, 3, 39, 5, 39, 57, 3, 35, 1, 5, 9, 41, 31, 5, 25, 45, 7, 87, 21,
+  11, 57, 17, 55, 21, 115, 59, 81, 27, 129, 47, 111, 33, 55, 5, 13, 27,
+  55, 93, 1, 57, 25
+};
+
+/* Verify that this host's size_t is not too wide for the above table.  */
+
+verify (enough_prime_offsets,
+	sizeof (size_t) * CHAR_BIT <= sizeof prime_offset);
+
+/* Given a vector of two file_data objects, read the file associated
+   with each one, and build the table of equivalence classes.
+   Return nonzero if either file appears to be a binary file.
+   If PRETEND_BINARY is nonzero, pretend they are binary regardless.  */
+
+bool
+GnuDiff::read_files (struct file_data filevec[], bool /*pretend_binary*/)
+{
+  int i;
+
+  find_identical_ends (filevec);
+
+  equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
+  if ((lin)(PTRDIFF_MAX / sizeof *equivs) <= equivs_alloc)
+    xalloc_die ();
+  equivs = (equivclass*)xmalloc (equivs_alloc * sizeof *equivs);
+  /* Equivalence class 0 is permanently safe for lines that were not
+     hashed.  Real equivalence classes start at 1.  */
+  equivs_index = 1;
+
+  /* Allocate (one plus) a prime number of hash buckets.  Use a prime
+     number between 1/3 and 2/3 of the value of equiv_allocs,
+     approximately.  */
+  for (i = 9;  1 << i < equivs_alloc / 3; i++)
+    continue;
+  nbuckets = ((size_t) 1 << i) - prime_offset[i];
+  if (PTRDIFF_MAX / sizeof *buckets <= nbuckets)
+    xalloc_die ();
+  buckets = (lin*)zalloc ((nbuckets + 1) * sizeof *buckets);
+  buckets++;
+
+  for (i = 0; i < 2; i++)
+    find_and_hash_each_line (&filevec[i]);
+
+  filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
+
+  free (equivs);
+  free (buckets - 1);
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/gnudiff_system.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,123 @@
+/* System dependent declarations.
+
+   Modified for KDiff3 by Joachim Eibl 2003.
+   The original file was part of GNU DIFF.
+
+   Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002
+   Free Software Foundation, Inc.
+
+   GNU DIFF is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU DIFF is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef GNUDIFF_SYSTEM_H
+#define GNUDIFF_SYSTEM_H
+
+//#include <config.h>
+
+
+
+/* Don't bother to support K&R C compilers any more; it's not worth
+   the trouble.  These macros prevent some library modules from being
+   compiled in K&R C mode.  */
+#define PARAMS(Args) Args
+#define PROTOTYPES 1
+
+/* Verify a requirement at compile-time (unlike assert, which is runtime).  */
+#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
+
+
+/* Determine whether an integer type is signed, and its bounds.
+   This code assumes two's (or one's!) complement with no holes.  */
+
+/* The extra casts work around common compiler bugs,
+   e.g. Cray C 5.0.3.0 when t == time_t.  */
+#ifndef TYPE_SIGNED
+# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+#endif
+#ifndef TYPE_MINIMUM
+# define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \
+			       ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \
+			       : (t) 0))
+#endif
+#ifndef TYPE_MAXIMUM
+# define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t)))
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+# include <stdlib.h>
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#if !EXIT_FAILURE
+# undef EXIT_FAILURE /* Sony NEWS-OS 4.0C defines EXIT_FAILURE to 0.  */
+# define EXIT_FAILURE 1
+#endif
+#define EXIT_TROUBLE 2
+
+#include <limits.h>
+#ifndef SSIZE_MAX
+# define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
+#endif
+
+#ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX TYPE_MAXIMUM (ptrdiff_t)
+#endif
+#ifndef SIZE_MAX
+# define SIZE_MAX TYPE_MAXIMUM (size_t)
+#endif
+#ifndef UINTMAX_MAX
+# define UINTMAX_MAX TYPE_MAXIMUM (uintmax_t)
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+
+/* CTYPE_DOMAIN (C) is nonzero if the unsigned char C can safely be given
+   as an argument to <ctype.h> macros like `isspace'.  */
+# define CTYPE_DOMAIN(c) 1
+#define ISPRINT(c) (CTYPE_DOMAIN (c) && isprint (c))
+#define ISSPACE(c) (CTYPE_DOMAIN (c) && isspace (c))
+
+# define TOLOWER(c) tolower (c)
+
+/* ISDIGIT differs from isdigit, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   POSIX 1003.1-2001 says that only '0' through '9' are digits.
+   Prefer ISDIGIT to isdigit unless it's important to use the locale's
+   definition of `digit' even when the host does not conform to POSIX.  */
+#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
+
+#undef MIN
+#undef MAX
+#define MIN(a, b) ((a) <= (b) ? (a) : (b))
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+
+/* The integer type of a line number.  Since files are read into main
+   memory, ptrdiff_t should be wide enough.  */
+
+typedef ptrdiff_t lin;
+#define LIN_MAX PTRDIFF_MAX
+verify (lin_is_signed, TYPE_SIGNED (lin));
+verify (lin_is_wide_enough, sizeof (ptrdiff_t) <= sizeof (lin));
+verify (lin_is_printable_as_long, sizeof (lin) <= sizeof (long));
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/gnudiff_xmalloc.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,88 @@
+/* xmalloc.c -- malloc with out of memory checking
+
+   Modified for KDiff3 by Joachim Eibl 2003.
+   The original file was part of GNU DIFF.
+
+   Copyright (C) 1990-1999, 2000, 2002 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#include "gnudiff_diff.h"
+/* If non NULL, call this function when memory is exhausted. */
+//void (*xalloc_fail_func) PARAMS ((void)) = 0;
+void (*xalloc_fail_func)(void) = 0;
+
+
+void GnuDiff::xalloc_die (void)
+{
+  if (xalloc_fail_func)
+    (*xalloc_fail_func) ();
+  //error (exit_failure, 0, "%s", _(xalloc_msg_memory_exhausted));
+  /* The `noreturn' cannot be given to error, since it may return if
+     its first argument is 0.  To help compilers understand the
+     xalloc_die does terminate, call exit. */
+  exit (EXIT_FAILURE);
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+void *
+GnuDiff::xmalloc (size_t n)
+{
+  void *p;
+
+  p = malloc (n == 0 ? 1 : n); // There are systems where malloc returns 0 for n==0.
+  if (p == 0)
+    xalloc_die ();
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.  */
+
+void *
+GnuDiff::xrealloc (void *p, size_t n)
+{
+  p = realloc (p, n==0 ? 1 : n);
+  if (p == 0)
+    xalloc_die ();
+  return p;
+}
+
+
+/* Yield a new block of SIZE bytes, initialized to zero.  */
+
+void *
+GnuDiff::zalloc (size_t size)
+{
+  void *p = xmalloc (size);
+  memset (p, 0, size);
+  return p;
+}
Binary file kdiff3/src/hi16-app-kdiff3.png has changed
Binary file kdiff3/src/hi32-app-kdiff3.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,973 @@
+/***************************************************************************
+                          kdiff3.cpp  -  description
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "difftextwindow.h"
+#include "mergeresultwindow.h"
+
+#include <iostream>
+
+// include files for QT
+#include <qdir.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qsplitter.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+#include <qlayout.h>
+#include <qpaintdevicemetrics.h>
+
+// include files for KDE
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kcmdlineargs.h>
+#include <kprinter.h>
+//#include <kkeydialog.h>
+
+// application specific includes
+#include "kdiff3.h"
+#include "optiondialog.h"
+#include "fileaccess.h"
+#include "kdiff3_part.h"
+#include "directorymergewindow.h"
+#include "smalldialogs.h"
+
+#define ID_STATUS_MSG 1
+
+KActionCollection* KDiff3App::actionCollection()
+{
+   if ( m_pKDiff3Shell==0 )
+      return m_pKDiff3Part->actionCollection();
+   else
+      return m_pKDiff3Shell->actionCollection();
+}
+
+KStatusBar* KDiff3App::statusBar()
+{
+   if ( m_pKDiff3Shell==0 )
+      return 0;
+   else
+      return m_pKDiff3Shell->statusBar();
+}
+
+KToolBar* KDiff3App::toolBar(const char* toolBarId )
+{
+   if ( m_pKDiff3Shell==0 )
+      return 0;
+   else
+      return m_pKDiff3Shell->toolBar( toolBarId );
+}
+
+bool KDiff3App::isPart()
+{
+   return m_pKDiff3Shell==0;
+}
+
+bool KDiff3App::isFileSaved()
+{
+   return m_bFileSaved;
+}
+
+KDiff3App::KDiff3App(QWidget* pParent, const char* name, KDiff3Part* pKDiff3Part )
+   :QSplitter(pParent, name)  //previously KMainWindow
+{
+   m_pKDiff3Part = pKDiff3Part;
+   m_pKDiff3Shell = dynamic_cast<KParts::MainWindow*>(pParent);
+
+   setCaption( "KDiff3" );
+
+   m_pMainSplitter = 0;
+   m_pDirectoryMergeWindow = 0;
+   m_pCornerWidget = 0;
+   m_pMainWidget = 0;
+   m_pDiffTextWindow1 = 0;
+   m_pDiffTextWindow2 = 0;
+   m_pDiffTextWindow3 = 0;
+   m_pDiffTextWindowFrame1 = 0;
+   m_pDiffTextWindowFrame2 = 0;
+   m_pDiffTextWindowFrame3 = 0;
+   m_pDiffWindowSplitter = 0;
+   m_pOverview        = 0;
+   m_bTripleDiff = false;
+   m_pMergeResultWindow = 0;
+   m_pMergeWindowFrame = 0;
+   m_bOutputModified = false;
+   m_bFileSaved = false;
+   m_bTimerBlock = false;
+   m_pHScrollBar = 0;
+
+   // Needed before any file operations via FileAccess happen.
+   if (!g_pProgressDialog)
+      g_pProgressDialog = new ProgressDialog(0);
+
+   // All default values must be set before calling readOptions().
+   m_pOptionDialog = new OptionDialog( m_pKDiff3Shell!=0, this );
+   connect( m_pOptionDialog, SIGNAL(applyClicked()), this, SLOT(slotRefresh()) );
+
+   m_pOptionDialog->readOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+   // Option handling: Only when pParent==0 (no parent)
+   KCmdLineArgs *args = isPart() ? 0 : KCmdLineArgs::parsedArgs();
+
+   if (args)
+   {
+      QString s;
+      QString title;
+      if ( args->isSet("confighelp") )
+      {
+         s = m_pOptionDialog->calcOptionHelp();
+         title = i18n("Current Configuration:");
+      }
+      else
+      {
+         s = m_pOptionDialog->parseOptions( args->getOptionList("cs") );
+         title = i18n("Config Option Error:");
+      }
+      if (!s.isEmpty())
+      {
+#ifdef _WIN32 
+         // A windows program has no console
+         //KMessageBox::information(0, s,i18n("KDiff3-Usage"));
+         QDialog* pDialog = new QDialog(this,"",true,Qt::WDestructiveClose);
+         pDialog->setCaption(title);
+         QVBoxLayout* pVBoxLayout = new QVBoxLayout( pDialog );
+         QTextEdit* pTextEdit = new QTextEdit(pDialog);
+         pTextEdit->setText(s);
+         pTextEdit->setReadOnly(true);
+         pTextEdit->setWordWrap(QTextEdit::NoWrap);
+         pVBoxLayout->addWidget(pTextEdit);
+         pDialog->resize(600,400);
+         pDialog->exec();
+#else
+         std::cerr << title.latin1() << std::endl;
+         std::cerr << s.latin1() << std::endl;
+#endif
+         exit(1);
+      }
+   }
+
+   m_sd1.setOptionDialog(m_pOptionDialog);
+   m_sd2.setOptionDialog(m_pOptionDialog);
+   m_sd3.setOptionDialog(m_pOptionDialog);
+
+   if (args!=0)
+   {
+      m_outputFilename = args->getOption("output");
+      if ( m_outputFilename.isEmpty() )
+         m_outputFilename = args->getOption("out");
+   }
+
+   m_bAuto = args!=0  && args->isSet("auto");
+   if ( m_bAuto && m_outputFilename.isEmpty() )
+   {
+      //KMessageBox::information(this, i18n("Option --auto used, but no output file specified."));
+      std::cerr << i18n("Option --auto used, but no output file specified.").ascii()<<std::endl;
+      m_bAuto = false;
+   }
+
+   if ( m_outputFilename.isEmpty() && args!=0 && args->isSet("merge") )
+   {
+      m_outputFilename = "unnamed.txt";
+      m_bDefaultFilename = true;
+   }
+   else
+      m_bDefaultFilename = false;
+
+   g_bAutoSolve = args!=0 && !args->isSet("qall");  // Note that this is effective only once.
+
+   if ( args!=0 )
+   {
+      m_sd1.setFilename( args->getOption("base") );
+      if ( m_sd1.isEmpty() )
+      {
+         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->url(0).url() );
+         if ( args->count() > 1 ) m_sd3.setFilename( args->url(1).url() );
+      }
+
+
+      QCStringList aliasList = args->getOptionList("fname");
+      QCStringList::Iterator ali = aliasList.begin();
+
+      QString an1 = args->getOption("L1");
+      if ( !an1.isEmpty() )              { m_sd1.setAliasName(an1);         }
+      else if ( ali != aliasList.end() ) { m_sd1.setAliasName(*ali); ++ali; }
+
+      QString an2 = args->getOption("L2");
+      if ( !an2.isEmpty() )              { m_sd2.setAliasName(an2);         }
+      else if ( ali != aliasList.end() ) { m_sd2.setAliasName(*ali); ++ali; }
+
+      QString an3 = args->getOption("L3");
+      if ( !an3.isEmpty() )              { m_sd3.setAliasName(an3);         }
+      else if ( ali != aliasList.end() ) { m_sd3.setAliasName(*ali); ++ali; }
+   }
+   ///////////////////////////////////////////////////////////////////
+   // call inits to invoke all other construction parts
+   initActions(actionCollection());
+   initStatusBar();
+
+   m_pFindDialog = new FindDialog( this );
+   connect( m_pFindDialog, SIGNAL(findNext()), this, SLOT(slotEditFindNext()));
+
+   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 );
+   wordWrap->setChecked( m_pOptionDialog->m_bWordWrap );
+   if ( ! isPart() )
+   {
+      viewToolBar->setChecked( m_pOptionDialog->m_bShowToolBar );
+      viewStatusBar->setChecked( m_pOptionDialog->m_bShowStatusBar );
+      slotViewToolBar();
+      slotViewStatusBar();
+      if( toolBar("mainToolBar")!=0 )
+         toolBar("mainToolBar")->setBarPos( (KToolBar::BarPosition) m_pOptionDialog->m_toolBarPos );
+/*      QSize size = m_pOptionDialog->m_geometry;
+      QPoint pos = m_pOptionDialog->m_position;
+      if(!size.isEmpty())
+      {
+         m_pKDiff3Shell->resize( size );
+         QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect();
+         if ( visibleRect.width()>100 && visibleRect.height()>100 )
+            m_pKDiff3Shell->move( pos );
+      }*/
+   }
+   slotRefresh();
+
+   m_pMainSplitter = this; //new QSplitter(this);
+   m_pMainSplitter->setOrientation( Vertical );
+//   setCentralWidget( m_pMainSplitter );
+   m_pDirectoryMergeSplitter = new QSplitter( m_pMainSplitter );
+   m_pDirectoryMergeSplitter->setOrientation( Horizontal );
+   m_pDirectoryMergeWindow = new DirectoryMergeWindow( m_pDirectoryMergeSplitter, m_pOptionDialog,
+      KApplication::kApplication()->iconLoader() );
+   m_pDirectoryMergeInfo = new DirectoryMergeInfo( m_pDirectoryMergeSplitter );
+   m_pDirectoryMergeWindow->setDirectoryMergeInfo( m_pDirectoryMergeInfo );
+   connect( m_pDirectoryMergeWindow, SIGNAL(startDiffMerge(QString,QString,QString,QString,QString,QString,QString,TotalDiffStatus*)),
+            this, SLOT( slotFileOpen2(QString,QString,QString,QString,QString,QString,QString,TotalDiffStatus*)));
+   connect( m_pDirectoryMergeWindow, SIGNAL(selectionChanged()), this, SLOT(slotUpdateAvailabilities()));
+   connect( m_pDirectoryMergeWindow, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(slotUpdateAvailabilities()));
+   connect( m_pDirectoryMergeWindow, SIGNAL(checkIfCanContinue(bool*)), this, SLOT(slotCheckIfCanContinue(bool*)));
+   connect( m_pDirectoryMergeWindow, SIGNAL(updateAvailabilities()), this, SLOT(slotUpdateAvailabilities()));
+   connect( m_pDirectoryMergeWindow, SIGNAL(statusBarMessage(const QString&)), this, SLOT(slotStatusMsg(const QString&)));
+
+   m_pDirectoryMergeWindow->initDirectoryMergeActions( this, actionCollection() );
+
+   if ( args!=0 )  args->clear(); // Free up some memory.
+
+   if (m_pKDiff3Shell==0)
+   {
+      completeInit();
+   }
+}
+
+
+void KDiff3App::completeInit( const QString& fn1, const QString& fn2, const QString& fn3 )
+{
+   if (m_pKDiff3Shell!=0)
+   {
+      QSize size=m_pOptionDialog->m_geometry;
+      QPoint pos=m_pOptionDialog->m_position;
+      if(!size.isEmpty())
+      {
+         m_pKDiff3Shell->resize( size );
+         QRect visibleRect = QRect( pos, size ) & QApplication::desktop()->rect();
+         if ( visibleRect.width()>100 && visibleRect.height()>100 )
+            m_pKDiff3Shell->move( pos );
+         if (!m_bAuto)
+         {
+            if ( m_pOptionDialog->m_bMaximised )
+               m_pKDiff3Shell->showMaximized();
+            else
+               m_pKDiff3Shell->show();
+         }
+      }
+   }
+   if ( ! fn1.isEmpty() )  { m_sd1.setFilename(fn1); }
+   if ( ! fn2.isEmpty() )  { m_sd2.setFilename(fn2); }
+   if ( ! fn3.isEmpty() )  { m_sd3.setFilename(fn3); }
+
+   bool bSuccess = improveFilenames(false);
+
+   if ( m_bAuto && m_bDirCompare )
+   {
+      std::cerr << i18n("Option --auto ignored for directory comparison.").ascii()<<std::endl;
+      m_bAuto = false;
+   }
+   if (!m_bDirCompare)
+   {
+      m_pDirectoryMergeSplitter->hide();
+
+      init( m_bAuto );
+      if ( m_bAuto )
+      {
+         SourceData* pSD=0;
+         if ( m_sd3.isEmpty() )
+         {
+            if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd1; }
+         }
+         else
+         {
+            if      ( m_totalDiffStatus.bBinaryBEqC ){ pSD = &m_sd3; } // B==C (assume A is old)
+            else if ( m_totalDiffStatus.bBinaryAEqB ){ pSD = &m_sd3; } // assuming C has changed
+            else if ( m_totalDiffStatus.bBinaryAEqC ){ pSD = &m_sd2; } // assuming B has changed
+         }
+
+         if ( pSD!=0 )
+         {
+            // Save this file directly, not via the merge result window.
+            bool bSuccess = false;
+            FileAccess fa( m_outputFilename );
+            if ( m_pOptionDialog->m_bDmCreateBakFiles && fa.exists() )
+            {
+               QString newName = m_outputFilename + ".orig";
+               if ( FileAccess::exists( newName ) ) FileAccess::removeFile( newName );
+               if ( !FileAccess::exists( newName ) ) fa.rename( newName );
+            }
+
+            bSuccess = pSD->saveNormalDataAs( m_outputFilename );
+            if ( bSuccess ) ::exit(0);
+            else KMessageBox::error( this, i18n("Saving failed.") );
+         }
+         else if ( m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0 )
+         {
+            bool bSuccess = m_pMergeResultWindow->saveDocument( m_pMergeResultWindowTitle->getFileName(), m_pMergeResultWindowTitle->getEncoding() );
+            if ( bSuccess ) ::exit(0);
+         }
+      }
+   }
+
+   if (m_pKDiff3Shell)
+      m_pKDiff3Shell->show();
+
+   if (statusBar() !=0 )
+      statusBar()->setSizeGripEnabled(true);
+
+   slotClipboardChanged(); // For initialisation.
+
+   slotUpdateAvailabilities();
+
+   if ( ! m_bDirCompare  &&  m_pKDiff3Shell!=0 )
+   {
+      bool bFileOpenError = false;
+      if ( ! m_sd1.isEmpty() && !m_sd1.hasData()  ||
+           ! m_sd2.isEmpty() && !m_sd2.hasData()  ||
+           ! m_sd3.isEmpty() && !m_sd3.hasData() )
+      {
+         QString text( i18n("Opening of these files failed:") );
+         text += "\n\n";
+         if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
+            text += " - " + m_sd1.getAliasName() + "\n";
+         if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
+            text += " - " + m_sd2.getAliasName() + "\n";
+         if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
+            text += " - " + m_sd3.getAliasName() + "\n";
+
+         KMessageBox::sorry( this, text, i18n("File Open Error") );
+         bFileOpenError = true;
+      }
+
+      if ( m_sd1.isEmpty() || m_sd2.isEmpty() || bFileOpenError )
+         slotFileOpen();
+   }
+   else if ( !bSuccess )  // Directory open failed
+   {
+      slotFileOpen();
+   }
+}
+
+KDiff3App::~KDiff3App()
+{
+
+}
+
+void KDiff3App::initActions( KActionCollection* ac )
+{
+   if (ac==0)   KMessageBox::error(0, "actionCollection==0");
+
+   fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), ac);
+   fileOpen->setStatusText(i18n("Opens documents for comparison..."));
+
+   fileReload  = new KAction(i18n("Reload"), /*QIconSet(QPixmap(reloadIcon)),*/ Key_F5, this, SLOT(slotReload()), ac, "file_reload");
+   
+   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);
+   fileSaveAs->setStatusText(i18n("Saves the current document as..."));
+   filePrint = KStdAction::print(this, SLOT(slotFilePrint()), ac);
+   filePrint->setStatusText(i18n("Print the differences"));
+   fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), ac);
+   fileQuit->setStatusText(i18n("Quits the application"));
+   editCut = KStdAction::cut(this, SLOT(slotEditCut()), ac);
+   editCut->setStatusText(i18n("Cuts the selected section and puts it to the clipboard"));
+   editCopy = KStdAction::copy(this, SLOT(slotEditCopy()), ac);
+   editCopy->setStatusText(i18n("Copies the selected section to the clipboard"));
+   editPaste = KStdAction::paste(this, SLOT(slotEditPaste()), ac);
+   editPaste->setStatusText(i18n("Pastes the clipboard contents to actual position"));
+   editSelectAll = KStdAction::selectAll(this, SLOT(slotEditSelectAll()), ac);
+   editSelectAll->setStatusText(i18n("Select everything in current window"));
+   editFind = KStdAction::find(this, SLOT(slotEditFind()), ac);
+   editFind->setStatusText(i18n("Search for a string"));
+   editFindNext = KStdAction::findNext(this, SLOT(slotEditFindNext()), ac);
+   editFindNext->setStatusText(i18n("Search again for the string"));
+   viewToolBar = KStdAction::showToolbar(this, SLOT(slotViewToolBar()), ac);
+   viewToolBar->setStatusText(i18n("Enables/disables the toolbar"));
+   viewStatusBar = KStdAction::showStatusbar(this, SLOT(slotViewStatusBar()), ac);
+   viewStatusBar->setStatusText(i18n("Enables/disables the statusbar"));
+   KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), ac);
+   KAction* pAction = KStdAction::preferences(this, SLOT(slotConfigure()), ac );
+   if ( isPart() )
+      pAction->setText(i18n("Configure KDiff3..."));
+
+
+#include "xpm/downend.xpm"
+#include "xpm/currentpos.xpm"
+#include "xpm/down1arrow.xpm"
+#include "xpm/down2arrow.xpm"
+#include "xpm/upend.xpm"
+#include "xpm/up1arrow.xpm"
+#include "xpm/up2arrow.xpm"
+#include "xpm/prevunsolved.xpm"
+#include "xpm/nextunsolved.xpm"
+#include "xpm/iconA.xpm"
+#include "xpm/iconB.xpm"
+#include "xpm/iconC.xpm"
+#include "xpm/autoadvance.xpm"
+#include "xpm/showwhitespace.xpm"
+#include "xpm/showwhitespacechars.xpm"
+#include "xpm/showlinenumbers.xpm"
+//#include "reload.xpm"
+
+   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");
+   QString omitsWhitespace = ".\n" + i18n("(Skips white space differences when \"Show White Space\" is disabled.)");
+   QString includeWhitespace = ".\n" + i18n("(Does not skip white space differences even when \"Show White Space\" is disabled.)");
+   goPrevDelta = new KAction(i18n("Go to Previous Delta"), QIconSet(QPixmap(up1arrow)), CTRL+Key_Up, this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta");
+   goPrevDelta->setToolTip( goPrevDelta->text() + omitsWhitespace );
+   goNextDelta = new KAction(i18n("Go to Next Delta"), QIconSet(QPixmap(down1arrow)), CTRL+Key_Down, this, SLOT(slotGoNextDelta()), ac, "go_next_delta");
+   goNextDelta->setToolTip( goNextDelta->text() + omitsWhitespace );
+   goPrevConflict = new KAction(i18n("Go to Previous Conflict"), QIconSet(QPixmap(up2arrow)), CTRL+Key_PageUp, this, SLOT(slotGoPrevConflict()), ac, "go_prev_conflict");
+   goPrevConflict->setToolTip( goPrevConflict->text() + omitsWhitespace );
+   goNextConflict = new KAction(i18n("Go to Next Conflict"), QIconSet(QPixmap(down2arrow)), CTRL+Key_PageDown, this, SLOT(slotGoNextConflict()), ac, "go_next_conflict");
+   goNextConflict->setToolTip( goNextConflict->text() + omitsWhitespace );
+   goPrevUnsolvedConflict = new KAction(i18n("Go to Previous Unsolved Conflict"), QIconSet(QPixmap(prevunsolved)), 0, this, SLOT(slotGoPrevUnsolvedConflict()), ac, "go_prev_unsolved_conflict");
+   goPrevUnsolvedConflict->setToolTip( goPrevUnsolvedConflict->text() + includeWhitespace );
+   goNextUnsolvedConflict = new KAction(i18n("Go to Next Unsolved Conflict"), QIconSet(QPixmap(nextunsolved)), 0, this, SLOT(slotGoNextUnsolvedConflict()), ac, "go_next_unsolved_conflict");
+   goNextUnsolvedConflict->setToolTip( goNextUnsolvedConflict->text() + includeWhitespace );
+   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(showwhitespacechars)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace_characters");
+   showWhiteSpace = new KToggleAction(i18n("Show White Space"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "diff_show_whitespace");
+
+   showLineNumbers = new KToggleAction(i18n("Show Line Numbers"), QIconSet(QPixmap(showlinenumbers)), 0, this, SLOT(slotShowLineNumbersToggled()), ac, "diff_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");
+   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()),      ac, "merge_autounsolve");
+   mergeRegExp  = new KAction(i18n("Run Regular Expression Auto Merge"),     0, this, SLOT(slotRegExpAutoMerge()),ac, "merge_regexp_automerge" );
+   mergeHistory = new KAction(i18n("Automatically Solve History Conflicts"), 0, this, SLOT(slotMergeHistory()), ac, "merge_versioncontrol_history" );
+   splitDiff    = new KAction(i18n("Split Diff At Selection"),               0, this, SLOT(slotSplitDiff()),    ac, "merge_splitdiff");
+   joinDiffs    = new KAction(i18n("Join Selected Diffs"),                   0, this, SLOT(slotJoinDiffs()),    ac, "merge_joindiffs");
+
+   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");
+   winFocusNext = new KAction(i18n("Focus Next Window"), ALT+Key_Right, this, SLOT(slotWinFocusNext()), ac, "win_focus_next");
+
+   overviewModeNormal = new KToggleAction(i18n("Normal Overview"), 0, this, SLOT(slotOverviewNormal()), ac, "diff_overview_normal");
+   overviewModeAB     = new KToggleAction(i18n("A vs. B Overview"), 0, this, SLOT(slotOverviewAB()), ac, "diff_overview_ab");
+   overviewModeAC     = new KToggleAction(i18n("A vs. C Overview"), 0, this, SLOT(slotOverviewAC()), ac, "diff_overview_ac");
+   overviewModeBC     = new KToggleAction(i18n("B vs. C Overview"), 0, this, SLOT(slotOverviewBC()), ac, "diff_overview_bc");
+   wordWrap     = new KToggleAction(i18n("Word Wrap Diff Windows"), 0, this, SLOT(slotWordWrapToggled()), ac, "diff_wordwrap");
+   addManualDiffHelp  = new KAction(i18n("Add Manual Diff Alignment"), Qt::CTRL+Qt::Key_Y, this, SLOT(slotAddManualDiffHelp()), ac, "diff_add_manual_diff_help");
+   clearManualDiffHelpList  = new KAction(i18n("Clear All Manual Diff Alignments"), Qt::CTRL+Qt::SHIFT+Qt::Key_Y, this, SLOT(slotClearManualDiffHelpList()), ac, "diff_clear_manual_diff_help_list");
+
+#ifdef _WIN32
+   new KAction(i18n("Focus Next Window"), Qt::CTRL+Qt::Key_Tab, this, SLOT(slotWinFocusNext()), ac, "win_focus_next", false, false);
+#endif
+   winFocusPrev = new KAction(i18n("Focus Prev Window"), Qt::ALT+Qt::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");
+
+   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 && Text View"), 0, this, SLOT(slotDirViewToggle()), actionCollection(), "win_dir_view_toggle");
+
+   m_pMergeEditorPopupMenu = new QPopupMenu( this );
+   chooseA->plug( m_pMergeEditorPopupMenu );
+   chooseB->plug( m_pMergeEditorPopupMenu );
+   chooseC->plug( m_pMergeEditorPopupMenu );
+}
+
+
+void KDiff3App::showPopupMenu( const QPoint& point )
+{
+   m_pMergeEditorPopupMenu->popup( point );
+}
+
+void KDiff3App::initStatusBar()
+{
+  ///////////////////////////////////////////////////////////////////
+  // STATUSBAR
+  if (statusBar() !=0 )
+     statusBar()->message( i18n("Ready.") );
+}
+
+void KDiff3App::saveOptions( KConfig* config )
+{
+   if (!isPart())
+   {
+      m_pOptionDialog->m_bMaximised = m_pKDiff3Shell->isMaximized();
+      if( ! m_pKDiff3Shell->isMaximized() )
+      {
+         m_pOptionDialog->m_geometry = m_pKDiff3Shell->size();
+         m_pOptionDialog->m_position = m_pKDiff3Shell->pos();
+      }
+      if ( toolBar("mainToolBar")!=0 )
+         m_pOptionDialog->m_toolBarPos = (int) toolBar("mainToolBar")->barPos();
+   }
+
+   m_pOptionDialog->saveOptions( config );
+}
+
+
+
+
+bool KDiff3App::queryClose()
+{
+   saveOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+   if(m_bOutputModified)
+   {
+      int result = KMessageBox::warningYesNoCancel(this,
+         i18n("The merge result hasn't been saved."),
+         i18n("Warning"), i18n("Save && Quit"), i18n("Quit Without Saving") );
+      if ( result==KMessageBox::Cancel )
+         return false;
+      else if ( result==KMessageBox::Yes )
+      {
+         slotFileSave();
+         if ( m_bOutputModified )
+         {
+            KMessageBox::sorry(this, i18n("Saving the merge result failed."), i18n("Warning") );
+            return false;
+         }
+      }
+   }
+
+   m_bOutputModified = false;
+
+   if ( m_pDirectoryMergeWindow->isDirectoryMergeInProgress() )
+   {
+      int result = KMessageBox::warningYesNo(this,
+         i18n("You are currently doing a directory merge. Are you sure, you want to abort?"),
+         i18n("Warning"), i18n("Quit"), i18n("Continue Merging") );
+      if ( result!=KMessageBox::Yes )
+         return false;
+   }
+
+   return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// SLOT IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+
+
+void KDiff3App::slotFileSave()
+{
+   if ( m_bDefaultFilename )
+   {
+      slotFileSaveAs();
+   }
+   else
+   {
+      slotStatusMsg(i18n("Saving file..."));
+
+      bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding() );
+      if ( bSuccess )
+      {
+         m_bFileSaved = true;
+         m_bOutputModified = false;
+         if ( m_bDirCompare )
+            m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename);
+      }
+
+      slotStatusMsg(i18n("Ready."));
+   }
+}
+
+void KDiff3App::slotFileSaveAs()
+{
+  slotStatusMsg(i18n("Saving file with a new filename..."));
+
+  QString s = KFileDialog::getSaveURL( QDir::currentDirPath(), 0, this, i18n("Save As...") ).url();
+  if(!s.isEmpty())
+  {
+     m_outputFilename = s;
+     m_pMergeResultWindowTitle->setFileName( m_outputFilename );
+     bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename, m_pMergeResultWindowTitle->getEncoding() );
+     if ( bSuccess )
+     {
+        m_bOutputModified = false;
+        if ( m_bDirCompare )
+           m_pDirectoryMergeWindow->mergeResultSaved(m_outputFilename);
+     }
+     //setCaption(url.fileName(),doc->isModified());
+
+     m_bDefaultFilename = false;
+  }
+
+  slotStatusMsg(i18n("Ready."));
+}
+
+
+void printDiffTextWindow( MyPainter& painter, const QRect& view, const QString& headerText, DiffTextWindow* pDiffTextWindow, int line, int linesPerPage, QColor fgColor )
+{
+   QRect clipRect = view;
+   clipRect.setTop(0);
+   painter.setClipRect( clipRect );
+   painter.translate( view.left() , 0 );
+   QFontMetrics fm = painter.fontMetrics();
+   //if ( fm.width(headerText) > view.width() )
+   {
+      // A simple wrapline algorithm
+      int l=0;
+      for (unsigned int p=0; p<headerText.length(); )
+      {
+         QString s = headerText.mid(p);
+         unsigned int i;
+         for(i=2;i<s.length();++i) 
+            if (fm.width(s,i)>view.width())
+            {
+               --i;
+               break;
+            }
+         //QString s2 = s.left(i);
+         painter.drawText( 0, l*fm.height() + fm.ascent(), s.left(i) );
+         p+=i;
+         ++l;
+      }
+      painter.setPen( fgColor );
+      painter.drawLine( 0, view.top()-2, view.width(), view.top()-2 );
+   }
+
+   painter.translate( 0, view.top() );
+   pDiffTextWindow->print( painter, view, line, linesPerPage );
+   painter.resetXForm();
+}
+
+void KDiff3App::slotFilePrint()
+{
+   if ( !m_pDiffTextWindow1 )
+      return;
+
+   KPrinter printer;
+
+   int firstSelectionD3LIdx = -1;
+   int lastSelectionD3LIdx = -1;
+   if (                           m_pDiffTextWindow1 ) { m_pDiffTextWindow1->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+   if ( firstSelectionD3LIdx<0 && m_pDiffTextWindow2 ) { m_pDiffTextWindow2->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+   if ( firstSelectionD3LIdx<0 && m_pDiffTextWindow3 ) { m_pDiffTextWindow3->getSelectionRange(&firstSelectionD3LIdx, &lastSelectionD3LIdx, eD3LLineCoords); }
+#ifdef KREPLACEMENTS_H  // Currently PrintSelection is not supported in KDEs print dialog.
+   if ( firstSelectionD3LIdx>=0 )
+   {
+      printer.setOptionEnabled(KPrinter::PrintSelection,true);
+   }
+#endif
+
+   printer.setPageSelection(KPrinter::ApplicationSide);
+   printer.setMinMax(1,10000);
+   printer.setCurrentPage(10000);
+
+   int currentFirstLine = m_pDiffTextWindow1->getFirstLine();
+   int currentFirstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx( currentFirstLine );
+
+   // do some printer initialization
+   printer.setFullPage( false );
+
+   // initialize the printer using the print dialog
+   if ( printer.setup( this ) )
+   {
+      slotStatusMsg( i18n( "Printing..." ) );
+      // create a painter to paint on the printer object
+      MyPainter painter( 0, m_pOptionDialog->m_bRightToLeftLanguage, width(), fontMetrics().width('W') );
+
+      // start painting
+      if( !painter.begin( &printer ) ) {               // paint on printer
+         slotStatusMsg( i18n( "Printing aborted." ) );
+         return;
+      }
+      QPaintDeviceMetrics metrics( painter.device() );
+      int dpiy = metrics.logicalDpiY();
+      int columnDistance = (int) ( (0.5/2.54)*dpiy ); // 0.5 cm between the columns
+
+      int columns = m_bTripleDiff ? 3 : 2;
+      int columnWidth = ( metrics.width()  - (columns-1)*columnDistance ) / columns;
+
+      QFont f = m_pOptionDialog->m_font;
+      f.setPointSizeFloat(f.pointSizeFloat()-1); // Print with slightly smaller font.
+      painter.setFont( f );
+      QFontMetrics fm = painter.fontMetrics();
+
+      QString topLineText = i18n("Top line"); 
+
+      //int headerWidth = fm.width( m_sd1.getAliasName() + ", "+topLineText+": 01234567" );
+      int headerLines = fm.width( m_sd1.getAliasName() + ", "+topLineText+": 01234567" )/columnWidth+1;
+
+      int headerMargin = headerLines * fm.height() + 3; // Text + one horizontal line
+      int footerMargin = fm.height() + 3;
+
+      QRect view ( 0, headerMargin, metrics.width(), metrics.height() - (headerMargin + footerMargin) );
+      QRect view1( 0*(columnWidth + columnDistance), view.top(), columnWidth,     view.height() );
+      QRect view2( 1*(columnWidth + columnDistance), view.top(), columnWidth,     view.height() );
+      QRect view3( 2*(columnWidth + columnDistance), view.top(), columnWidth,     view.height() );
+
+      int linesPerPage = view.height() / fm.height();
+      int charactersPerLine = columnWidth / fm.width("W");
+      if ( m_pOptionDialog->m_bWordWrap )
+      {
+         // For printing the lines are wrapped differently (this invalidates the first line)
+         recalcWordWrap( charactersPerLine );
+      }
+
+      int totalNofLines = max2(m_pDiffTextWindow1->getNofLines(), m_pDiffTextWindow2->getNofLines());
+      if ( m_bTripleDiff && m_pDiffTextWindow3)
+         totalNofLines = max2(totalNofLines, m_pDiffTextWindow3->getNofLines());
+
+      QValueList<int> pageList = printer.pageList();
+
+      bool bPrintCurrentPage=false;
+      bool bFirstPrintedPage = false;
+
+      bool bPrintSelection = false;
+      int totalNofPages = (totalNofLines+linesPerPage-1) / linesPerPage;
+      int line=-1;
+      int selectionEndLine = -1;
+
+#ifdef KREPLACEMENTS_H
+      if ( printer.printRange()==KPrinter::AllPages )
+      {
+         pageList.clear();
+         for(int i=0; i<totalNofPages; ++i)
+         {
+            pageList.push_back(i+1);
+         }
+      }
+
+      if ( printer.printRange()==KPrinter::Selection )
+#else
+      if ( !pageList.empty() && pageList.front()==9999 )
+#endif
+      {
+         bPrintSelection = true;
+         if ( firstSelectionD3LIdx >=0 )
+         {
+            line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( firstSelectionD3LIdx );
+            selectionEndLine = m_pDiffTextWindow1->convertDiff3LineIdxToLine( lastSelectionD3LIdx+1 );
+            totalNofPages = (selectionEndLine-line+linesPerPage-1) / linesPerPage;
+         }
+      }
+
+      int page = 1;
+
+      QValueList<int>::iterator pageListIt = pageList.begin();
+      for(;;)
+      {
+         if (!bPrintSelection)
+         {
+            if (pageListIt==pageList.end())
+               break;
+            page = *pageListIt;
+            line = (page - 1) * linesPerPage;
+            if (page==10000)  // This means "Print the current page"
+            {
+               bPrintCurrentPage=true;
+               // Detect the first visible line in the window.
+               line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx );
+            }
+         }
+         else
+         {
+            if ( line>=selectionEndLine )
+            {
+               break;
+            }
+            else
+            {
+               if ( selectionEndLine-line < linesPerPage )
+                  linesPerPage=selectionEndLine-line;
+            }
+         }
+         if (line>=0 && line<totalNofLines )
+         {
+
+            if (bFirstPrintedPage)
+               printer.newPage();
+
+            painter.setClipping(true);
+
+            painter.setPen( m_pOptionDialog->m_colorA );
+            QString headerText1 = m_sd1.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow1->calcTopLineInFile(line)+1);
+            printDiffTextWindow( painter, view1, headerText1, m_pDiffTextWindow1, line, linesPerPage, m_pOptionDialog->m_fgColor );
+
+            painter.setPen( m_pOptionDialog->m_colorB );
+            QString headerText2 = m_sd2.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow2->calcTopLineInFile(line)+1);
+            printDiffTextWindow( painter, view2, headerText2, m_pDiffTextWindow2, line, linesPerPage, m_pOptionDialog->m_fgColor );
+
+            if ( m_bTripleDiff && m_pDiffTextWindow3 )
+            {
+               painter.setPen( m_pOptionDialog->m_colorC );
+               QString headerText3 = m_sd3.getAliasName() + ", "+topLineText+": " + QString::number(m_pDiffTextWindow3->calcTopLineInFile(line)+1);
+               printDiffTextWindow( painter, view3, headerText3, m_pDiffTextWindow3, line, linesPerPage, m_pOptionDialog->m_fgColor );
+            }
+            painter.setClipping(false);
+
+            painter.setPen( m_pOptionDialog->m_fgColor );
+            painter.drawLine( 0, view.bottom()+3, view.width(), view.bottom()+3 ); 
+            QString s = bPrintCurrentPage ? QString("") 
+                                          : QString::number( page ) + "/" + QString::number(totalNofPages);
+            if ( bPrintSelection ) s+=" (" + i18n("Selection") + ")";
+            painter.drawText( (view.right() - painter.fontMetrics().width( s ))/2,
+                        view.bottom() + painter.fontMetrics().ascent() + 5, s );
+
+            bFirstPrintedPage = true;
+         }
+
+         if ( bPrintSelection )
+         {
+            line+=linesPerPage;
+            ++page;
+         }
+         else
+         {
+            ++pageListIt;
+         }
+      }
+
+      painter.end();
+
+      if ( m_pOptionDialog->m_bWordWrap )
+      {
+         recalcWordWrap();
+         m_pDiffVScrollBar->setValue( m_pDiffTextWindow1->convertDiff3LineIdxToLine( currentFirstD3LIdx ) );
+      }
+
+      slotStatusMsg( i18n( "Printing completed." ) );
+   }
+   else
+   {
+      slotStatusMsg( i18n( "Printing aborted." ) );
+   }
+}
+
+void KDiff3App::slotFileQuit()
+{
+   slotStatusMsg(i18n("Exiting..."));
+
+   if( !queryClose() )
+       return;      // Don't quit
+
+   KApplication::exit( isFileSaved() ? 0 : 1 );
+}
+
+
+
+void KDiff3App::slotViewToolBar()
+{
+   slotStatusMsg(i18n("Toggling toolbar..."));
+   m_pOptionDialog->m_bShowToolBar = viewToolBar->isChecked();
+   ///////////////////////////////////////////////////////////////////
+   // turn Toolbar on or off
+   if ( toolBar("mainToolBar") !=0 )
+   {
+      if(!m_pOptionDialog->m_bShowToolBar)
+      {
+         toolBar("mainToolBar")->hide();
+      }
+      else
+      {
+         toolBar("mainToolBar")->show();
+      }
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotViewStatusBar()
+{
+   slotStatusMsg(i18n("Toggle the statusbar..."));
+   m_pOptionDialog->m_bShowStatusBar = viewStatusBar->isChecked();
+   ///////////////////////////////////////////////////////////////////
+   //turn Statusbar on or off
+   if (statusBar() !=0 )
+   {
+      if(!viewStatusBar->isChecked())
+      {
+         statusBar()->hide();
+      }
+      else
+      {
+         statusBar()->show();
+      }
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+
+void KDiff3App::slotStatusMsg(const QString &text)
+{
+   ///////////////////////////////////////////////////////////////////
+   // change status message permanently
+   if (statusBar() !=0 )
+   {
+      statusBar()->clear();
+      statusBar()->message( text );
+   }
+}
+
+
+
+
+#include "kdiff3.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.desktop	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,83 @@
+
+[Desktop Entry]
+Encoding=UTF-8
+Name=KDiff3
+Name[hi]=के-डिफ3
+Name[sv]=Kdiff3
+Name[ta]=கேடிஃபà¯3
+Name[xx]=xxKDiff3xx
+GenericName=Diff/Patch Frontend
+GenericName[bg]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð½Ð° Diff/Patch
+GenericName[bs]=Interfejs za Diff/Patch
+GenericName[ca]=Interfície per a diff/patch
+GenericName[cs]=Rozhraní pro Diff/Patch
+GenericName[cy]=Blaen Gwahaniaethau/Clytiau
+GenericName[da]=Forende for diff/patch
+GenericName[de]=Graphische Oberfläche zu Diff/Patch
+GenericName[el]=ΣÏστημα υποστήÏιξης χÏήστη για τα Diff/Patch
+GenericName[es]=Interfaz Diff/Patch
+GenericName[et]=Võrdlemise ja liitmise rakendus
+GenericName[fr]=Interface graphique à diff / patch
+GenericName[ga]=Comhéadan Diff/Patch
+GenericName[hi]=डिफ/पैच फà¥à¤°à¤¨à¥à¤Ÿà¤à¤£à¥à¤¡
+GenericName[hu]=Grafikus diff/patch
+GenericName[is]=Diff/Patch viðmót
+GenericName[it]=Interfaccia per diff/patch
+GenericName[ja]=Diff/Patch フロントエンド
+GenericName[lt]=Diff/Patch naudotojo sÄ…saja
+GenericName[ms]=Bahagian Depan Beza/Tampal
+GenericName[nb]=Endrings-/lappeprogram
+GenericName[nl]=Een schil voor Diff/Patch
+GenericName[pa]=Diff/Patch ਮà©à©±à¨–
+GenericName[pl]=Interfejs do programów Diff/Patch
+GenericName[pt]=Interface do Diff/Patch
+GenericName[pt_BR]=Um front-end para Diff/Patch
+GenericName[ru]=ГрафичеÑкий Ð¸Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ðº Diff и Patch
+GenericName[sr]=Ð˜Ð½Ñ‚ÐµÑ€Ñ„ÐµÑ˜Ñ Ð·Ð° diff и patch
+GenericName[sr@Latn]=Interfejs za diff i patch
+GenericName[sv]=Jämförelse- och programfixgränssnitt
+GenericName[ta]= Diff/Patch Frontend
+GenericName[tg]=ИнтерфейÑи графикӣ ба Diff ва Patch
+GenericName[tr]=Diff/Patch Arayüzü
+GenericName[uk]=Ð†Ð½Ñ‚ÐµÑ€Ñ„ÐµÐ¹Ñ Ð´Ð¾ diff/patch
+GenericName[xx]=xxDiff/Patch Frontendxx
+GenericName[zh_CN]=Diff/Patch å‰ç«¯
+GenericName[zu]=Diff/PatchIsiqalo sokugcina
+Exec=kdiff3 %i %m -caption "%c"
+Icon=kdiff3
+Type=Application
+DocPath=kdiff3/index.html
+Comment=A File And Directory Comparison And Merge Tool
+Comment[bg]=ИнÑтрумент за ÑравнÑване и Ñливане на файлове и директории
+Comment[bs]=Alat za upoređivanje i spajanje datoteka i direktorija
+Comment[ca]=Una eina per a comparar i fusionar fitxers o directoris
+Comment[cs]=Nástroj pro porovnávání a sluÄování souborů a adresářů
+Comment[da]=Et indfletningsværktøj for filer og mapper
+Comment[de]=Programm zum Vergleichen und Zusammenführen von Dateien und Ordnern
+Comment[el]=Ένα εÏγαλείο σÏγκÏισης και συγχώνευσης αÏχείων και καταλόγων
+Comment[es]=Una herramienta para mezclar y comparar archivos y directorios
+Comment[et]=Failide ja kataloogide võrdlemise ja liitmise tööriist
+Comment[fr]=Un outil de comparaison et de fusion de fichiers et dossiers
+Comment[hi]=à¤à¤• फाइल तथा डिरेकà¥à¤Ÿà¥à¤°à¥€ तà¥à¤²à¤¨à¤¾ तथा विलीन उपकरण
+Comment[hu]=Segédprogram fájlok, könyvtárak összehasonlításához
+Comment[is]=Skráa og möppu samanburðar og sameiningartól
+Comment[it]=Uno strumento di confronto e unione di file e directory
+Comment[ja]=ファイル/ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æ¯”較/çµ±åˆãƒ„ール
+Comment[ka]=ფáƒáƒ˜áƒšáƒ—რდრსáƒáƒ¥áƒáƒ¦áƒáƒšáƒ“ეთრშედáƒáƒ áƒ”ბის დრშერწყმის ხელსáƒáƒ¬áƒ§áƒ
+Comment[ms]=Perbandingan Fail Dan Direktori Dan Alatan Gabungan
+Comment[nb]=Et verktøy for å sammenlikne og slå sammen filer og mapper
+Comment[nl]=Hulpmiddel voor het vergelijken en samenvoegen van bestanden en mappen
+Comment[pa]=ਇੱਕ ਫਾਇਲ ਅਤੇ ਡਾਇਰੈਕਟਰੀ ਤà©à¨²à¨¨à¨¾ ਅਤੇ ਮਿਲਾਨ ਸੰਦ ਹੈ
+Comment[pl]=Narzędzie do porównywania oraz łączenia plików i katalogów
+Comment[pt]=Uma Ferramenta de Comparação e Junção de Ficheiros e Pastas
+Comment[pt_BR]=Uma Ferramenta de Comparação e Mesclagem de Arquivos e Diretórios
+Comment[ru]=Утилита ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð¸ Ð¾Ð±ÑŠÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² и каталогов
+Comment[sr]=Ðлат за поређење и Ñтапање фајлова и директоријума
+Comment[sr@Latn]=Alat za poređenje i stapanje fajlova i direktorijuma
+Comment[sv]=Ett jämförelseverktyg för fil- och katalogjämförelser
+Comment[tg]=ÐÑбоби баробаркунӣ ва пайванди файлҳо ва каталогҳо
+Comment[tr]=Bir Dosya Ve Klasör Karşılaştırma Ve Birleştirme Aracı
+Comment[uk]=ЗаÑіб-утиліта Ð´Ð»Ñ Ð¿Ð¾Ñ€Ñ–Ð²Ð½ÑÐ½Ð½Ñ Ñ– Ð¿Ð¾Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² та каталогів
+Comment[xx]=xxA File And Directory Comparison And Merge Toolxx
+Comment[zh_CN]=一个文件和目录的比较åŠåˆå¹¶å·¥å…·
+Terminal=false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,409 @@
+/***************************************************************************
+                          kdiff3.h  -  description
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef KDIFF3_H
+#define KDIFF3_H
+
+#include "diff.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// include files for Qt
+#include <qdialog.h>
+#include <qsplitter.h>
+#include <qscrollbar.h>
+
+// include files for KDE
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kurl.h>
+#include <kparts/mainwindow.h>
+
+
+// forward declaration of the KDiff3 classes
+class OptionDialog;
+class FindDialog;
+class ManualDiffHelpDialog;
+class DiffTextWindow;
+class DiffTextWindowFrame;
+class MergeResultWindow;
+class WindowTitleWidget;
+class Overview;
+
+class QScrollBar;
+class QComboBox;
+class QLineEdit;
+class QCheckBox;
+class QSplitter;
+
+
+class KDiff3Part;
+class DirectoryMergeWindow;
+class DirectoryMergeInfo;
+
+
+class ReversibleScrollBar : public QScrollBar
+{
+   Q_OBJECT
+   bool* m_pbRightToLeftLanguage;
+   int m_realVal;
+public:
+   ReversibleScrollBar( Orientation o, QWidget* pParent, bool* pbRightToLeftLanguage )
+      : QScrollBar( o, pParent )
+   {
+      m_pbRightToLeftLanguage=pbRightToLeftLanguage;
+      m_realVal=0;
+      connect( this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)));
+   }
+   void setAgain(){ setValue(m_realVal); }
+public slots:
+   void slotValueChanged(int i)
+   {
+      m_realVal = i;
+      if(m_pbRightToLeftLanguage && *m_pbRightToLeftLanguage)
+         m_realVal = maxValue()-(i-minValue());
+      emit valueChanged2(m_realVal);
+   }
+   void setValue(int i)
+   {
+      if(m_pbRightToLeftLanguage && *m_pbRightToLeftLanguage)
+         QScrollBar::setValue( maxValue()-(i-minValue())  );
+      else
+         QScrollBar::setValue( i );
+   }
+signals:
+   void valueChanged2(int);
+};
+
+class KDiff3App : public QSplitter
+{
+  Q_OBJECT
+
+  public:
+    /** constructor of KDiff3App, calls all init functions to create the application.
+     */
+    KDiff3App( QWidget* parent, const char* name, KDiff3Part* pKDiff3Part );
+    ~KDiff3App();
+
+    bool isPart();
+
+    /** initializes the KActions of the application */
+    void initActions( KActionCollection* );
+
+    /** save general Options like all bar positions and status as well as the geometry
+        and the recent file list to the configuration file */
+    void saveOptions( KConfig* );
+
+    /** read general Options again and initialize all variables like the recent file list */
+    void readOptions( KConfig* );
+
+    // Finish initialisation (virtual, so that it can be called from the shell too.)
+    virtual void completeInit(const QString& fn1="", const QString& fn2="", const QString& fn3="");
+
+    /** queryClose is called by KMainWindow on each closeEvent of a window. Against the
+     * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall
+     * be saved if Modified; on cancel the closeEvent is rejected.
+     * @see KMainWindow#queryClose
+     * @see KMainWindow#closeEvent
+     */
+    virtual bool queryClose();
+    virtual bool isFileSaved();
+
+  signals:
+     void createNewInstance( const QString& fn1, const QString& fn2, const QString& fn3 );
+  protected:
+    void initDirectoryMergeActions();
+    /** sets up the statusbar for the main window by initialzing a statuslabel. */
+    void initStatusBar();
+
+    /** creates the centerwidget of the KMainWindow instance and sets it as the view */
+    void initView();
+
+  public slots:
+
+    /** open a file and load it into the document*/
+    void slotFileOpen();
+    void slotFileOpen2( QString fn1, QString fn2, QString fn3, QString ofn,
+                        QString an1, QString an2, QString an3, TotalDiffStatus* pTotalDiffStatus );
+
+    void slotFileNameChanged(const QString& fileName, int winIdx);
+
+    /** save a document */
+    void slotFileSave();
+    /** save a document by a new filename*/
+    void slotFileSaveAs();
+
+    void slotFilePrint();
+
+    /** closes all open windows by calling close() on each memberList item until the list is empty, then quits the application.
+     * If queryClose() returns false because the user canceled the saveModified() dialog, the closing breaks.
+     */
+    void slotFileQuit();
+    /** put the marked text/object into the clipboard and remove
+     *  it from the document
+     */
+    void slotEditCut();
+    /** put the marked text/object into the clipboard
+     */
+    void slotEditCopy();
+    /** paste the clipboard into the document
+     */
+    void slotEditPaste();
+    /** toggles the toolbar
+     */
+    void slotViewToolBar();
+    /** toggles the statusbar
+     */
+    void slotViewStatusBar();
+    /** changes the statusbar contents for the standard label permanently, used to indicate current actions.
+     * @param text the text that is displayed in the statusbar
+     */
+    void slotStatusMsg(const QString &text);
+
+  private:
+    /** the configuration object of the application */
+    //KConfig *config;
+
+    // KAction pointers to enable/disable actions
+    KAction* fileOpen;
+    KAction* fileSave;
+    KAction* fileSaveAs;
+    KAction* filePrint;
+    KAction* fileQuit;
+    KAction* fileReload;
+    KAction* editCut;
+    KAction* editCopy;
+    KAction* editPaste;
+    KAction* editSelectAll;
+    KToggleAction* viewToolBar;
+    KToggleAction* viewStatusBar;
+
+////////////////////////////////////////////////////////////////////////
+// Special KDiff3 specific stuff starts here
+    KAction *editFind;
+    KAction *editFindNext;
+
+    KAction *goCurrent;
+    KAction *goTop;
+    KAction *goBottom;
+    KAction *goPrevUnsolvedConflict;
+    KAction *goNextUnsolvedConflict;
+    KAction *goPrevConflict;
+    KAction *goNextConflict;
+    KAction *goPrevDelta;
+    KAction *goNextDelta;
+    KToggleAction *chooseA;
+    KToggleAction *chooseB;
+    KToggleAction *chooseC;
+    KToggleAction *autoAdvance;
+    KToggleAction *wordWrap;
+    KAction* splitDiff;
+    KAction* joinDiffs;
+    KAction* addManualDiffHelp;
+    KAction* clearManualDiffHelpList;
+    KToggleAction *showWhiteSpaceCharacters;
+    KToggleAction *showWhiteSpace;
+    KToggleAction *showLineNumbers;
+    KAction* chooseAEverywhere;
+    KAction* chooseBEverywhere;
+    KAction* chooseCEverywhere;
+    KAction* chooseAForUnsolvedConflicts;
+    KAction* chooseBForUnsolvedConflicts;
+    KAction* chooseCForUnsolvedConflicts;
+    KAction* chooseAForUnsolvedWhiteSpaceConflicts;
+    KAction* chooseBForUnsolvedWhiteSpaceConflicts;
+    KAction* chooseCForUnsolvedWhiteSpaceConflicts;
+    KAction* autoSolve;
+    KAction* unsolve;
+    KAction* mergeHistory;
+    KAction* mergeRegExp;
+    KToggleAction *showWindowA;
+    KToggleAction *showWindowB;
+    KToggleAction *showWindowC;
+    KAction *winFocusNext;
+    KAction *winFocusPrev;
+    KAction* winToggleSplitOrientation;
+    KToggleAction *dirShowBoth;
+    KAction *dirViewToggle;
+    KToggleAction *overviewModeNormal;
+    KToggleAction *overviewModeAB;
+    KToggleAction *overviewModeAC;
+    KToggleAction *overviewModeBC;
+
+
+    QPopupMenu* m_pMergeEditorPopupMenu;
+
+    QSplitter*  m_pMainSplitter;
+    QWidget*    m_pMainWidget;
+    QWidget*    m_pMergeWindowFrame;
+    ReversibleScrollBar* m_pHScrollBar;
+    QScrollBar* m_pDiffVScrollBar;
+    QScrollBar* m_pMergeVScrollBar;
+
+    DiffTextWindow* m_pDiffTextWindow1;
+    DiffTextWindow* m_pDiffTextWindow2;
+    DiffTextWindow* m_pDiffTextWindow3;
+    DiffTextWindowFrame* m_pDiffTextWindowFrame1;
+    DiffTextWindowFrame* m_pDiffTextWindowFrame2;
+    DiffTextWindowFrame* m_pDiffTextWindowFrame3;
+    QSplitter* m_pDiffWindowSplitter;
+
+    MergeResultWindow* m_pMergeResultWindow;
+    WindowTitleWidget* m_pMergeResultWindowTitle;
+    bool m_bTripleDiff;
+
+    QSplitter* m_pDirectoryMergeSplitter;
+    DirectoryMergeWindow* m_pDirectoryMergeWindow;
+    DirectoryMergeInfo* m_pDirectoryMergeInfo;
+    bool m_bDirCompare;
+
+    Overview* m_pOverview;
+
+    QWidget* m_pCornerWidget;
+
+    TotalDiffStatus m_totalDiffStatus;
+
+    SourceData m_sd1;
+    SourceData m_sd2;
+    SourceData m_sd3;
+
+   QString m_outputFilename;
+   bool m_bDefaultFilename;
+
+   DiffList m_diffList12;
+   DiffList m_diffList23;
+   DiffList m_diffList13;
+
+   DiffBufferInfo m_diffBufferInfo;
+   Diff3LineList m_diff3LineList;
+   Diff3LineVector m_diff3LineVector;
+   //ManualDiffHelpDialog* m_pManualDiffHelpDialog;
+   ManualDiffHelpList m_manualDiffHelpList;
+
+   int m_neededLines;
+   int m_maxWidth;
+   int m_DTWHeight;
+   bool m_bOutputModified;
+   bool m_bFileSaved;
+   bool m_bTimerBlock;      // Synchronisation
+
+   OptionDialog* m_pOptionDialog;
+   FindDialog*   m_pFindDialog;
+
+   void init( bool bAuto=false, TotalDiffStatus* pTotalDiffStatus=0, bool bLoadFiles=true );
+
+   virtual bool eventFilter( QObject* o, QEvent* e );
+   virtual void resizeEvent(QResizeEvent*);
+
+   bool improveFilenames(bool bCreateNewInstance);
+
+   bool runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList, int winIdx1, int winIdx2 );
+   bool runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList );
+   bool canContinue();
+
+   void choose(int choice);
+
+   KActionCollection* actionCollection();
+   KStatusBar*        statusBar();
+   KToolBar*          toolBar(const char*);
+   KDiff3Part*        m_pKDiff3Part;
+   KParts::MainWindow*       m_pKDiff3Shell;
+   bool m_bAuto;
+   void recalcWordWrap(int nofVisibleColumns=-1);
+
+public slots:
+   void resizeDiffTextWindow(int newWidth, int newHeight);
+   void resizeMergeResultWindow();
+   void slotRecalcWordWrap();
+
+   void showPopupMenu( const QPoint& point );
+
+   void scrollDiffTextWindow( int deltaX, int deltaY );
+   void scrollMergeResultWindow( int deltaX, int deltaY );
+   void setDiff3Line( int line );
+   void sourceMask( int srcMask, int enabledMask );
+
+   void slotDirShowBoth();
+   void slotDirViewToggle();
+
+   void slotUpdateAvailabilities();
+   void slotEditSelectAll();
+   void slotEditFind();
+   void slotEditFindNext();
+   void slotGoCurrent();
+   void slotGoTop();
+   void slotGoBottom();
+   void slotGoPrevUnsolvedConflict();
+   void slotGoNextUnsolvedConflict();
+   void slotGoPrevConflict();
+   void slotGoNextConflict();
+   void slotGoPrevDelta();
+   void slotGoNextDelta();
+   void slotChooseA();
+   void slotChooseB();
+   void slotChooseC();
+   void slotAutoSolve();
+   void slotUnsolve();
+   void slotMergeHistory();
+   void slotRegExpAutoMerge();
+   void slotChooseAEverywhere();
+   void slotChooseBEverywhere();
+   void slotChooseCEverywhere();
+   void slotChooseAForUnsolvedConflicts();
+   void slotChooseBForUnsolvedConflicts();
+   void slotChooseCForUnsolvedConflicts();
+   void slotChooseAForUnsolvedWhiteSpaceConflicts();
+   void slotChooseBForUnsolvedWhiteSpaceConflicts();
+   void slotChooseCForUnsolvedWhiteSpaceConflicts();
+   void slotConfigure();
+   void slotConfigureKeys();
+   void slotRefresh();
+   void slotSelectionEnd();
+   void slotSelectionStart();
+   void slotClipboardChanged();
+   void slotOutputModified(bool);
+   void slotAfterFirstPaint();
+   void slotMergeCurrentFile();
+   void slotReload();
+   void slotCheckIfCanContinue( bool* pbContinue );
+   void slotShowWhiteSpaceToggled();
+   void slotShowLineNumbersToggled();
+   void slotAutoAdvanceToggled();
+   void slotWordWrapToggled();
+   void slotShowWindowAToggled();
+   void slotShowWindowBToggled();
+   void slotShowWindowCToggled();
+   void slotWinFocusNext();
+   void slotWinFocusPrev();
+   void slotWinToggleSplitterOrientation();
+   void slotOverviewNormal();
+   void slotOverviewAB();
+   void slotOverviewAC();
+   void slotOverviewBC();
+   void slotSplitDiff();
+   void slotJoinDiffs();
+   void slotAddManualDiffHelp();
+   void slotClearManualDiffHelpList();
+
+   void slotNoRelevantChangesDetected();
+};
+
+#endif // KDIFF3_H
Binary file kdiff3/src/kdiff3.ico has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.lsm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,16 @@
+Begin3
+Title:          kdiff3 -- Comparison and Merge of Files and Directories
+Version:        0.9.89
+Entered-date:   
+Description:    Tool for comparison and merge of two or three files or directories
+Keywords:       KDE Qt
+Author:         Joachim Eibl <joachim at gmx.de>
+Maintained-by:  Joachim Eibl <joachim at gmx.de>
+Home-page:      http://kdiff3.sourceforge.net
+Alternate-site: http://extragear.kde.org/apps/kdiff3
+Primary-site:   http://sourceforge.net/project/showfiles.php?group_id=58666
+                xxxxxx  kdiff3-0.9.89.tar.gz
+                xxx     kdiff3-0.9.89.lsm
+Platform:       Linux. Needs Qt, runs even better on KDE
+Copying-policy: GPL
+End
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.pro	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,57 @@
+TEMPLATE = app
+# When unresolved items remain during linking: Try adding "shared" in the CONFIG.
+CONFIG  += qt warn_on thread release
+HEADERS  = version.h                     \
+           diff.h                        \
+           difftextwindow.h              \
+           mergeresultwindow.h           \
+           kdiff3.h                      \
+           merger.h                      \
+           optiondialog.h                \
+           kreplacements/kreplacements.h \
+           directorymergewindow.h        \
+           fileaccess.h                  \
+           kdiff3_shell.h                \
+           kdiff3_part.h                 \
+           smalldialogs.h
+SOURCES  = main.cpp                      \
+           diff.cpp                      \
+           difftextwindow.cpp            \
+           kdiff3.cpp                    \
+           merger.cpp                    \
+           mergeresultwindow.cpp         \
+           optiondialog.cpp              \
+           pdiff.cpp                     \
+           directorymergewindow.cpp      \
+           fileaccess.cpp                \
+           smalldialogs.cpp              \
+           kdiff3_shell.cpp              \
+           kdiff3_part.cpp               \
+           gnudiff_analyze.cpp           \
+           gnudiff_io.cpp                \
+           gnudiff_xmalloc.cpp           \
+           common.cpp                    \
+           kreplacements/kreplacements.cpp \
+           kreplacements/ShellContextMenu.cpp
+TARGET   = kdiff3
+INCLUDEPATH += . ./kreplacements
+
+win32 {
+#   QMAKE_CXXFLAGS_DEBUG  -= -Zi
+#   QMAKE_CXXFLAGS_DEBUG  += -GX -GR -Z7 /FR -DQT_NO_ASCII_CAST
+#   QMAKE_LFLAGS_DEBUG  += /PDB:NONE
+#   QMAKE_CXXFLAGS_RELEASE  += -GX -GR -DNDEBUG -DQT_NO_ASCII_CAST
+
+   QMAKE_CXXFLAGS_DEBUG  += -DQT_NO_ASCII_CAST
+   QMAKE_CXXFLAGS_RELEASE  += -DNDEBUG -DQT_NO_ASCII_CAST
+   RC_FILE = kdiff3.rc
+}
+unix {
+  documentation.path = /usr/local/share/doc/kdiff3
+  documentation.files = ../doc/*
+
+  INSTALLS += documentation
+
+  target.path = /usr/local/bin
+  INSTALLS += target
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.rc	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1 @@
+IDI_ICON1               ICON    DISCARDABLE     "kdiff3.ico"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_meta_unload.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1 @@
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_part.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,309 @@
+/***************************************************************************
+ * Copyright (C) 2003-2006 Joachim Eibl <joachim.eibl at gmx.de>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#include "kdiff3_part.h"
+
+#include <kinstance.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kfiledialog.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include "kdiff3.h"
+#include "fileaccess.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <iostream>
+
+#include "version.h"
+
+KDiff3Part::KDiff3Part( QWidget *parentWidget, const char *widgetName,
+                                  QObject *parent, const char *name )
+    : KParts::ReadOnlyPart(parent, name)
+{
+    // we need an instance
+    setInstance( KDiff3PartFactory::instance() );
+
+    // this should be your custom internal widget
+    m_widget = new KDiff3App( parentWidget, widgetName, this );
+    
+    // This hack is necessary to avoid a crash when the program terminates.
+    m_bIsShell = dynamic_cast<KParts::MainWindow*>(parentWidget)!=0;
+
+    // notify the part that this is our internal widget
+    setWidget(m_widget);
+
+    // create our actions
+    //KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+    //KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+    //KStdAction::save(this, SLOT(save()), actionCollection());
+
+    setXMLFile("kdiff3_part.rc");
+
+    // we are read-write by default
+    setReadWrite(true);
+
+    // we are not modified since we haven't done anything yet
+    setModified(false);
+}
+
+KDiff3Part::~KDiff3Part()
+{
+   if ( m_widget!=0  && ! m_bIsShell )
+   {
+      m_widget->saveOptions( m_widget->isPart() ? instance()->config() : kapp->config() );
+   }
+}
+
+void KDiff3Part::setReadWrite(bool /*rw*/)
+{
+//    ReadWritePart::setReadWrite(rw);
+}
+
+void KDiff3Part::setModified(bool /*modified*/)
+{
+/*
+    // get a handle on our Save action and make sure it is valid
+    KAction *save = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
+    if (!save)
+        return;
+
+    // if so, we either enable or disable it based on the current
+    // state
+    if (modified)
+        save->setEnabled(true);
+    else
+        save->setEnabled(false);
+
+    // in any event, we want our parent to do it's thing
+    ReadWritePart::setModified(modified);
+*/
+}
+
+static void getNameAndVersion( const QString& str, const QString& lineStart, QString& fileName, QString& version )
+{
+   if ( str.left( lineStart.length() )==lineStart && fileName.isEmpty() )
+   {
+      unsigned int pos = lineStart.length();
+      while ( pos<str.length() && (str[pos]==' ' || str[pos]=='\t') ) ++pos;
+      unsigned int pos2 = str.length()-1;
+      while ( pos2>pos )
+      { 
+         while (pos2>pos && str[pos2]!=' ' && str[pos2]!='\t') --pos2;
+         fileName = str.mid( pos, pos2-pos );
+         std::cerr << "KDiff3: " << fileName.latin1() << std::endl;
+         if ( FileAccess(fileName).exists() ) break;
+         --pos2;
+      }
+      
+      int vpos = str.findRev("\t", -1);
+      if ( vpos>0 && vpos>(int)pos2 )
+      {
+         version = str.mid( vpos+1 );
+         while( !version.right(1)[0].isLetterOrNumber() )
+            version.truncate( version.length()-1 );
+      }
+   }
+}
+
+
+bool KDiff3Part::openFile()
+{
+   // m_file is always local so we can use QFile on it
+   std::cerr << "KDiff3: " << m_file.latin1() << std::endl;
+   QFile file(m_file);
+   if (file.open(IO_ReadOnly) == false)
+      return false;
+
+   // our example widget is text-based, so we use QTextStream instead
+   // of a raw QDataStream
+   QTextStream stream(&file);
+   QString str;
+   QString fileName1;
+   QString fileName2;
+   QString version1;
+   QString version2;
+   while (!stream.eof() && (fileName1.isEmpty() || fileName2.isEmpty()) )
+   {
+      str = stream.readLine() + "\n";
+      getNameAndVersion( str, "---", fileName1, version1 );
+      getNameAndVersion( str, "+++", fileName2, version2 );
+   }
+
+   file.close();
+
+   if ( fileName1.isEmpty() && fileName2.isEmpty() )
+   {
+      KMessageBox::sorry(m_widget, i18n("Couldn't find files for comparison."));
+      return false;
+   }
+
+   FileAccess f1(fileName1);
+   FileAccess f2(fileName2);
+
+   if ( f1.exists() && f2.exists() && fileName1!=fileName2 )
+   {
+      m_widget->slotFileOpen2( fileName1, fileName2, "", "", "", "", "", 0 );
+      return true;
+   }
+   else if ( version1.isEmpty() && f1.exists() )
+   {
+      // Normal patch
+      // patch -f -u --ignore-whitespace -i [inputfile] -o [outfile] [patchfile]
+      QString tempFileName = FileAccess::tempFileName();
+      QString cmd = "patch -f -u --ignore-whitespace -i \"" + m_file +
+                  "\" -o \""+tempFileName + "\" \"" + fileName1+ "\"";
+
+      ::system( cmd.ascii() );
+
+      m_widget->slotFileOpen2( fileName1, tempFileName, "", "",
+                               "", version2.isEmpty() ? fileName2 : "REV:"+version2+":"+fileName2, "", 0 ); // alias names
+//    std::cerr << "KDiff3: f1:" << fileName1.latin1() <<"<->"<<tempFileName.latin1()<< std::endl;
+      FileAccess::removeTempFile( tempFileName );
+   }
+   else if ( version2.isEmpty() && f2.exists() )
+   {
+      // Reverse patch
+      // patch -f -u -R --ignore-whitespace -i [inputfile] -o [outfile] [patchfile]
+      QString tempFileName = FileAccess::tempFileName();
+      QString cmd = "patch -f -u -R --ignore-whitespace -i \"" + m_file +
+                  "\" -o \""+tempFileName + "\" \"" + fileName2+"\"";
+
+      ::system( cmd.ascii() );
+
+      m_widget->slotFileOpen2( tempFileName, fileName2, "", "",
+                               version1.isEmpty() ? fileName1 : "REV:"+version1+":"+fileName1, "", "", 0 ); // alias name
+//    std::cerr << "KDiff3: f2:" << fileName2.latin1() <<"<->"<<tempFileName.latin1()<< std::endl;
+      FileAccess::removeTempFile( tempFileName );
+   }
+   else if ( !version1.isEmpty() && !version2.isEmpty() )
+   {
+   std::cerr << "KDiff3: f1/2:" << fileName1.latin1() <<"<->"<<fileName2.latin1()<< std::endl;
+      // Assuming that files are on CVS: Try to get them
+      // cvs update -p -r [REV] [FILE] > [OUTPUTFILE]
+
+      QString tempFileName1 = FileAccess::tempFileName();
+      QString cmd1 = "cvs update -p -r " + version1 + " \"" + fileName1 + "\" >\""+tempFileName1+"\"";
+      ::system( cmd1.ascii() );
+
+      QString tempFileName2 = FileAccess::tempFileName();
+      QString cmd2 = "cvs update -p -r " + version2 + " \"" + fileName2 + "\" >\""+tempFileName2+"\"";
+      ::system( cmd2.ascii() );
+
+      m_widget->slotFileOpen2( tempFileName1, tempFileName2, "", "",
+         "REV:"+version1+":"+fileName1,
+         "REV:"+version2+":"+fileName2,
+         "", 0
+      );
+
+//    std::cerr << "KDiff3: f1/2:" << tempFileName1.latin1() <<"<->"<<tempFileName2.latin1()<< std::endl;
+      FileAccess::removeTempFile( tempFileName1 );
+      FileAccess::removeTempFile( tempFileName2 );
+      return true;
+   }
+   else
+   {
+      KMessageBox::sorry(m_widget, i18n("Couldn't find files for comparison."));
+   }
+
+   return true;
+}
+
+bool KDiff3Part::saveFile()
+{
+/*    // if we aren't read-write, return immediately
+    if (isReadWrite() == false)
+        return false;
+
+    // m_file is always local, so we use QFile
+    QFile file(m_file);
+    if (file.open(IO_WriteOnly) == false)
+        return false;
+
+    // use QTextStream to dump the text to the file
+    QTextStream stream(&file);
+    //stream << m_widget->text();
+
+    file.close();
+    return true;
+*/
+    return false;  // Not implemented
+}
+
+
+// It's usually safe to leave the factory code alone.. with the
+// notable exception of the KAboutData data
+#include <kaboutdata.h>
+#include <klocale.h>
+
+KInstance*  KDiff3PartFactory::s_instance = 0L;
+KAboutData* KDiff3PartFactory::s_about = 0L;
+
+KDiff3PartFactory::KDiff3PartFactory()
+    : KParts::Factory()
+{
+}
+
+KDiff3PartFactory::~KDiff3PartFactory()
+{
+    delete s_instance;
+    delete s_about;
+
+    s_instance = 0L;
+}
+
+KParts::Part* KDiff3PartFactory::createPartObject( QWidget *parentWidget, const char *widgetName,
+                                                        QObject *parent, const char *name,
+                                                        const char *classname, const QStringList&/*args*/ )
+{
+    // Create an instance of our Part
+    KDiff3Part* obj = new KDiff3Part( parentWidget, widgetName, parent, name );
+
+    // See if we are to be read-write or not
+    if (QCString(classname) == "KParts::ReadOnlyPart")
+        obj->setReadWrite(false);
+
+    return obj;
+}
+
+KInstance* KDiff3PartFactory::instance()
+{
+    if( !s_instance )
+    {
+        s_about = new KAboutData("kdiff3part", I18N_NOOP("KDiff3Part"), VERSION);
+        s_about->addAuthor("Joachim Eibl", 0, "joachim.eibl at gmx.de");
+        s_instance = new KInstance(s_about);
+    }
+    return s_instance;
+}
+
+extern "C"
+{
+    void* init_libkdiff3part()
+    {
+        return new KDiff3PartFactory;
+    }
+}
+
+// Suppress warning with --enable-final
+#undef VERSION
+
+#include "kdiff3_part.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_part.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * Copyright (C) 2003-2006 Joachim Eibl <joachim.eibl at gmx.de>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#ifndef _KDIFF3PART_H_
+#define _KDIFF3PART_H_
+
+#include <kparts/part.h>
+#include <kparts/factory.h>
+
+class QWidget;
+class QPainter;
+class KURL;
+class KDiff3App;
+
+/**
+ * This is a "Part".  It that does all the real work in a KPart
+ * application.
+ *
+ * @short Main Part
+ * @author Joachim Eibl <joachim.eibl at gmx.de>
+ */
+class KDiff3Part : public KParts::ReadOnlyPart
+{
+    Q_OBJECT
+public:
+    /**
+     * Default constructor
+     */
+    KDiff3Part(QWidget *parentWidget, const char *widgetName,
+                    QObject *parent, const char *name);
+
+    /**
+     * Destructor
+     */
+    virtual ~KDiff3Part();
+
+    /**
+     * This is a virtual function inherited from KParts::ReadWritePart.
+     * A shell will use this to inform this Part if it should act
+     * read-only
+     */
+    virtual void setReadWrite(bool rw);
+
+    /**
+     * Reimplemented to disable and enable Save action
+     */
+    virtual void setModified(bool modified);
+
+protected:
+    /**
+     * This must be implemented by each part
+     */
+    virtual bool openFile();
+
+    /**
+     * This must be implemented by each read-write part
+     */
+    virtual bool saveFile();
+
+private:
+    KDiff3App* m_widget;
+    bool m_bIsShell;
+};
+
+class KInstance;
+class KAboutData;
+
+class KDiff3PartFactory : public KParts::Factory
+{
+    Q_OBJECT
+public:
+    KDiff3PartFactory();
+    virtual ~KDiff3PartFactory();
+    virtual KParts::Part* createPartObject( QWidget *parentWidget, const char *widgetName,
+                                            QObject *parent, const char *name,
+                                            const char *classname, const QStringList &args );
+    static KInstance* instance();
+
+private:
+    static KInstance* s_instance;
+    static KAboutData* s_about;
+};
+
+#endif // _KDIFF3PART_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_part.rc	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kdiff3_part" version="9">
+<MenuBar>
+  <Menu name="movement"><text>&amp;KDiff3</text>
+    <Action name="go_top"/>
+    <Action name="go_bottom"/>
+    <Action name="go_prev_delta"/>
+    <Action name="go_next_delta"/>
+    <Action name="diff_showwhitespace"/>
+    <Action name="diff_showlinenumbers"/>
+    <Action name="diff_wordwrap"/>
+    <Action name="win_toggle_split_orientation"/>
+    <Action name="options_configure"><text>Configure KDiff3</text></Action>
+  </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>KDiff3</text>
+  <Action name="go_top"/>
+  <Action name="go_bottom"/>
+  <Action name="go_prev_delta"/>
+  <Action name="go_next_delta"/>
+  <Action name="diff_showwhitespace"/>
+  <Action name="diff_showlinenumbers"/>
+</ToolBar>
+</kpartgui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_shell.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,191 @@
+/***************************************************************************
+ * Copyright (C) 2003-2006 Joachim Eibl <joachim.eibl at gmx.de>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#include "kdiff3_shell.h"
+#include "kdiff3.h"
+
+#include <kkeydialog.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kurl.h>
+
+#include <kedittoolbar.h>
+
+#include <kaction.h>
+#include <kstdaction.h>
+
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kstatusbar.h>
+#include <klocale.h>
+
+#include <iostream>
+
+KDiff3Shell::KDiff3Shell(bool bCompleteInit)
+    : KParts::MainWindow( 0L, "kdiff3" )
+{
+    m_bUnderConstruction = true;
+    // set the shell's ui resource file
+    setXMLFile("kdiff3_shell.rc");
+
+    // and a status bar
+    statusBar()->show();
+
+    // this routine will find and load our Part.  it finds the Part by
+    // name which is a bad idea usually.. but it's alright in this
+    // case since our Part is made for this Shell
+    KLibFactory *factory = KLibLoader::self()->factory("libkdiff3part");
+    if (factory)
+    {
+        // now that the Part is loaded, we cast it to a Part to get
+        // our hands on it
+        m_part = static_cast<KParts::ReadWritePart *>(factory->create(this,
+                                "kdiff3_part", "KParts::ReadWritePart" ));
+
+        if (m_part)
+        {
+            // and integrate the part's GUI with the shell's
+            createGUI(m_part);
+
+            // tell the KParts::MainWindow that this is indeed the main widget
+            setCentralWidget(m_part->widget());
+
+            if (bCompleteInit)
+               ((KDiff3App*)m_part->widget())->completeInit();
+            connect(((KDiff3App*)m_part->widget()), SIGNAL(createNewInstance(const QString&, const QString&, const QString&)), this, SLOT(slotNewInstance(const QString&, const QString&, const QString&)));
+        }
+    }
+    else
+    {
+        // if we couldn't find our Part, we exit since the Shell by
+        // itself can't do anything useful
+        KMessageBox::error(this, i18n("Could not find our part!\n"
+           "This usually happens due to an installation problem. "
+           "Please read the README-file in the source package for details.")
+           );
+        //kapp->quit();
+        
+        ::exit(-1); //kapp->quit() doesn't work here yet.
+
+        // we return here, cause kapp->quit() only means "exit the
+        // next time we enter the event loop...
+        
+        return;
+    }
+
+    // apply the saved mainwindow settings, if any, and ask the mainwindow
+    // to automatically save settings if changed: window size, toolbar
+    // position, icon size, etc.
+    setAutoSaveSettings();
+    m_bUnderConstruction = false;
+}
+
+KDiff3Shell::~KDiff3Shell()
+{
+}
+
+bool KDiff3Shell::queryClose()
+{
+   if (m_part)
+      return ((KDiff3App*)m_part->widget())->queryClose();
+   else
+      return true;
+}
+
+bool KDiff3Shell::queryExit()
+{
+   return true;
+}
+
+void KDiff3Shell::closeEvent(QCloseEvent*e)
+{
+   if ( queryClose() )
+   {
+      e->accept();
+      bool bFileSaved = ((KDiff3App*)m_part->widget())->isFileSaved();
+      KApplication::exit( bFileSaved ? 0 : 1 );
+   }
+   else
+      e->ignore();
+}
+
+void KDiff3Shell::optionsShowToolbar()
+{
+    // this is all very cut and paste code for showing/hiding the
+    // toolbar
+    if (m_toolbarAction->isChecked())
+        toolBar()->show();
+    else
+        toolBar()->hide();
+}
+
+void KDiff3Shell::optionsShowStatusbar()
+{
+    // this is all very cut and paste code for showing/hiding the
+    // statusbar
+    if (m_statusbarAction->isChecked())
+        statusBar()->show();
+    else
+        statusBar()->hide();
+}
+
+void KDiff3Shell::optionsConfigureKeys()
+{
+    KKeyDialog::configure(actionCollection(), "kdiff3_shell.rc");
+}
+
+void KDiff3Shell::optionsConfigureToolbars()
+{
+#if defined(KDE_MAKE_VERSION)
+# if KDE_VERSION >= KDE_MAKE_VERSION(3,1,0)
+    saveMainWindowSettings(KGlobal::config(), autoSaveGroup());
+# else
+    saveMainWindowSettings(KGlobal::config() );
+# endif
+#else
+    saveMainWindowSettings(KGlobal::config() );
+#endif
+
+    // use the standard toolbar editor
+    KEditToolbar dlg(factory());
+    connect(&dlg, SIGNAL(newToolbarConfig()),
+            this, SLOT(applyNewToolbarConfig()));
+    dlg.exec();
+}
+
+void KDiff3Shell::applyNewToolbarConfig()
+{
+#if defined(KDE_MAKE_VERSION)
+# if KDE_VERSION >= KDE_MAKE_VERSION(3,1,0)
+    applyMainWindowSettings(KGlobal::config(), autoSaveGroup());
+# else
+    applyMainWindowSettings(KGlobal::config());
+# endif
+#else
+    applyMainWindowSettings(KGlobal::config());
+#endif
+}
+
+void KDiff3Shell::slotNewInstance( const QString& fn1, const QString& fn2, const QString& fn3 )
+{
+   KDiff3Shell* pKDiff3Shell = new KDiff3Shell(false);
+   ((KDiff3App*)pKDiff3Shell->m_part->widget())->completeInit(fn1,fn2,fn3);
+}
+
+#include "kdiff3_shell.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_shell.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2003-2006 Joachim Eibl <joachim.eibl at gmx.de>           *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#ifndef _KDIFF3SHELL_H_
+#define _KDIFF3SHELL_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+class KToggleAction;
+
+/**
+ * This is the application "Shell".  It has a menubar, toolbar, and
+ * statusbar but relies on the "Part" to do all the real work.
+ *
+ * @short Application Shell
+ * @author Joachim Eibl <joachim.eibl at gmx.de>
+ */
+class KDiff3Shell : public KParts::MainWindow
+{
+    Q_OBJECT
+public:
+    /**
+     * Default Constructor
+     */
+    KDiff3Shell(bool bCompleteInit=true);
+
+    /**
+     * Default Destructor
+     */
+    virtual ~KDiff3Shell();
+
+    bool queryClose();
+    bool queryExit();
+    virtual void closeEvent(QCloseEvent*e);
+
+private slots:
+    void optionsShowToolbar();
+    void optionsShowStatusbar();
+    void optionsConfigureKeys();
+    void optionsConfigureToolbars();
+
+    void applyNewToolbarConfig();
+    void slotNewInstance( const QString& fn1, const QString& fn2, const QString& fn3 );
+
+private:
+    KParts::ReadWritePart *m_part;
+
+    KToggleAction *m_toolbarAction;
+    KToggleAction *m_statusbarAction;
+    bool m_bUnderConstruction;
+};
+
+#endif // _KDIFF3_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_shell.rc	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,128 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<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_save_merge_state"/>
+    <Action name="dir_load_merge_state"/> -->
+    <Action name="dir_fold_all"/>
+    <Action name="dir_unfold_all"/>
+    <Action name="dir_show_identical_files"/>
+    <Action name="dir_show_different_files"/>
+    <Action name="dir_show_files_only_in_a"/>
+    <Action name="dir_show_files_only_in_b"/>
+    <Action name="dir_show_files_only_in_c"/>
+    <Action name="dir_choose_a_everywhere"/>
+    <Action name="dir_choose_b_everywhere"/>
+    <Action name="dir_choose_c_everywhere"/>
+    <Action name="dir_autochoose_everywhere"/>
+    <Action name="dir_nothing_everywhere"/>
+    <Action name="dir_synchronize_directories"/>
+    <Action name="dir_choose_newer_files"/>
+    <Action name="dir_compare_explicitly_selected_files"/>
+    <Action name="dir_merge_explicitly_selected_files"/>
+    <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"/>
+    <Action name="go_top"/>
+    <Action name="go_bottom"/>
+    <Action name="go_prev_delta"/>
+    <Action name="go_next_delta"/>
+    <Action name="go_prev_conflict"/>
+    <Action name="go_next_conflict"/>
+    <Action name="go_prev_unsolved_conflict"/>
+    <Action name="go_next_unsolved_conflict"/>
+  </Menu>
+  <Menu name="diff"><text>D&amp;iffview</text>
+    <Action name="diff_showlinenumbers"/>
+    <Action name="diff_show_whitespace_characters"/>
+    <Action name="diff_show_whitespace"/>
+    <Action name="diff_overview_normal"/>
+    <Action name="diff_overview_ab"/>
+    <Action name="diff_overview_ac"/>
+    <Action name="diff_overview_bc"/>
+    <Action name="diff_wordwrap"/>
+    <Action name="diff_add_manual_diff_help"/>
+    <Action name="diff_clear_manual_diff_help_list"/>
+  </Menu>  
+  <Menu name="merge"><text>&amp;Merge</text>
+    <Action name="merge_current"/>
+    <Action name="merge_choose_a"/>
+    <Action name="merge_choose_b"/>
+    <Action name="merge_choose_c"/>
+    <Action name="merge_autoadvance"/>
+    <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_splitdiff"/>
+    <Action name="merge_joindiffs"/>
+    <Action name="merge_regexp_automerge"/>
+    <Action name="merge_versioncontrol_history"/>
+  </Menu>
+  <Menu name="window"><text>&amp;Window</text>
+    <Action name="win_focus_prev"/>
+    <Action name="win_focus_next"/>
+    <Action name="win_show_a"/>
+    <Action name="win_show_b"/>
+    <Action name="win_show_c"/>
+    <Action name="win_dir_show_both"/>
+    <Action name="win_dir_view_toggle"/>
+    <Action name="win_toggle_split_orientation"/>
+  </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+  <Action name="merge_current"/>
+  <Action name="go_current"/>
+  <Action name="go_top"/>
+  <Action name="go_bottom"/>
+  <Action name="go_prev_delta"/>
+  <Action name="go_next_delta"/>
+  <Action name="go_prev_conflict"/>
+  <Action name="go_next_conflict"/>
+  <Action name="go_prev_unsolved_conflict"/>
+  <Action name="go_next_unsolved_conflict"/>
+  <Action name="merge_choose_a"/>
+  <Action name="merge_choose_b"/>
+  <Action name="merge_choose_c"/>
+  <Action name="merge_autoadvance"/>
+  <Action name="diff_show_whitespace"/>
+  <Action name="diff_show_whitespace_characters"/>
+  <Action name="diff_showlinenumbers"/>
+  <Action name="dir_show_identical_files"/>
+  <Action name="dir_show_files_only_in_a"/>
+  <Action name="dir_show_files_only_in_b"/>
+</ToolBar>
+</kpartgui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3part.desktop	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,17 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=KDiff3Part
+Name[cs]=Komponenta KDiff3
+Name[fr]=Composant KDiff3
+Name[hi]=के-डिफ3पारà¥à¤Ÿ
+Name[nb]=KDiff3-del
+Name[pt_BR]=Componente KDiff3
+Name[sv]=Kdiff3-del
+Name[ta]=கேடிஃபà¯3 பகà¯à®¤à®¿
+Name[tg]=ҚиÑмиKDiff3
+Name[xx]=xxKDiff3Partxx
+Name[zh_CN]=KDiff3 组件
+MimeType=text/x-diff
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=libkdiff3part
+Type=Service
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/README	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,30 @@
+About the "kreplacements"-directory:
+====================================
+
+I want to be able to compile and use KDiff3 without KDE too.
+Since KDiff3 is a KDE program, which uses many KDE-classes and
+functions there must be some replacement.
+
+In many cases this is just the corresponding Qt-class, but often
+I wrote something myself. For several very KDE-specific functions
+there is no real replacement, but only stub functions that allow
+the program to compile and link.
+
+This stuff is not intended to be used for anything else but KDiff3.
+Think of it rather as a big hack, that only has the advantage
+that I need not mess up the normal program with many ugly
+#ifdef/#endif-clauses.
+
+Most include files in this directory only include kreplacements.h
+where the actual declarations are. The implementions are in
+kreplacements.cpp.
+
+The *.moc-files are dummies. The new KDE-philosophy seems to be
+that *.moc-files are directly included into the sources.  
+The Qt-philosophy still is to generate moc*.cpp files which will
+be compiled seperately. With these dummy-moc-files both versions
+can be compiled.
+
+
+Joachim
+(2003-10-02)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/ShellContextMenu.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,474 @@
+// ShellContextMenu.cpp: Implementierung der Klasse CShellContextMenu.
+//
+//////////////////////////////////////////////////////////////////////
+#ifdef _WIN32
+#include <windows.h>
+#include <shlobj.h>
+#include <malloc.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qwidget.h>
+#include <qdir.h>
+#include <qpopupmenu.h>
+#include "ShellContextMenu.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Konstruktion/Destruktion
+//////////////////////////////////////////////////////////////////////
+
+#define MIN_ID 100
+#define MAX_ID 10000
+
+
+void showShellContextMenu( const QString& itemPath, QPoint pt, QWidget* pParentWidget, QPopupMenu* pMenu )
+{
+    CShellContextMenu scm;
+    scm.SetObjects(QDir::convertSeparators(itemPath));
+    int id = scm.ShowContextMenu (pParentWidget, pt, pMenu);
+    if (id>=1)
+       pMenu->activateItemAt(id-1);
+}
+
+IContextMenu2 * g_IContext2 = NULL;
+IContextMenu3 * g_IContext3 = NULL;
+
+CShellContextMenu::CShellContextMenu()
+{
+	m_psfFolder = NULL;
+	m_pidlArray = NULL;
+	m_hMenu = NULL;
+}
+
+CShellContextMenu::~CShellContextMenu()
+{
+	// free all allocated datas
+	if (m_psfFolder && bDelete)
+		m_psfFolder->Release ();
+	m_psfFolder = NULL;
+	FreePIDLArray (m_pidlArray);
+	m_pidlArray = NULL;
+
+	if (m_hMenu)
+		DestroyMenu( m_hMenu );
+}
+
+
+
+// this functions determines which version of IContextMenu is avaibale for those objects (always the highest one)
+// and returns that interface
+BOOL CShellContextMenu::GetContextMenu (void ** ppContextMenu, int & iMenuType)
+{
+	*ppContextMenu = NULL;
+	LPCONTEXTMENU icm1 = NULL;
+	
+	// first we retrieve the normal IContextMenu interface (every object should have it)
+	m_psfFolder->GetUIObjectOf (NULL, nItems, (LPCITEMIDLIST *) m_pidlArray, IID_IContextMenu, NULL, (void**) &icm1);
+
+	if (icm1)
+	{	// since we got an IContextMenu interface we can now obtain the higher version interfaces via that
+		if (icm1->QueryInterface (IID_IContextMenu3, ppContextMenu) == NOERROR)
+			iMenuType = 3;
+		else if (icm1->QueryInterface (IID_IContextMenu2, ppContextMenu) == NOERROR)
+			iMenuType = 2;
+
+		if (*ppContextMenu) 
+			icm1->Release(); // we can now release version 1 interface, cause we got a higher one
+		else 
+		{	
+			iMenuType = 1;
+			*ppContextMenu = icm1;	// since no higher versions were found
+		}							// redirect ppContextMenu to version 1 interface
+	}
+	else
+		return (FALSE);	// something went wrong
+	
+	return (TRUE); // success
+}
+
+
+LRESULT CALLBACK CShellContextMenu::HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+	switch (message)
+	{ 
+	case WM_MENUCHAR:	// only supported by IContextMenu3
+		if (g_IContext3)
+		{
+			LRESULT lResult = 0;
+			g_IContext3->HandleMenuMsg2 (message, wParam, lParam, &lResult);
+			return (lResult);
+		}
+		break;
+
+	case WM_DRAWITEM:
+	case WM_MEASUREITEM:
+		if (wParam) 
+			break; // if wParam != 0 then the message is not menu-related
+  
+	case WM_INITMENUPOPUP:
+		if (g_IContext2)
+			g_IContext2->HandleMenuMsg (message, wParam, lParam);
+		else	// version 3
+			g_IContext3->HandleMenuMsg (message, wParam, lParam);
+		return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that we handled WM_INITPOPUPMENU by ourself
+		break;
+
+	default:
+		break;
+	}
+
+	// call original WndProc of window to prevent undefined bevhaviour of window
+	return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), hWnd, message, wParam, lParam);
+}
+
+
+UINT CShellContextMenu::ShowContextMenu(QWidget * pParentWidget, QPoint pt, QPopupMenu* pMenu )
+{
+        HWND hWnd = pParentWidget->winId();
+        int iMenuType = 0;	// to know which version of IContextMenu is supported
+	LPCONTEXTMENU pContextMenu;	// common pointer to IContextMenu and higher version interface
+   
+	if (!GetContextMenu ((void**) &pContextMenu, iMenuType))	
+		return (0);	// something went wrong
+
+	if (!m_hMenu)
+	{
+		DestroyMenu( m_hMenu );
+		m_hMenu = CreatePopupMenu ();
+	}
+
+        UINT_PTR i;
+        for( i=0; i<pMenu->count(); ++i )
+        {
+           QString s = pMenu->text(pMenu->idAt(i));
+           if (!s.isEmpty())
+              AppendMenuW( m_hMenu, MF_STRING, i+1, (LPCWSTR)s.ucs2() );
+        }
+        AppendMenuW( m_hMenu, MF_SEPARATOR, i+1, L"" );
+
+	// lets fill the our popupmenu  
+	pContextMenu->QueryContextMenu (m_hMenu, GetMenuItemCount (m_hMenu), MIN_ID, MAX_ID, CMF_NORMAL | CMF_EXPLORE);
+ 
+	// subclass window to handle menurelated messages in CShellContextMenu 
+	WNDPROC OldWndProc;
+	if (iMenuType > 1)	// only subclass if its version 2 or 3
+	{
+		OldWndProc = (WNDPROC) SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) HookWndProc);
+		if (iMenuType == 2)
+			g_IContext2 = (LPCONTEXTMENU2) pContextMenu;
+		else	// version 3
+			g_IContext3 = (LPCONTEXTMENU3) pContextMenu;
+	}
+	else
+		OldWndProc = NULL;
+
+	UINT idCommand = TrackPopupMenu (m_hMenu,TPM_RETURNCMD | TPM_LEFTALIGN, pt.x(), pt.y(), 0, pParentWidget->winId(), 0);
+
+	if (OldWndProc) // unsubclass
+		SetWindowLong (hWnd, GWL_WNDPROC, (DWORD) OldWndProc);
+
+	if (idCommand >= MIN_ID && idCommand <= MAX_ID)	// see if returned idCommand belongs to shell menu entries
+	{
+		InvokeCommand (pContextMenu, idCommand - MIN_ID);	// execute related command
+		idCommand = 0;
+	}
+	
+	pContextMenu->Release();
+	g_IContext2 = NULL;
+	g_IContext3 = NULL;
+
+	return (idCommand);
+}
+
+
+void CShellContextMenu::InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand)
+{
+	CMINVOKECOMMANDINFO cmi = {0};
+	cmi.cbSize = sizeof (CMINVOKECOMMANDINFO);
+	cmi.lpVerb = (LPSTR) MAKEINTRESOURCE (idCommand);
+	cmi.nShow = SW_SHOWNORMAL;
+	
+	pContextMenu->InvokeCommand (&cmi);
+}
+
+
+void CShellContextMenu::SetObjects(const QString& strObject)
+{
+	// only one object is passed
+	QStringList strArray;
+	strArray << strObject;	// create a CStringArray with one element
+	
+	SetObjects (strArray);		// and pass it to SetObjects (CStringArray &strArray)
+								// for further processing
+}
+
+
+void CShellContextMenu::SetObjects(const QStringList &strList)
+{
+	// free all allocated datas
+	if (m_psfFolder && bDelete)
+		m_psfFolder->Release ();
+	m_psfFolder = NULL;
+	FreePIDLArray (m_pidlArray);
+	m_pidlArray = NULL;
+	
+	// get IShellFolder interface of Desktop (root of shell namespace)
+	IShellFolder * psfDesktop = NULL;
+	SHGetDesktopFolder (&psfDesktop);	// needed to obtain full qualified pidl
+
+	// ParseDisplayName creates a PIDL from a file system path relative to the IShellFolder interface
+	// but since we use the Desktop as our interface and the Desktop is the namespace root
+	// that means that it's a fully qualified PIDL, which is what we need
+	LPITEMIDLIST pidl = NULL;
+	
+	psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[0].ucs2(), NULL, &pidl, NULL);
+
+	// now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface
+	LPITEMIDLIST pidlItem = NULL;	// relative pidl
+	SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL);
+	free (pidlItem);
+	// get interface to IMalloc (need to free the PIDLs allocated by the shell functions)
+	LPMALLOC lpMalloc = NULL;
+	SHGetMalloc (&lpMalloc);
+	lpMalloc->Free (pidl);
+
+	// now we have the IShellFolder interface to the parent folder specified in the first element in strArray
+	// since we assume that all objects are in the same folder (as it's stated in the MSDN)
+	// we now have the IShellFolder interface to every objects parent folder
+	
+	IShellFolder * psfFolder = NULL;
+	nItems = strList.size ();
+	for (int i = 0; i < nItems; i++)
+	{
+                pidl=0;
+		psfDesktop->ParseDisplayName (NULL, 0, (LPOLESTR)strList[i].ucs2(), NULL, &pidl, NULL);
+                if (pidl)
+                {
+                     m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST));
+                     // get relative pidl via SHBindToParent
+                     SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem);
+                     m_pidlArray[i] = CopyPIDL (pidlItem);	// copy relative pidl to pidlArray
+                     free (pidlItem);
+                     lpMalloc->Free (pidl);		// free pidl allocated by ParseDisplayName
+                     psfFolder->Release ();
+                }
+	}
+	lpMalloc->Release ();
+	psfDesktop->Release ();
+
+	bDelete = TRUE;	// indicates that m_psfFolder should be deleted by CShellContextMenu
+}
+
+
+// only one full qualified PIDL has been passed
+void CShellContextMenu::SetObjects(LPITEMIDLIST /*pidl*/)
+{
+/*
+   // free all allocated datas
+	if (m_psfFolder && bDelete)
+		m_psfFolder->Release ();
+	m_psfFolder = NULL;
+	FreePIDLArray (m_pidlArray);
+	m_pidlArray = NULL;
+
+		// full qualified PIDL is passed so we need
+	// its parent IShellFolder interface and its relative PIDL to that
+	LPITEMIDLIST pidlItem = NULL;
+	SHBindToParent ((LPCITEMIDLIST) pidl, IID_IShellFolder, (void **) &m_psfFolder, (LPCITEMIDLIST *) &pidlItem);	
+
+	m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST));	// allocate ony for one elemnt
+	m_pidlArray[0] = CopyPIDL (pidlItem);
+
+
+	// now free pidlItem via IMalloc interface (but not m_psfFolder, that we need later
+	LPMALLOC lpMalloc = NULL;
+	SHGetMalloc (&lpMalloc);
+	lpMalloc->Free (pidlItem);
+	lpMalloc->Release();
+
+	nItems = 1;
+	bDelete = TRUE;	// indicates that m_psfFolder should be deleted by CShellContextMenu
+*/
+}
+
+
+// IShellFolder interface with a relative pidl has been passed
+void CShellContextMenu::SetObjects(IShellFolder *psfFolder, LPITEMIDLIST pidlItem)
+{
+	// free all allocated datas
+	if (m_psfFolder && bDelete)
+		m_psfFolder->Release ();
+	m_psfFolder = NULL;
+	FreePIDLArray (m_pidlArray);
+	m_pidlArray = NULL;
+
+	m_psfFolder = psfFolder;
+
+	m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST));
+	m_pidlArray[0] = CopyPIDL (pidlItem);
+	
+	nItems = 1;
+	bDelete = FALSE;	// indicates wheter m_psfFolder should be deleted by CShellContextMenu
+}
+
+void CShellContextMenu::SetObjects(IShellFolder * psfFolder, LPITEMIDLIST *pidlArray, int nItemCount)
+{
+	// free all allocated datas
+	if (m_psfFolder && bDelete)
+		m_psfFolder->Release ();
+	m_psfFolder = NULL;
+	FreePIDLArray (m_pidlArray);
+	m_pidlArray = NULL;
+
+	m_psfFolder = psfFolder;
+
+	m_pidlArray = (LPITEMIDLIST *) malloc (nItemCount * sizeof (LPITEMIDLIST));
+
+	for (int i = 0; i < nItemCount; i++)
+		m_pidlArray[i] = CopyPIDL (pidlArray[i]);
+
+	nItems = nItemCount;
+	bDelete = FALSE;	// indicates wheter m_psfFolder should be deleted by CShellContextMenu
+}
+
+
+void CShellContextMenu::FreePIDLArray(LPITEMIDLIST *pidlArray)
+{
+	if (!pidlArray)
+		return;
+
+	int iSize = _msize (pidlArray) / sizeof (LPITEMIDLIST);
+
+	for (int i = 0; i < iSize; i++)
+		free (pidlArray[i]);
+	free (pidlArray);
+}
+
+
+LPITEMIDLIST CShellContextMenu::CopyPIDL (LPCITEMIDLIST pidl, int cb)
+{
+	if (cb == -1)
+		cb = GetPIDLSize (pidl); // Calculate size of list.
+
+    LPITEMIDLIST pidlRet = (LPITEMIDLIST) calloc (cb + sizeof (USHORT), sizeof (BYTE));
+    if (pidlRet)
+		CopyMemory(pidlRet, pidl, cb);
+
+    return (pidlRet);
+}
+
+
+UINT CShellContextMenu::GetPIDLSize (LPCITEMIDLIST pidl)
+{  
+	if (!pidl) 
+		return 0;
+	int nSize = 0;
+	LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl;
+	while (pidlTemp->mkid.cb)
+	{
+		nSize += pidlTemp->mkid.cb;
+		pidlTemp = (LPITEMIDLIST) (((LPBYTE) pidlTemp) + pidlTemp->mkid.cb);
+	}
+	return nSize;
+}
+
+HMENU  CShellContextMenu::GetMenu()
+{
+	if (!m_hMenu)
+	{
+		m_hMenu = CreatePopupMenu();	// create the popupmenu (its empty)
+	}
+	return (m_hMenu);
+}
+
+
+// this is workaround function for the Shell API Function SHBindToParent
+// SHBindToParent is not available under Win95/98
+HRESULT CShellContextMenu::SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast)
+{
+	HRESULT hr = 0;
+	if (!pidl || !ppv)
+		return E_POINTER;
+	
+	int nCount = GetPIDLCount (pidl);
+	if (nCount == 0)	// desktop pidl of invalid pidl
+		return E_POINTER;
+
+	IShellFolder * psfDesktop = NULL;
+	SHGetDesktopFolder (&psfDesktop);
+	if (nCount == 1)	// desktop pidl
+	{
+		if ((hr = psfDesktop->QueryInterface(riid, ppv)) == S_OK)
+		{
+			if (ppidlLast) 
+				*ppidlLast = CopyPIDL (pidl);
+		}
+		psfDesktop->Release ();
+		return hr;
+	}
+
+	LPBYTE pRel = GetPIDLPos (pidl, nCount - 1);
+	LPITEMIDLIST pidlParent = NULL;
+	pidlParent = CopyPIDL (pidl, pRel - (LPBYTE) pidl);
+	IShellFolder * psfFolder = NULL;
+	
+	if ((hr = psfDesktop->BindToObject (pidlParent, NULL, IID_IShellFolder, (void **) &psfFolder)) != S_OK)
+	{
+		free (pidlParent);
+		psfDesktop->Release ();
+		return hr;
+	}
+	if ((hr = psfFolder->QueryInterface (riid, ppv)) == S_OK)
+	{
+		if (ppidlLast)
+			*ppidlLast = CopyPIDL ((LPCITEMIDLIST) pRel);
+	}
+	free (pidlParent);
+	psfFolder->Release ();
+	psfDesktop->Release ();
+	return hr;
+}
+
+
+LPBYTE CShellContextMenu::GetPIDLPos (LPCITEMIDLIST pidl, int nPos)
+{
+	if (!pidl)
+		return 0;
+	int nCount = 0;
+	
+	BYTE * pCur = (BYTE *) pidl;
+	while (((LPCITEMIDLIST) pCur)->mkid.cb)
+	{
+		if (nCount == nPos)
+			return pCur;
+		nCount++;
+		pCur += ((LPCITEMIDLIST) pCur)->mkid.cb;	// + sizeof(pidl->mkid.cb);
+	}
+	if (nCount == nPos) 
+		return pCur;
+	return NULL;
+}
+
+
+int CShellContextMenu::GetPIDLCount (LPCITEMIDLIST pidl)
+{
+	if (!pidl)
+		return 0;
+
+	int nCount = 0;
+	BYTE*  pCur = (BYTE *) pidl;
+	while (((LPCITEMIDLIST) pCur)->mkid.cb)
+	{
+		nCount++;
+		pCur += ((LPCITEMIDLIST) pCur)->mkid.cb;
+	}
+	return nCount;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/ShellContextMenu.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,44 @@
+// ShellContextMenu.h: Schnittstelle für die Klasse CShellContextMenu.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef SHELLCONTEXTMENU_H
+#define SHELLCONTEXTMENU_H
+
+/////////////////////////////////////////////////////////////////////
+// class to show shell contextmenu of files/folders/shell objects
+// developed by R. Engels 2003
+/////////////////////////////////////////////////////////////////////
+
+class CShellContextMenu  
+{
+public:
+	HMENU GetMenu ();
+	void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST pidlItem);
+	void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST * pidlArray, int nItemCount);
+	void SetObjects (LPITEMIDLIST pidl);
+	void SetObjects (const QString& strObject);
+	void SetObjects (const QStringList& strList);
+	UINT ShowContextMenu (QWidget* pParent, QPoint pt, QPopupMenu* pMenu);
+	CShellContextMenu();
+	virtual ~CShellContextMenu();
+
+private:
+	int nItems;
+	BOOL bDelete;
+	HMENU m_hMenu;
+	IShellFolder * m_psfFolder;
+	LPITEMIDLIST * m_pidlArray;	
+	
+	void InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand);
+	BOOL GetContextMenu (void ** ppContextMenu, int & iMenuType);
+	HRESULT SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast);
+	static LRESULT CALLBACK HookWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+	void FreePIDLArray (LPITEMIDLIST * pidlArray);
+	LPITEMIDLIST CopyPIDL (LPCITEMIDLIST pidl, int cb = -1);
+	UINT GetPIDLSize (LPCITEMIDLIST pidl);
+	LPBYTE GetPIDLPos (LPCITEMIDLIST pidl, int nPos);
+	int GetPIDLCount (LPCITEMIDLIST pidl);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kaboutdata.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kaccel.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kaction.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kapplication.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kcmdlineargs.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kcolorbtn.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kconfig.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kdialogbase.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kedittoolbar.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kfiledialog.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kfontdialog.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kiconloader.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kinstance.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kio/global.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kio/job.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kio/jobclasses.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kkeydialog.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/klibloader.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/klocale.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmainwindow.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmenubar.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmessagebox.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/konq_popupmenu.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kparts/factory.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kparts/mainwindow.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kparts/part.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kpopupmenu.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kprinter.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kprogress.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1185 @@
+/***************************************************************************
+                          kreplacements.cpp  -  description
+                             -------------------
+    begin                : Sat Aug 3 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+
+#include "kreplacements.h"
+#include "common.h"
+
+#include <assert.h>
+
+#include <qnamespace.h>
+#include <qmessagebox.h>
+#include <qpopupmenu.h>
+#include <qmenubar.h>
+#include <qpainter.h>
+#include <qcolordialog.h>
+#include <qfontdialog.h>
+#include <qlabel.h>
+#include <qtextbrowser.h>
+#include <qtextstream.h>
+#include <qlayout.h>
+#include <qdockarea.h>
+
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+
+static QString s_copyright;
+static QString s_email;
+static QString s_description;
+static QString s_appName;
+static QString s_version;
+static QString s_homepage;
+static KAboutData* s_pAboutData;
+
+
+#ifdef _WIN32
+#include <process.h>
+#include <windows.h>
+#endif
+
+static void showHelp()
+{
+   #ifdef _WIN32
+      char buf[200];
+      int r= SearchPathA( 0, ".",  0, sizeof(buf), buf, 0 );
+
+      QString exePath;
+      if (r!=0)  {  exePath = buf; }
+      else       {  exePath = "."; }
+
+      QFileInfo helpFile( exePath + "\\doc\\en\\index.html" );
+      if ( ! helpFile.exists() ) {  helpFile.setFile( exePath + "\\..\\doc\\en\\index.html" );     }
+      if ( ! helpFile.exists() ) {  helpFile.setFile( exePath + "\\doc\\index.html"         );     }
+      if ( ! helpFile.exists() ) {  helpFile.setFile( exePath + "\\..\\doc\\index.html"     );     }
+      if ( ! helpFile.exists() )
+      {
+         QMessageBox::warning( 0, "KDiff3 documentation not found",
+            "Couldn't find the documentation. \n\n"
+            "The documentation can also be found at the homepage:\n\n "
+            "    http://kdiff3.sourceforge.net/");
+         return;
+      }
+
+      HINSTANCE hi = FindExecutableA( helpFile.fileName().ascii(), helpFile.dirPath(true).ascii(), buf );
+      if ( int(hi)<=32 )
+      {
+         static QTextBrowser* pBrowser = 0;
+         if (pBrowser==0)
+         {
+            pBrowser = new QTextBrowser( 0 );
+            pBrowser->setMinimumSize( 600, 400 );
+         }
+         pBrowser->setSource(helpFile.filePath());
+         pBrowser->show();
+      }
+      else
+      {
+         QFileInfo prog( buf );
+         _spawnlp( _P_NOWAIT , prog.filePath().ascii(), prog.fileName().ascii(), ("\"file:///"+helpFile.absFilePath()+"\"").ascii(), NULL );
+      }
+
+   #else
+      static QTextBrowser* pBrowser = 0;
+      if (pBrowser==0)
+      {
+         pBrowser = new QTextBrowser( 0 );
+         pBrowser->setMinimumSize( 600, 400 );
+      }
+      pBrowser->setSource("/usr/local/share/doc/kdiff3/en/index.html");
+      pBrowser->show();
+   #endif
+}
+
+QString getTranslationDir()
+{
+   #ifdef _WIN32
+      char buf[200];
+      int r= SearchPathA( 0, ".",  0, sizeof(buf), buf, 0 );
+
+      QString exePath;
+      if (r!=0)  {  exePath = buf; }
+      else       {  exePath = "."; }
+      return exePath+"/translations";
+   #else
+      return ".";
+   #endif
+}
+
+// static
+void KMessageBox::error( QWidget* parent, const QString& text, const QString& caption )
+{
+   QMessageBox::critical( parent, caption, text );
+}
+
+int KMessageBox::warningContinueCancel( QWidget* parent, const QString& text, const QString& caption,
+   const QString& button1 )
+{
+   return  0 == QMessageBox::warning( parent, caption, text, button1, "Cancel" ) ? Continue : Cancel;
+}
+
+void KMessageBox::sorry(  QWidget* parent, const QString& text, const QString& caption )
+{
+   QMessageBox::information( parent, caption, text );
+}
+
+void KMessageBox::information(  QWidget* parent, const QString& text, const QString& caption )
+{
+   QMessageBox::information( parent, caption, text );
+}
+
+int  KMessageBox::warningYesNo( QWidget* parent, const QString& text, const QString& caption,
+   const QString& button1, const QString& button2 )
+{
+   return  0 == QMessageBox::warning( parent, caption, text, button1, button2, QString::null, 1, 1 ) ? Yes : No;
+}
+
+int KMessageBox::warningYesNoCancel( QWidget* parent, const QString& text, const QString& caption,
+   const QString& button1, const QString& button2 )
+{
+   int val = QMessageBox::warning( parent, caption, text,
+      button1, button2, i18n("Cancel") );
+   if ( val==0 ) return Yes;
+   if ( val==1 ) return No;
+   else return Cancel;
+}
+
+
+KDialogBase::KDialogBase( int, const QString& caption, int, int, QWidget* parent, const char* name,
+  bool /*modal*/, bool )
+: QTabDialog( parent, name, true /* modal */ )
+{
+   setCaption( caption );
+   setDefaultButton();
+   setHelpButton();
+   setCancelButton();
+   //setApplyButton();
+   setOkButton();
+   setDefaultButton();
+
+   connect( this, SIGNAL( defaultButtonPressed() ), this, SLOT(slotDefault()) );
+   connect( this, SIGNAL( helpButtonPressed() ), this, SLOT(slotHelp()));
+   connect( this, SIGNAL( applyButtonPressed() ), this, SLOT( slotApply() ));
+}
+
+KDialogBase::~KDialogBase()
+{
+}
+
+void KDialogBase::incInitialSize ( const QSize& )
+{
+}
+
+void KDialogBase::setHelp(const QString&, const QString& )
+{
+}
+
+
+int KDialogBase::BarIcon(const QString& /*iconName*/, int )
+{
+   return 0; // Not used for replacement.
+}
+
+
+QVBox* KDialogBase::addVBoxPage( const QString& name, const QString& /*info*/, int )
+{
+   QVBox* p = new QVBox(this, name.ascii());
+   addTab( p, name );
+   return p;
+}
+
+QFrame* KDialogBase::addPage(  const QString& name, const QString& /*info*/, int )
+{
+   QFrame* p = new QFrame( this, name.ascii() );
+   addTab( p, name );
+   return p;
+}
+
+int KDialogBase::spacingHint()
+{
+   return 5;
+}
+
+static bool s_inAccept = false;
+static bool s_bAccepted = false;
+void KDialogBase::accept()
+{
+   if( ! s_inAccept )
+   {
+      s_bAccepted = false;
+      s_inAccept = true;
+      slotOk();
+      s_inAccept = false;
+      if ( s_bAccepted )
+         QTabDialog::accept();
+   }
+   else
+   {
+      s_bAccepted = true;   
+   }   
+}
+
+void KDialogBase::slotDefault( )
+{
+}
+void KDialogBase::slotOk()
+{
+}
+void KDialogBase::slotCancel( )
+{
+}
+void KDialogBase::slotApply( )
+{
+   emit applyClicked();
+}
+void KDialogBase::slotHelp( )
+{
+   showHelp();
+}
+
+KURL KFileDialog::getSaveURL( const QString &startDir,
+                              const QString &filter,
+                              QWidget *parent, const QString &caption)
+{
+   QString s = QFileDialog::getSaveFileName(startDir, filter, parent, 0, caption);
+   return KURL(s);
+}
+
+KURL KFileDialog::getOpenURL( const QString &  startDir,
+                           const QString &  filter,
+                           QWidget *  parent,
+                           const QString &  caption )
+{
+   QString s = QFileDialog::getOpenFileName(startDir, filter, parent, 0, caption);
+   return KURL(s);
+}
+
+KURL KFileDialog::getExistingURL( const QString &  startDir,
+                               QWidget *  parent,
+                               const QString &  caption)
+{
+   QString s = QFileDialog::getExistingDirectory(startDir, parent, 0, caption);
+   return KURL(s);
+}
+
+QString KFileDialog::getSaveFileName (const QString &startDir, 
+                        const QString &filter, 
+                        QWidget *parent, 
+                        const QString &caption)
+{
+   return QFileDialog::getSaveFileName( startDir, filter, parent, 0, caption );
+}
+
+
+KToolBar::BarPosition KToolBar::barPos()
+{
+   if ( m_pMainWindow->leftDock()->hasDockWindow(this) ) return Left;
+   if ( m_pMainWindow->rightDock()->hasDockWindow(this) ) return Right;
+   if ( m_pMainWindow->topDock()->hasDockWindow(this) ) return Top;
+   if ( m_pMainWindow->bottomDock()->hasDockWindow(this) ) return Bottom;
+   return Top;
+}
+
+void KToolBar::setBarPos(BarPosition bp)
+{
+   if ( bp == Left ) m_pMainWindow->moveDockWindow( this, DockLeft );
+   else if ( bp == Right ) m_pMainWindow->moveDockWindow( this, DockRight );
+   else if ( bp == Bottom ) m_pMainWindow->moveDockWindow( this, DockBottom );
+   else if ( bp == Top ) m_pMainWindow->moveDockWindow( this, DockTop );
+}
+
+KToolBar::KToolBar( QMainWindow* parent )
+: QToolBar( parent )
+{
+   m_pMainWindow = parent;
+}
+
+
+KMainWindow::KMainWindow( QWidget* parent, const char* name )
+: QMainWindow( parent, name ), m_actionCollection(this)
+{
+   fileMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&File"), fileMenu);
+   editMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Edit"), editMenu);
+   directoryMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Directory"), directoryMenu);
+   dirCurrentItemMenu = 0;
+   dirCurrentSyncItemMenu = 0;
+   movementMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Movement"), movementMenu);
+   diffMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("D&iffview"), diffMenu);
+   mergeMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Merge"), mergeMenu);
+   windowsMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Window"), windowsMenu);
+   settingsMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Settings"), settingsMenu);
+   helpMenu = new QPopupMenu();
+   menuBar()->insertItem(i18n("&Help"), helpMenu);
+
+   m_pToolBar = new KToolBar(this);
+      
+   memberList = new QList<KMainWindow>;
+   memberList->append(this);
+}
+
+KToolBar* KMainWindow::toolBar(const QString&)
+{
+   return m_pToolBar;
+}
+
+KActionCollection* KMainWindow::actionCollection()
+{
+   return &m_actionCollection;
+}
+
+void KMainWindow::createGUI()
+{
+   KStdAction::help(this, SLOT(slotHelp()), actionCollection());
+   KStdAction::about(this, SLOT(slotAbout()), actionCollection());
+   KStdAction::aboutQt(actionCollection());
+}
+
+void KMainWindow::slotAbout()
+{
+   QTabDialog d;
+   d.setCaption("About " + s_appName);
+   QTextBrowser* tb1 = new QTextBrowser(&d);
+   tb1->setWordWrap( QTextEdit::NoWrap );
+   tb1->setText(
+      s_appName + " Version " + s_version +
+      "\n\n" + s_description + 
+      "\n\n" + s_copyright +
+      "\n\nHomepage: " + s_homepage +
+      "\n\nLicence: GNU GPL Version 2"
+      );
+   d.addTab(tb1,i18n("&About"));
+      
+   std::list<KAboutData::AboutDataEntry>::iterator i;
+   
+   QString s2;   
+   for( i=s_pAboutData->m_authorList.begin(); i!=s_pAboutData->m_authorList.end(); ++i )
+   {
+      if ( !i->m_name.isEmpty() )    s2 +=         i->m_name    + "\n";
+      if ( !i->m_task.isEmpty() )    s2 += "   " + i->m_task    + "\n";
+      if ( !i->m_email.isEmpty() )   s2 += "   " + i->m_email   + "\n";
+      if ( !i->m_weblink.isEmpty() ) s2 += "   " + i->m_weblink + "\n";
+      s2 += "\n";
+   }
+   QTextBrowser* tb2 = new QTextBrowser(&d);
+   tb2->setWordWrap( QTextEdit::NoWrap );
+   tb2->setText(s2);
+   d.addTab(tb2,i18n("A&uthor"));
+   
+   QString s3;
+   for( i=s_pAboutData->m_creditList.begin(); i!=s_pAboutData->m_creditList.end(); ++i )
+   {
+      if ( !i->m_name.isEmpty() )    s3 +=         i->m_name    + "\n";
+      if ( !i->m_task.isEmpty() )    s3 += "   " + i->m_task    + "\n";
+      if ( !i->m_email.isEmpty() )   s3 += "   " + i->m_email   + "\n";
+      if ( !i->m_weblink.isEmpty() ) s3 += "   " + i->m_weblink + "\n";
+      s3 += "\n";
+   }
+   QTextBrowser* tb3 = new QTextBrowser(&d);
+   tb3->setWordWrap( QTextEdit::NoWrap );
+   tb3->setText(s3);
+   d.addTab(tb3,i18n("&Thanks To"));
+   
+   d.resize(400,300);
+   d.exec();
+/*
+   QMessageBox::information(
+      this,
+      "About " + s_appName,
+      s_appName + " Version " + s_version +
+      "\n\n" + s_description + 
+      "\n\n" + s_copyright +
+      "\n\nHomepage: " + s_homepage +
+      "\n\nLicence: GNU GPL Version 2"
+      );
+*/
+}
+
+void KMainWindow::slotHelp()
+{
+   showHelp();
+}
+
+
+QString KStandardDirs::findResource(const QString& resource, const QString& /*appName*/)
+{
+   if (resource=="config")
+   {
+      QString home = QDir::homeDirPath();
+      return home + "/.kdiff3rc";
+   }
+   return QString();
+}
+
+KConfig::KConfig()
+{
+}
+
+void KConfig::readConfigFile( const QString& configFileName )
+{
+   if ( !configFileName.isEmpty() )
+   {
+      m_fileName = configFileName;
+   }
+   else
+   {
+      m_fileName = KStandardDirs().findResource("config","kdiff3rc");
+   }
+
+   QFile f( m_fileName );
+   if ( f.open(IO_ReadOnly) )
+   {                               // file opened successfully
+      QTextStream t( &f );         // use a text stream
+      load(t);
+      f.close();
+   }
+}
+
+KConfig::~KConfig()
+{
+   QFile f(m_fileName);
+   if ( f.open( IO_WriteOnly | IO_Translate ) )
+   {                               // file opened successfully
+       QTextStream t( &f );        // use a text stream
+       save(t);
+       f.close();
+   }
+}
+
+void KConfig::setGroup(const QString&)
+{
+}
+
+void KAction::init(QObject* receiver, const char* slot, KActionCollection* actionCollection, 
+                   const char* name, bool bToggle, bool bMenu)
+{
+   QString n(name);
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   if( slot!=0 )
+   {
+      if (!bToggle)
+         connect(this, SIGNAL(activated()), receiver, slot);
+      else
+      {
+         connect(this, SIGNAL(toggled(bool)), receiver, slot);
+      }
+   }
+
+   if (bMenu)
+   {
+      if( n[0]=='g')       addTo( p->movementMenu );
+      else if( n.left(16)=="dir_current_sync")
+      {
+         if ( p->dirCurrentItemMenu==0 )
+         {
+            p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(i18n("Current Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(i18n("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+         }
+         addTo( p->dirCurrentItemMenu );
+      }
+      else if( n.left(11)=="dir_current")
+      {
+         if ( p->dirCurrentItemMenu==0 )
+         {
+            p->dirCurrentItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(i18n("Current Item Merge Operation"), p->dirCurrentItemMenu);
+            p->dirCurrentSyncItemMenu = new QPopupMenu();
+            p->directoryMenu->insertItem(i18n("Current Item Sync Operation"), p->dirCurrentSyncItemMenu);
+         }
+         addTo( p->dirCurrentSyncItemMenu );
+      }
+      else if( n.left(4)=="diff")  addTo( p->diffMenu );
+      else if( name[0]=='d')  addTo( p->directoryMenu );
+      else if( name[0]=='f')  addTo( p->fileMenu );
+      else if( name[0]=='w')  addTo( p->windowsMenu );
+      else                    addTo( p->mergeMenu );
+   }
+}
+
+
+KAction::KAction(const QString& text, const QIconSet& icon, int accel,
+ QObject* receiver, const char* slot, KActionCollection* actionCollection,
+ const char* name, bool bToggle, bool bMenu
+ )
+: QAction ( text, icon, text, accel, actionCollection->m_pMainWindow, name, bToggle )
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   if ( !icon.isNull() && p ) this->addTo( p->m_pToolBar );
+
+   init(receiver,slot,actionCollection,name,bToggle,bMenu);
+}
+
+KAction::KAction(const QString& text, int accel,
+ QObject* receiver, const char* slot, KActionCollection* actionCollection,
+ const char* name, bool bToggle, bool bMenu
+ )
+: QAction ( text, text, accel, actionCollection->m_pMainWindow, name, bToggle )
+{
+   init(receiver,slot,actionCollection,name,bToggle,bMenu);
+}
+
+void KAction::setStatusText(const QString&)
+{
+}
+
+void KAction::plug(QPopupMenu* menu)
+{
+   addTo(menu);
+}
+
+
+KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bMenu)
+: KAction( text, icon, accel, receiver, slot, actionCollection, name, true, bMenu)
+{
+}
+
+KToggleAction::KToggleAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bMenu)
+: KAction( text, accel, receiver, slot, actionCollection, name, true, bMenu)
+{
+}
+
+KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, KActionCollection* actionCollection, const char* name, bool bMenu)
+: KAction( text, icon, accel, 0, 0, actionCollection, name, true, bMenu)
+{
+}
+
+void KToggleAction::setChecked(bool bChecked)
+{
+   blockSignals( true );
+   setOn( bChecked );
+   blockSignals( false );
+}
+
+bool KToggleAction::isChecked()
+{
+   return isOn();
+}
+
+
+
+//static
+KAction* KStdAction::open( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   #include "../xpm/fileopen.xpm"
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Open"), QIconSet(QPixmap(fileopen)), Qt::CTRL+Qt::Key_O, parent, slot, actionCollection, "open", false, false);
+   if(p){ a->addTo( p->fileMenu ); }
+   return a;
+}
+
+KAction* KStdAction::save( QWidget* parent, const char* slot, KActionCollection* actionCollection )
+{
+   #include "../xpm/filesave.xpm"
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Save"), QIconSet(QPixmap(filesave)), Qt::CTRL+Qt::Key_S, parent, slot, actionCollection, "save", false, false);
+   if(p){ a->addTo( p->fileMenu ); }
+   return a;
+}
+
+KAction* KStdAction::saveAs( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Save As..."), 0, parent, slot, actionCollection, "saveas", false, false);
+   if(p) a->addTo( p->fileMenu );
+   return a;
+}
+
+KAction* KStdAction::print( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   #include "../xpm/fileprint.xpm"
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Print..."), QIconSet(QPixmap(fileprint)),Qt::CTRL+Qt::Key_P, parent, slot, actionCollection, "print", false, false);
+   if(p) a->addTo( p->fileMenu );
+   return a;
+}
+
+KAction* KStdAction::quit( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Quit"), Qt::CTRL+Qt::Key_Q, parent, slot, actionCollection, "quit", false, false);
+   if(p) a->addTo( p->fileMenu );
+   return a;
+}
+
+KAction* KStdAction::cut( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Cut"), Qt::CTRL+Qt::Key_X, parent, slot, actionCollection, "cut", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+KAction* KStdAction::copy( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Copy"), Qt::CTRL+Qt::Key_C, parent, slot, actionCollection, "copy", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+KAction* KStdAction::paste( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Paste"), Qt::CTRL+Qt::Key_V, parent, slot, actionCollection, "paste", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+KAction* KStdAction::selectAll( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Select All"), Qt::CTRL+Qt::Key_A, parent, slot, actionCollection, "selectall", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+KToggleAction* KStdAction::showToolbar( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KToggleAction* a = new KToggleAction( i18n("Show Toolbar"), 0, parent, slot, actionCollection, "showtoolbar", false );
+   if(p) a->addTo( p->settingsMenu );
+   return a;
+}
+
+KToggleAction* KStdAction::showStatusbar( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KToggleAction* a = new KToggleAction( i18n("Show &Statusbar"), 0, parent, slot, actionCollection, "showstatusbar", false );
+   if(p) a->addTo( p->settingsMenu );
+   return a;
+}
+
+KAction* KStdAction::preferences( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("&Configure %1...").arg("KDiff3"), 0, parent, slot, actionCollection, "settings", false, false );
+   if(p) a->addTo( p->settingsMenu );
+   return a;
+}
+KAction* KStdAction::keyBindings( QWidget*, const char*, KActionCollection*)
+{
+   return 0;
+}
+
+KAction* KStdAction::about( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("About")+" KDiff3", 0, parent, slot, actionCollection, "about_kdiff3", false, false );
+   if(p) a->addTo( p->helpMenu );
+   return a;
+}
+
+KAction* KStdAction::aboutQt( KActionCollection* actionCollection )
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("About")+" Qt", 0, qApp, SLOT(aboutQt()), actionCollection, "about_qt", false, false );
+   if(p) a->addTo( p->helpMenu );
+   return a;
+}
+
+KAction* KStdAction::help( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Help"), Qt::Key_F1, parent, slot, actionCollection, "help", false, false );
+   if(p) a->addTo( p->helpMenu );
+   return a;
+}
+KAction* KStdAction::find( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Find"), Qt::CTRL+Qt::Key_F, parent, slot, actionCollection, "find", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+KAction* KStdAction::findNext( QWidget* parent, const char* slot, KActionCollection* actionCollection)
+{
+   KMainWindow* p = actionCollection->m_pMainWindow;
+   KAction* a = new KAction( i18n("Find Next"), Qt::Key_F3, parent, slot, actionCollection, "findNext", false, false );
+   if(p) a->addTo( p->editMenu );
+   return a;
+}
+
+
+
+
+KFontChooser::KFontChooser( QWidget* pParent, const QString& /*name*/, bool, const QStringList&, bool, int )
+: QWidget(pParent)
+{
+   m_pParent = pParent;
+   QVBoxLayout* pLayout = new QVBoxLayout( this );
+   m_pSelectFont = new QPushButton(i18n("Select Font"), this );
+   connect(m_pSelectFont, SIGNAL(clicked()), this, SLOT(slotSelectFont()));
+   pLayout->addWidget(m_pSelectFont);
+
+   m_pLabel = new QLabel( "", this );
+   m_pLabel->setFont( m_font );
+   m_pLabel->setMinimumWidth(200);
+   m_pLabel->setText( "The quick brown fox jumps over the river\n"
+                      "but the little red hen escapes with a shiver.\n"
+                      ":-)");
+   pLayout->addWidget(m_pLabel);
+}
+
+QFont KFontChooser::font()
+{
+   return m_font;//QFont("courier",10);
+}
+
+void KFontChooser::setFont( const QFont& font, bool )
+{
+   m_font = font;
+   m_pLabel->setFont( m_font );
+   //update();
+}
+
+void KFontChooser::slotSelectFont()
+{
+   for(;;)
+   {
+      bool bOk;
+      m_font = QFontDialog::getFont(&bOk, m_font );
+      m_pLabel->setFont( m_font );   
+      QFontMetrics fm(m_font);
+
+      // Variable width font.
+      if ( fm.width('W')!=fm.width('i') )
+      {
+         int result = KMessageBox::warningYesNo(m_pParent, i18n(
+            "You selected a variable width font.\n\n"
+            "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"));
+         if (result==KMessageBox::Yes)
+            return;
+      }
+      else
+         return;
+   }
+}
+
+
+KColorButton::KColorButton(QWidget* parent)
+: QPushButton(parent)
+{
+   connect( this, SIGNAL(clicked()), this, SLOT(slotClicked()));
+}
+
+QColor KColorButton::color()
+{
+   return m_color;
+}
+
+void KColorButton::setColor( const QColor& color )
+{
+   m_color = color;
+   update();
+}
+
+void KColorButton::paintEvent( QPaintEvent* e )
+{
+   QPushButton::paintEvent(e);
+   QPainter p(this);
+
+   int w = width();
+   int h = height();
+   p.fillRect( 10, 5, w-20, h-10, m_color );
+   p.drawRect( 10, 5, w-20, h-10 );
+}
+
+void KColorButton::slotClicked()
+{
+   // Under Windows ChooseColor() should be used. (Nicer if few colors exist.)
+   QColor c = QColorDialog::getColor ( m_color, this );
+   if ( c.isValid() ) m_color = c;
+   update();
+}
+
+KPrinter::KPrinter()
+{
+}
+QValueList<int> KPrinter::pageList()
+{
+   QValueList<int> vl;
+   int to = toPage();
+   for(int i=fromPage(); i<=to; ++i)
+   {
+      vl.push_back(i);
+   }
+   return vl;
+}
+void KPrinter::setCurrentPage(int)
+{
+}
+void KPrinter::setPageSelection(e_PageSelection)
+{
+}
+
+
+QPixmap KIconLoader::loadIcon( const QString&, int )
+{
+   return QPixmap();
+}
+
+KAboutData::KAboutData( const QString& /*name*/, const QString& appName, const QString& version,
+      const QString& description, int,
+      const QString& copyright, int, const QString& homepage, const QString& email)
+{
+   s_copyright = copyright;
+   s_email = email;
+   s_appName = appName;
+   s_description = description;
+   s_version = version;
+   s_homepage = homepage;
+}
+
+KAboutData::KAboutData( const QString& /*name*/, const QString& /*appName*/, const QString& /*version*/ )
+{
+}
+
+void KAboutData::addAuthor(const char* name, const char* task, const char* email, const char* weblink)
+{
+   m_authorList.push_back( AboutDataEntry( name, task, email, weblink) );
+}
+
+void KAboutData::addCredit(const char* name, const char* task, const char* email, const char* weblink)
+{
+   m_creditList.push_back( AboutDataEntry( name, task, email, weblink) );
+}
+
+/*  Option structure: e.g.:
+  { "m", 0, 0 },
+  { "merge", I18N_NOOP("Automatically merge the input."), 0 },
+  { "o", 0, 0 },
+  { "output file", I18N_NOOP("Output file. Implies -m. E.g.: -o newfile.txt"), 0 },
+  { "+[File1]", I18N_NOOP("file1 to open (base)"), 0 },
+  { "+[File2]", I18N_NOOP("file2 to open"), 0 },
+  { "+[File3]", I18N_NOOP("file3 to open"), 0 },
+*/
+////////////////
+static KCmdLineArgs s_cmdLineArgs;
+static int s_argc;
+static char** s_argv;
+static KCmdLineOptions* s_pOptions;
+
+static std::vector<QCStringList> s_vOption;
+static std::vector<const char*> s_vArg;
+
+KCmdLineArgs* KCmdLineArgs::parsedArgs()  // static
+{
+   return &s_cmdLineArgs;
+}
+
+void KCmdLineArgs::init( int argc, char**argv, KAboutData* pAboutData )  // static
+{
+   s_argc = argc;
+   s_argv = argv;
+   s_pAboutData = pAboutData;
+}
+
+void KCmdLineArgs::addCmdLineOptions( KCmdLineOptions* options ) // static
+{
+   s_pOptions = options;
+}
+
+int KCmdLineArgs::count()
+{
+   return s_vArg.size();
+}
+
+QString KCmdLineArgs::arg(int idx)
+{
+   return QString::fromLocal8Bit( s_vArg[idx] );
+}
+
+void KCmdLineArgs::clear()
+{
+}
+
+QString KCmdLineArgs::getOption( const QString& s )
+{
+   // Find the option
+   int j=0;
+   for( j=0; j<(int)s_vOption.size(); ++j )
+   {
+      const char* optName = s_pOptions[j].name;
+      const char* pos = strchr( optName,' ' );
+      int len = pos==0 ? strlen( optName ) : pos - optName;
+
+      if( s == (const char*)( QCString( optName, len+1) ) )
+      {
+         return s_vOption[j].isEmpty() ? QString() : s_vOption[j].last();
+      }
+   }
+   assert(false);
+   return QString();
+}
+
+QCStringList KCmdLineArgs::getOptionList( const QString& s )
+{   
+   // Find the option
+   int j=0;
+   for( j=0; j<(int)s_vOption.size(); ++j )
+   {
+      const char* optName = s_pOptions[j].name;
+      const char* pos = strchr( optName,' ' );
+      int len = pos==0 ? strlen( optName ) : pos - optName;
+
+      if( s == (const char*)( QCString( optName, len+1) ) )
+      {
+         return s_vOption[j];
+      }
+   }
+
+   assert(false);
+   return QCStringList();
+}
+
+bool KCmdLineArgs::isSet(const QString& s)
+{
+   // Find the option
+   int j=0;
+   for( j=0; j<(int)s_vOption.size(); ++j )
+   {
+      const char* optName = s_pOptions[j].name;
+      if( s == QString( optName ) )
+      {
+         return ! s_vOption[j].isEmpty();
+      }
+   }
+   assert(false);
+   return false;
+}
+
+///////////////////
+KApplication* kapp;
+
+KApplication::KApplication()
+: QApplication( s_argc,s_argv )
+{
+   kapp = this;
+
+   int nofOptions=0;
+   int nofArgs=0;
+   int i=0;
+   while( s_pOptions[i].name != 0 )
+   {
+      if ( s_pOptions[i].name[0]=='[' )
+         nofArgs++;
+      else
+         nofOptions++;
+
+      ++i;
+   }
+
+   // First find the option "-config" or "--config" to allow loading of options
+   QString configFileName;
+   for( i=1; i<s_argc-1; ++i )
+   {
+      QString arg = s_argv[i];
+      if ( arg == "-config" || arg == "--config" )
+      {
+         configFileName = s_argv[i+1];
+      }
+   }
+   m_config.readConfigFile(configFileName);
+
+   QStringList ignorableCmdLineOptionsList = m_config.readListEntry("IgnorableCmdLineOptions", QString("-u;-query;-html;-abort"), '|');
+   QString ignorableCmdLineOptions;
+   if ( !ignorableCmdLineOptionsList.isEmpty() ) 
+      ignorableCmdLineOptions = ignorableCmdLineOptionsList.front() + ";";
+
+   s_vOption.resize(nofOptions);
+
+   for( i=1; i<s_argc; ++i )
+   {
+      if ( s_argv[i][0]=='-' )  // An option
+      {
+         if ( ignorableCmdLineOptions.contains(QString(s_argv[i])+";") )
+            continue;
+         // Find the option
+         int j=0;
+         for( j=0; j<nofOptions; ++j )
+         {
+            const char* optName = s_pOptions[j].name;
+            const char* pos = strchr( optName,' ' );
+            int len = pos==0 ? strlen( optName ) : pos - optName;
+            int len2 = strlen(s_argv[i]);
+
+            if( len>0 && ( s_argv[i][1]=='-' && len2-2==len && memcmp( &s_argv[i][2], optName, len )==0  ||
+                                                len2-1==len && memcmp( &s_argv[i][1], optName, len )==0  ))
+            {
+               if (s_pOptions[j].description == 0)  // alias, because without description.
+               {
+                  ++j;
+                  optName = s_pOptions[j].name;
+                  pos = strchr( optName,' ' );
+               }
+               if (pos!=0){ ++i; s_vOption[j].append(s_argv[i]); } //use param
+               else       { s_vOption[j].append("1"); }           //set state
+               break;
+            }
+         }
+         if (j==nofOptions)
+         {
+            QString s;
+            s = QString("Unknown option: ") +  s_argv[i] + "\n";
+            s += "If KDiff3 should ignore this option, run KDiff3 normally and edit\n"
+                 "the \"Command line options to ignore\" in the \"Integration Settings\".\n\n";
+
+            s += "KDiff3-Usage when starting via commandline: \n";
+            s += "- Comparing 2 files:\t\tkdiff3 file1 file2\n";
+            s += "- Merging 2 files:  \t\tkdiff3 file1 file2 -o outputfile\n";
+            s += "- Comparing 3 files:\t\tkdiff3 file1 file2 file3\n";
+            s += "- Merging 3 files:  \t\tkdiff3 file1 file2 file3 -o outputfile\n";
+            s += "     Note that file1 will be treated as base of file2 and file3.\n";
+            s += "\n";
+            s += "If you start without arguments, then a dialog will appear\n";
+            s += "where you can select your files via a filebrowser.\n";
+            s += "\n";
+
+            s += "Options:\n";
+
+            j=0;
+            int pos=s.length();
+            for( j=0; j<nofOptions; ++j )
+            {
+               if ( s_pOptions[j].description!=0 )
+               {
+                  if (s_pOptions[j].name[0]!='+')
+                  {
+                     s += "-";
+                     if ( strlen(s_pOptions[j].name)>1 ) s += "-";
+                  }
+                  s += s_pOptions[j].name;
+                  s += QString().fill(' ', minMaxLimiter( 20 - ((int)s.length()-pos), 3, 20 ) );
+                  s += s_pOptions[j].description;
+                  s +="\n";
+                  pos=s.length();
+               }
+               else
+               {
+                  s += "-";
+                  if ( strlen(s_pOptions[j].name)>1 ) s += "-";
+                  s += s_pOptions[j].name;
+                  s += ", ";
+               }
+            }
+
+            s += "\n"+i18n("For more documentation, see the help-menu or the subdirectory doc.")+"\n";
+#ifdef _WIN32
+            // A windows program has no console
+            if ( 0==QMessageBox::information(0, i18n("KDiff3-Usage"), s, i18n("Ignore"),i18n("Exit") ) )
+               continue;
+#else
+            std::cerr << s.latin1() << std::endl;
+#endif
+
+            ::exit(-1);
+         }
+      }
+      else
+         s_vArg.push_back( s_argv[i] );
+   }
+}
+
+KConfig* KApplication::config()
+{
+   return &m_config;
+}
+
+bool KApplication::isRestored()
+{
+   return false;
+}
+
+KApplication* KApplication::kApplication()
+{
+   return kapp;
+}
+
+KIconLoader* KApplication::iconLoader()
+{
+   return &m_iconLoader;
+}
+
+
+namespace KIO
+{
+   SimpleJob* mkdir( KURL ){return 0;}
+   SimpleJob* rmdir( KURL ){return 0;}
+   SimpleJob* file_delete( KURL, bool ){return 0;}
+   FileCopyJob* file_move(  KURL, KURL, int, bool, bool, bool ) {return 0;}
+   FileCopyJob* file_copy(  KURL, KURL, int, bool, bool, bool ) {return 0;}
+   CopyJob* link(  KURL, KURL, bool ) {return 0;}
+   ListJob* listRecursive( KURL, bool, bool ){return 0;}
+   ListJob* listDir( KURL, bool, bool ){return 0;}
+   StatJob* stat( KURL, bool, int, bool ){return 0;}
+   TransferJob* get( KURL, bool, bool ){return (TransferJob*)0;}
+   TransferJob* put( KURL, int, bool, bool, bool ){return (TransferJob*)0;}
+};
+
+KActionCollection* KParts::Part::actionCollection()
+{
+   return 0;
+}
+
+KApplication* KParts::Part::instance()
+{
+   return kapp;
+}
+
+
+KLibLoader* KLibLoader::self()
+{
+   static KLibLoader ll;
+   return &ll;
+}
+
+extern "C" void* init_libkdiff3part();
+KLibFactory* KLibLoader::factory(QString const&)
+{
+   return (KLibFactory*) init_libkdiff3part();
+}
+
+QObject* KLibFactory::create(QObject* pParent, const QString& name, const QString& classname )
+{
+   KParts::Factory* f = dynamic_cast<KParts::Factory*>(this);
+   if (f!=0)
+      return f->createPartObject( (QWidget*)pParent, name.ascii(),
+                                            pParent, name.ascii(),
+                                            classname.ascii(),  QStringList() );
+   else
+      return 0;
+}
+
+
+
+
+#include "kreplacements.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,505 @@
+/***************************************************************************
+                          kreplacements.h  -  description
+                             -------------------
+    begin                : Sat Aug 3 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef KREPLACEMENTS_H
+#define KREPLACEMENTS_H
+
+#include "common.h"
+
+#include <qobject.h>
+#include <qtabdialog.h>
+#include <qmainwindow.h>
+#include <qaction.h>
+#include <qfiledialog.h>
+#include <qapplication.h>
+#include <qvbox.h>
+#include <qpushbutton.h>
+#include <qstatusbar.h>
+#include <qtoolbar.h>
+#include <qprogressbar.h>
+#include <qpopupmenu.h>
+#include <qstringlist.h>
+#include <qprinter.h>
+
+#include <map>
+#include <list>
+
+QString getTranslationDir();
+
+class KMainWindow;
+
+class KURL
+{
+public:
+   KURL(){}
+   KURL(const QString& s){ m_s = s; }
+   static KURL fromPathOrURL( const QString& s ){ return KURL(s); }
+   QString url() const { return m_s; }
+   bool isEmpty() const { return m_s.isEmpty(); }
+   QString prettyURL() const { return m_s; }
+   bool isLocalFile() const { return true; }
+   bool isValid() const { return true; }
+   QString path() const { return m_s; }
+   void setPath( const QString& s ){ m_s=s; }
+   QString fileName() const { return m_s; } // not really needed
+   void addPath( const QString& s ){ m_s += "/" + s; }
+private:
+   QString m_s;
+};
+
+class KMessageBox
+{
+public:
+   static void error( QWidget* parent, const QString& text, const QString& caption=QString() );
+   static int warningContinueCancel( QWidget* parent, const QString& text, const QString& caption=QString(),
+      const QString& button1=QString("Continue") );
+   static void sorry(  QWidget* parent, const QString& text, const QString& caption=QString() );
+   static void information(  QWidget* parent, const QString& text, const QString& caption=QString() );
+   static int  warningYesNo( QWidget* parent, const QString& text, const QString& caption,
+      const QString& button1, const QString& button2 );
+   static int warningYesNoCancel(
+         QWidget* parent, const QString& text, const QString& caption,
+         const QString& button1, const QString& button2 );
+
+   enum {Cancel=-1, No=0, Yes=1, Continue=1};
+};
+
+#define i18n(x) QObject::tr(x)
+#define I18N_NOOP(x) x
+#define RESTORE(x)
+#define _UNLOAD(x)
+
+typedef QPopupMenu KPopupMenu;
+
+class KDialogBase : public QTabDialog
+{
+   Q_OBJECT
+public:
+   KDialogBase( int, const QString& caption, int, int, QWidget* parent, const char* name,
+     bool /*modal*/, bool );
+   ~KDialogBase();
+
+   void incInitialSize ( const QSize& );
+   void setHelp(const QString& helpfilename, const QString& );
+   enum {IconList, Help, Default, Apply, Ok, Cancel };
+
+   int BarIcon(const QString& iconName, int );
+
+   QVBox* addVBoxPage( const QString& name, const QString& info, int );
+   QFrame* addPage(  const QString& name, const QString& info, int );
+   int spacingHint();
+
+   virtual void accept();
+signals:
+   void applyClicked();
+
+protected slots:
+    virtual void slotOk( void );
+    virtual void slotApply( void );
+    virtual void slotHelp( void );
+    virtual void slotCancel( void );
+    virtual void slotDefault( void );
+};
+
+class KFileDialog : public QFileDialog
+{
+public:
+   static KURL getSaveURL( const QString &startDir=QString::null,
+                           const QString &filter=QString::null,
+                           QWidget *parent=0, const QString &caption=QString::null);
+   static KURL getOpenURL( const QString &  startDir = QString::null,
+                           const QString &  filter = QString::null,
+                           QWidget *  parent = 0,
+                           const QString &  caption = QString::null );
+   static KURL getExistingURL( const QString &  startDir = QString::null,
+                               QWidget *  parent = 0,
+                               const QString &  caption = QString::null );
+   static QString getSaveFileName (const QString &startDir=QString::null, 
+                                   const QString &filter=QString::null, 
+                                   QWidget *parent=0, 
+                                   const QString &caption=QString::null);
+};
+
+typedef QStatusBar KStatusBar;
+
+class KToolBar : public QToolBar
+{
+public:
+   KToolBar(QMainWindow* parent);
+
+   enum BarPosition {Top, Bottom, Left, Right};
+   BarPosition barPos();
+   void setBarPos(BarPosition);
+private:
+   QMainWindow* m_pMainWindow;
+};
+
+class KActionCollection
+{
+public:
+   KMainWindow* m_pMainWindow;
+   KActionCollection( KMainWindow* p){ m_pMainWindow=p; }
+};
+
+class KKeyDialog
+{
+public:
+   static void configure(void*, QWidget*){}
+   static void configureKeys(KActionCollection*, const QString&){}
+   static void configure(KActionCollection*, const QString&){}
+};
+
+namespace KParts
+{
+   class ReadWritePart;
+}
+
+class KMainWindow : public QMainWindow
+{
+   Q_OBJECT
+private:
+   KStatusBar m_statusBar;
+   KActionCollection m_actionCollection;
+protected:
+   virtual bool queryClose() = 0;
+   virtual bool queryExit() = 0;
+public:
+   QPopupMenu* fileMenu;
+   QPopupMenu* editMenu;
+   QPopupMenu* directoryMenu;
+   QPopupMenu* dirCurrentItemMenu;
+   QPopupMenu* dirCurrentSyncItemMenu;
+   QPopupMenu* movementMenu;
+   QPopupMenu* mergeMenu;
+   QPopupMenu* diffMenu;
+   QPopupMenu* windowsMenu;
+   QPopupMenu* settingsMenu;
+   QPopupMenu* helpMenu;
+
+   KToolBar*  m_pToolBar;
+
+   KMainWindow( QWidget* parent, const char* name );
+   KToolBar* toolBar(const QString& s = QString::null);
+   KActionCollection* actionCollection();
+   void createGUI();
+   void createGUI(KParts::ReadWritePart*){createGUI();}
+
+   QList<KMainWindow>* memberList;
+public slots:
+   void slotHelp();
+   void slotAbout();
+};
+
+class KConfig : public ValueMap
+{
+   QString m_fileName;
+public:
+   KConfig();
+   ~KConfig();
+   void readConfigFile(const QString& configFileName);
+
+   void setGroup(const QString&);
+};
+
+class KAction : public QAction
+{
+   Q_OBJECT
+public:
+   KAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bToggle=false, bool bMenu=true);
+   KAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bToggle=false, bool bMenu=true);
+   void init(QObject* receiver, const char* slot, KActionCollection* actionCollection, 
+        const char* name, bool bToggle, bool bMenu);
+   void setStatusText(const QString&);
+   void plug(QPopupMenu*);
+};
+
+class KToggleAction : public KAction
+{
+public:
+   KToggleAction(const QString& text, const QIconSet& icon, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bMenu=true);
+   KToggleAction(const QString& text, int accel, QObject* receiver, const char* slot, KActionCollection* actionCollection, const char* name, bool bMenu=true);
+   KToggleAction(const QString& text, const QIconSet& icon, int accel, KActionCollection* actionCollection, const char* name, bool bMenu=true);
+   void setChecked(bool);
+   bool isChecked();
+};
+
+
+class KStdAction
+{
+public:
+   static KAction* open( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* save( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* saveAs( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* print( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* quit( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* cut( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* copy( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* paste( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* selectAll( QWidget* parent, const char* slot, KActionCollection* );
+   static KToggleAction* showToolbar( QWidget* parent, const char* slot, KActionCollection* );
+   static KToggleAction* showStatusbar( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* preferences( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* about( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* aboutQt( KActionCollection* );
+   static KAction* help( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* find( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* findNext( QWidget* parent, const char* slot, KActionCollection* );
+   static KAction* keyBindings( QWidget* parent, const char* slot, KActionCollection* );
+};
+
+class KIcon
+{
+public:
+   enum {SizeMedium,Small};
+};
+
+class KFontChooser : public QWidget
+{
+   Q_OBJECT
+   QFont m_font;
+   QPushButton* m_pSelectFont;
+   QLabel* m_pLabel;
+   QWidget* m_pParent;
+public:
+   KFontChooser( QWidget* pParent, const QString& name, bool, const QStringList&, bool, int );
+   QFont font();
+   void setFont( const QFont&, bool );
+private slots:
+   void slotSelectFont();
+};
+
+class KColorButton : public QPushButton
+{
+   Q_OBJECT
+   QColor m_color;
+public:
+   KColorButton(QWidget* parent);
+   QColor color();
+   void setColor(const QColor&);
+   virtual void paintEvent(QPaintEvent* e);
+public slots:
+   void slotClicked();
+};
+
+class KPrinter : public QPrinter
+{
+public:
+   KPrinter();
+   enum e_PageSelection {ApplicationSide};
+   QValueList<int> pageList();
+   void setCurrentPage(int);
+   void setPageSelection(e_PageSelection);
+};
+
+class KStandardDirs
+{
+public:
+   QString findResource(const QString& resource, const QString& appName);
+};   
+
+struct KCmdLineOptions
+{
+   const char* name;
+   const char* description;
+   int def;
+};
+
+#define KCmdLineLastOption {0,0,0}
+
+class KAboutData
+{
+public:
+   KAboutData( const QString& name, const QString& appName, const QString& version,
+      const QString& description, int licence,
+      const QString& copyright, int w, const QString& homepage, const QString& email);
+   KAboutData( const QString& name, const QString& appName, const QString& version );
+   void addAuthor(const char* name=0, const char* task=0, const char* email=0, const char* weblink=0);
+   void addCredit(const char* name=0, const char* task=0, const char* email=0, const char* weblink=0);
+   enum { License_GPL };
+   
+   struct AboutDataEntry
+   {
+      AboutDataEntry(const QString& name, const QString& task, const QString& email, const QString& weblink)
+      : m_name(name), m_task(task), m_email(email), m_weblink(weblink)  
+      {}
+      QString m_name;
+      QString m_task;
+      QString m_email;
+      QString m_weblink;
+   };
+   
+   std::list<AboutDataEntry> m_authorList;
+   std::list<AboutDataEntry> m_creditList;
+};
+
+typedef QValueList<QCString> QCStringList;
+
+class KCmdLineArgs
+{
+public:
+   static KCmdLineArgs* parsedArgs();
+   static void init( int argc, char**argv, KAboutData* );
+   static void addCmdLineOptions( KCmdLineOptions* options ); // Add our own options.
+
+   int count();
+   QString arg(int);
+   KURL url(int i){ return KURL(arg(i)); }
+   void clear();
+   QString getOption(const QString&);
+   QCStringList getOptionList( const QString& );
+   bool isSet(const QString&);
+};
+
+class KIconLoader
+{
+public:
+   QPixmap loadIcon(const QString& name, int);
+};
+
+class KApplication : public QApplication
+{
+   KConfig m_config;
+   KIconLoader m_iconLoader;
+public:
+   KApplication();
+   static KApplication* kApplication();
+   KIconLoader* iconLoader();
+   KConfig* config();
+   bool isRestored();
+};
+
+extern KApplication* kapp;
+
+class KLibFactory : public QObject
+{
+   Q_OBJECT
+public:
+   QObject* create(QObject*,const QString&,const QString&);
+};
+
+class KLibLoader
+{
+public:
+   static KLibLoader* self();
+   KLibFactory* factory(const QString&);
+};
+
+class KEditToolbar : public QDialog
+{
+public:
+   KEditToolbar( int ){}
+};
+
+class KGlobal
+{
+public:
+   static KConfig* config() { return 0; }
+};
+
+namespace KIO
+{
+   enum UDSEntry {};
+   typedef QValueList<UDSEntry> UDSEntryList;
+   class Job : public QObject
+   {
+   public:
+      void kill(bool){}
+      bool error() {return false;}
+      void showErrorDialog( QWidget* ) {}
+   };
+   class SimpleJob : public Job {};
+   SimpleJob* mkdir( KURL );
+   SimpleJob* rmdir( KURL );
+   SimpleJob* file_delete( KURL, bool );
+   class FileCopyJob : public Job {};
+   FileCopyJob* file_move(  KURL, KURL, int, bool, bool, bool );
+   FileCopyJob* file_copy(  KURL, KURL, int, bool, bool, bool );
+   class CopyJob : public Job {};
+   CopyJob* link( KURL, KURL, bool );
+   class ListJob : public Job {};
+   ListJob* listRecursive( KURL, bool, bool );
+   ListJob* listDir( KURL, bool, bool );
+   class StatJob : public Job {
+      public: UDSEntry statResult(){ return (UDSEntry)0; }
+   };
+   StatJob* stat( KURL, bool, int, bool );
+   class TransferJob : public Job {};
+   TransferJob* get( KURL, bool, bool );
+   TransferJob* put( KURL, int, bool, bool, bool );
+};
+
+typedef QProgressBar KProgress;
+
+class KInstance : public QObject
+{
+public:
+   KInstance(KAboutData*){}
+};
+
+namespace KParts
+{
+   class MainWindow : public KMainWindow
+   {
+   public:
+      MainWindow( QWidget* parent, const char* name ) : KMainWindow(parent,name) {}
+      void setXMLFile(const QString&){}
+      void setAutoSaveSettings(){}
+      void saveMainWindowSettings(KConfig*){}
+      void applyMainWindowSettings(KConfig*){}
+      int factory(){return 0;}
+   };
+
+   class Part : public QObject
+   {
+   public:
+      KActionCollection* actionCollection();
+      KApplication* instance();
+      void setWidget( QWidget* w ){ m_pWidget=w; }
+      QWidget* widget(){return m_pWidget;}
+      void setXMLFile(const QString&){}
+   private:
+      QWidget* m_pWidget;
+   };
+
+   class ReadOnlyPart : public Part
+   {
+   public:
+   ReadOnlyPart(){}
+   ReadOnlyPart(QObject*,const QCString&){}
+   void setInstance( KInstance* ){}
+   QString m_file;
+   };
+
+   class ReadWritePart : public ReadOnlyPart
+   {
+   public:
+   ReadWritePart(QObject*,const QCString&){}
+   void setReadWrite(bool){}
+   };
+
+   class Factory : public KLibFactory
+   {
+      Q_OBJECT
+   public:
+   virtual KParts::Part* createPartObject( QWidget *parentWidget, const char *widgetName,
+                                            QObject *parent, const char *name,
+                                            const char *classname, const QStringList &args )=0;
+   };
+};
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kstandarddirs.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kstatusbar.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kstdaction.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/ktempfile.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kunload.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kurl.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kurldrag.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
Binary file kdiff3/src/lo16-app-kdiff3.png has changed
Binary file kdiff3/src/lo32-app-kdiff3.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/main.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,231 @@
+/***************************************************************************
+                          main.cpp  -  Where everything starts.
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include "kdiff3_shell.h"
+#include <kstandarddirs.h>
+#include "version.h"
+#include <qtextcodec.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <vector>
+
+#ifdef KREPLACEMENTS_H
+#include "optiondialog.h"
+#endif
+#include "common.h"
+
+static const char *description =
+   I18N_NOOP("Tool for Comparison and Merge of Files and Directories");
+
+static KCmdLineOptions options[] =
+{
+  { "m", 0, 0 },
+  { "merge", I18N_NOOP("Merge the input."), 0 },
+  { "b", 0, 0 },
+  { "base file", I18N_NOOP("Explicit base file. For compatibility with certain tools."), 0 },
+  { "o", 0, 0 },
+  { "output file", I18N_NOOP("Output file. Implies -m. E.g.: -o newfile.txt"), 0 },
+  { "out file",    I18N_NOOP("Output file, again. (For compatibility with certain tools.)"), 0 },
+  { "auto",        I18N_NOOP("No GUI if all conflicts are auto-solvable. (Needs -o file)"), 0 },
+  { "qall",        I18N_NOOP("Don't solve conflicts automatically. (For compatibility...)"), 0 },
+  { "L1 alias1",   I18N_NOOP("Visible name replacement for input file 1 (base)."), 0 },
+  { "L2 alias2",   I18N_NOOP("Visible name replacement for input file 2."), 0 },
+  { "L3 alias3",   I18N_NOOP("Visible name replacement for input file 3."), 0 },
+  { "L", 0, 0 },
+  { "fname alias", I18N_NOOP("Alternative visible name replacement. Supply this once for every input."), 0 },
+  { "cs string",   I18N_NOOP("Override a config setting. Use once for every setting. E.g.: --cs \"AutoAdvance=1\""), 0 },
+  { "confighelp",  I18N_NOOP("Show list of config settings and current values."), 0 },
+  { "config file", I18N_NOOP("Use a different config file."), 0 }
+};
+static KCmdLineOptions options2[] =
+{
+  { "+[File1]", I18N_NOOP("file1 to open (base, if not specified via --base)"), 0 },
+  { "+[File2]", I18N_NOOP("file2 to open"), 0 },
+  { "+[File3]", I18N_NOOP("file3 to open"), 0 }
+};
+
+
+void initialiseCmdLineArgs(std::vector<KCmdLineOptions>& vOptions, QStringList& ignorableOptions)
+{
+   vOptions.insert( vOptions.end(), options, (KCmdLineOptions*)((char*)options+sizeof(options)));
+   QString configFileName = KStandardDirs().findResource("config","kdiff3rc");
+   QFile configFile( configFileName );
+   if ( configFile.open( IO_ReadOnly ) )
+   {
+      QTextStream ts( &configFile );
+      while(!ts.atEnd())
+      {
+         QString line = ts.readLine();
+         if ( line.startsWith("IgnorableCmdLineOptions=") )
+         {
+            int pos = line.find('=');
+            if (pos>=0)
+            {
+               QString s = line.mid(pos+1);
+               QStringList sl = QStringList::split( '|', s );
+               if (!sl.isEmpty())
+               {
+                  ignorableOptions = QStringList::split( ';', sl.front() );
+                  for (QStringList::iterator i=ignorableOptions.begin(); i!=ignorableOptions.end(); ++i)
+                  {
+                     KCmdLineOptions ignoreOption;
+                     (*i).remove('-');
+                     if (!(*i).isEmpty())
+                     {
+                        ignoreOption.name = (*i).latin1();
+                        ignoreOption.description = I18N_NOOP("Ignored. (User defined.)");
+                        ignoreOption.def = 0;
+                        vOptions.push_back(ignoreOption);
+                     }
+                  }
+               }
+            }
+            break;
+         }
+      }
+   }
+   vOptions.insert(vOptions.end(),options2,(KCmdLineOptions*)((char*)options2+sizeof(options2)));
+
+   KCmdLineOptions last = KCmdLineLastOption;
+   vOptions.push_back(last);
+   KCmdLineArgs::addCmdLineOptions( &vOptions[0] ); // Add our own options.
+}
+
+
+#ifdef _WIN32
+#include <process.h>
+// This command checks the comm
+static bool isOptionUsed(const QString& s, int argc, char* argv[])
+{
+   for(int j=0; j<argc; ++j )
+   {
+      if( "-"+s == argv[j] || "--"+s==argv[j] )
+      {
+         return true;
+      }
+   }
+   return false;
+}
+#endif
+
+
+
+int main(int argc, char *argv[])
+{
+#ifdef _WIN32
+   /* KDiff3 can be used as replacement for the text-diff and merge tool provided by
+      Clearcase. This is experimental and so far has only been tested under Windows.
+
+      There are two ways to use KDiff3 with clearcase
+      -  The file lib/mgrs/map contains the list of compare/merge tasks on one side and 
+         the tool on the other. Originally this contains only clearcase tools, but you can
+         edit this file and put kdiff3 there instead. (Recommended method)
+      -  Exchange the original program with KDiff3: (Hackish, no fine control)
+         1. In the Clearcase "bin"-directory rename "cleardiffmrg.exe" to "cleardiffmrg_orig.exe".
+         2. Copy kdiff3.exe into that "bin"-directory and rename it to "cleardiffmrg.exe".
+            (Also copy the other files that are needed by KDiff3 there.)
+         Now when a file comparison or merge is done by Clearcase then of course KDiff3 will be
+         run instead.
+         If the commandline contains the option "-directory" then KDiff3 can't do it but will
+         run "cleardiffmrg_orig.exe" instead.
+   */
+
+   // Write all args into a temporary file. Uncomment this for debugging purposes.
+   /*
+   FILE* f = fopen("c:\\t.txt","w");
+   for(int i=0; i< argc; ++i)
+      fprintf(f,"Arg %d: %s\n", i, argv[i]);
+
+   // Call orig cleardiffmrg.exe to see what result it returns.
+   int result=0;
+   result = ::_spawnvp(_P_WAIT , "C:\\Programme\\Rational\\ClearCase\\bin\\cleardiffmrg.exe", argv );
+   fprintf(f,"Result: %d\n", result );
+   fclose(f);
+   return result;
+   */
+
+   // KDiff3 can replace cleardiffmrg from clearcase. But not all functions.
+   if ( isOptionUsed( "directory", argc,argv ) )
+   {
+      return ::_spawnvp(_P_WAIT , "cleardiffmrg_orig", argv );      
+   }
+
+#endif
+   //QApplication::setColorSpec( QApplication::ManyColor ); // Grab all 216 colors
+
+   KAboutData aboutData( "kdiff3", I18N_NOOP("KDiff3"),
+      VERSION, description, KAboutData::License_GPL,
+      "(c) 2002-2006 Joachim Eibl", 0, "http://kdiff3.sourceforge.net/", "joachim.eibl" "@" "gmx.de");
+   aboutData.addAuthor("Joachim Eibl",0, "joachim.eibl" "@" "gmx.de");
+   aboutData.addCredit("Eike Sauer", "Bugfixes, Debian package maintainer" );
+   aboutData.addCredit("Sebastien Fricker", "Windows installer" );
+   aboutData.addCredit("Stephan Binner", "i18n-help", "binner" "@" "kde.org" );
+   aboutData.addCredit("Stefan Partheymueller", "Clipboard-patch" );
+   aboutData.addCredit("David Faure", "KIO-Help", "faure" "@" "kde.org" );
+   aboutData.addCredit("Bernd Gehrmann", "Class CvsIgnoreList from Cervisia" );
+   aboutData.addCredit("Andre Woebbeking", "Class StringMatcher" );
+   aboutData.addCredit("Michael Denio", "Directory Equality-Coloring patch");
+   aboutData.addCredit("Paul Eggert, Mike Haertel, David Hayes, Richard Stallman, Len Tower", "GNU-Diffutils");
+   aboutData.addCredit(I18N_NOOP("+ Many thanks to those who reported bugs and contributed ideas!"));
+
+   KCmdLineArgs::init( argc, argv, &aboutData );
+   std::vector<KCmdLineOptions> vOptions;
+   QStringList ignorableOptions;
+   initialiseCmdLineArgs(vOptions, ignorableOptions);
+
+   KApplication app;
+
+#ifdef KREPLACEMENTS_H
+   QString locale;
+
+   locale = app.config()->readEntry("Language", "Auto");
+   int spacePos = locale.find(' ');
+   if (spacePos>0) locale = locale.left(spacePos);
+   QTranslator kdiff3Translator( 0 );
+   QTranslator qtTranslator( 0 );
+   if (locale != "en_orig")
+   {
+      if ( locale == "Auto" || locale.isEmpty() )
+         locale = QTextCodec::locale();
+         
+      QString translationDir = getTranslationDir();
+      kdiff3Translator.load( QString("kdiff3_")+locale, translationDir );
+      app.installTranslator( &kdiff3Translator );
+      
+      qtTranslator.load( QString("qt_")+locale, translationDir );
+      app.installTranslator( &qtTranslator );
+   }
+#endif
+
+  if (app.isRestored())
+  {
+     RESTORE(KDiff3Shell);
+  }
+  else
+  {
+     new KDiff3Shell();
+  }
+
+  int retVal = app.exec();
+  return retVal;
+}
+
+// Suppress warning with --enable-final
+#undef VERSION
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/merger.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,87 @@
+/***************************************************************************
+                          merger.cpp  -  description
+                             -------------------
+    begin                : Sun Mar 24 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "merger.h"
+#include <assert.h>
+#include <iostream>
+#include <iomanip>
+
+Merger::Merger( const DiffList* pDiffListAB, const DiffList* pDiffListCA )
+: md1( pDiffListAB, 0 ), md2( pDiffListCA, 1 )
+{
+}
+
+
+Merger::MergeData::MergeData( const DiffList* p, int i )
+: d(0,0,0)
+{
+   idx=i;
+   pDiffList = p;
+   if ( p!=0 )
+   {
+      it=p->begin();
+      update();
+   }
+}
+
+bool Merger::MergeData::eq()
+{
+   return pDiffList==0 || d.nofEquals > 0;
+}
+
+bool Merger::MergeData::isEnd()
+{
+   return ( pDiffList==0 || ( it==pDiffList->end() && d.nofEquals==0 && 
+      ( idx == 0 ? d.diff1==0 : d.diff2==0 )
+      ) );  
+}
+
+void Merger::MergeData::update()
+{
+   if ( d.nofEquals > 0 )
+      --d.nofEquals;
+   else if ( idx==0 && d.diff1 > 0 )
+      --d.diff1;
+   else if ( idx==1 && d.diff2 > 0 )
+      --d.diff2; 
+
+   while( d.nofEquals == 0  && (idx==0 && d.diff1 == 0 || idx==1 && d.diff2 == 0) 
+       && pDiffList!=0  &&  it != pDiffList->end() )
+   {
+      d = *it;
+      ++it;
+   }
+}
+
+void Merger::next()
+{
+   md1.update();
+   md2.update();
+}
+
+int Merger::whatChanged()
+{
+   int changed = 0;
+   changed |= md1.eq()  ?  0 : 1;
+   changed |= md2.eq()  ?  0 : 2;
+   return changed;
+}
+
+bool Merger::isEndReached()
+{
+   return md1.isEnd() && md2.isEnd();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/merger.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,61 @@
+/***************************************************************************
+                          merger.h  -  description
+                             -------------------
+    begin                : Sun Mar 24 2002
+    copyright            : (C) 2002-2004 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef MERGER_H
+#define MERGER_H
+
+#include "diff.h"
+
+
+class Merger
+{
+public:
+
+   Merger( const DiffList* pDiffList1, const DiffList* pDiffList2 );
+
+   /** Go one step. */
+   void next();
+
+   /** Information about what changed. Can be used for coloring.
+       The return value is 0 if nothing changed here,
+       bit 1 is set if a difference from pDiffList1 was detected,
+       bit 2 is set if a difference from pDiffList2 was detected.
+   */
+   int whatChanged();
+
+   /** End of both diff lists reached. */
+   bool isEndReached();
+private:
+
+   struct MergeData
+   {
+      DiffList::const_iterator it;
+      const DiffList* pDiffList;
+      Diff d;
+      int idx;
+    
+      MergeData( const DiffList* p, int i );
+      bool eq();
+      void update();
+      bool isEnd();
+   };
+
+   MergeData md1;
+   MergeData md2;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/mergeresultwindow.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,3181 @@
+/***************************************************************************
+                          mergeresultwindow.cpp  -  description
+                             -------------------
+    begin                : Sun Apr 14 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "mergeresultwindow.h"
+#include "optiondialog.h"
+
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qcursor.h>
+#include <qpopupmenu.h>
+#include <qstatusbar.h>
+#include <qregexp.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qlayout.h>
+#include <qtextcodec.h>
+#include <qdragobject.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <iostream>
+
+int g_bAutoSolve = true;
+
+#undef leftInfoWidth
+#define leftInfoWidth 3
+
+MergeResultWindow::MergeResultWindow(
+   QWidget* pParent,
+   OptionDialog* pOptionDialog,
+   QStatusBar* pStatusBar
+   )
+: QWidget( pParent, 0, WRepaintNoErase )
+{
+   setFocusPolicy( QWidget::ClickFocus );
+
+   m_firstLine = 0;
+   m_firstColumn = 0;
+   m_nofColumns = 0;
+   m_nofLines = 0;
+   m_totalSize = 0;
+   m_bMyUpdate = false;
+   m_bInsertMode = true;
+   m_scrollDeltaX = 0;
+   m_scrollDeltaY = 0;
+   m_bModified = false;
+   m_eOverviewMode=Overview::eOMNormal;
+
+   m_pldA = 0;
+   m_pldB = 0;
+   m_pldC = 0;
+   m_sizeA = 0;
+   m_sizeB = 0;
+   m_sizeC = 0;
+
+   m_pDiff3LineList = 0;
+   m_pTotalDiffStatus = 0;
+   m_pStatusBar = pStatusBar;
+
+   m_pOptionDialog = pOptionDialog;
+   m_bPaintingAllowed = false;
+   m_delayedDrawTimer = 0;
+
+   m_cursorXPos=0;
+   m_cursorOldXPos=0;
+   m_cursorYPos=0;
+   m_bCursorOn = true;
+   m_bCursorUpdate = false;
+   connect( &m_cursorTimer, SIGNAL(timeout()), this, SLOT( slotCursorUpdate() ) );
+   m_cursorTimer.start( 500 /*ms*/, true /*single shot*/ );
+   m_selection.reset();
+
+   setMinimumSize( QSize(20,20) );
+   setFont( m_pOptionDialog->m_font );
+}
+
+void MergeResultWindow::init(
+   const LineData* pLineDataA, int sizeA,
+   const LineData* pLineDataB, int sizeB,
+   const LineData* pLineDataC, int sizeC,
+   const Diff3LineList* pDiff3LineList,
+   TotalDiffStatus* pTotalDiffStatus
+   )
+{
+   m_firstLine = 0;
+   m_firstColumn = 0;
+   m_nofColumns = 0;
+   m_nofLines = 0;
+   m_bMyUpdate = false;
+   m_bInsertMode = true;
+   m_scrollDeltaX = 0;
+   m_scrollDeltaY = 0;
+   setModified( false );
+   
+   m_pldA = pLineDataA;
+   m_pldB = pLineDataB;
+   m_pldC = pLineDataC;
+   m_sizeA = sizeA;
+   m_sizeB = sizeB;
+   m_sizeC = sizeC;
+
+   m_pDiff3LineList = pDiff3LineList;
+   m_pTotalDiffStatus = pTotalDiffStatus;
+   
+   m_selection.reset();
+   m_cursorXPos=0;
+   m_cursorOldXPos=0;
+   m_cursorYPos=0;
+
+   merge( g_bAutoSolve, -1 );
+   g_bAutoSolve = true;
+   update();
+   updateSourceMask();
+
+   int wsc;
+   int nofUnsolved = getNrOfUnsolvedConflicts(&wsc);
+   if (m_pStatusBar)
+      m_pStatusBar->message( i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)")
+         .arg(nofUnsolved).arg(wsc) );
+}
+
+void MergeResultWindow::reset()
+{
+   m_pDiff3LineList = 0;
+   m_pTotalDiffStatus = 0;
+   m_pldA = 0;
+   m_pldB = 0;
+   m_pldC = 0;
+}
+
+// Calculate the merge information for the given Diff3Line.
+// Results will be stored in mergeDetails, bConflict, bLineRemoved and src.
+void mergeOneLine(
+   const Diff3Line& d, e_MergeDetails& mergeDetails, bool& bConflict,
+   bool& bLineRemoved, int& src, bool bTwoInputs
+   )
+{
+   mergeDetails = eDefault;
+   bConflict = false;
+   bLineRemoved = false;
+   src = 0;
+
+   if ( bTwoInputs )   // Only two input files
+   {
+      if ( d.lineA!=-1 && d.lineB!=-1 )
+      {
+         if ( d.pFineAB == 0 )
+         {
+            mergeDetails = eNoChange;           src = A;
+         }
+         else
+         {
+            mergeDetails = eBChanged;           bConflict = true;
+         }
+      }
+      else
+      {
+         if ( d.lineA!=-1 && d.lineB==-1 )
+         {
+            mergeDetails = eBDeleted;   bConflict = true;
+         }
+         else if ( d.lineA==-1 && d.lineB!=-1 )
+         {
+            mergeDetails = eBDeleted;   bConflict = true;
+         }
+      }
+      return;
+   }
+
+   // A is base.
+   if ( d.lineA!=-1 && d.lineB!=-1 && d.lineC!=-1 )
+   {
+      if ( d.pFineAB == 0  &&  d.pFineBC == 0 &&  d.pFineCA == 0)
+      {
+         mergeDetails = eNoChange;           src = A;
+      }
+      else if( d.pFineAB == 0  &&  d.pFineBC != 0  &&  d.pFineCA != 0 )
+      {
+         mergeDetails = eCChanged;           src = C;
+      }
+      else if( d.pFineAB != 0  &&  d.pFineBC != 0  &&  d.pFineCA == 0 )
+      {
+         mergeDetails = eBChanged;           src = B;
+      }
+      else if( d.pFineAB != 0  &&  d.pFineBC == 0  &&  d.pFineCA != 0 )
+      {
+         mergeDetails = eBCChangedAndEqual;  src = C;
+      }
+      else if( d.pFineAB != 0  &&  d.pFineBC != 0  &&  d.pFineCA != 0 )
+      {
+         mergeDetails = eBCChanged;           bConflict = true;
+      }
+      else
+         assert(false);
+   }
+   else if ( d.lineA!=-1 && d.lineB!=-1 && d.lineC==-1 )
+   {
+      if( d.pFineAB != 0 )
+      {
+         mergeDetails = eBChanged_CDeleted;   bConflict = true;
+      }
+      else
+      {
+         mergeDetails = eCDeleted;            bLineRemoved = true;        src = C;
+      }
+   }
+   else if ( d.lineA!=-1 && d.lineB==-1 && d.lineC!=-1 )
+   {
+      if( d.pFineCA != 0 )
+      {
+         mergeDetails = eCChanged_BDeleted;   bConflict = true;
+      }
+      else
+      {
+         mergeDetails = eBDeleted;            bLineRemoved = true;        src = B;
+      }
+   }
+   else if ( d.lineA==-1 && d.lineB!=-1 && d.lineC!=-1 )
+   {
+      if( d.pFineBC != 0 )
+      {
+         mergeDetails = eBCAdded;             bConflict = true;
+      }
+      else // B==C
+      {
+         mergeDetails = eBCAddedAndEqual;     src = C;
+      }
+   }
+   else if ( d.lineA==-1 && d.lineB==-1 && d.lineC!= -1 )
+   {
+      mergeDetails = eCAdded;                 src = C;
+   }
+   else if ( d.lineA==-1 && d.lineB!=-1 && d.lineC== -1 )
+   {
+      mergeDetails = eBAdded;                 src = B;
+   }
+   else if ( d.lineA!=-1 && d.lineB==-1 && d.lineC==-1 )
+   {
+      mergeDetails = eBCDeleted;              bLineRemoved = true;     src = C;
+   }
+   else
+      assert(false);
+}
+
+bool MergeResultWindow::sameKindCheck( const MergeLine& ml1, const MergeLine& ml2 )
+{
+   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
+      return (
+         !ml1.bConflict && !ml2.bConflict && ml1.bDelta && ml2.bDelta && ml1.srcSelect == ml2.srcSelect ||
+         !ml1.bDelta && !ml2.bDelta
+         );
+}
+
+void MergeResultWindow::merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly, bool bWhiteSpaceOnly )
+{
+   if ( !bConflictsOnly )
+   {
+      if(m_bModified)
+      {
+         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;
+      }
+
+      m_mergeLineList.clear();
+      m_totalSize = 0;
+      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 );
+
+         // 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;
+               }
+            }
+            ml.mergeEditLineList.setTotalSizePtr(&m_totalSize);
+            m_mergeLineList.push_back( ml );
+         }
+
+         if ( ! ml.bConflict )
+         {
+            MergeLine& tmpBack = m_mergeLineList.back();
+            MergeEditLine mel(ml.id3l);
+            mel.setSource( ml.srcSelect, bLineRemoved );
+            tmpBack.mergeEditLineList.push_back(mel);
+         }
+         else if ( back==0  || ! back->bConflict || !bSame )
+         {
+            MergeLine& tmpBack = m_mergeLineList.back();
+            MergeEditLine mel(ml.id3l);
+            mel.setConflict();
+            tmpBack.mergeEditLineList.push_back(mel);
+         }
+      }
+   }
+
+   if ( !bAutoSolve )
+   {
+      // Change all auto selections
+      MergeLineList::iterator mlIt;
+      for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt )
+      {
+         MergeLine& ml = *mlIt;
+         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 )
+            {
+               MergeEditLine mel(ml.id3l);;
+               mel.setConflict();
+               ml.bConflict = true;
+               ml.mergeEditLineList.push_back(mel);
+            }
+            else
+            {
+               Diff3LineList::const_iterator d3llit=ml.id3l;
+               int j;
+
+               for( j=0; j<ml.srcRangeLength; ++j )
+               {
+                  MergeEditLine mel(d3llit);
+                  mel.setSource( defaultSelector, false );
+
+                  int srcLine = defaultSelector==1 ? d3llit->lineA :
+                                defaultSelector==2 ? d3llit->lineB :
+                                defaultSelector==3 ? d3llit->lineC : -1;
+
+                  if ( srcLine != -1 )
+                  {
+                     ml.mergeEditLineList.push_back(mel);
+                  }
+
+                  ++d3llit;
+               }
+
+               if ( ml.mergeEditLineList.empty() ) // Make a line nevertheless
+               {
+                  MergeEditLine mel(ml.id3l);
+                  mel.setRemoved( defaultSelector );
+                  ml.mergeEditLineList.push_back(mel);
+               }
+            }
+         }
+      }
+   }
+
+   MergeLineList::iterator mlIt;
+   for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt )
+   {
+      MergeLine& ml = *mlIt;
+      // Remove all lines that are empty, because no src lines are there.
+
+      int oldSrcLine = -1;
+      int oldSrc = -1;
+      MergeEditLineList::iterator melIt;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); )
+      {
+         MergeEditLine& mel = *melIt;
+         int melsrc = mel.src();
+
+         int srcLine = mel.isRemoved() ? -1 :
+                       melsrc==1 ? mel.id3l()->lineA :
+                       melsrc==2 ? mel.id3l()->lineB :
+                       melsrc==3 ? mel.id3l()->lineC : -1;
+
+         // At least one line remains because oldSrc != melsrc for first line in list
+         // Other empty lines will be removed
+         if ( srcLine == -1 && oldSrcLine==-1 && oldSrc == melsrc )
+            melIt = ml.mergeEditLineList.erase( melIt );
+         else
+            ++melIt;
+
+         oldSrcLine = srcLine;
+         oldSrc = melsrc;
+      }
+   }
+
+   if ( bAutoSolve && !bConflictsOnly )
+   {
+      if ( m_pOptionDialog->m_bRunHistoryAutoMergeOnMergeStart )
+         slotMergeHistory();
+      if ( m_pOptionDialog->m_bRunRegExpAutoMergeOnMergeStart )
+         slotRegExpAutoMerge();
+      if ( m_pldC != 0 && ! doRelevantChangesExist() )
+         emit noRelevantChangesDetected();
+   }
+
+   int nrOfSolvedConflicts = 0;
+   int nrOfUnsolvedConflicts = 0;
+   int nrOfWhiteSpaceConflicts = 0;
+
+   MergeLineList::iterator i;
+   for ( i = m_mergeLineList.begin();  i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->bConflict )
+         ++nrOfUnsolvedConflicts;
+      else if ( i->bDelta )
+         ++nrOfSolvedConflicts;
+
+      if ( i->bWhiteSpaceConflict )
+         ++nrOfWhiteSpaceConflicts;
+   }
+
+   m_pTotalDiffStatus->nofUnsolvedConflicts = nrOfUnsolvedConflicts;
+   m_pTotalDiffStatus->nofSolvedConflicts = nrOfSolvedConflicts;
+   m_pTotalDiffStatus->nofWhitespaceConflicts = nrOfWhiteSpaceConflicts;
+
+
+   m_cursorXPos=0;
+   m_cursorOldXPos=0;
+   m_cursorYPos=0;
+   //m_firstLine = 0; // Must not set line/column without scrolling there
+   //m_firstColumn = 0;
+
+   setModified(false);
+
+   m_currentMergeLineIt = m_mergeLineList.begin();
+   slotGoTop();
+
+   updateAvailabilities();
+   update();
+}
+
+void MergeResultWindow::setFirstLine(int firstLine)
+{
+   m_firstLine = max2(0,firstLine);
+   update();
+}
+
+void MergeResultWindow::setFirstColumn(int firstCol)
+{
+   m_firstColumn = max2(0,firstCol);
+   update();
+}
+
+int MergeResultWindow::getNofColumns()
+{
+   return m_nofColumns;
+}
+
+int MergeResultWindow::getNofLines()
+{
+   return m_totalSize;
+}
+
+int MergeResultWindow::getNofVisibleColumns()
+{
+   QFontMetrics fm = fontMetrics();
+   return width()/fm.width('W')-4;
+}
+
+int MergeResultWindow::getNofVisibleLines()
+{
+   QFontMetrics fm = fontMetrics();
+   return (height()-3)/fm.height()-2;
+}
+
+void MergeResultWindow::resizeEvent( QResizeEvent* e )
+{
+   QWidget::resizeEvent(e);
+   emit resizeSignal();
+}
+
+Overview::e_OverviewMode MergeResultWindow::getOverviewMode()
+{
+   return m_eOverviewMode;
+}
+
+void MergeResultWindow::setOverviewMode( Overview::e_OverviewMode eOverviewMode )
+{
+   m_eOverviewMode = eOverviewMode;
+}
+
+// Check whether we should ignore current delta when moving to next/previous delta
+bool MergeResultWindow::checkOverviewIgnore(MergeLineList::iterator &i)
+{
+   if (m_eOverviewMode == Overview::eOMNormal) return false;
+   if (m_eOverviewMode == Overview::eOMAvsB)
+      return i->mergeDetails == eCAdded || i->mergeDetails == eCDeleted || i->mergeDetails == eCChanged;
+   if (m_eOverviewMode == Overview::eOMAvsC)
+      return i->mergeDetails == eBAdded || i->mergeDetails == eBDeleted || i->mergeDetails == eBChanged;
+   if (m_eOverviewMode == Overview::eOMBvsC)
+      return i->mergeDetails == eBCAddedAndEqual || i->mergeDetails == eBCDeleted || i->mergeDetails == eBCChangedAndEqual;
+   return false;
+}
+
+// Go to prev/next delta/conflict or first/last delta.
+void MergeResultWindow::go( e_Direction eDir, e_EndPoint eEndPoint )
+{
+   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!=m_mergeLineList.end() && ! i->bDelta )
+      {
+         if ( eDir==eUp )  ++i;                       // search downwards
+         else              --i;                       // search upwards
+      }
+   }
+   else if ( eEndPoint == eDelta  &&  i!=m_mergeLineList.end())
+   {
+      do
+      {
+         if ( eDir==eUp )  --i;
+         else              ++i;
+      }
+      while ( i!=m_mergeLineList.end() && ( i->bDelta == false || checkOverviewIgnore(i) || bSkipWhiteConflicts && i->bWhiteSpaceConflict ) );
+   }
+   else if ( eEndPoint == eConflict  &&  i!=m_mergeLineList.end() )
+   {
+      do
+      {
+         if ( eDir==eUp )  --i;
+         else              ++i;
+      }
+      while ( i!=m_mergeLineList.end() && (i->bConflict == false || bSkipWhiteConflicts && i->bWhiteSpaceConflict ) );
+   }
+   else if ( i!=m_mergeLineList.end()  &&  eEndPoint == eUnsolvedConflict )
+   {
+      do
+      {
+         if ( eDir==eUp )  --i;
+         else              ++i;
+      }
+      while ( i!=m_mergeLineList.end() && ! i->mergeEditLineList.begin()->isConflict() );
+   }
+
+   if ( isVisible() )
+      setFocus();
+
+   setFastSelector( i );
+}
+
+bool MergeResultWindow::isDeltaAboveCurrent()
+{
+   bool bSkipWhiteConflicts = ! m_pOptionDialog->m_bShowWhiteSpace;
+   if (m_mergeLineList.empty()) return false;
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (i == m_mergeLineList.begin()) return false;
+   do
+   {
+      --i;
+      if ( i->bDelta && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true;
+   }
+   while (i!=m_mergeLineList.begin());
+
+   return false;
+}
+
+bool MergeResultWindow::isDeltaBelowCurrent()
+{
+   bool bSkipWhiteConflicts = ! m_pOptionDialog->m_bShowWhiteSpace;
+   if (m_mergeLineList.empty()) return false;
+
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (i!=m_mergeLineList.end())
+   {
+      ++i;
+      for( ; i!=m_mergeLineList.end(); ++i )
+      {
+         if ( i->bDelta && !( bSkipWhiteConflicts && i->bWhiteSpaceConflict ) ) return true;
+      }
+   }
+   return false;
+}
+
+bool MergeResultWindow::isConflictAboveCurrent()
+{
+   if (m_mergeLineList.empty()) return false;
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (i == m_mergeLineList.begin()) return false;
+
+   do
+   {
+      --i;
+      if ( i->bConflict ) return true;
+   } 
+   while (i!=m_mergeLineList.begin());
+   
+   return false;
+}
+
+bool MergeResultWindow::isConflictBelowCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (m_mergeLineList.empty()) return false;
+   
+   if (i!=m_mergeLineList.end())
+   {
+      ++i;
+      for( ; i!=m_mergeLineList.end(); ++i )
+      {
+         if ( i->bConflict ) return true;
+      }
+   }
+   return false;
+}
+
+bool MergeResultWindow::isUnsolvedConflictAboveCurrent()
+{
+   if (m_mergeLineList.empty()) return false;
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (i == m_mergeLineList.begin()) return false;
+   
+   do
+   {
+      --i;
+      if ( i->mergeEditLineList.begin()->isConflict() ) return true;
+   } 
+   while (i!=m_mergeLineList.begin());
+   
+   return false;
+}
+
+bool MergeResultWindow::isUnsolvedConflictBelowCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   if (m_mergeLineList.empty()) return false;
+   
+   if (i!=m_mergeLineList.end())
+   {
+      ++i;
+      for( ; i!=m_mergeLineList.end(); ++i )
+      {
+         if ( i->mergeEditLineList.begin()->isConflict() ) return true;
+      }
+   }
+   return false;
+}
+
+void MergeResultWindow::slotGoTop()
+{
+   go( eUp, eEnd );
+}
+
+void MergeResultWindow::slotGoCurrent()
+{
+   setFastSelector( m_currentMergeLineIt );
+}
+
+void MergeResultWindow::slotGoBottom()
+{
+   go( eDown, eEnd );
+}
+
+void MergeResultWindow::slotGoPrevDelta()
+{
+   go( eUp, eDelta );
+}
+
+void MergeResultWindow::slotGoNextDelta()
+{
+   go( eDown, eDelta );
+}
+
+void MergeResultWindow::slotGoPrevConflict()
+{
+   go( eUp, eConflict );
+}
+
+void MergeResultWindow::slotGoNextConflict()
+{
+   go( eDown, eConflict );
+}
+
+void MergeResultWindow::slotGoPrevUnsolvedConflict()
+{
+   go( eUp, eUnsolvedConflict );
+}
+
+void MergeResultWindow::slotGoNextUnsolvedConflict()
+{
+   go( eDown, eUnsolvedConflict );
+}
+
+/** The line is given as a index in the Diff3LineList.
+    The function calculates the corresponding iterator. */
+void MergeResultWindow::slotSetFastSelectorLine( int line )
+{
+   MergeLineList::iterator i;
+   for ( i = m_mergeLineList.begin();  i!=m_mergeLineList.end(); ++i )
+   {
+      if ( line>=i->d3lLineIdx  && line < i->d3lLineIdx + i->srcRangeLength )
+      {
+         //if ( i->bDelta )
+         {
+            setFastSelector( i );
+         }
+         break;
+      }
+   }
+}
+
+int MergeResultWindow::getNrOfUnsolvedConflicts( int* pNrOfWhiteSpaceConflicts )
+{
+   int nrOfUnsolvedConflicts = 0;
+   if (pNrOfWhiteSpaceConflicts!=0)
+      *pNrOfWhiteSpaceConflicts = 0;
+
+   MergeLineList::iterator mlIt = m_mergeLineList.begin();
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      MergeEditLineList::iterator melIt = ml.mergeEditLineList.begin();
+      if ( melIt->isConflict() )
+      {
+         ++nrOfUnsolvedConflicts;
+         if ( ml.bWhiteSpaceConflict &&  pNrOfWhiteSpaceConflicts!=0 )
+            ++ *pNrOfWhiteSpaceConflicts;
+      }
+   }
+
+   return nrOfUnsolvedConflicts;
+}
+
+void MergeResultWindow::showNrOfConflicts()
+{
+   int nrOfConflicts = 0;
+   MergeLineList::iterator i;
+   for ( i = m_mergeLineList.begin();  i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->bConflict || i->bDelta )
+         ++nrOfConflicts;
+   }
+   QString totalInfo;
+   if ( m_pTotalDiffStatus->bBinaryAEqB && m_pTotalDiffStatus->bBinaryAEqC )
+      totalInfo += i18n("All input files are binary equal.");
+   else  if ( m_pTotalDiffStatus->bTextAEqB && m_pTotalDiffStatus->bTextAEqC )
+      totalInfo += i18n("All input files contain the same text.");
+   else {
+      if    ( m_pTotalDiffStatus->bBinaryAEqB ) totalInfo += i18n("Files A and B are binary equal.\n");
+      else if ( m_pTotalDiffStatus->bTextAEqB ) totalInfo += i18n("Files A and B have equal text. \n");
+      if    ( m_pTotalDiffStatus->bBinaryAEqC ) totalInfo += i18n("Files A and C are binary equal.\n");
+      else if ( m_pTotalDiffStatus->bTextAEqC ) totalInfo += i18n("Files A and C have equal text. \n");
+      if    ( m_pTotalDiffStatus->bBinaryBEqC ) totalInfo += i18n("Files B and C are binary equal.\n");
+      else if ( m_pTotalDiffStatus->bTextBEqC ) totalInfo += i18n("Files B and C have equal text. \n");
+   }
+
+   int nrOfUnsolvedConflicts = getNrOfUnsolvedConflicts();
+
+   KMessageBox::information( this,
+      i18n("Total number of conflicts: ") + QString::number(nrOfConflicts) +
+      i18n("\nNr of automatically solved conflicts: ") + QString::number(nrOfConflicts-nrOfUnsolvedConflicts) +
+      i18n("\nNr of unsolved conflicts: ") + QString::number(nrOfUnsolvedConflicts) +
+      "\n"+totalInfo,
+      i18n("Conflicts")
+      );
+}
+
+void MergeResultWindow::setFastSelector(MergeLineList::iterator i)
+{
+   if ( i==m_mergeLineList.end() )
+      return;
+   m_currentMergeLineIt = i;
+   emit setFastSelectorRange( i->d3lLineIdx, i->srcRangeLength );
+
+   int line1 = 0;
+
+   MergeLineList::iterator mlIt = m_mergeLineList.begin();
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      if(mlIt==m_currentMergeLineIt)
+         break;
+      line1 += mlIt->mergeEditLineList.size();
+   }
+
+   int nofLines = m_currentMergeLineIt->mergeEditLineList.size();
+   int newFirstLine = getBestFirstLine( line1, nofLines, m_firstLine, getNofVisibleLines() );
+   if ( newFirstLine != m_firstLine )
+   {
+      scroll( 0, newFirstLine - m_firstLine );
+   }
+
+   if ( m_selection.isEmpty() )
+   {
+      m_cursorXPos = 0;
+      m_cursorOldXPos = 0;
+      m_cursorYPos = line1;
+   }
+
+   update();
+   updateSourceMask();
+   emit updateAvailabilities();
+}
+
+void MergeResultWindow::choose( int selector )
+{
+   if ( m_currentMergeLineIt==m_mergeLineList.end() )
+      return;
+
+   setModified();
+
+   // First find range for which this change works.
+   MergeLine& ml = *m_currentMergeLineIt;
+
+   MergeEditLineList::iterator melIt;
+
+   // Now check if selector is active for this range already.
+   bool bActive = false;
+
+   // Remove unneeded lines in the range.
+   for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); )
+   {
+      MergeEditLine& mel = *melIt;
+      if ( mel.src()==selector )
+         bActive = true;
+
+      if ( mel.src()==selector || !mel.isEditableText() || mel.isModified() )
+         melIt = ml.mergeEditLineList.erase( melIt );
+      else
+         ++melIt;
+   }
+
+   if ( !bActive )  // Selected source wasn't active.
+   {     // Append the lines from selected source here at rangeEnd.
+      Diff3LineList::const_iterator d3llit=ml.id3l;
+      int j;
+
+      for( j=0; j<ml.srcRangeLength; ++j )
+      {
+         MergeEditLine mel(d3llit);
+         mel.setSource( selector, false );
+         ml.mergeEditLineList.push_back(mel);
+
+         ++d3llit;
+      }
+   }
+
+   if ( ! ml.mergeEditLineList.empty() )
+   {
+      // Remove all lines that are empty, because no src lines are there.
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); )
+      {
+         MergeEditLine& mel = *melIt;
+
+         int srcLine = mel.src()==1 ? mel.id3l()->lineA :
+                       mel.src()==2 ? mel.id3l()->lineB :
+                       mel.src()==3 ? mel.id3l()->lineC : -1;
+
+         if ( srcLine == -1 )
+            melIt = ml.mergeEditLineList.erase( melIt );
+         else
+            ++melIt;
+      }
+   }
+
+   if ( ml.mergeEditLineList.empty() )
+   {
+      // Insert a dummy line:
+      MergeEditLine mel(ml.id3l);
+
+      if ( bActive )  mel.setConflict();         // All src entries deleted => conflict
+      else            mel.setRemoved(selector);  // No lines in corresponding src found.
+
+      ml.mergeEditLineList.push_back(mel);
+   }
+
+   if ( m_cursorYPos >= m_totalSize )
+   {
+      m_cursorYPos = m_totalSize-1;
+      m_cursorXPos = 0;
+   }
+
+   update();
+   updateSourceMask();
+   emit updateAvailabilities();
+   int wsc;
+   int nofUnsolved = getNrOfUnsolvedConflicts(&wsc);
+   m_pStatusBar->message( i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)")
+         .arg(nofUnsolved).arg(wsc) );
+}
+
+// bConflictsOnly: automatically choose for conflicts only (true) or for everywhere (false)
+void MergeResultWindow::chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly )
+{
+   resetSelection();
+
+   merge( false, selector, bConflictsOnly, bWhiteSpaceOnly );
+   setModified( true );
+   update();
+   int wsc;
+   int nofUnsolved = getNrOfUnsolvedConflicts(&wsc);
+   m_pStatusBar->message( i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)")
+         .arg(nofUnsolved).arg(wsc) );
+}
+
+void MergeResultWindow::slotAutoSolve()
+{
+   resetSelection();
+   merge( true, -1 );
+   setModified( true );
+   update();
+   int wsc;
+   int nofUnsolved = getNrOfUnsolvedConflicts(&wsc);
+   m_pStatusBar->message( i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)")
+         .arg(nofUnsolved).arg(wsc) );
+}
+
+void MergeResultWindow::slotUnsolve()
+{
+   resetSelection();
+   merge( false, -1 );
+   setModified( true );
+   update();
+   int wsc;
+   int nofUnsolved = getNrOfUnsolvedConflicts(&wsc);
+   m_pStatusBar->message( i18n("Number of remaining unsolved conflicts: %1 (of which %2 are whitespace)")
+         .arg(nofUnsolved).arg(wsc) );
+}
+
+
+static void findHistoryRange( bool bThreeFiles, const Diff3LineList* pD3LList, 
+                             Diff3LineList::const_iterator& iBegin, Diff3LineList::const_iterator& iEnd, int& idxBegin, int& idxEnd )
+{
+   QRegExp historyStart(".*\\$Log.*\\$.*");
+   QString historyLead;
+   // Search for start of history
+   for( iBegin = pD3LList->begin(), idxBegin=0; iBegin!=pD3LList->end(); ++iBegin, ++idxBegin )
+   {
+      if ( historyStart.exactMatch( iBegin->getString(A) ) && 
+           historyStart.exactMatch( iBegin->getString(B) ) && 
+           ( !bThreeFiles || historyStart.exactMatch( iBegin->getString(C) ) ) )
+      {
+         historyLead = iBegin->getString(A).section(' ', 0, 0, QString::SectionIncludeLeadingSep);
+         break;
+      }
+   }
+   // Search for end of history
+   for( iEnd = iBegin, idxEnd = idxBegin; iEnd!=pD3LList->end(); ++iEnd, ++idxEnd )
+   {
+      QString sA = iEnd->getString(A);
+      QString sB = iEnd->getString(B);
+      QString sC = iEnd->getString(C);
+      if ( ! ((sA.isNull() || historyLead == sA.section(' ',0,0,QString::SectionIncludeLeadingSep)) &&
+           (sB.isNull() || historyLead == sB.section(' ',0,0,QString::SectionIncludeLeadingSep)) &&
+           (!bThreeFiles || sC.isNull() || historyLead == sC.section(' ',0,0,QString::SectionIncludeLeadingSep))
+         ))
+      {
+         break; // End of the history
+      }
+   }
+}
+
+bool findParenthesesGroups( const QString& s, QStringList& sl )
+{
+   sl.clear();
+   int i=0;
+   std::list<int> startPosStack;
+   int length = s.length();
+   for( i=0; i<length; ++i )
+   {
+      if ( s[i]=='\\' && i+1<length && ( s[i+1]=='\\' || s[i+1]=='(' || s[i+1]==')' ) )
+      {
+         ++i;
+         continue;
+      }
+      if ( s[i]=='(' )
+      {
+         startPosStack.push_back(i);
+      }
+      else if ( s[i]==')' )
+      {
+         if (startPosStack.empty())
+            return false; // Parentheses don't match
+         int startPos = startPosStack.back();
+         startPosStack.pop_back();
+         sl.push_back( s.mid( startPos+1, i-startPos-1 ) );
+      }
+   }
+   return startPosStack.empty(); // false if parentheses don't match
+}
+
+QString calcHistorySortKey( const QString& keyOrder, QRegExp& matchedRegExpr, const QStringList& parenthesesGroupList )
+{
+   QStringList keyOrderList = QStringList::split(',', keyOrder );
+   QString key;
+   for ( QStringList::iterator keyIt = keyOrderList.begin(); keyIt!=keyOrderList.end(); ++keyIt )
+   {
+      if ( (*keyIt).isEmpty() )
+         continue;
+      bool bOk=false;
+      int groupIdx = (*keyIt).toInt(&bOk);
+      if (!bOk || groupIdx<0 || groupIdx >(int)parenthesesGroupList.size() )
+         continue;
+      QString s = matchedRegExpr.cap( groupIdx );
+      if ( groupIdx == 0 )
+      {
+         key += s + " ";
+         continue;
+      }
+
+      QString groupRegExp = parenthesesGroupList[groupIdx-1];
+      if( groupRegExp.find('|')<0 || groupRegExp.find('(')>=0 )
+      {
+         bool bOk = false;
+         int i = s.toInt( &bOk );
+         if ( bOk && i>=0 && i<10000 )
+            s.sprintf("%04d", i);  // This should help for correct sorting of numbers.
+         key += s + " ";
+      }
+      else
+      {
+         // Assume that the groupRegExp consists of something like "Jan|Feb|Mar|Apr"
+         // s is the string that managed to match.
+         // Now we want to know at which position it occurred. e.g. Jan=0, Feb=1, Mar=2, etc.
+         QStringList sl = QStringList::split( '|', groupRegExp );
+         int idx = sl.findIndex( s );
+         if (idx<0)
+         {
+            // Didn't match
+         }
+         else
+         {
+            QString sIdx;
+            sIdx.sprintf("%02d", idx+1 ); // Up to 99 words in the groupRegExp (more than 12 aren't expected)
+            key += sIdx + " ";
+         }
+      }
+   }
+   return key;
+}
+
+void MergeResultWindow::collectHistoryInformation(
+   int src, Diff3LineList::const_iterator iHistoryBegin, Diff3LineList::const_iterator iHistoryEnd,
+   HistoryMap& historyMap,
+   std::list< HistoryMap::iterator >& hitList  // list of iterators
+   )
+{
+   std::list< HistoryMap::iterator >::iterator itHitListFront = hitList.begin();
+   Diff3LineList::const_iterator id3l = iHistoryBegin;
+   QString historyLead;
+   {
+      const LineData* pld = id3l->getLineData(src);
+      QString s( pld->pLine, pld->size );
+      historyLead = s.section(' ',0,0,QString::SectionIncludeLeadingSep);
+   }
+   QRegExp historyStart = m_pOptionDialog->m_historyStartRegExp;
+   ++id3l; // Skip line with "$Log ... $"
+   QRegExp newHistoryEntry = m_pOptionDialog->m_historyEntryStartRegExp;
+   QStringList parenthesesGroups;
+   findParenthesesGroups( m_pOptionDialog->m_historyEntryStartRegExp, parenthesesGroups );
+   QString key;
+   MergeEditLineList melList;
+   bool bPrevLineIsEmpty = true;
+   bool bUseRegExp = !m_pOptionDialog->m_historyEntryStartRegExp.isEmpty();
+   for(; id3l != iHistoryEnd; ++id3l )
+   {
+      const LineData* pld = id3l->getLineData(src);
+      if ( !pld ) continue;
+      QString s( pld->pLine, pld->size );
+      if (historyLead.isNull()) historyLead = s.section(' ',0,0,QString::SectionIncludeLeadingSep);
+      QString sLine = s.mid(historyLead.length());
+      if ( ( !bUseRegExp && !sLine.stripWhiteSpace().isEmpty() && bPrevLineIsEmpty )
+           || bUseRegExp && newHistoryEntry.exactMatch( sLine ) 
+         )
+      {
+         if ( !key.isEmpty() && !melList.empty() )
+         {
+            // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key.
+            std::pair<HistoryMap::iterator, bool> p = historyMap.insert(HistoryMap::value_type(key,HistoryMapEntry()));
+            HistoryMapEntry& hme = p.first->second;
+            if ( src==A ) hme.mellA = melList;
+            if ( src==B ) hme.mellB = melList;
+            if ( src==C ) hme.mellC = melList;
+            if ( p.second ) // Not in list yet?
+            {
+               hitList.insert( itHitListFront, p.first );
+            }
+         }
+
+         if ( ! bUseRegExp )
+            key = sLine;
+         else
+            key = calcHistorySortKey(m_pOptionDialog->m_historyEntryStartSortKeyOrder,newHistoryEntry,parenthesesGroups);
+
+         melList.clear();
+         melList.push_back( MergeEditLine(id3l,src) );
+      }
+      else if ( ! historyStart.exactMatch( s ) )
+      {
+         melList.push_back( MergeEditLine(id3l,src) );
+      }
+
+      bPrevLineIsEmpty = sLine.stripWhiteSpace().isEmpty();
+   }
+   if ( !key.isEmpty() )
+   {
+      // Only insert new HistoryMapEntry if key not found; in either case p.first is a valid iterator to element key.
+      std::pair<HistoryMap::iterator, bool> p = historyMap.insert(HistoryMap::value_type(key,HistoryMapEntry()));
+      HistoryMapEntry& hme = p.first->second;
+      if ( src==A ) hme.mellA = melList;
+      if ( src==B ) hme.mellB = melList;
+      if ( src==C ) hme.mellC = melList;
+      if ( p.second ) // Not in list yet?
+      {
+         hitList.insert( itHitListFront, p.first );
+      }
+   }
+   // End of the history
+}
+
+MergeResultWindow::MergeEditLineList& MergeResultWindow::HistoryMapEntry::choice( bool bThreeInputs )
+{
+   if ( !bThreeInputs )
+      return mellA.empty() ? mellB : mellA;
+   else
+   {
+      if ( mellA.empty() )
+         return mellC.empty() ? mellB : mellC;       // A doesn't exist, return one that exists
+      else if ( ! mellB.empty() && ! mellC.empty() )
+      {                                              // A, B and C exist
+         return mellA;
+      }
+      else
+         return mellB.empty() ? mellB : mellC;       // A exists, return the one that doesn't exist
+   }
+}
+
+bool MergeResultWindow::HistoryMapEntry::staysInPlace( bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd )
+{
+   // The entry should stay in place if the decision made by the automerger is correct.
+   Diff3LineList::const_iterator& iHistoryLast = iHistoryEnd;
+   --iHistoryLast;
+   if ( !bThreeInputs )
+   {
+      if ( !mellA.empty() && !mellB.empty() && mellA.begin()->id3l()==mellB.begin()->id3l() && 
+           mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast )
+      {
+         iHistoryEnd = mellA.begin()->id3l();
+         return true;
+      }
+      else
+      {
+         return false;
+      }
+   }
+   else
+   {
+      if ( !mellA.empty() && !mellB.empty() && !mellC.empty() 
+           && mellA.begin()->id3l()==mellB.begin()->id3l() && mellA.begin()->id3l()==mellC.begin()->id3l()
+           && mellA.back().id3l() == iHistoryLast && mellB.back().id3l() == iHistoryLast && mellC.back().id3l() == iHistoryLast )
+      {
+         iHistoryEnd = mellA.begin()->id3l();
+         return true;
+      }
+      else
+      {
+         return false;
+      }
+   }
+}
+
+void MergeResultWindow::slotMergeHistory()
+{
+   Diff3LineList::const_iterator iD3LHistoryBegin;
+   Diff3LineList::const_iterator iD3LHistoryEnd;
+   int d3lHistoryBeginLineIdx = -1;
+   int d3lHistoryEndLineIdx = -1;
+
+   // Search for history start, history end in the diff3LineList
+   findHistoryRange( m_pldC!=0, m_pDiff3LineList, iD3LHistoryBegin, iD3LHistoryEnd, d3lHistoryBeginLineIdx, d3lHistoryEndLineIdx );
+
+   if (  iD3LHistoryBegin != m_pDiff3LineList->end() )
+   {
+      // Now collect the historyMap information
+      HistoryMap historyMap;
+      std::list< HistoryMap::iterator > hitList;
+      if (m_pldC==0)
+      {
+         collectHistoryInformation( A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList );
+         collectHistoryInformation( B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList );
+      }
+      else
+      {
+         collectHistoryInformation( A, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList );
+         collectHistoryInformation( B, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList );
+         collectHistoryInformation( C, iD3LHistoryBegin, iD3LHistoryEnd, historyMap, hitList );
+      }
+
+      Diff3LineList::const_iterator iD3LHistoryOrigEnd = iD3LHistoryEnd;
+
+      bool bHistoryMergeSorting = m_pOptionDialog->m_bHistoryMergeSorting  && ! m_pOptionDialog->m_historyEntryStartSortKeyOrder.isEmpty() && 
+                                  ! m_pOptionDialog->m_historyEntryStartRegExp.isEmpty();
+
+      // Remove parts from the historyMap and hitList that stay in place
+      if ( bHistoryMergeSorting )
+      {
+         while ( ! historyMap.empty() )
+         {
+            HistoryMap::iterator hMapIt = historyMap.begin();
+            if( hMapIt->second.staysInPlace( m_pldC!=0, iD3LHistoryEnd ) )
+               historyMap.erase(hMapIt);
+            else
+               break;
+         }
+      }
+      else
+      {
+         while ( ! hitList.empty() )
+         {
+            HistoryMap::iterator hMapIt = hitList.back();
+            if( hMapIt->second.staysInPlace( m_pldC!=0, iD3LHistoryEnd ) )
+               hitList.pop_back();
+            else
+               break;
+         }
+      }
+      while (iD3LHistoryOrigEnd != iD3LHistoryEnd)
+      {
+         --iD3LHistoryOrigEnd;
+         --d3lHistoryEndLineIdx;
+      }
+
+      MergeLineList::iterator iMLLStart = splitAtDiff3LineIdx(d3lHistoryBeginLineIdx);
+      MergeLineList::iterator iMLLEnd   = splitAtDiff3LineIdx(d3lHistoryEndLineIdx);
+      // Now join all MergeLines in the history
+      MergeLineList::iterator i = iMLLStart;
+      if ( i != iMLLEnd )
+      {
+         ++i;
+         while ( i!=iMLLEnd )
+         {
+            iMLLStart->join(*i);
+            i = m_mergeLineList.erase( i );
+         }
+      }
+      iMLLStart->mergeEditLineList.clear();
+      // Now insert the complete history into the first MergeLine of the history
+      iMLLStart->mergeEditLineList.push_back( MergeEditLine( iD3LHistoryBegin, m_pldC == 0 ? B : C ) );
+      QString lead = iD3LHistoryBegin->getString(A).section(' ',0,0,QString::SectionIncludeLeadingSep);
+      MergeEditLine mel( m_pDiff3LineList->end() );
+      mel.setString( lead );
+      iMLLStart->mergeEditLineList.push_back(mel);
+
+      if ( bHistoryMergeSorting )
+      {
+         // Create a sorted history
+         HistoryMap::reverse_iterator hmit;
+         for ( hmit = historyMap.rbegin(); hmit != historyMap.rend(); ++hmit )
+         {
+            HistoryMapEntry& hme = hmit->second;
+            MergeEditLineList& mell = hme.choice(m_pldC!=0);
+            if (!mell.empty())
+               iMLLStart->mergeEditLineList.splice( iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end() );
+         }
+      }
+      else
+      {
+         // Create history in order of appearance
+         std::list< HistoryMap::iterator >::iterator hlit;
+         for ( hlit = hitList.begin(); hlit != hitList.end(); ++hlit )
+         {
+            HistoryMapEntry& hme = (*hlit)->second;
+            MergeEditLineList& mell = hme.choice(m_pldC!=0);
+            if (!mell.empty())
+               iMLLStart->mergeEditLineList.splice( iMLLStart->mergeEditLineList.end(), mell, mell.begin(), mell.end() );
+         }
+      }
+      setFastSelector( iMLLStart );
+      update();
+   }
+}
+
+void MergeResultWindow::slotRegExpAutoMerge()
+{
+   if ( m_pOptionDialog->m_autoMergeRegExp.isEmpty() )
+      return;
+
+   QRegExp vcsKeywords = m_pOptionDialog->m_autoMergeRegExp;
+   MergeLineList::iterator i;
+   for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i )
+   {
+      if (i->bConflict )
+      {
+         Diff3LineList::const_iterator id3l = i->id3l;
+         if ( vcsKeywords.exactMatch( id3l->getString(A) ) && 
+              vcsKeywords.exactMatch( id3l->getString(B) ) &&
+              (m_pldC==0 || vcsKeywords.exactMatch( id3l->getString(C) )))
+         {
+            MergeEditLine& mel = *i->mergeEditLineList.begin();
+            mel.setSource( m_pldC==0 ? B : C, false );
+            splitAtDiff3LineIdx( i->d3lLineIdx+1 );
+         }
+      }
+   }
+   update();
+}
+
+// This doesn't detect user modifications and should only be called after automatic merge
+// This will only do something for three file merge.
+// Irrelevant changes are those where all contributions from B are already contained in C.
+// Also irrelevant are conflicts automatically solved (automerge regexp and history automerge)
+// Precondition: The VCS-keyword would also be C.
+bool MergeResultWindow::doRelevantChangesExist()
+{
+   if ( m_pldC==0 || m_mergeLineList.size() <= 1 )
+      return true;
+
+   MergeLineList::iterator i;
+   for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i )
+   {
+      if ( ( i->bConflict && i->mergeEditLineList.begin()->src()!=C )
+         || i->srcSelect == B )
+      {
+         return true;
+      }
+   }
+
+   return false;
+}
+
+// Returns the iterator to the MergeLine after the split
+MergeResultWindow::MergeLineList::iterator MergeResultWindow::splitAtDiff3LineIdx( int d3lLineIdx )
+{
+   MergeLineList::iterator i;
+   for ( i = m_mergeLineList.begin();  i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->d3lLineIdx==d3lLineIdx )
+      {
+         // No split needed, this is the beginning of a MergeLine
+         return i;
+      }
+      else if ( i->d3lLineIdx > d3lLineIdx )
+      {
+         // The split must be in the previous MergeLine
+         --i;
+         MergeLine& ml = *i;
+         MergeLine newML;
+         ml.split(newML,d3lLineIdx);
+         ++i;
+         return m_mergeLineList.insert( i, newML );
+      }
+   }
+   // The split must be in the previous MergeLine
+   --i;
+   MergeLine& ml = *i;
+   MergeLine newML;
+   ml.split(newML,d3lLineIdx);
+   ++i;
+   return m_mergeLineList.insert( i, newML );
+}
+
+void MergeResultWindow::slotSplitDiff( int firstD3lLineIdx, int lastD3lLineIdx )
+{
+   if (lastD3lLineIdx>=0)
+      splitAtDiff3LineIdx( lastD3lLineIdx + 1 );
+   setFastSelector( splitAtDiff3LineIdx(firstD3lLineIdx) );
+}
+
+void MergeResultWindow::slotJoinDiffs( int firstD3lLineIdx, int lastD3lLineIdx )
+{
+   MergeLineList::iterator i;
+   MergeLineList::iterator iMLLStart = m_mergeLineList.end();
+   MergeLineList::iterator iMLLEnd   = m_mergeLineList.end();
+   for ( i=m_mergeLineList.begin(); i!=m_mergeLineList.end(); ++i )
+   {
+      MergeLine& ml = *i;
+      if ( firstD3lLineIdx >= ml.d3lLineIdx && firstD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength )
+      {
+         iMLLStart = i;
+      }
+      if ( lastD3lLineIdx >= ml.d3lLineIdx && lastD3lLineIdx < ml.d3lLineIdx + ml.srcRangeLength )
+      {
+         iMLLEnd = i;
+         ++iMLLEnd;
+         break;
+      }
+   }
+
+   bool bJoined = false;
+   for( i=iMLLStart;  i!=iMLLEnd && i!=m_mergeLineList.end(); )
+   {
+      if ( i==iMLLStart )
+      {
+         ++i;
+      }
+      else
+      {
+         iMLLStart->join(*i);
+         i = m_mergeLineList.erase( i );
+         bJoined = true;
+      }
+   }
+   if (bJoined)
+   {
+      iMLLStart->mergeEditLineList.clear();
+      // Insert a conflict line as placeholder
+      iMLLStart->mergeEditLineList.push_back( MergeEditLine( iMLLStart->id3l ) );
+   }
+   setFastSelector( iMLLStart );
+}
+
+void MergeResultWindow::myUpdate(int afterMilliSecs)
+{
+   killTimer(m_delayedDrawTimer);
+   m_bMyUpdate = true;
+   m_delayedDrawTimer = startTimer( afterMilliSecs );
+}
+
+void MergeResultWindow::timerEvent(QTimerEvent*)
+{
+   killTimer(m_delayedDrawTimer);
+   m_delayedDrawTimer = 0;
+
+   if ( m_bMyUpdate )
+   {
+      update();
+      m_bMyUpdate = false;
+   }
+
+   if ( m_scrollDeltaX != 0 || m_scrollDeltaY != 0 )
+   {
+      m_selection.end( m_selection.lastLine + m_scrollDeltaY, m_selection.lastPos +  m_scrollDeltaX );
+      emit scroll( m_scrollDeltaX, m_scrollDeltaY );
+      killTimer(m_delayedDrawTimer);
+      m_delayedDrawTimer = startTimer(50);
+   }
+}
+
+QString MergeResultWindow::MergeEditLine::getString( const MergeResultWindow* mrw )
+{
+   if ( isRemoved() )   { return QString(); }
+
+   if ( ! isModified() )
+   {
+      int src = m_src;
+      const Diff3Line& d3l = *m_id3l;
+      if ( src == 0 )   { return QString(); }
+
+      const LineData* pld = 0;
+      assert( src == A || src == B || src == C );
+      if      ( src == A && d3l.lineA!=-1 ) pld = &mrw->m_pldA[ d3l.lineA ];
+      else if ( src == B && d3l.lineB!=-1 ) pld = &mrw->m_pldB[ d3l.lineB ];
+      else if ( src == C && d3l.lineC!=-1 ) pld = &mrw->m_pldC[ d3l.lineC ];
+
+      if ( pld == 0 )
+      {
+         // assert(false);      This is no error.
+         return QString();
+      }
+
+      return QString( pld->pLine, pld->size );
+   }
+   else
+   {
+      return m_str;
+   }
+   return 0;
+}
+
+/// Converts the cursor-posOnScreen into a text index, considering tabulators.
+int convertToPosInText( const QString& s, int posOnScreen, int tabSize )
+{
+   int localPosOnScreen = 0;
+   int size=s.length();
+   for ( int i=0; i<size; ++i )
+   {
+      if ( localPosOnScreen>=posOnScreen )
+         return i;
+
+      // All letters except tabulator have width one.
+      int letterWidth = s[i]!='\t' ? 1 : tabber( localPosOnScreen, tabSize );
+
+      localPosOnScreen += letterWidth;
+
+      if ( localPosOnScreen>posOnScreen )
+         return i;
+   }
+   return size;
+}
+
+
+/// Converts the index into the text to a cursor-posOnScreen considering tabulators.
+int convertToPosOnScreen( const QString& p, int posInText, int tabSize )
+{
+   int posOnScreen = 0;
+   for ( int i=0; i<posInText; ++i )
+   {
+      // All letters except tabulator have width one.
+      int letterWidth = p[i]!='\t' ? 1 : tabber( posOnScreen, tabSize );
+
+      posOnScreen += letterWidth;
+   }
+   return posOnScreen;
+}
+
+void MergeResultWindow::writeLine(
+   MyPainter& p, int line, const QString& str,
+   int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict
+   )
+{
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width("W");
+   int fontAscent = fm.ascent();
+
+   int topLineYOffset = 0;
+   int xOffset = fontWidth * leftInfoWidth;
+
+   int yOffset = ( line-m_firstLine ) * fontHeight;
+   if ( yOffset < 0 || yOffset > height() )
+      return;
+
+   yOffset += topLineYOffset;
+
+   QString srcName = " ";
+   if ( bUserModified )                                     srcName = "m";
+   else if ( srcSelect == A && mergeDetails != eNoChange )  srcName = "A";
+   else if ( srcSelect == B )                               srcName = "B";
+   else if ( srcSelect == C )                               srcName = "C";
+
+   if ( rangeMark & 4 )
+   {
+      p.fillRect( xOffset, yOffset, width(), fontHeight, m_pOptionDialog->m_currentRangeBgColor );
+   }
+
+   if( (srcSelect > 0 || bUserModified ) && !bLineRemoved )
+   {
+      int outPos = 0;
+      QString s;
+      int size = str.length();
+      for ( int i=0; i<size; ++i )
+      {
+         int spaces = 1;
+         if ( str[i]=='\t' )
+         {
+            spaces = tabber( outPos, m_pOptionDialog->m_tabSize );
+            for( int j=0; j<spaces; ++j )
+               s+=' ';
+         }
+         else
+         {
+            s+=str[i];
+         }
+         outPos += spaces;
+      }
+
+      if ( m_selection.lineWithin( line ) )
+      {
+         int firstPosInLine = convertToPosOnScreen( str, convertToPosInText( str, m_selection.firstPosInLine(line), m_pOptionDialog->m_tabSize ),m_pOptionDialog->m_tabSize );
+         int lastPosInLine  = convertToPosOnScreen( str, convertToPosInText( str, m_selection.lastPosInLine(line), m_pOptionDialog->m_tabSize ), m_pOptionDialog->m_tabSize );
+         int lengthInLine = max2(0,lastPosInLine - firstPosInLine);
+         if (lengthInLine>0) m_selection.bSelectionContainsData = true;
+
+         if ( lengthInLine < int(s.length()) )
+         {                                // Draw a normal line first
+            p.setPen( m_pOptionDialog->m_fgColor );
+            p.drawText( xOffset, yOffset+fontAscent,  s.mid(m_firstColumn), true );
+         }
+         int firstPosInLine2 = max2( firstPosInLine, m_firstColumn );
+         int lengthInLine2 = max2(0,lastPosInLine - firstPosInLine2);
+
+         if( m_selection.lineWithin( line+1 ) )
+            p.fillRect( xOffset + fontWidth*(firstPosInLine2-m_firstColumn), yOffset,
+               width(), fontHeight, colorGroup().highlight() );
+         else if ( lengthInLine2>0 )
+            p.fillRect( xOffset + fontWidth*(firstPosInLine2-m_firstColumn), yOffset,
+               fontWidth*lengthInLine2, fontHeight, colorGroup().highlight() );
+
+         p.setPen( colorGroup().highlightedText() );
+         p.drawText( xOffset + fontWidth*(firstPosInLine2-m_firstColumn), yOffset+fontAscent,
+            s.mid(firstPosInLine2,lengthInLine2), true );
+      }
+      else
+      {
+         p.setPen( m_pOptionDialog->m_fgColor );
+         p.drawText( xOffset, yOffset+fontAscent, s.mid(m_firstColumn), true );
+      }
+
+      p.setPen( m_pOptionDialog->m_fgColor );
+      if ( m_cursorYPos==line )
+      {
+         m_cursorXPos = minMaxLimiter( m_cursorXPos, 0, outPos );
+         m_cursorXPos = convertToPosOnScreen( str, convertToPosInText( str, m_cursorXPos, m_pOptionDialog->m_tabSize ),m_pOptionDialog->m_tabSize );
+      }
+
+      p.drawText( 1, yOffset+fontAscent, srcName, true );
+   }
+   else if ( bLineRemoved )
+   {
+      p.setPen( m_pOptionDialog->m_colorForConflict );
+      p.drawText( xOffset, yOffset+fontAscent, i18n("<No src line>") );
+      p.drawText( 1, yOffset+fontAscent, srcName );
+      if ( m_cursorYPos==line ) m_cursorXPos = 0;
+   }
+   else if ( srcSelect == 0 )
+   {
+      p.setPen( m_pOptionDialog->m_colorForConflict );
+      if ( bWhiteSpaceConflict )
+         p.drawText( xOffset, yOffset+fontAscent, i18n("<Merge Conflict (Whitespace only)>") );
+      else
+         p.drawText( xOffset, yOffset+fontAscent, i18n("<Merge Conflict>") );
+      p.drawText( 1, yOffset+fontAscent, "?" );
+      if ( m_cursorYPos==line ) m_cursorXPos = 0;
+   }
+   else assert(false);
+
+   xOffset -= fontWidth;
+   p.setPen( m_pOptionDialog->m_fgColor );
+   if ( rangeMark & 1 ) // begin mark
+   {
+      p.drawLine( xOffset, yOffset+1, xOffset, yOffset+fontHeight/2 );
+      p.drawLine( xOffset, yOffset+1, xOffset-2, yOffset+1 );
+   }
+   else
+   {
+      p.drawLine( xOffset, yOffset, xOffset, yOffset+fontHeight/2 );
+   }
+
+   if ( rangeMark & 2 ) // end mark
+   {
+      p.drawLine( xOffset, yOffset+fontHeight/2, xOffset, yOffset+fontHeight-1 );
+      p.drawLine( xOffset, yOffset+fontHeight-1, xOffset-2, yOffset+fontHeight-1 );
+   }
+   else
+   {
+      p.drawLine( xOffset, yOffset+fontHeight/2, xOffset, yOffset+fontHeight );
+   }
+
+   if ( rangeMark & 4 )
+   {
+      p.fillRect( xOffset + 3, yOffset, 3, fontHeight, m_pOptionDialog->m_fgColor );
+/*      p.setPen( blue );
+      p.drawLine( xOffset+2, yOffset, xOffset+2, yOffset+fontHeight-1 );
+      p.drawLine( xOffset+3, yOffset, xOffset+3, yOffset+fontHeight-1 );*/
+   }
+}
+
+void MergeResultWindow::setPaintingAllowed(bool bPaintingAllowed)
+{
+   m_bPaintingAllowed = bPaintingAllowed;
+   if ( !m_bPaintingAllowed )
+   {
+      m_currentMergeLineIt = m_mergeLineList.end();
+      reset();
+   }
+}
+
+void MergeResultWindow::paintEvent( QPaintEvent*  )
+{
+   if (m_pDiff3LineList==0 || !m_bPaintingAllowed) return;
+
+   bool bOldSelectionContainsData = m_selection.bSelectionContainsData;
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width("W");
+   int fontAscent = fm.ascent();
+
+   if ( !m_bCursorUpdate )  // Don't redraw everything for blinking cursor?
+   {
+      m_selection.bSelectionContainsData = false;
+      if ( size() != m_pixmap.size() )
+         m_pixmap.resize(size());
+
+      MyPainter p(&m_pixmap, m_pOptionDialog->m_bRightToLeftLanguage, width(), fontWidth);
+      p.setFont( font() );
+      p.QPainter::fillRect( rect(), m_pOptionDialog->m_bgColor );
+
+      //int visibleLines = height() / fontHeight;
+
+      int lastVisibleLine = m_firstLine + getNofVisibleLines() + 5;
+      int nofColumns = 0;
+      int line = 0;
+      MergeLineList::iterator mlIt = m_mergeLineList.begin();
+      for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+      {
+         MergeLine& ml = *mlIt;
+         if ( line > lastVisibleLine  || line + ml.mergeEditLineList.size() < m_firstLine)
+         {
+            line += ml.mergeEditLineList.size();
+         }
+         else
+         {
+            MergeEditLineList::iterator melIt;
+            for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+            {
+               if (line>=m_firstLine && line<=lastVisibleLine)
+               {
+                  MergeEditLine& mel = *melIt;
+                  MergeEditLineList::iterator melIt1 = melIt;
+                  ++melIt1;
+
+                  int rangeMark = 0;
+                  if ( melIt==ml.mergeEditLineList.begin() ) rangeMark |= 1; // Begin range mark
+                  if ( melIt1==ml.mergeEditLineList.end() )  rangeMark |= 2; // End range mark
+
+                  if ( mlIt == m_currentMergeLineIt )        rangeMark |= 4; // Mark of the current line
+
+                  QString s;
+                  s = mel.getString( this );
+                  if ( convertToPosOnScreen(s,s.length(),m_pOptionDialog->m_tabSize) >nofColumns)
+                     nofColumns = s.length();
+
+                  writeLine( p, line, s, mel.src(), ml.mergeDetails, rangeMark,
+                     mel.isModified(), mel.isRemoved(), ml.bWhiteSpaceConflict );
+               }
+               ++line;
+            }
+         }
+      }
+
+      if ( line != m_nofLines || nofColumns != m_nofColumns )
+      {
+         m_nofLines = line;
+         assert( m_nofLines == m_totalSize );
+
+         m_nofColumns = nofColumns;
+         emit resizeSignal();
+      }
+
+      p.end();
+   }
+
+   QPainter painter(this);
+
+   int topLineYOffset = 0;
+   int xOffset = fontWidth * leftInfoWidth;
+   int yOffset = ( m_cursorYPos - m_firstLine ) * fontHeight + topLineYOffset;
+   int xCursor = ( m_cursorXPos - m_firstColumn ) * fontWidth + xOffset;
+
+   if ( !m_bCursorUpdate )
+      painter.drawPixmap(0,0, m_pixmap);
+   else
+   {
+      if (!m_pOptionDialog->m_bRightToLeftLanguage)
+         painter.drawPixmap(xCursor-2, yOffset, m_pixmap,
+                            xCursor-2, yOffset, 5, fontAscent+2 );
+      else
+         painter.drawPixmap(width()-1-4-(xCursor-2), yOffset, m_pixmap,
+                            width()-1-4-(xCursor-2), yOffset, 5, fontAscent+2 );
+      m_bCursorUpdate = false;
+   }
+   painter.end();
+
+   if ( m_bCursorOn && hasFocus() && m_cursorYPos>=m_firstLine )
+   {
+      MyPainter painter(this, m_pOptionDialog->m_bRightToLeftLanguage, width(), fontWidth);
+      int topLineYOffset = 0;
+      int xOffset = fontWidth * leftInfoWidth;
+
+      int yOffset = ( m_cursorYPos-m_firstLine ) * fontHeight + topLineYOffset;
+
+      int xCursor = ( m_cursorXPos - m_firstColumn ) * fontWidth + xOffset;
+
+      painter.setPen( m_pOptionDialog->m_fgColor );
+
+      painter.drawLine( xCursor, yOffset, xCursor, yOffset+fontAscent );
+      painter.drawLine( xCursor-2, yOffset, xCursor+2, yOffset );
+      painter.drawLine( xCursor-2, yOffset+fontAscent+1, xCursor+2, yOffset+fontAscent+1 );
+   }
+
+   if( !bOldSelectionContainsData  &&  m_selection.bSelectionContainsData )
+      emit newSelection();
+}
+
+void MergeResultWindow::updateSourceMask()
+{
+   int srcMask=0; 
+   int enabledMask = 0;
+   if( !hasFocus() || m_pDiff3LineList==0 || !m_bPaintingAllowed || m_currentMergeLineIt == m_mergeLineList.end() )
+   {
+      srcMask = 0;
+      enabledMask = 0;
+   }
+   else
+   {
+      enabledMask = m_pldC==0 ? 3 : 7;
+      MergeLine& ml = *m_currentMergeLineIt;
+
+      srcMask = 0;
+      bool bModified = false;
+      MergeEditLineList::iterator melIt;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+      {
+         MergeEditLine& mel = *melIt;
+         if ( mel.src()==1 ) srcMask |= 1;
+         if ( mel.src()==2 ) srcMask |= 2;
+         if ( mel.src()==3 ) srcMask |= 4;
+         if ( mel.isModified() || !mel.isEditableText() ) bModified = true;
+      }
+
+      if ( ml.mergeDetails == eNoChange ) 
+      {
+         srcMask = 0; 
+         enabledMask = bModified ? 1 : 0; 
+      }
+   }
+
+   emit sourceMask( srcMask, enabledMask );
+}
+
+void MergeResultWindow::focusInEvent( QFocusEvent* e )
+{
+   updateSourceMask();
+   QWidget::focusInEvent(e);
+}
+
+void MergeResultWindow::convertToLinePos( int x, int y, int& line, int& pos )
+{
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width('W');
+   int xOffset = (leftInfoWidth-m_firstColumn)*fontWidth;
+   int topLineYOffset = 0;
+
+   int yOffset = topLineYOffset - m_firstLine * fontHeight;
+
+   line = min2( ( y - yOffset ) / fontHeight, m_totalSize-1 );
+   if ( ! m_pOptionDialog->m_bRightToLeftLanguage )
+      pos  = ( x - xOffset ) / fontWidth;
+   else 
+      pos  = ( (width() - 1 - x) - xOffset ) / fontWidth;
+}
+
+void MergeResultWindow::mousePressEvent ( QMouseEvent* e )
+{
+   m_bCursorOn = true;
+
+   int line;
+   int pos;
+   convertToLinePos( e->x(), e->y(), line, pos );
+
+   bool bLMB = e->button() == Qt::LeftButton;
+   bool bMMB = e->button() == Qt::MidButton;
+   bool bRMB = e->button() == Qt::RightButton;
+
+   if ( bLMB && pos < m_firstColumn || bRMB )       // Fast range selection
+   {
+      m_cursorXPos = 0;
+      m_cursorOldXPos = 0;
+      m_cursorYPos = max2(line,0);
+      int l = 0;
+      MergeLineList::iterator i = m_mergeLineList.begin();
+      for(i = m_mergeLineList.begin();i!=m_mergeLineList.end(); ++i)
+      {
+         if (l==line)
+            break;
+
+         l += i->mergeEditLineList.size();
+         if (l>line)
+            break;
+      }
+      m_selection.reset();     // Disable current selection
+
+      m_bCursorOn = true;
+      setFastSelector( i );
+
+      if (bRMB)
+      {
+         showPopupMenu( QCursor::pos() );
+      }
+   }
+   else if ( bLMB )                  // Normal cursor placement
+   {
+      pos = max2(pos,0);
+      line = max2(line,0);
+      if ( e->state() & Qt::ShiftButton )
+      {
+         if (m_selection.firstLine==-1)
+            m_selection.start( line, pos );
+         m_selection.end( line, pos );
+      }
+      else
+      {
+         // Selection
+         m_selection.reset();
+         m_selection.start( line, pos );
+         m_selection.end( line, pos );
+      }
+      m_cursorXPos = pos;
+      m_cursorOldXPos = pos;
+      m_cursorYPos = line;
+
+      update();
+      //showStatusLine( line, m_winIdx, m_pFilename, m_pDiff3LineList, m_pStatusBar );
+   }
+   else if ( bMMB )        // Paste clipboard
+   {
+      pos = max2(pos,0);
+      line = max2(line,0);
+
+      m_selection.reset();
+      m_cursorXPos = pos;
+      m_cursorOldXPos = pos;
+      m_cursorYPos = line;
+
+      pasteClipboard( true );
+   }
+}
+
+void MergeResultWindow::mouseDoubleClickEvent( QMouseEvent* e )
+{
+   if ( e->button() == Qt::LeftButton )
+   {
+      int line;
+      int pos;
+      convertToLinePos( e->x(), e->y(), line, pos );
+      m_cursorXPos = pos;
+      m_cursorOldXPos = pos;
+      m_cursorYPos = line;
+
+      // Get the string data of the current line
+
+      MergeLineList::iterator mlIt;
+      MergeEditLineList::iterator melIt;
+      calcIteratorFromLineNr( line, mlIt, melIt );
+      QString s = melIt->getString( this );
+
+      if ( !s.isEmpty() )
+      {
+         int pos1, pos2;
+
+         calcTokenPos( s, pos, pos1, pos2, m_pOptionDialog->m_tabSize );
+
+         resetSelection();
+         m_selection.start( line, convertToPosOnScreen( s, pos1, m_pOptionDialog->m_tabSize ) );
+         m_selection.end( line, convertToPosOnScreen( s, pos2, m_pOptionDialog->m_tabSize ) );
+
+         update();
+         // emit selectionEnd() happens in the mouseReleaseEvent.
+      }
+   }
+}
+
+void MergeResultWindow::mouseReleaseEvent ( QMouseEvent * e )
+{
+   if ( e->button() == Qt::LeftButton )
+   {
+      killTimer(m_delayedDrawTimer);
+      m_delayedDrawTimer = 0;
+
+      if (m_selection.firstLine != -1 )
+      {
+         emit selectionEnd();
+      }
+   }
+}
+
+void MergeResultWindow::mouseMoveEvent ( QMouseEvent * e )
+{
+   int line;
+   int pos;
+   convertToLinePos( e->x(), e->y(), line, pos );
+   m_cursorXPos = pos;
+   m_cursorOldXPos = pos;
+   m_cursorYPos = line;
+   if (m_selection.firstLine != -1 )
+   {
+      m_selection.end( line, pos );
+      myUpdate(0);
+
+      //showStatusLine( line, m_winIdx, m_pFilename, m_pDiff3LineList, m_pStatusBar );
+
+      // Scroll because mouse moved out of the window
+      const QFontMetrics& fm = fontMetrics();
+      int fontWidth = fm.width('W');
+      int topLineYOffset = 0;
+      int deltaX=0;
+      int deltaY=0;
+      if ( ! m_pOptionDialog->m_bRightToLeftLanguage )
+      {
+         if ( e->x() < leftInfoWidth*fontWidth )       deltaX=-1;
+         if ( e->x() > width()     )                   deltaX=+1;
+      }
+      else
+      {
+         if ( e->x() > width()-1-leftInfoWidth*fontWidth )   deltaX=-1;
+         if ( e->x() < fontWidth )                           deltaX=+1;
+      }
+      if ( e->y() < topLineYOffset )    deltaY=-1;
+      if ( e->y() > height() )          deltaY=+1;
+      m_scrollDeltaX = deltaX;
+      m_scrollDeltaY = deltaY;
+      if ( deltaX != 0 || deltaY!= 0)
+      {
+         emit scroll( deltaX, deltaY );
+      }
+   }
+}
+
+
+void MergeResultWindow::slotCursorUpdate()
+{
+   m_cursorTimer.stop();
+   m_bCursorOn = !m_bCursorOn;
+
+   if ( isVisible() )
+   {
+      m_bCursorUpdate = true;
+
+      const QFontMetrics& fm = fontMetrics();
+      int fontWidth = fm.width("W");
+      int topLineYOffset = 0;
+      int xOffset = fontWidth * leftInfoWidth;
+      int yOffset = ( m_cursorYPos - m_firstLine ) * fm.height() + topLineYOffset;
+      int xCursor = ( m_cursorXPos - m_firstColumn ) * fontWidth + xOffset;
+
+      if (!m_pOptionDialog->m_bRightToLeftLanguage)
+         repaint( xCursor-2, yOffset, 5, fm.ascent()+2 );
+      else
+         repaint( width()-1-4-(xCursor-2), yOffset, 5, fm.ascent()+2 );
+
+      m_bCursorUpdate=false;
+   }
+
+   m_cursorTimer.start(500,true);
+}
+
+
+void MergeResultWindow::wheelEvent( QWheelEvent* e )
+{
+    int d = -e->delta()*QApplication::wheelScrollLines()/120;
+    e->accept();
+    scroll( 0, min2(d, getNofVisibleLines()) );
+}
+
+
+void MergeResultWindow::keyPressEvent( QKeyEvent* e )
+{
+   int y = m_cursorYPos;
+   MergeLineList::iterator mlIt;
+   MergeEditLineList::iterator melIt;
+   calcIteratorFromLineNr( y, mlIt, melIt );
+
+   QString str = melIt->getString( this );
+   int x = convertToPosInText( str, m_cursorXPos, m_pOptionDialog->m_tabSize );
+
+   bool bCtrl  = ( e->state() & Qt::ControlButton ) != 0 ;
+   bool bShift = ( e->state() & Qt::ShiftButton   ) != 0 ;
+   #ifdef _WIN32
+   bool bAlt   = ( e->state() & Qt::AltButton     ) != 0 ;
+   if ( bCtrl && bAlt ){ bCtrl=false; bAlt=false; }  // AltGr-Key pressed.
+   #endif
+
+   bool bYMoveKey = false;
+   // Special keys
+   switch ( e->key() )
+   {
+      case  Qt::Key_Escape:       break;
+      //case  Key_Tab:          break;
+      case  Qt::Key_Backtab:      break;
+      case  Qt::Key_Delete:
+      {
+         if ( deleteSelection2( str, x, y, mlIt, melIt )) break;
+         if( !melIt->isEditableText() )  break;
+         if (x>=(int)str.length())
+         {
+            if ( y<m_totalSize-1 )
+            {
+               setModified();
+               MergeLineList::iterator mlIt1;
+               MergeEditLineList::iterator melIt1;
+               calcIteratorFromLineNr( y+1, mlIt1, melIt1 );
+               if ( melIt1->isEditableText() )
+               {
+                  QString s2 = melIt1->getString( this );
+                  melIt->setString( str + s2 );
+
+                  // Remove the line
+                  if ( mlIt1->mergeEditLineList.size()>1 )
+                     mlIt1->mergeEditLineList.erase( melIt1 );
+                  else
+                     melIt1->setRemoved();
+               }
+            }
+         }
+         else
+         {
+            QString s = str.left(x);
+            s += str.mid( x+1 );
+            melIt->setString( s );
+            setModified();
+         }
+         break;
+      }
+      case  Qt::Key_Backspace:
+      {
+         if ( deleteSelection2( str, x, y, mlIt, melIt )) break;
+         if( !melIt->isEditableText() )  break;
+         if (x==0)
+         {
+            if ( y>0 )
+            {
+               setModified();
+               MergeLineList::iterator mlIt1;
+               MergeEditLineList::iterator melIt1;
+               calcIteratorFromLineNr( y-1, mlIt1, melIt1 );
+               if ( melIt1->isEditableText() )
+               {
+                  QString s1 = melIt1->getString( this );
+                  melIt1->setString( s1 + str );
+
+                  // Remove the previous line
+                  if ( mlIt->mergeEditLineList.size()>1 )
+                     mlIt->mergeEditLineList.erase( melIt );
+                  else
+                     melIt->setRemoved();
+
+                  --y;
+                  x=str.length();
+               }
+            }
+         }
+         else
+         {
+            QString s = str.left( x-1 );
+            s += str.mid( x );
+            --x;
+            melIt->setString( s );
+            setModified();
+         }
+         break;
+      }
+      case  Qt::Key_Return:
+      case  Qt::Key_Enter:
+      {
+         if( !melIt->isEditableText() )  break;
+         deleteSelection2( str, x, y, mlIt, melIt );
+         setModified();
+         QString indentation;
+         if ( m_pOptionDialog->m_bAutoIndentation )
+         {  // calc last indentation
+            MergeLineList::iterator mlIt1 = mlIt;
+            MergeEditLineList::iterator melIt1 = melIt;
+            for(;;) {
+               const QString s = melIt1->getString(this);
+               if ( !s.isEmpty() ) {
+                  unsigned int i;
+                  for( i=0; i<s.length(); ++i ){ if(s[i]!=' ' && s[i]!='\t') break; }
+                  if (i<s.length()) {
+                     indentation = s.left(i);
+                     break;
+                  }
+               }
+               --melIt1;
+               if ( melIt1 == mlIt1->mergeEditLineList.end() ) {
+                  --mlIt1;
+                  if ( mlIt1 == m_mergeLineList.end() ) break;
+                  melIt1 = mlIt1->mergeEditLineList.end();
+                  --melIt1;
+               }
+            }
+         }
+         MergeEditLine mel(mlIt->id3l);  // Associate every mel with an id3l, even if not really valid.
+         mel.setString( indentation + str.mid(x) );
+
+         if ( x<(int)str.length() ) // Cut off the old line.
+         {
+            // Since ps possibly points into melIt->str, first copy it into a temporary.
+            QString temp = str.left(x);
+            melIt->setString( temp );
+         }
+
+         ++melIt;
+         mlIt->mergeEditLineList.insert( melIt, mel );
+         x = indentation.length();
+         ++y;
+         break;
+      }
+      case  Qt::Key_Insert:   m_bInsertMode = !m_bInsertMode;    break;
+      case  Qt::Key_Pause:        break;
+      case  Qt::Key_Print:        break;
+      case  Qt::Key_SysReq:       break;
+      case  Qt::Key_Home:     x=0;        if(bCtrl){y=0;      }  break;   // cursor movement
+      case  Qt::Key_End:      x=INT_MAX;  if(bCtrl){y=INT_MAX;}  break;
+
+      case  Qt::Key_Left:
+      case  Qt::Key_Right:
+         if ( (e->key()==Qt::Key_Left) ^ m_pOptionDialog->m_bRightToLeftLanguage ) // operator^: XOR
+         {
+            if ( !bCtrl )
+            {
+               --x;
+               if(x<0 && y>0){--y; x=INT_MAX;}
+            }
+            else
+            {
+               while( x>0  &&  (str[x-1]==' ' || str[x-1]=='\t') ) --x;
+               while( x>0  &&  (str[x-1]!=' ' && str[x-1]!='\t') ) --x;
+            }
+         }
+         else
+         {
+            if ( !bCtrl )
+            {
+               ++x;  if(x>(int)str.length() && y<m_totalSize-1){ ++y; x=0; }
+            }
+
+            else
+            {
+               while( x<(int)str.length()  &&  (str[x]==' ' || str[x]=='\t') ) ++x;
+               while( x<(int)str.length()  &&  (str[x]!=' ' && str[x]!='\t') ) ++x;
+            }
+         }
+         break;
+
+      case  Qt::Key_Up:       if (!bCtrl){ --y;                     bYMoveKey=true; }  break;
+      case  Qt::Key_Down:     if (!bCtrl){ ++y;                     bYMoveKey=true; }  break;
+      case  Qt::Key_PageUp:   if (!bCtrl){ y-=getNofVisibleLines(); bYMoveKey=true; }  break;
+      case  Qt::Key_PageDown: if (!bCtrl){ y+=getNofVisibleLines(); bYMoveKey=true; }  break;
+      default:
+      {
+         QString t = e->text();
+         if( t.isEmpty() || bCtrl )
+         {  e->ignore();       return; }
+         else
+         {
+            if( bCtrl )
+            {
+               e->ignore();       return;
+            }
+            else
+            {
+               if( !melIt->isEditableText() )  break;
+               deleteSelection2( str, x, y, mlIt, melIt );
+
+               setModified();
+               // Characters to insert
+               QString s=str;
+               if ( t[0]=='\t' && m_pOptionDialog->m_bReplaceTabs )
+               {
+                  int spaces = (m_cursorXPos / m_pOptionDialog->m_tabSize + 1)*m_pOptionDialog->m_tabSize - m_cursorXPos;
+                  t.fill( ' ', spaces );
+               }
+               if ( m_bInsertMode )
+                  s.insert( x, t );
+               else
+                  s.replace( x, t.length(), t );
+
+               melIt->setString( s );
+               x += t.length();
+               bShift = false;
+            }
+         }
+      }
+   }
+
+   y = minMaxLimiter( y, 0, m_totalSize-1 );
+
+   calcIteratorFromLineNr( y, mlIt, melIt );
+   str = melIt->getString( this );
+
+   x = minMaxLimiter( x, 0, (int)str.length() );
+
+   int newFirstLine = m_firstLine;
+   int newFirstColumn = m_firstColumn;
+
+   if ( y<m_firstLine )
+      newFirstLine = y;
+   else if ( y > m_firstLine + getNofVisibleLines() )
+      newFirstLine = y - getNofVisibleLines();
+
+   if (bYMoveKey)
+      x=convertToPosInText( str, m_cursorOldXPos, m_pOptionDialog->m_tabSize );
+
+   int xOnScreen = convertToPosOnScreen( str, x, m_pOptionDialog->m_tabSize );
+   if ( xOnScreen<m_firstColumn )
+      newFirstColumn = xOnScreen;
+   else if ( xOnScreen > m_firstColumn + getNofVisibleColumns() )
+      newFirstColumn = xOnScreen - getNofVisibleColumns();
+
+   if ( bShift )
+   {
+      if (m_selection.firstLine==-1)
+         m_selection.start( m_cursorYPos, m_cursorXPos );
+
+      m_selection.end( y, xOnScreen );
+   }
+   else
+      m_selection.reset();
+
+   m_cursorYPos = y;
+   m_cursorXPos = xOnScreen;
+   if ( ! bYMoveKey )
+      m_cursorOldXPos = m_cursorXPos;
+
+   m_bCursorOn = false;
+
+   if ( newFirstLine!=m_firstLine  ||  newFirstColumn!=m_firstColumn )
+   {
+      m_bCursorOn = true;
+      scroll( newFirstColumn-m_firstColumn, newFirstLine-m_firstLine );
+      return;
+   }
+
+   m_bCursorOn = true;
+   update();
+}
+
+void MergeResultWindow::calcIteratorFromLineNr(
+   int line,
+   MergeResultWindow::MergeLineList::iterator& mlIt,
+   MergeResultWindow::MergeEditLineList::iterator& melIt
+   )
+{
+   for( mlIt = m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      if ( line > ml.mergeEditLineList.size() )
+      {
+         line -= ml.mergeEditLineList.size();
+      }
+      else
+      {
+         for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+         {
+            --line;
+            if (line<0) return;
+         }
+      }
+   }
+   assert(false);
+}
+
+
+QString MergeResultWindow::getSelection()
+{
+   QString selectionString;
+
+   int line = 0;
+   MergeLineList::iterator mlIt = m_mergeLineList.begin();
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      MergeEditLineList::iterator melIt;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+      {
+         MergeEditLine& mel = *melIt;
+
+         if ( m_selection.lineWithin(line) )
+         {
+            int outPos = 0;
+            if (mel.isEditableText())
+            {
+               const QString str = mel.getString( this );
+
+               // Consider tabs
+
+               for( unsigned int i=0; i<str.length(); ++i )
+               {
+                  int spaces = 1;
+                  if ( str[i]=='\t' )
+                  {
+                     spaces = tabber( outPos, m_pOptionDialog->m_tabSize );
+                  }
+
+                  if( m_selection.within( line, outPos ) )
+                  {
+                     selectionString += str[i];
+                  }
+
+                  outPos += spaces;
+               }
+            }
+            else if ( mel.isConflict() )
+            {
+               selectionString += i18n("<Merge Conflict>");
+            }
+
+            if( m_selection.within( line, outPos ) )
+            {
+               #ifdef _WIN32
+               selectionString += '\r';
+               #endif
+               selectionString += '\n';
+            }
+         }
+
+         ++line;
+      }
+   }
+
+   return selectionString;
+}
+
+bool MergeResultWindow::deleteSelection2( QString& s, int& x, int& y,
+                MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt )
+{
+   if (m_selection.firstLine!=-1  &&  m_selection.bSelectionContainsData )
+   {
+      deleteSelection();
+      y = m_cursorYPos;
+      calcIteratorFromLineNr( y, mlIt, melIt );
+      s = melIt->getString( this );
+      x = convertToPosInText( s, m_cursorXPos, m_pOptionDialog->m_tabSize );
+      return true;
+   }
+   return false;
+}
+
+void MergeResultWindow::deleteSelection()
+{
+   if ( m_selection.firstLine==-1 ||  !m_selection.bSelectionContainsData )
+   {
+      return;
+   }
+   setModified();
+
+   int line = 0;
+   MergeLineList::iterator mlItFirst;
+   MergeEditLineList::iterator melItFirst;
+   QString firstLineString;
+
+   int firstLine = -1;
+   int lastLine = -1;
+
+   MergeLineList::iterator mlIt;
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      MergeEditLineList::iterator melIt;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+      {
+         MergeEditLine& mel = *melIt;
+
+         if ( mel.isEditableText()  &&  m_selection.lineWithin(line) )
+         {
+            if ( firstLine==-1 )
+               firstLine = line;
+            lastLine = line;
+         }
+
+         ++line;
+      }
+   }
+
+   if ( firstLine == -1 )
+   {
+      return; // Nothing to delete.
+   }
+
+   line = 0;
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      MergeEditLineList::iterator melIt, melIt1;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); )
+      {
+         MergeEditLine& mel = *melIt;
+         melIt1 = melIt;
+         ++melIt1;
+
+         if ( mel.isEditableText()  &&  m_selection.lineWithin(line) )
+         {
+            QString lineString = mel.getString( this );
+
+            int firstPosInLine = m_selection.firstPosInLine(line);
+            int lastPosInLine = m_selection.lastPosInLine(line);
+
+            if ( line==firstLine )
+            {
+               mlItFirst = mlIt;
+               melItFirst = melIt;
+               int pos = convertToPosInText( lineString, firstPosInLine, m_pOptionDialog->m_tabSize );
+               firstLineString = lineString.left( pos );
+            }
+
+            if ( line==lastLine )
+            {
+               // This is the last line in the selection
+               int pos = convertToPosInText( lineString, lastPosInLine, m_pOptionDialog->m_tabSize );
+               firstLineString += lineString.mid( pos ); // rest of line
+               melItFirst->setString( firstLineString );
+            }
+
+            if ( line!=firstLine )
+            {
+               // Remove the line
+               if ( mlIt->mergeEditLineList.size()>1 )
+                  mlIt->mergeEditLineList.erase( melIt );
+               else
+                  melIt->setRemoved();
+            }
+         }
+
+         ++line;
+         melIt = melIt1;
+      }
+   }
+
+   m_cursorYPos = m_selection.beginLine();
+   m_cursorXPos = m_selection.beginPos();
+   m_cursorOldXPos = m_cursorXPos;
+
+   m_selection.reset();
+}
+
+void MergeResultWindow::pasteClipboard( bool bFromSelection )
+{
+   if (m_selection.firstLine != -1 )
+      deleteSelection();
+
+   setModified();
+
+   int y = m_cursorYPos;
+   MergeLineList::iterator mlIt;
+   MergeEditLineList::iterator melIt, melItAfter;
+   calcIteratorFromLineNr( y, mlIt, melIt );
+   melItAfter = melIt;
+   ++melItAfter;
+   QString str = melIt->getString( this );
+   int x = convertToPosInText( str, m_cursorXPos, m_pOptionDialog->m_tabSize );
+
+   if ( !QApplication::clipboard()->supportsSelection() )
+      bFromSelection = false;
+
+   QString clipBoard = QApplication::clipboard()->text( bFromSelection ? QClipboard::Selection : QClipboard::Clipboard );
+
+   QString currentLine = str.left(x);
+   QString endOfLine = str.mid(x);
+   int i;
+   int len = clipBoard.length();
+   for( i=0; i<len; ++i )
+   {
+      QChar c = clipBoard[i];
+      if ( c == '\r' ) continue;
+      if ( c == '\n' )
+      {
+         melIt->setString( currentLine );
+         MergeEditLine mel(mlIt->id3l); // Associate every mel with an id3l, even if not really valid.
+         melIt = mlIt->mergeEditLineList.insert( melItAfter, mel );
+         currentLine = "";
+         x=0;
+         ++y;
+      }
+      else
+      {
+         currentLine += c;
+         ++x;
+      }
+   }
+
+   currentLine += endOfLine;
+   melIt->setString( currentLine );
+
+   m_cursorYPos = y;
+   m_cursorXPos = convertToPosOnScreen( currentLine, x, m_pOptionDialog->m_tabSize );
+   m_cursorOldXPos = m_cursorXPos;
+
+   update();
+}
+
+void MergeResultWindow::resetSelection()
+{
+   m_selection.reset();
+   update();
+}
+
+void MergeResultWindow::setModified(bool bModified)
+{
+   if (bModified != m_bModified)
+   {
+      m_bModified = bModified;
+      emit modifiedChanged(m_bModified);
+   }
+}
+
+/// Saves and returns true when successful.
+bool MergeResultWindow::saveDocument( const QString& fileName, QTextCodec* pEncoding )
+{
+   // Are still conflicts somewhere?
+   if ( getNrOfUnsolvedConflicts()>0 )
+   {
+      KMessageBox::error( this,
+         i18n("Not all conflicts are solved yet.\n"
+              "File not saved.\n"),
+         i18n("Conflicts Left"));
+      return false;
+   }
+
+   update();
+
+   FileAccess file( fileName, true /*bWantToWrite*/ );
+   if ( m_pOptionDialog->m_bDmCreateBakFiles && file.exists() )
+   {
+      bool bSuccess = file.createBackup(".orig");
+      if ( !bSuccess )
+      {
+         KMessageBox::error( this, file.getStatusText() + i18n("\n\nCreating backup failed. File not saved."), i18n("File Save Error") );
+         return false;
+      }
+   }
+
+   QByteArray dataArray;
+   QTextStream textOutStream(dataArray, IO_WriteOnly);
+   textOutStream.setCodec( pEncoding );
+
+   int line = 0;
+   MergeLineList::iterator mlIt = m_mergeLineList.begin();
+   for(mlIt = m_mergeLineList.begin();mlIt!=m_mergeLineList.end(); ++mlIt)
+   {
+      MergeLine& ml = *mlIt;
+      MergeEditLineList::iterator melIt;
+      for( melIt = ml.mergeEditLineList.begin(); melIt != ml.mergeEditLineList.end(); ++melIt )
+      {
+         MergeEditLine& mel = *melIt;
+
+         if ( mel.isEditableText() )
+         {
+            QString str = mel.getString( this );
+
+            if (line>0) // Prepend line feed, but not for first line
+            {
+               if ( m_pOptionDialog->m_lineEndStyle == eLineEndDos )
+               {   str.prepend("\r\n"); }
+               else
+               {   str.prepend("\n");   }
+            }
+
+            textOutStream << str;
+         }
+
+         ++line;
+      }
+   }
+   bool bSuccess = file.writeFile( dataArray.data(), dataArray.size() );
+   if ( ! bSuccess )
+   {
+      KMessageBox::error( this, i18n("Error while writing."), i18n("File Save Error") );
+      return false;
+   }
+
+   setModified( false );
+   update();
+
+   return true;
+}
+
+QString MergeResultWindow::getString( int lineIdx )
+{
+   MergeResultWindow::MergeLineList::iterator mlIt;
+   MergeResultWindow::MergeEditLineList::iterator melIt;
+   calcIteratorFromLineNr( lineIdx, mlIt, melIt );
+   QString s = melIt->getString( this );
+   return s;
+}
+
+bool MergeResultWindow::findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive )
+{
+   int it = d3vLine;
+   int endIt = bDirDown ? getNofLines() : -1;
+   int step =  bDirDown ? 1 : -1;
+   int startPos = posInLine;
+
+   for( ; it!=endIt; it+=step )
+   {
+      QString line = getString( it );
+      if ( !line.isEmpty() )
+      {
+         int pos = line.find( s, startPos, bCaseSensitive );
+         if ( pos != -1 )
+         {
+            d3vLine = it;
+            posInLine = pos;
+            return true;
+         }
+
+         startPos = 0;
+      }
+   }
+   return false;
+}
+
+void MergeResultWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos )
+{
+   if ( lastLine >= getNofLines() )
+   {
+      lastLine = getNofLines()-1;
+      QString s = getString( lastLine );
+      endPos = s.length();
+   }
+   m_selection.reset();
+   m_selection.start( firstLine, convertToPosOnScreen( getString(firstLine), startPos, m_pOptionDialog->m_tabSize ) );
+   m_selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos, m_pOptionDialog->m_tabSize ) );
+   update();
+}
+
+Overview::Overview( QWidget* pParent, OptionDialog* pOptions )
+: QWidget( pParent, 0, WRepaintNoErase )
+{
+   m_pDiff3LineList = 0;
+   m_pOptions = pOptions;
+   m_bTripleDiff = false;
+   m_eOverviewMode = eOMNormal;
+   m_nofLines = 1;
+   m_bPaintingAllowed = false;
+   setFixedWidth(20);
+}
+
+void Overview::init( Diff3LineList* pDiff3LineList, bool bTripleDiff )
+{
+   m_pDiff3LineList = pDiff3LineList;
+   m_bTripleDiff = bTripleDiff;
+   m_pixmap.resize( QSize(0,0) );   // make sure that a redraw happens
+   update();
+}
+
+void Overview::reset()
+{
+   m_pDiff3LineList = 0;
+}
+
+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;
+   m_pageHeight = pageHeight;
+   update();
+}
+void Overview::setFirstLine( int firstLine )
+{
+   m_firstLine = firstLine;
+   update();
+}
+
+void Overview::setOverviewMode( e_OverviewMode eOverviewMode )
+{
+   m_eOverviewMode = eOverviewMode;
+   slotRedraw();
+}
+
+Overview::e_OverviewMode Overview::getOverviewMode()
+{
+   return m_eOverviewMode;
+}
+
+void Overview::mousePressEvent( QMouseEvent* e )
+{
+   int h = height()-1;
+   int h1 = h * m_pageHeight / max2(1,m_nofLines)+3;
+   if ( h>0 )
+      emit setLine( ( e->y() - h1/2 )*m_nofLines/h );
+}
+
+void Overview::mouseMoveEvent( QMouseEvent* e )
+{
+   mousePressEvent(e);
+}
+
+void Overview::setPaintingAllowed( bool bAllowPainting )
+{
+   if (m_bPaintingAllowed != bAllowPainting)
+   {
+      m_bPaintingAllowed = bAllowPainting;
+      if ( m_bPaintingAllowed ) update();
+      else reset();
+   }
+}
+
+void Overview::drawColumn( QPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines )
+{
+   p.setPen(Qt::black);
+   p.drawLine( x, 0, x, h );
+
+   if (nofLines==0) return;
+   
+   int line = 0;
+   int oldY = 0;
+   int oldConflictY = -1;
+   int wrapLineIdx=0;
+   Diff3LineList::const_iterator i;
+   for( i = m_pDiff3LineList->begin(); i!= m_pDiff3LineList->end();  )
+   {
+      const Diff3Line& d3l = *i;
+      int y = h * (line+1) / nofLines;
+      e_MergeDetails md;
+      bool bConflict;
+      bool bLineRemoved;
+      int src;
+      mergeOneLine( d3l, md, bConflict, bLineRemoved, src, !m_bTripleDiff );
+
+      QColor c = m_pOptions->m_bgColor;
+      bool bWhiteSpaceChange = false;
+      //if( bConflict )  c=m_pOptions->m_colorForConflict;
+      //else
+      if ( eOverviewMode==eOMNormal )
+      {
+         switch( md )
+         {
+         case eDefault:
+         case eNoChange:
+                        c = m_pOptions->m_bgColor;
+                        break;
+
+         case eBAdded:
+         case eBDeleted:
+         case eBChanged:
+                        c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorB;
+                        bWhiteSpaceChange = d3l.bAEqB || d3l.bWhiteLineA && d3l.bWhiteLineB;
+                        break;
+
+         case eCAdded:
+         case eCDeleted:
+         case eCChanged:
+                        bWhiteSpaceChange = d3l.bAEqC || d3l.bWhiteLineA && d3l.bWhiteLineC;
+                        c = bConflict ? m_pOptions->m_colorForConflict : m_pOptions->m_colorC;
+                        break;
+
+         case eBCChanged:         // conflict
+         case eBCChangedAndEqual: // possible conflict
+         case eBCDeleted:         // possible conflict
+         case eBChanged_CDeleted: // conflict
+         case eCChanged_BDeleted: // conflict
+         case eBCAdded:           // conflict
+         case eBCAddedAndEqual:   // possible conflict
+                     c=m_pOptions->m_colorForConflict;
+                     break;
+         default: assert(false); break;
+         }
+      }
+      else if ( eOverviewMode==eOMAvsB )
+      {
+         switch( md )
+         {
+         case eDefault:
+         case eNoChange:
+         case eCAdded:
+         case eCDeleted:
+         case eCChanged:  break;
+         default:         c = m_pOptions->m_colorForConflict;
+                          bWhiteSpaceChange = d3l.bAEqB || d3l.bWhiteLineA && d3l.bWhiteLineB;
+                          break;
+         }
+      }
+      else if ( eOverviewMode==eOMAvsC )
+      {
+         switch( md )
+         {
+         case eDefault:
+         case eNoChange:
+         case eBAdded:
+         case eBDeleted:
+         case eBChanged:  break;
+         default:         c = m_pOptions->m_colorForConflict;
+                          bWhiteSpaceChange = d3l.bAEqC || d3l.bWhiteLineA && d3l.bWhiteLineC;
+                          break;
+         }
+      }
+      else if ( eOverviewMode==eOMBvsC )
+      {
+         switch( md )
+         {
+         case eDefault:
+         case eNoChange:
+         case eBCChangedAndEqual:
+         case eBCDeleted:      
+         case eBCAddedAndEqual:   break;
+         default:                 c=m_pOptions->m_colorForConflict;
+                                  bWhiteSpaceChange = d3l.bBEqC || d3l.bWhiteLineB && d3l.bWhiteLineC;
+                                  break;
+         }
+      }
+
+      if (!bWhiteSpaceChange || m_pOptions->m_bShowWhiteSpace )
+      {
+         // Make sure that lines with conflict are not overwritten.
+         if (  c == m_pOptions->m_colorForConflict )
+         {
+            p.fillRect(x+1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Qt::Dense4Pattern) : QBrush(c) );
+            oldConflictY = oldY;
+         }
+         else if ( c!=m_pOptions->m_bgColor  &&  oldY>oldConflictY )
+         {
+            p.fillRect(x+1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Qt::Dense4Pattern) : QBrush(c) );
+         }
+      }
+
+      oldY = y;
+
+      ++line;
+      if ( m_pOptions->m_bWordWrap )
+      {
+         ++wrapLineIdx;
+         if(wrapLineIdx>=d3l.linesNeededForDisplay)
+         {
+            wrapLineIdx=0;
+            ++i;
+         }
+      }
+      else
+      {
+         ++i;
+      }
+   }
+}
+
+void Overview::paintEvent( QPaintEvent* )
+{
+   if (m_pDiff3LineList==0 || !m_bPaintingAllowed ) return;
+   int h = height()-1;
+   int w = width();
+   
+
+   if ( m_pixmap.size() != size() )
+   {
+      if ( m_pOptions->m_bWordWrap )
+      {
+         m_nofLines = 0;
+         Diff3LineList::const_iterator i;
+         for( i = m_pDiff3LineList->begin(); i!= m_pDiff3LineList->end(); ++i )
+         {
+            m_nofLines += i->linesNeededForDisplay;
+         }
+      }
+      else
+      {
+         m_nofLines = m_pDiff3LineList->size();
+      }
+   
+      m_pixmap.resize( size() );
+
+      QPainter p(&m_pixmap);
+      p.fillRect( rect(), m_pOptions->m_bgColor );
+
+      if ( !m_bTripleDiff || m_eOverviewMode == eOMNormal )
+      {
+         drawColumn( p, eOMNormal, 0, w, h, m_nofLines );
+      }
+      else
+      {
+         drawColumn( p, eOMNormal, 0, w/2, h, m_nofLines );
+         drawColumn( p, m_eOverviewMode, w/2, w/2, h, m_nofLines );
+      }
+   }
+
+   QPainter painter( this );
+   painter.drawPixmap( 0,0, m_pixmap );
+
+   int y1 = h * m_firstLine / m_nofLines-1;
+   int h1 = h * m_pageHeight / m_nofLines+3;
+   painter.setPen(Qt::black);
+   painter.drawRect( 1, y1, w-1, h1 );
+}
+
+WindowTitleWidget::WindowTitleWidget(OptionDialog* pOptionDialog, QWidget* pParent)
+:QWidget(pParent)
+{
+   m_pOptionDialog = pOptionDialog;
+   //setAutoFillBackground(true);
+
+   QHBoxLayout* pHLayout = new QHBoxLayout(this);
+   pHLayout->setMargin(2);
+   pHLayout->setSpacing(2);
+
+   m_pLabel = new QLabel(i18n("Output")+":", this);
+   pHLayout->addWidget( m_pLabel );
+
+   m_pFileNameLineEdit = new QLineEdit(this);
+   pHLayout->addWidget( m_pFileNameLineEdit, 6 );
+   m_pFileNameLineEdit->installEventFilter( this );
+   m_pFileNameLineEdit->setReadOnly( true );
+
+   //m_pBrowseButton = new QPushButton("...");
+   //pHLayout->addWidget( m_pBrowseButton, 0 );
+   //connect( m_pBrowseButton, SIGNAL(clicked()), this, SLOT(slotBrowseButtonClicked()));
+
+   m_pModifiedLabel = new QLabel(i18n("[Modified]"),this);
+   pHLayout->addWidget( m_pModifiedLabel );
+   m_pModifiedLabel->setMinimumSize( m_pModifiedLabel->sizeHint() );
+   m_pModifiedLabel->setText("");
+
+   pHLayout->addStretch(1);
+
+   m_pEncodingLabel = new QLabel(i18n("Encoding for saving")+":",this);
+   pHLayout->addWidget( m_pEncodingLabel );
+
+   m_pEncodingSelector = new QComboBox(this);
+   pHLayout->addWidget( m_pEncodingSelector, 3 );
+   setEncodings(0,0,0);
+}
+
+void WindowTitleWidget::setFileName( const QString& fileName )
+{
+   m_pFileNameLineEdit->setText( QDir::convertSeparators(fileName) );
+}
+
+QString WindowTitleWidget::getFileName()
+{
+   return m_pFileNameLineEdit->text();
+}
+
+void WindowTitleWidget::setEncodings( QTextCodec* pCodecForA, QTextCodec* pCodecForB, QTextCodec* pCodecForC )
+{
+   m_pEncodingSelector->clear();
+   m_codecMap.clear();
+
+   // First sort codec names:
+   std::map<QString, QTextCodec*> names;
+   int i;
+   for(i=0;;++i)
+   {
+       QTextCodec* c = QTextCodec::codecForIndex(i);
+       if ( c==0 ) break;
+       else  names[QString(c->name())]=c;
+   }
+
+   i=0;
+   if ( pCodecForA )
+   {
+      m_pEncodingSelector->insertItem( i18n("Codec from") + " A: " + pCodecForA->name(), i );
+      m_codecMap[i]=pCodecForA;
+      ++i;
+   }
+   if ( pCodecForB )
+   {
+      m_pEncodingSelector->insertItem( i18n("Codec from") + " B: " + pCodecForB->name(), i );
+      m_codecMap[i]=pCodecForB;
+      ++i;
+   }
+   if ( pCodecForC )
+   {
+      m_pEncodingSelector->insertItem( i18n("Codec from") + " C: " + pCodecForC->name(), i );
+      m_codecMap[i]=pCodecForC;
+      ++i;
+   }
+
+   std::map<QString, QTextCodec*>::iterator it;
+   for(it=names.begin();it!=names.end();++it)
+   {
+      m_pEncodingSelector->insertItem( it->first, i );
+      m_codecMap[i]=it->second;
+      ++i;
+   }
+   m_pEncodingSelector->setMinimumSize( m_pEncodingSelector->sizeHint() );
+
+   if ( pCodecForC && pCodecForB && pCodecForA )
+   {
+      if ( pCodecForA == pCodecForB )
+         m_pEncodingSelector->setCurrentItem( 2 ); // C
+      else if ( pCodecForA == pCodecForC )
+         m_pEncodingSelector->setCurrentItem( 1 ); // B
+      else
+         m_pEncodingSelector->setCurrentItem( 2 ); // C
+   }
+   else if ( pCodecForA && pCodecForB )
+      m_pEncodingSelector->setCurrentItem( 1 ); // B
+   else
+      m_pEncodingSelector->setCurrentItem( 0 );
+}
+
+QTextCodec* WindowTitleWidget::getEncoding()
+{
+   return m_codecMap[ m_pEncodingSelector->currentItem() ];
+}
+
+void WindowTitleWidget::setEncoding(QTextCodec* pEncoding)
+{
+   m_pEncodingSelector->setCurrentText( QString( pEncoding->name() ) );
+}
+
+//void WindowTitleWidget::slotBrowseButtonClicked()
+//{
+//   QString current = m_pFileNameLineEdit->text();
+//
+//   KURL newURL = KFileDialog::getSaveURL( current, 0, this, i18n("Select file (not saving yet)"));
+//   if ( !newURL.isEmpty() )
+//   {
+//      m_pFileNameLineEdit->setText( newURL.url() ); 
+//   }
+//}
+
+void WindowTitleWidget::slotSetModified( bool bModified )
+{
+   m_pModifiedLabel->setText( bModified ? i18n("[Modified]") : "" );
+}
+
+bool WindowTitleWidget::eventFilter( QObject* o, QEvent* e )
+{
+   if ( e->type()==QEvent::FocusIn || e->type()==QEvent::FocusOut )
+   {
+      QPalette p = m_pLabel->palette();
+
+      QColor c1 = m_pOptionDialog->m_fgColor;
+      QColor c2 = Qt::lightGray;
+      if ( e->type()==QEvent::FocusOut )
+         c2 = m_pOptionDialog->m_bgColor;
+
+      p.setColor(QColorGroup::Background, c2);
+      setPalette( p );
+
+      p.setColor(QColorGroup::Foreground, c1);
+      m_pLabel->setPalette( p );
+      m_pEncodingLabel->setPalette( p );
+      m_pEncodingSelector->setPalette( p );
+   }
+   if (o == m_pFileNameLineEdit && e->type()==QEvent::Drop)
+   {
+      QDropEvent* d = static_cast<QDropEvent*>(e);
+
+      if ( QUriDrag::canDecode( d ) ) 
+      {
+         QStringList lst;
+         QUriDrag::decodeLocalFiles( d, lst );
+
+         if ( lst.count() > 0 )
+         {
+            static_cast<QLineEdit*>(o)->setText( lst[0] );
+            static_cast<QLineEdit*>(o)->setFocus();
+            return true;
+         }
+      }
+   }
+   return false;
+}
+
+#include "mergeresultwindow.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/mergeresultwindow.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,444 @@
+/***************************************************************************
+                          mergeresultwindow.h  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002-2006 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef MERGERESULTWINDOW_H
+#define MERGERESULTWINDOW_H
+
+#include "diff.h"
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+
+class QPainter;
+
+class Overview : public QWidget
+{
+   Q_OBJECT
+public:
+   Overview( QWidget* pParent, OptionDialog* pOptions );
+
+   void init( Diff3LineList* pDiff3LineList, bool bTripleDiff );
+   void reset();
+   void setRange( int firstLine, int pageHeight );
+   void setPaintingAllowed( bool bAllowPainting );
+
+   enum e_OverviewMode { eOMNormal, eOMAvsB, eOMAvsC, eOMBvsC };
+   void setOverviewMode( e_OverviewMode eOverviewMode );
+   e_OverviewMode getOverviewMode();
+
+public slots:
+   void setFirstLine(int firstLine);
+   void slotRedraw();
+signals:
+   void setLine(int);
+private:
+   const Diff3LineList* m_pDiff3LineList;
+   OptionDialog* m_pOptions;
+   bool m_bTripleDiff;
+   int m_firstLine;
+   int m_pageHeight;
+   QPixmap m_pixmap;
+   bool m_bPaintingAllowed;
+   e_OverviewMode m_eOverviewMode;
+   int m_nofLines;
+
+   virtual void paintEvent( QPaintEvent* e );
+   virtual void mousePressEvent( QMouseEvent* e );
+   virtual void mouseMoveEvent( QMouseEvent* e );
+   void drawColumn( QPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines );
+};
+
+
+enum e_MergeDetails
+{
+   eDefault,
+   eNoChange,
+   eBChanged,
+   eCChanged,
+   eBCChanged,         // conflict
+   eBCChangedAndEqual, // possible conflict
+   eBDeleted,
+   eCDeleted,
+   eBCDeleted,         // possible conflict
+
+   eBChanged_CDeleted, // conflict
+   eCChanged_BDeleted, // conflict
+   eBAdded,
+   eCAdded,
+   eBCAdded,           // conflict
+   eBCAddedAndEqual    // possible conflict
+};
+
+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
+{
+   Q_OBJECT
+public:
+   MergeResultWindow(
+      QWidget* pParent,
+      OptionDialog* pOptionDialog,
+      QStatusBar* pStatusBar
+      );
+
+   void init(
+      const LineData* pLineDataA, int sizeA,
+      const LineData* pLineDataB, int sizeB,
+      const LineData* pLineDataC, int sizeC,
+      const Diff3LineList* pDiff3LineList,
+      TotalDiffStatus* pTotalDiffStatus
+      );
+
+   void reset();
+
+   bool saveDocument( const QString& fileName, QTextCodec* pEncoding );
+   int getNrOfUnsolvedConflicts(int* pNrOfWhiteSpaceConflicts=0);
+   void choose(int selector);
+   void chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly );
+
+   int getNofColumns();
+   int getNofLines();
+   int getNofVisibleColumns();
+   int getNofVisibleLines();
+   QString getSelection();
+   void resetSelection();
+   void showNrOfConflicts();
+   bool isDeltaAboveCurrent();
+   bool isDeltaBelowCurrent();
+   bool isConflictAboveCurrent();
+   bool isConflictBelowCurrent();
+   bool isUnsolvedConflictAboveCurrent();
+   bool isUnsolvedConflictBelowCurrent();
+   bool findString( const QString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive );
+   void setSelection( int firstLine, int startPos, int lastLine, int endPos );
+   void setOverviewMode( Overview::e_OverviewMode eOverviewMode );
+   Overview::e_OverviewMode getOverviewMode();
+public slots:
+   void setFirstLine(int firstLine);
+   void setFirstColumn(int firstCol);
+
+   void slotGoCurrent();
+   void slotGoTop();
+   void slotGoBottom();
+   void slotGoPrevDelta();
+   void slotGoNextDelta();
+   void slotGoPrevUnsolvedConflict();
+   void slotGoNextUnsolvedConflict();
+   void slotGoPrevConflict();
+   void slotGoNextConflict();
+   void slotAutoSolve();
+   void slotUnsolve();
+   void slotMergeHistory();
+   void slotRegExpAutoMerge();
+   void slotSplitDiff( int firstD3lLineIdx, int lastD3lLineIdx );
+   void slotJoinDiffs( int firstD3lLineIdx, int lastD3lLineIdx );
+   void slotSetFastSelectorLine(int);
+   void setPaintingAllowed(bool);
+   void updateSourceMask();
+
+signals:
+   void scroll( int deltaX, int deltaY );
+   void modifiedChanged(bool bModified);
+   void setFastSelectorRange( int line1, int nofLines );
+   void sourceMask( int srcMask, int enabledMask );
+   void resizeSignal();
+   void selectionEnd();
+   void newSelection();
+   void updateAvailabilities();
+   void showPopupMenu( const QPoint& point );
+   void noRelevantChangesDetected();
+
+private:
+   void merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly=false, bool bWhiteSpaceOnly=false );
+   QString getString( int lineIdx );
+
+   OptionDialog* m_pOptionDialog;
+
+   const LineData* m_pldA;
+   const LineData* m_pldB;
+   const LineData* m_pldC;
+   int m_sizeA;
+   int m_sizeB;
+   int m_sizeC;
+
+   const Diff3LineList* m_pDiff3LineList;
+   TotalDiffStatus* m_pTotalDiffStatus;
+
+   bool m_bPaintingAllowed;
+   int m_delayedDrawTimer;
+   Overview::e_OverviewMode m_eOverviewMode;
+
+private:
+   class MergeEditLine
+   {
+   public:
+      MergeEditLine(Diff3LineList::const_iterator i, int src=0){m_id3l=i; m_src=src; m_bLineRemoved=false; }
+      void setConflict() { m_src=0; m_bLineRemoved=false; m_str=QString(); }
+      bool isConflict()  { return  m_src==0 && !m_bLineRemoved && m_str.isNull(); }
+      void setRemoved(int src=0)  { m_src=src; m_bLineRemoved=true; m_str=QString(); }
+      bool isRemoved()   { return m_bLineRemoved; }
+      bool isEditableText() { return !isConflict() && !isRemoved(); }
+      void setString( const QString& s ){ m_str=s; m_bLineRemoved=false; m_src=0; }
+      QString getString( const MergeResultWindow* );
+      bool isModified() { return ! m_str.isNull() ||  (m_bLineRemoved && m_src==0); }
+
+      void setSource( int src, bool bLineRemoved ) { m_src=src; m_bLineRemoved =bLineRemoved; }
+      int src() { return m_src; }
+      Diff3LineList::const_iterator id3l(){return m_id3l;}
+      // getString() is implemented as MergeResultWindow::getString()
+   private:
+      Diff3LineList::const_iterator m_id3l;
+      int m_src;         // 1, 2 or 3 for A, B or C respectively, or 0 when line is from neither source.
+      QString m_str;    // String when modified by user or null-string when orig data is used.
+      bool m_bLineRemoved;
+   };
+
+   class MergeEditLineList : private std::list<MergeEditLine>
+   { // I want to know the size immediately!
+   private:
+      typedef std::list<MergeEditLine> BASE;
+      int m_size;
+      int* m_pTotalSize;
+   public:
+      typedef std::list<MergeEditLine>::iterator iterator;
+      typedef std::list<MergeEditLine>::const_iterator const_iterator;
+      MergeEditLineList(){m_size=0; m_pTotalSize=0; }
+      void clear()                             { ds(-m_size); BASE::clear();          }
+      void push_back( const MergeEditLine& m)  { ds(+1); BASE::push_back(m);     }
+      void push_front( const MergeEditLine& m) { ds(+1); BASE::push_front(m);    }
+      iterator erase( iterator i )             { ds(-1); return BASE::erase(i);  }
+      iterator insert( iterator i, const MergeEditLine& m ) { ds(+1); return BASE::insert(i,m); }
+      int size(){ if (!m_pTotalSize) m_size = BASE::size(); return m_size; }
+      iterator begin(){return BASE::begin();}
+      iterator end(){return BASE::end();}
+      MergeEditLine& front(){return BASE::front();}
+      MergeEditLine& back(){return BASE::back();}
+      bool empty() { return m_size==0; }
+      void splice(iterator destPos, MergeEditLineList& srcList, iterator srcFirst, iterator srcLast)
+      {
+         int* pTotalSize = getTotalSizePtr() ? getTotalSizePtr() : srcList.getTotalSizePtr();
+         srcList.setTotalSizePtr(0); // Force size-recalc after splice, because splice doesn't handle size-tracking
+         setTotalSizePtr(0);
+         BASE::splice( destPos, srcList, srcFirst, srcLast );
+         srcList.setTotalSizePtr( pTotalSize );
+         setTotalSizePtr( pTotalSize );
+      }
+
+      void setTotalSizePtr(int* pTotalSize)
+      {
+         if ( pTotalSize==0 && m_pTotalSize!=0 ) { *m_pTotalSize -= size(); }
+         else if ( pTotalSize!=0 && m_pTotalSize==0 ) { *pTotalSize += size(); }
+         m_pTotalSize = pTotalSize;
+      }
+      int* getTotalSizePtr()
+      {
+         return m_pTotalSize;
+      }
+
+   private:
+      void ds(int deltaSize) 
+      {
+         m_size+=deltaSize; 
+         if (m_pTotalSize!=0)  *m_pTotalSize+=deltaSize;
+      }
+   };
+
+   friend class MergeEditLine;
+
+   struct MergeLine
+   {
+      MergeLine()
+      {
+         srcSelect=0; mergeDetails=eDefault; d3lLineIdx = -1; srcRangeLength=0;
+         bConflict=false; bDelta=false; bWhiteSpaceConflict=false;
+      }
+      Diff3LineList::const_iterator id3l;
+      int d3lLineIdx;  // Needed to show the correct window pos.
+      int srcRangeLength; // how many src-lines have this properties
+      e_MergeDetails mergeDetails;
+      bool bConflict;
+      bool bWhiteSpaceConflict;
+      bool bDelta;
+      int srcSelect;
+      MergeEditLineList mergeEditLineList;
+      void split( MergeLine& ml2, int d3lLineIdx2 ) // The caller must insert the ml2 after this ml in the m_mergeLineList
+      {
+         if ( d3lLineIdx2<d3lLineIdx || d3lLineIdx2 >= d3lLineIdx + srcRangeLength ) 
+            return; //Error
+         ml2.mergeDetails = mergeDetails;
+         ml2.bConflict = bConflict;
+         ml2.bWhiteSpaceConflict = bWhiteSpaceConflict;
+         ml2.bDelta = bDelta;
+         ml2.srcSelect = srcSelect;
+
+         ml2.d3lLineIdx = d3lLineIdx2;
+         ml2.srcRangeLength = srcRangeLength - (d3lLineIdx2-d3lLineIdx);
+         srcRangeLength = d3lLineIdx2-d3lLineIdx; // current MergeLine controls fewer lines
+         ml2.id3l = id3l;
+         for(int i=0; i<srcRangeLength; ++i)
+            ++ml2.id3l;
+
+         ml2.mergeEditLineList.clear();
+         // Search for best place to splice
+         for(MergeEditLineList::iterator i=mergeEditLineList.begin(); i!=mergeEditLineList.end();++i)
+         {
+            if (i->id3l()==ml2.id3l)
+            {
+               ml2.mergeEditLineList.splice( ml2.mergeEditLineList.begin(), mergeEditLineList, i, mergeEditLineList.end() );
+               return;
+            }
+         }
+         ml2.mergeEditLineList.setTotalSizePtr( mergeEditLineList.getTotalSizePtr() );
+         ml2.mergeEditLineList.push_back(MergeEditLine(ml2.id3l));
+      }
+      void join( MergeLine& ml2 ) // The caller must remove the ml2 from the m_mergeLineList after this call
+      {
+         srcRangeLength += ml2.srcRangeLength;
+         ml2.mergeEditLineList.clear();
+         mergeEditLineList.clear();
+         mergeEditLineList.push_back(MergeEditLine(id3l)); // Create a simple conflict
+         if ( ml2.bConflict ) bConflict = true;
+         if ( !ml2.bWhiteSpaceConflict ) bWhiteSpaceConflict = false;
+         if ( ml2.bDelta ) bDelta = true;
+      }
+   };
+
+private:
+   static bool sameKindCheck( const MergeLine& ml1, const MergeLine& ml2 );
+   struct HistoryMapEntry
+   {
+      MergeEditLineList mellA;
+      MergeEditLineList mellB;
+      MergeEditLineList mellC;
+      MergeEditLineList& choice( bool bThreeInputs );
+      bool staysInPlace( bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd );
+   };
+   typedef std::map<QString,HistoryMapEntry> HistoryMap;
+   void collectHistoryInformation( int src, Diff3LineList::const_iterator iHistoryBegin, Diff3LineList::const_iterator iHistoryEnd, HistoryMap& historyMap, std::list< HistoryMap::iterator >& hitList );
+
+   typedef std::list<MergeLine> MergeLineList;
+   MergeLineList m_mergeLineList;
+   MergeLineList::iterator m_currentMergeLineIt;
+   int m_currentPos;
+   bool checkOverviewIgnore(MergeLineList::iterator &i);
+
+   enum e_Direction { eUp, eDown };
+   enum e_EndPoint  { eDelta, eConflict, eUnsolvedConflict, eLine, eEnd };
+   void go( e_Direction eDir, e_EndPoint eEndPoint );
+   void calcIteratorFromLineNr(
+      int line,
+      MergeLineList::iterator& mlIt,
+      MergeEditLineList::iterator& melIt
+      );
+   MergeLineList::iterator splitAtDiff3LineIdx( int d3lLineIdx );
+
+   virtual void paintEvent( QPaintEvent* e );
+
+
+   void myUpdate(int afterMilliSecs);
+   virtual void timerEvent(QTimerEvent*);
+   void writeLine(
+      MyPainter& p, int line, const QString& str,
+      int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict
+      );
+   void setFastSelector(MergeLineList::iterator i);
+   void convertToLinePos( int x, int y, int& line, int& pos );
+   virtual void mousePressEvent ( QMouseEvent* e );
+   virtual void mouseDoubleClickEvent ( QMouseEvent* e );
+   virtual void mouseReleaseEvent ( QMouseEvent * );
+   virtual void mouseMoveEvent ( QMouseEvent * );
+   virtual void resizeEvent( QResizeEvent* e );
+   virtual void keyPressEvent( QKeyEvent* e );
+   virtual void wheelEvent( QWheelEvent* e );
+   virtual void focusInEvent( QFocusEvent* e );
+   virtual bool focusNextPrevChild(bool){return false;}
+
+   QPixmap m_pixmap;
+   int m_firstLine;
+   int m_firstColumn;
+   int m_nofColumns;
+   int m_nofLines;
+   int m_totalSize; //Same as m_nofLines, but calculated differently
+   bool m_bMyUpdate;
+   bool m_bInsertMode;
+   bool m_bModified;
+   void setModified(bool bModified=true);
+
+   int m_scrollDeltaX;
+   int m_scrollDeltaY;
+   int m_cursorXPos;
+   int m_cursorYPos;
+   int m_cursorOldXPos;
+   bool m_bCursorOn; // blinking on and off each second
+   QTimer m_cursorTimer;
+   bool m_bCursorUpdate;
+   QStatusBar* m_pStatusBar;
+
+   Selection m_selection;
+
+   bool deleteSelection2( QString& str, int& x, int& y,
+                    MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt );
+   bool doRelevantChangesExist();
+public slots:
+   void deleteSelection();
+   void pasteClipboard(bool bFromSelection);
+private slots:
+   void slotCursorUpdate();
+};
+
+class QLineEdit;
+class QTextCodec;
+class QComboBox;
+class QLabel;
+class WindowTitleWidget : public QWidget
+{
+   Q_OBJECT
+private:
+   QLabel*      m_pLabel;
+   QLineEdit*   m_pFileNameLineEdit;
+   //QPushButton* m_pBrowseButton;
+   QLabel*      m_pModifiedLabel;
+   QLabel*      m_pEncodingLabel;
+   QComboBox*   m_pEncodingSelector;
+   OptionDialog* m_pOptionDialog;
+   std::map<int, QTextCodec*> m_codecMap;
+public:
+   WindowTitleWidget(OptionDialog* pOptionDialog, QWidget* pParent );
+   QTextCodec* getEncoding();
+   void        setFileName(const QString& fileName );
+   QString     getFileName();
+   void setEncodings( QTextCodec* pCodecForA, QTextCodec* pCodecForB, QTextCodec* pCodecForC );
+   void setEncoding( QTextCodec* pCodec );
+
+   bool eventFilter( QObject* o, QEvent* e );
+public slots:
+   void slotSetModified( bool bModified );
+//private slots:
+//   void slotBrowseButtonClicked();
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/optiondialog.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,1677 @@
+/*
+ *   kdiff3 - Text Diff And Merge Tool
+ *   Copyright (C) 2002-2006  Joachim Eibl, joachim.eibl at gmx.de
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qfont.h>
+#include <qframe.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h> 
+#include <qvbox.h>
+#include <qvalidator.h>
+#include <qtooltip.h>
+#include <qtextcodec.h>
+#include <qradiobutton.h>
+#include <qvbuttongroup.h>
+#include <qsettings.h>
+
+#include <kapplication.h>
+#include <kcolorbtn.h>
+#include <kfontdialog.h> // For KFontChooser
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kmainwindow.h> //For ktoolbar.h
+
+//#include <kkeydialog.h>
+#include <map>
+
+#include "optiondialog.h"
+#include "diff.h"
+#include "smalldialogs.h"
+
+#include <iostream>
+
+#ifndef KREPLACEMENTS_H
+#include <kglobalsettings.h>
+#endif
+
+static QString s_historyEntryStartRegExpToolTip;
+static QString s_historyEntryStartSortKeyOrderToolTip;
+static QString s_autoMergeRegExpToolTip;
+static QString s_historyStartRegExpToolTip;
+
+void OptionDialog::addOptionItem(OptionItem* p)
+{
+   m_optionItemList.push_back(p);
+}
+
+class OptionItem
+{
+public:
+   OptionItem( OptionDialog* pOptionDialog, const QString& saveName )
+   {
+      assert(pOptionDialog!=0);
+      pOptionDialog->addOptionItem( this );
+      m_saveName = saveName;
+   }
+   virtual ~OptionItem(){}
+   virtual void setToDefault()=0;
+   virtual void setToCurrent()=0;
+   virtual void apply()=0;
+   virtual void write(ValueMap*)=0;
+   virtual void read(ValueMap*)=0;
+   QString getSaveName(){return m_saveName;}
+protected:
+   QString m_saveName;
+};
+
+class OptionCheckBox : public QCheckBox, public OptionItem
+{
+public:
+   OptionCheckBox( QString text, bool bDefaultVal, const QString& saveName, bool* pbVar,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QCheckBox( text, pParent ), OptionItem( pOD, saveName )
+   {
+      m_pbVar = pbVar;
+      m_bDefaultVal = bDefaultVal;
+   }
+   void setToDefault(){ setChecked( m_bDefaultVal );      }
+   void setToCurrent(){ setChecked( *m_pbVar );           }
+   void apply()       { *m_pbVar = isChecked();                              }
+   void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pbVar );   }
+   void read (ValueMap* config){ *m_pbVar = config->readBoolEntry( m_saveName, *m_pbVar ); }
+private:
+   OptionCheckBox( const OptionCheckBox& ); // private copy constructor without implementation
+   bool* m_pbVar;
+   bool m_bDefaultVal;
+};
+
+class OptionRadioButton : public QRadioButton, public OptionItem
+{
+public:
+   OptionRadioButton( QString text, bool bDefaultVal, const QString& saveName, bool* pbVar,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QRadioButton( text, pParent ), OptionItem( pOD, saveName )
+   {
+      m_pbVar = pbVar;
+      m_bDefaultVal = bDefaultVal;
+   }
+   void setToDefault(){ setChecked( m_bDefaultVal );      }
+   void setToCurrent(){ setChecked( *m_pbVar );           }
+   void apply()       { *m_pbVar = isChecked();                              }
+   void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pbVar );   }
+   void read (ValueMap* config){ *m_pbVar = config->readBoolEntry( m_saveName, *m_pbVar ); }
+private:
+   OptionRadioButton( const OptionRadioButton& ); // private copy constructor without implementation
+   bool* m_pbVar;
+   bool m_bDefaultVal;
+};
+
+
+template<class T>
+class OptionT : public OptionItem
+{
+public:
+   OptionT( const T& defaultVal, const QString& saveName, T* pVar, OptionDialog* pOD )
+   : OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+      *m_pVar = defaultVal;
+   }
+   OptionT( const QString& saveName, T* pVar, OptionDialog* pOD )
+   : OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+   }
+   void setToDefault(){}
+   void setToCurrent(){}
+   void apply()       {}
+   void write(ValueMap* vm){ writeEntry( vm, m_saveName, *m_pVar ); }
+   void read (ValueMap* vm){ readEntry ( vm, m_saveName, *m_pVar ); }
+private:
+   OptionT( const OptionT& ); // private copy constructor without implementation
+   T* m_pVar;
+};
+
+template <class T> void writeEntry(ValueMap* vm, const QString& saveName, const T& v ) {   vm->writeEntry( saveName, v ); }
+static void writeEntry(ValueMap* vm, const QString& saveName, const QStringList& v )   {   vm->writeEntry( saveName, v, '|' ); }
+
+static void readEntry(ValueMap* vm, const QString& saveName, bool& v )       {   v = vm->readBoolEntry( saveName, v ); }
+static void readEntry(ValueMap* vm, const QString& saveName, int&  v )       {   v = vm->readNumEntry( saveName, v ); }
+static void readEntry(ValueMap* vm, const QString& saveName, QSize& v )      {   v = vm->readSizeEntry( saveName, &v ); }
+static void readEntry(ValueMap* vm, const QString& saveName, QPoint& v )     {   v = vm->readPointEntry( saveName, &v ); }
+static void readEntry(ValueMap* vm, const QString& saveName, QStringList& v ){   v = vm->readListEntry( saveName, QStringList(), '|' ); }
+
+typedef OptionT<bool> OptionToggleAction;
+typedef OptionT<int>  OptionNum;
+typedef OptionT<QPoint> OptionPoint;
+typedef OptionT<QSize> OptionSize;
+typedef OptionT<QStringList> OptionStringList;
+
+class OptionFontChooser : public KFontChooser, public OptionItem
+{
+public:
+   OptionFontChooser( const QFont& defaultVal, const QString& saveName, QFont* pbVar, QWidget* pParent, OptionDialog* pOD )
+   :KFontChooser( pParent,"font",true/*onlyFixed*/,QStringList(),false,6 ),
+    OptionItem( pOD, saveName )
+   {
+      m_pbVar = pbVar;
+      *m_pbVar = defaultVal;
+      m_default = defaultVal;
+   }
+   void setToDefault(){ setFont( m_default, true /*only fixed*/ ); }
+   void setToCurrent(){ setFont( *m_pbVar, true /*only fixed*/ ); }
+   void apply()       { *m_pbVar = font();}
+   void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pbVar );   }
+   void read (ValueMap* config){ *m_pbVar = config->readFontEntry( m_saveName, m_pbVar ); }
+private:
+   OptionFontChooser( const OptionToggleAction& ); // private copy constructor without implementation
+   QFont* m_pbVar;
+   QFont m_default;
+};
+
+class OptionColorButton : public KColorButton, public OptionItem
+{
+public:
+   OptionColorButton( QColor defaultVal, const QString& saveName, QColor* pVar, QWidget* pParent, OptionDialog* pOD )
+   : KColorButton( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+      m_defaultVal = defaultVal;
+   }
+   void setToDefault(){ setColor( m_defaultVal );      }
+   void setToCurrent(){ setColor( *m_pVar );           }
+   void apply()       { *m_pVar = color();                              }
+   void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar );   }
+   void read (ValueMap* config){ *m_pVar = config->readColorEntry( m_saveName, m_pVar ); }
+private:
+   OptionColorButton( const OptionColorButton& ); // private copy constructor without implementation
+   QColor* m_pVar;
+   QColor m_defaultVal;
+};
+
+class OptionLineEdit : public QComboBox, public OptionItem
+{
+public:
+   OptionLineEdit( const QString& defaultVal, const QString& saveName, QString* pVar,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      setMinimumWidth(50);
+      setEditable(true);
+      m_pVar = pVar;
+      m_defaultVal = defaultVal;
+      m_list.push_back(defaultVal);
+      insertText();
+   }
+   void setToDefault(){ setCurrentText( m_defaultVal );   }
+   void setToCurrent(){ setCurrentText( *m_pVar );        }
+   void apply()       { *m_pVar = currentText(); insertText();            }
+   void write(ValueMap* config){ config->writeEntry( m_saveName, m_list, '|' );      }
+   void read (ValueMap* config){ 
+      m_list = config->readListEntry( m_saveName, m_defaultVal, '|' ); 
+      if ( !m_list.empty() ) *m_pVar = m_list.front();
+      clear();
+      insertStringList(m_list);
+   }
+private:
+   void insertText()
+   {  // Check if the text exists. If yes remove it and push it in as first element
+      QString current = currentText();
+      m_list.remove( current );
+      m_list.push_front( current );
+      clear();
+      if ( m_list.size()>10 ) 
+         m_list.erase( m_list.at(10),m_list.end() );
+      insertStringList(m_list);
+   }
+   OptionLineEdit( const OptionLineEdit& ); // private copy constructor without implementation
+   QString* m_pVar;
+   QString m_defaultVal;
+   QStringList m_list;
+};
+
+#if defined QT_NO_VALIDATOR
+#error No validator
+#endif
+class OptionIntEdit : public QLineEdit, public OptionItem
+{
+public:
+   OptionIntEdit( int defaultVal, const QString& saveName, int* pVar, int rangeMin, int rangeMax,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QLineEdit( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+      m_defaultVal = defaultVal;
+      QIntValidator* v = new QIntValidator(this);
+      v->setRange( rangeMin, rangeMax );
+      setValidator( v );
+   }
+   void setToDefault(){ QString s;  s.setNum(m_defaultVal); setText( s );  }
+   void setToCurrent(){ QString s;  s.setNum(*m_pVar);      setText( s );  }
+   void apply()       { const QIntValidator* v=static_cast<const QIntValidator*>(validator());
+                        *m_pVar = minMaxLimiter( text().toInt(), v->bottom(), v->top());
+                        setText( QString::number(*m_pVar) );  }
+   void write(ValueMap* config){ config->writeEntry(m_saveName, *m_pVar );   }
+   void read (ValueMap* config){ *m_pVar = config->readNumEntry( m_saveName, *m_pVar ); }
+private:
+   OptionIntEdit( const OptionIntEdit& ); // private copy constructor without implementation
+   int* m_pVar;
+   int m_defaultVal;
+};
+
+class OptionComboBox : public QComboBox, public OptionItem
+{
+public:
+   OptionComboBox( int defaultVal, const QString& saveName, int* pVarNum,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      setMinimumWidth(50);
+      m_pVarNum = pVarNum;
+      m_pVarStr = 0;
+      m_defaultVal = defaultVal;
+      setEditable(false);
+   }
+   OptionComboBox( int defaultVal, const QString& saveName, QString* pVarStr,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVarNum = 0;
+      m_pVarStr = pVarStr;
+      m_defaultVal = defaultVal;
+      setEditable(false);
+   }
+   void setToDefault()
+   { 
+      setCurrentItem( m_defaultVal ); 
+      if (m_pVarStr!=0){ *m_pVarStr=currentText(); } 
+   }
+   void setToCurrent()
+   { 
+      if (m_pVarNum!=0) setCurrentItem( *m_pVarNum );
+      else              setText( *m_pVarStr );
+   }
+   void apply()
+   { 
+      if (m_pVarNum!=0){ *m_pVarNum = currentItem(); }
+      else             { *m_pVarStr = currentText(); }
+   }
+   void write(ValueMap* config)
+   { 
+      if (m_pVarStr!=0) config->writeEntry(m_saveName, *m_pVarStr );
+      else              config->writeEntry(m_saveName, *m_pVarNum );   
+   }
+   void read (ValueMap* config)
+   {
+      if (m_pVarStr!=0)  setText( config->readEntry( m_saveName, currentText() ) );
+      else               *m_pVarNum = config->readNumEntry( m_saveName, *m_pVarNum ); 
+   }
+private:
+   OptionComboBox( const OptionIntEdit& ); // private copy constructor without implementation
+   int* m_pVarNum;
+   QString* m_pVarStr;
+   int m_defaultVal;
+   
+   void setText(const QString& s)
+   {
+      // Find the string in the combobox-list, don't change the value if nothing fits.
+      for( int i=0; i<count(); ++i )
+      {
+         if ( text(i)==s )
+         {
+            if (m_pVarNum!=0) *m_pVarNum = i;
+            if (m_pVarStr!=0) *m_pVarStr = s;
+            setCurrentItem(i);
+            return;
+         }
+      }
+   }
+};
+
+class OptionEncodingComboBox : public QComboBox, public OptionItem
+{
+   std::vector<QTextCodec*> m_codecVec;
+   QTextCodec** m_ppVarCodec;
+public:
+   OptionEncodingComboBox( const QString& saveName, QTextCodec** ppVarCodec,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QComboBox( pParent ), OptionItem( pOD, saveName )
+   {
+      m_ppVarCodec = ppVarCodec;
+      insertCodec( i18n("Unicode, 8 bit"),  QTextCodec::codecForName("UTF-8") );
+      insertCodec( i18n("Unicode"), QTextCodec::codecForName("iso-10646-UCS-2") );
+      insertCodec( i18n("Latin1"), QTextCodec::codecForName("iso 8859-1") );
+
+      // First sort codec names:
+      std::map<QString, QTextCodec*> names;
+      int i;
+      for(i=0;;++i)
+      {
+         QTextCodec* c = QTextCodec::codecForIndex(i);
+         if ( c==0 ) break;
+         else  names[QString(c->name()).upper()]=c;
+      }
+
+      std::map<QString, QTextCodec*>::iterator it;
+      for(it=names.begin();it!=names.end();++it)
+      {
+         insertCodec( "", it->second );
+      }
+
+      QToolTip::add( this, i18n(
+         "Change this if non-ASCII characters are not displayed correctly."
+         ));
+   }
+   void insertCodec( const QString& visibleCodecName, QTextCodec* c )
+   {
+      if (c!=0)
+      {
+         for( unsigned int i=0; i<m_codecVec.size(); ++i )
+         {
+            if ( c==m_codecVec[i] )
+               return;  // don't insert any codec twice
+         }
+         insertItem( visibleCodecName.isEmpty() ? QString(c->name()) : visibleCodecName+" ("+c->name()+")", m_codecVec.size() );
+         m_codecVec.push_back( c );
+      }
+   }
+   void setToDefault()
+   {
+      QString defaultName = QTextCodec::codecForLocale()->name();
+      for(int i=0;i<count();++i)
+      {
+         if (defaultName==text(i) &&
+             m_codecVec[i]==QTextCodec::codecForLocale())
+         {
+            setCurrentItem(i);
+            if (m_ppVarCodec!=0){ *m_ppVarCodec=m_codecVec[i]; }
+            return;
+         }
+      }
+
+      setCurrentItem( 0 );
+      if (m_ppVarCodec!=0){ *m_ppVarCodec=m_codecVec[0]; }
+   }
+   void setToCurrent()
+   {
+      if (m_ppVarCodec!=0)
+      {
+         for(unsigned int i=0; i<m_codecVec.size(); ++i)
+         {
+            if ( *m_ppVarCodec==m_codecVec[i] )
+            {
+               setCurrentItem( i );
+               break;
+            }
+         }
+      }
+   }
+   void apply()
+   {
+      if (m_ppVarCodec!=0){ *m_ppVarCodec = m_codecVec[ currentItem() ]; }
+   }
+   void write(ValueMap* config)
+   {
+      if (m_ppVarCodec!=0) config->writeEntry(m_saveName, (*m_ppVarCodec)->name() );
+   }
+   void read (ValueMap* config)
+   {
+      QString codecName = config->readEntry( m_saveName, m_codecVec[ currentItem() ]->name() );
+      for(unsigned int i=0; i<m_codecVec.size(); ++i)
+      {
+         if ( codecName == m_codecVec[i]->name() )
+         {
+            setCurrentItem( i );
+            if (m_ppVarCodec!=0) *m_ppVarCodec = m_codecVec[i];
+            break;
+         }
+      }
+   }
+};
+
+
+OptionDialog::OptionDialog( bool bShowDirMergeSettings, QWidget *parent, char *name )
+  :KDialogBase( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel,
+                Ok, parent, name, true /*modal*/, true )
+{
+   setHelp( "kdiff3/index.html", QString::null );
+
+   setupFontPage();
+   setupColorPage();
+   setupEditPage();
+   setupDiffPage();
+   setupMergePage();
+   setupOtherOptions();
+   if (bShowDirMergeSettings)
+      setupDirectoryMergePage();
+
+   setupRegionalPage();
+   setupIntegrationPage();
+
+   //setupKeysPage();
+
+   // Initialize all values in the dialog
+   resetToDefaults();
+   slotApply();
+}
+
+OptionDialog::~OptionDialog( void )
+{
+}
+
+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 );
+   new OptionToggleAction( false, "WordWrap", &m_bWordWrap, this );
+
+   new OptionToggleAction( true,  "ShowIdenticalFiles", &m_bDmShowIdenticalFiles, this );
+
+   new OptionToggleAction( true,  "Show Toolbar", &m_bShowToolBar, this );
+   new OptionToggleAction( true,  "Show Statusbar", &m_bShowStatusBar, this );
+
+   new OptionNum( (int)KToolBar::Top, "ToolBarPos", &m_toolBarPos, this );
+   new OptionSize( QSize(600,400),"Geometry", &m_geometry, this );
+   new OptionPoint( QPoint(0,22), "Position", &m_position, this );
+   new OptionToggleAction( false, "WindowStateMaximised", &m_bMaximised, this );
+
+   new OptionStringList( "RecentAFiles", &m_recentAFiles, this );
+   new OptionStringList( "RecentBFiles", &m_recentBFiles, this );
+   new OptionStringList( "RecentCFiles", &m_recentCFiles, this );
+   new OptionStringList( "RecentOutputFiles", &m_recentOutputFiles, this );
+}
+
+void OptionDialog::setupFontPage( void )
+{
+   QFrame *page = addPage( i18n("Font"), i18n("Editor & Diff Output Font" ),
+                             BarIcon("fonts", KIcon::SizeMedium ) );
+
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QFont defaultFont =
+#ifdef _WIN32
+      QFont("Courier New", 10 );
+#elif defined( KREPLACEMENTS_H )
+      QFont("Courier", 10 );
+#else
+      KGlobalSettings::fixedFont();
+#endif
+
+   OptionFontChooser* pFontChooser = new OptionFontChooser( defaultFont, "Font", &m_font, page, this );
+   topLayout->addWidget( pFontChooser );
+
+   QGridLayout *gbox = new QGridLayout( 1, 2 );
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   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"
+      "If the font doesn't support italic characters, then this does nothing.")
+      );
+}
+
+
+void OptionDialog::setupColorPage( void )
+{
+  QFrame *page = addPage( i18n("Color"), i18n("Colors Settings"),
+     BarIcon("colorize", KIcon::SizeMedium ) );
+  QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+  QGridLayout *gbox = new QGridLayout( 7, 2 );
+  gbox->setColStretch(1,5);
+  topLayout->addLayout(gbox);
+
+  QLabel* label;
+  int line = 0;
+
+  int depth = QColor::numBitPlanes();
+  bool bLowColor = depth<=8;
+
+  label = new QLabel( i18n("Editor and Diff Views:"), page );
+  gbox->addWidget( label, line, 0 );
+  QFont f( label->font() );
+  f.setBold(true);
+  label->setFont(f);
+  ++line;
+
+  OptionColorButton* pFgColor = new OptionColorButton( Qt::black,"FgColor", &m_fgColor, page, this );
+  label = new QLabel( pFgColor, i18n("Foreground color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pFgColor, line, 1 );
+  ++line;
+
+  OptionColorButton* pBgColor = new OptionColorButton( Qt::white, "BgColor", &m_bgColor, page, this );
+  label = new QLabel( pBgColor, i18n("Background color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pBgColor, line, 1 );
+
+  ++line;
+
+  OptionColorButton* pDiffBgColor = new OptionColorButton( 
+     bLowColor ? Qt::lightGray : qRgb(224,224,224), "DiffBgColor", &m_diffBgColor, page, this );
+  label = new QLabel( pDiffBgColor, i18n("Diff background color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pDiffBgColor, line, 1 );
+  ++line;
+
+  OptionColorButton* pColorA = new OptionColorButton(
+     bLowColor ? qRgb(0,0,255) : qRgb(0,0,200)/*blue*/, "ColorA", &m_colorA, page, this );
+  label = new QLabel( pColorA, i18n("Color A:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColorA, line, 1 );
+  ++line;
+
+  OptionColorButton* pColorB = new OptionColorButton(
+     bLowColor ? qRgb(0,128,0) : qRgb(0,150,0)/*green*/, "ColorB", &m_colorB, page, this );
+  label = new QLabel( pColorB, i18n("Color B:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColorB, line, 1 );
+  ++line;
+
+  OptionColorButton* pColorC = new OptionColorButton(
+     bLowColor ? qRgb(128,0,128) : qRgb(150,0,150)/*magenta*/, "ColorC", &m_colorC, page, this );
+  label = new QLabel( pColorC, i18n("Color C:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColorC, line, 1 );
+  ++line;
+
+  OptionColorButton* pColorForConflict = new OptionColorButton( Qt::red, "ColorForConflict", &m_colorForConflict, page, this );
+  label = new QLabel( pColorForConflict, i18n("Conflict color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColorForConflict, line, 1 );
+  ++line;
+
+  OptionColorButton* pColor = new OptionColorButton( 
+     bLowColor ? qRgb(192,192,192) : qRgb(220,220,100), "CurrentRangeBgColor", &m_currentRangeBgColor, page, this );
+  label = new QLabel( pColor, i18n("Current range background color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  ++line;
+
+  pColor = new OptionColorButton( 
+     bLowColor ? qRgb(255,255,0) : qRgb(255,255,150), "CurrentRangeDiffBgColor", &m_currentRangeDiffBgColor, page, this );
+  label = new QLabel( pColor, i18n("Current range diff background color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  ++line;
+
+  pColor = new OptionColorButton( qRgb(0xff,0xd0,0x80), "ManualAlignmentRangeColor", &m_manualHelpRangeColor, page, this );
+  label = new QLabel( pColor, i18n("Color for manually aligned difference ranges:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  ++line;
+
+  label = new QLabel( i18n("Directory Comparison View:"), page );
+  gbox->addWidget( label, line, 0 );
+  label->setFont(f);
+  ++line;
+
+  pColor = new OptionColorButton( qRgb(0,0xd0,0), "NewestFileColor", &m_newestFileColor, page, this );
+  label = new QLabel( pColor, i18n("Newest file color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  QString dirColorTip = i18n( "Changing this color will only be effective when starting the next directory comparison.");
+  QToolTip::add( label, dirColorTip );
+  ++line;
+
+  pColor = new OptionColorButton( qRgb(0xf0,0,0), "OldestFileColor", &m_oldestFileColor, page, this );
+  label = new QLabel( pColor, i18n("Oldest file color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  QToolTip::add( label, dirColorTip );
+  ++line;
+
+  pColor = new OptionColorButton( qRgb(0xc0,0xc0,0), "MidAgeFileColor", &m_midAgeFileColor, page, this );
+  label = new QLabel( pColor, i18n("Middle age file color:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  QToolTip::add( label, dirColorTip );
+  ++line;
+
+  pColor = new OptionColorButton( qRgb(0,0,0), "MissingFileColor", &m_missingFileColor, page, this );
+  label = new QLabel( pColor, i18n("Color for missing files:"), page );
+  gbox->addWidget( label, line, 0 );
+  gbox->addWidget( pColor, line, 1 );
+  QToolTip::add( label, dirColorTip );
+  ++line;
+
+  topLayout->addStretch(10);
+}
+
+
+void OptionDialog::setupEditPage( void )
+{
+   QFrame *page = addPage( i18n("Editor"), i18n("Editor Behavior"),
+                           BarIcon("edit", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 4, 2 );
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   QLabel* label;
+   int line=0;
+
+   OptionCheckBox* pReplaceTabs = new OptionCheckBox( i18n("Tab inserts spaces"), false, "ReplaceTabs", &m_bReplaceTabs, page, this );
+   gbox->addMultiCellWidget( pReplaceTabs, line, line, 0, 1 );
+   QToolTip::add( pReplaceTabs, i18n(
+      "On: Pressing tab generates the appropriate number of spaces.\n"
+      "Off: A Tab-character will be inserted.")
+      );
+   ++line;
+
+   OptionIntEdit* pTabSize = new OptionIntEdit( 8, "TabSize", &m_tabSize, 1, 100, page, this );
+   label = new QLabel( pTabSize, i18n("Tab size:"), page );
+   gbox->addWidget( label, line, 0 );
+   gbox->addWidget( pTabSize, line, 1 );
+   ++line;
+
+   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 );
+   gbox->addMultiCellWidget( pAutoCopySelection, line, line, 0, 1 );
+   QToolTip::add( pAutoCopySelection, i18n(
+      "On: Any selection is immediately written to the clipboard.\n"
+      "Off: You must explicitely copy e.g. via Ctrl-C."
+      ));
+   ++line;
+   
+   label = new QLabel( i18n("Line end style:"), page );
+   gbox->addWidget( label, line, 0 );
+   #ifdef _WIN32
+   int defaultLineEndStyle = eLineEndDos;
+   #else
+   int defaultLineEndStyle = eLineEndUnix;
+   #endif
+   OptionComboBox* pLineEndStyle = new OptionComboBox( defaultLineEndStyle, "LineEndStyle", &m_lineEndStyle, page, this );
+   gbox->addWidget( pLineEndStyle, line, 1 );
+   pLineEndStyle->insertItem( "Unix", eLineEndUnix );
+   pLineEndStyle->insertItem( "Dos/Windows", eLineEndDos );
+   QToolTip::add( label, i18n(
+      "Sets the line endings for when an edited file is saved.\n"
+      "DOS/Windows: CR+LF; UNIX: LF; with CR=0D, LF=0A")
+      );
+   ++line;
+      
+   topLayout->addStretch(10);
+}
+
+
+void OptionDialog::setupDiffPage( void )
+{
+   QFrame *page = addPage( i18n("Diff"), i18n("Diff Settings"),
+                           BarIcon("misc", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 3, 2 );
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   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* 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* 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* pIgnoreCase = new OptionCheckBox( i18n("Ignore case"), false, "IgnoreCase", &m_bIgnoreCase, page, this );
+   gbox->addMultiCellWidget( pIgnoreCase, line, line, 0, 1 );
+   QToolTip::add( pIgnoreCase, i18n(
+      "Treat case differences like white space changes. ('a'<=>'A')")
+      );
+   ++line;
+
+   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 );
+   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* 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;
+
+   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 );
+   QToolTip::add( label,i18n(
+      "When in Auto-Advance mode the result of the current selection is shown \n"
+      "for the specified time, before jumping to the next conflict. Range: 0-2000 ms")
+      );
+   ++line;
+
+   topLayout->addStretch(10);
+}
+
+void OptionDialog::setupMergePage( void )
+{
+   QFrame *page = addPage( i18n("Merge"), i18n("Merge Settings"),
+                           BarIcon("misc", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page );
+   topLayout->setMargin( 5 );
+   topLayout->setSpacing( spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout();
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   QLabel* label=0;
+
+   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( label, 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( label, i18n(
+      "Allow the merge algorithm to automatically select an input for "
+      "white-space-only changes." )
+      );
+   ++line;
+
+   QGroupBox* pGroupBox = new QGroupBox( 2, Qt::Horizontal, i18n("Automatic Merge Regular Expression"), page);
+   gbox->addMultiCellWidget( pGroupBox, line,line,0,1);
+   ++line;
+   {
+      QWidget* page = new QWidget( pGroupBox );
+      QGridLayout* gbox = new QGridLayout( page, 2, 2, spacingHint() );
+      gbox->setColStretch(1,10);
+      int line = 0;
+
+      label = new QLabel( i18n("Auto merge regular expression:"), page );
+      gbox->addWidget( label, line, 0 );
+      m_pAutoMergeRegExpLineEdit = new OptionLineEdit( ".*\\$(Version|Header|Date|Author).*\\$.*", "AutoMergeRegExp", &m_autoMergeRegExp, page, this );
+      gbox->addWidget( m_pAutoMergeRegExpLineEdit, line, 1 );
+      s_autoMergeRegExpToolTip = i18n("Regular expression for lines where KDiff3 should automatically choose one source.\n"
+                                      "When a line with a conflict matches the regular expression then\n"
+                                      "- if available - C, otherwise B will be chosen.");
+      QToolTip::add( label, s_autoMergeRegExpToolTip );
+      ++line;
+
+      OptionCheckBox* pAutoMergeRegExp = new OptionCheckBox( i18n("Run regular expression auto merge on merge start"), false, "RunRegExpAutoMergeOnMergeStart", &m_bRunRegExpAutoMergeOnMergeStart, page, this );
+      gbox->addMultiCellWidget( pAutoMergeRegExp, line, line, 0, 1 );
+      QToolTip::add( pAutoMergeRegExp, i18n( "Run the merge for auto merge regular expressions\n"
+                                             "immediately when a merge starts.\n"));
+      ++line;
+   }
+
+   pGroupBox = new QGroupBox( 2, Qt::Horizontal, i18n("Version Control History Merging"), page);
+   gbox->addMultiCellWidget( pGroupBox, line,line,0,1);
+   ++line;
+   {
+      QWidget* page = new QWidget( pGroupBox );
+      QGridLayout* gbox = new QGridLayout( page, 2, 2, spacingHint() );
+      gbox->setColStretch(1,10);
+      int line = 0;
+
+      label = new QLabel( i18n("History start regular expression:"), page );
+      gbox->addWidget( label, line, 0 );
+      m_pHistoryStartRegExpLineEdit = new OptionLineEdit( ".*\\$Log.*\\$.*", "HistoryStartRegExp", &m_historyStartRegExp, page, this );
+      gbox->addWidget( m_pHistoryStartRegExpLineEdit, line, 1 );
+      s_historyStartRegExpToolTip = i18n("Regular expression for the start of the version control history entry.\n"
+                                 "Usually this line contains the \"$Log$\"-keyword.\n"
+                                 "Default value: \".*\\$Log.*\\$.*\"");
+      QToolTip::add( label, s_historyStartRegExpToolTip );
+      ++line;
+   
+      label = new QLabel( i18n("History entry start regular expression:"), page );
+      gbox->addWidget( label, line, 0 );
+      // Example line:  "** \main\rolle_fsp_dev_008\1   17 Aug 2001 10:45:44   rolle"
+      QString historyEntryStartDefault =
+         "\\s*\\\\main\\\\(\\S+)\\s+"  // Start with  "\main\"
+         "([0-9]+) "          // day
+         "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) " //month
+         "([0-9][0-9][0-9][0-9]) " // year
+         "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])\\s+(.*)";  // time, name
+   
+      m_pHistoryEntryStartRegExpLineEdit = new OptionLineEdit( historyEntryStartDefault, "HistoryEntryStartRegExp", &m_historyEntryStartRegExp, page, this );
+      gbox->addWidget( m_pHistoryEntryStartRegExpLineEdit, line, 1 );
+      s_historyEntryStartRegExpToolTip = i18n("A version control history entry consists of several lines.\n"
+                                 "Specify the regular expression to detect the first line (without the leading comment).\n"
+                                 "Use parentheses to group the keys you want to use for sorting.\n"
+                                 "If left empty, then KDiff3 assumes that empty lines separate history entries.\n"
+                                 "See the documentation for details.");
+      QToolTip::add( label, s_historyEntryStartRegExpToolTip );
+      ++line;
+   
+      m_pHistoryMergeSorting = new OptionCheckBox( i18n("History merge sorting"), false, "HistoryMergeSorting", &m_bHistoryMergeSorting, page, this );
+      gbox->addMultiCellWidget( m_pHistoryMergeSorting, line, line, 0, 1 );
+      QToolTip::add( m_pHistoryMergeSorting, i18n("Sort version control history by a key.") );
+      ++line;
+            //QString branch = newHistoryEntry.cap(1);
+            //int day    = newHistoryEntry.cap(2).toInt();
+            //int month  = QString("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec").find(newHistoryEntry.cap(3))/4 + 1;
+            //int year   = newHistoryEntry.cap(4).toInt();
+            //QString time = newHistoryEntry.cap(5);
+            //QString name = newHistoryEntry.cap(6);
+      QString defaultSortKeyOrder = "4,3,2,5,1,6"; //QDate(year,month,day).toString(Qt::ISODate) +" "+ time + " " + branch + " " + name;
+
+      label = new QLabel( i18n("History entry start sort key order:"), page );
+      gbox->addWidget( label, line, 0 );
+      m_pHistorySortKeyOrderLineEdit = new OptionLineEdit( defaultSortKeyOrder, "HistoryEntryStartSortKeyOrder", &m_historyEntryStartSortKeyOrder, page, this );
+      gbox->addWidget( m_pHistorySortKeyOrderLineEdit, line, 1 );
+      s_historyEntryStartSortKeyOrderToolTip = i18n("Each parentheses used in the regular expression for the history start entry\n"
+                                 "groups a key that can be used for sorting.\n"
+                                 "Specify the list of keys (that are numbered in order of occurrence\n"
+                                 "starting with 1) using ',' as separator (e.g. \"4,5,6,1,2,3,7\").\n"
+                                 "If left empty, then no sorting will be done.\n"
+                                 "See the documentation for details.");
+      QToolTip::add( label, s_historyEntryStartSortKeyOrderToolTip );
+      m_pHistorySortKeyOrderLineEdit->setEnabled(false);
+      connect( m_pHistoryMergeSorting, SIGNAL(toggled(bool)), m_pHistorySortKeyOrderLineEdit, SLOT(setEnabled(bool)));
+      ++line;
+
+      m_pHistoryAutoMerge = new OptionCheckBox( i18n("Merge version control history on merge start"), false, "RunHistoryAutoMergeOnMergeStart", &m_bRunHistoryAutoMergeOnMergeStart, page, this );
+      gbox->addMultiCellWidget( m_pHistoryAutoMerge, line, line, 0, 1 );
+      QToolTip::add( m_pHistoryAutoMerge, i18n("Run version control history automerge on merge start.") );
+      ++line;
+   }
+
+   QPushButton* pButton = new QPushButton( i18n("Test your regular expressions"), page );
+   gbox->addWidget( pButton, line, 0 );
+   connect( pButton, SIGNAL(clicked()), this, SLOT(slotHistoryMergeRegExpTester()));
+   ++line;
+
+   label = new QLabel( i18n("Irrelevant merge command:"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionLineEdit* pLE = new OptionLineEdit( "", "IrrelevantMergeCmd", &m_IrrelevantMergeCmd, page, this );
+   gbox->addWidget( pLE, line, 1 );
+   QToolTip::add( label, i18n("If specified this script is run after automerge\n"
+                              "when no other relevant changes were detected.\n"
+                              "Called with the parameters: filename1 filename2 filename3") );
+   ++line;
+
+   topLayout->addStretch(10);
+}
+
+void OptionDialog::setupDirectoryMergePage( void )
+{
+   QFrame *page = addPage( i18n("Directory Merge"), i18n("Directory Merge"),
+                           BarIcon("folder", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 11, 2 );
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   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 );
+   gbox->addWidget( label, line, 0 );
+   OptionLineEdit* pFilePattern = new OptionLineEdit( "*", "FilePattern", &m_DmFilePattern, page, this );
+   gbox->addWidget( pFilePattern, line, 1 );
+   QToolTip::add( label, i18n(
+      "Pattern(s) of files to be analyzed. \n"
+      "Wildcards: '*' and '?'\n"
+      "Several Patterns can be specified by using the separator: ';'"
+      ));
+   ++line;
+
+   label = new QLabel( i18n("File-anti-pattern(s):"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionLineEdit* pFileAntiPattern = new OptionLineEdit( "*.orig;*.o;*.obj", "FileAntiPattern", &m_DmFileAntiPattern, page, this );
+   gbox->addWidget( pFileAntiPattern, line, 1 );
+   QToolTip::add( label, i18n(
+      "Pattern(s) of files to be excluded from analysis. \n"
+      "Wildcards: '*' and '?'\n"
+      "Several Patterns can be specified by using the separator: ';'"
+      ));
+   ++line;
+
+   label = new QLabel( i18n("Dir-anti-pattern(s):"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionLineEdit* pDirAntiPattern = new OptionLineEdit( "CVS;.deps;.svn", "DirAntiPattern", &m_DmDirAntiPattern, page, this );
+   gbox->addWidget( pDirAntiPattern, line, 1 );
+   QToolTip::add( label, i18n(
+      "Pattern(s) of directories to be excluded from analysis. \n"
+      "Wildcards: '*' and '?'\n"
+      "Several Patterns can be specified by using the separator: ';'"
+      ));
+   ++line;
+
+   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"
+      "Via local \".cvsignore\"-files this can be directory specific."
+      ));
+   ++line;
+
+   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.") );
+#else
+   QToolTip::add( pFindHidden, i18n("Finds files and directories starting with '.'.") );
+#endif
+   ++line;
+
+   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"
+      "Off: Compare the links."
+      ));
+   ++line;
+
+   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"
+      "Off: Compare the links."
+      ));
+   ++line;
+
+   //OptionCheckBox* pShowOnlyDeltas = new OptionCheckBox( i18n("List only deltas"),false,"ListOnlyDeltas", &m_bDmShowOnlyDeltas, page, this );
+   //gbox->addMultiCellWidget( pShowOnlyDeltas, line, line, 0, 1 );
+   //QToolTip::add( pShowOnlyDeltas, i18n(
+   //              "Files and directories without change will not appear in the list."));
+   //++line;
+
+#ifdef _WIN32
+   bool bCaseSensitiveFilenameComparison = false;
+#else
+   bool bCaseSensitiveFilenameComparison = true;
+#endif
+   OptionCheckBox* pCaseSensitiveFileNames = new OptionCheckBox( i18n("Case sensitive filename comparison"),bCaseSensitiveFilenameComparison,"CaseSensitiveFilenameComparison", &m_bDmCaseSensitiveFilenameComparison, page, this );
+   gbox->addMultiCellWidget( pCaseSensitiveFileNames, line, line, 0, 1 );
+   QToolTip::add( pCaseSensitiveFileNames, i18n(
+                 "The directory comparison will compare files or directories when their names match.\n"
+                 "Set this option if the case of the names must match. (Default for Windows is off, otherwise on.)"));
+   ++line;
+
+   QVButtonGroup* pBG = new QVButtonGroup(i18n("File Comparison Mode"),page);
+   gbox->addMultiCellWidget( pBG, line, line, 0, 1 );
+   ++line;
+   
+   OptionRadioButton* pBinaryComparison = new OptionRadioButton( i18n("Binary comparison"), true, "BinaryComparison", &m_bDmBinaryComparison, pBG, this );
+   QToolTip::add( pBinaryComparison, i18n("Binary comparison of each file. (Default)") );
+   
+   OptionRadioButton* pFullAnalysis = new OptionRadioButton( i18n("Full analysis"), false, "FullAnalysis", &m_bDmFullAnalysis, pBG, this );
+   QToolTip::add( pFullAnalysis, i18n("Do a full analysis and show statistics information in extra columns.\n"
+                                      "(Slower than a binary comparison, much slower for binary files.)") );
+   
+   OptionRadioButton* pTrustDate = new OptionRadioButton( i18n("Trust the modification date (unsafe)"), false, "TrustDate", &m_bDmTrustDate, pBG, this );
+   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.") );
+
+   OptionRadioButton* pTrustSize = new OptionRadioButton( i18n("Trust the size (unsafe)"), false, "TrustSize", &m_bDmTrustSize, pBG, this );
+   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.") );
+
+   // Some two Dir-options: Affects only the default actions.
+   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"
+                  "both directories are the same afterwards.\n"
+                  "Works only when comparing two directories without specifying a destination."  ) );
+   ++line;
+
+   // Allow white-space only differences to be considered equal
+   OptionCheckBox* pWhiteSpaceDiffsEqual = new OptionCheckBox( i18n("White space differences considered equal"), false,"WhiteSpaceEqual", &m_bDmWhiteSpaceEqual, page, this );
+   gbox->addMultiCellWidget( pWhiteSpaceDiffsEqual, line, line, 0, 1 );
+   QToolTip::add( pWhiteSpaceDiffsEqual, i18n(
+                  "If files differ only by white space consider them equal.\n"
+                  "This is only active when full analysis is chosen."  ) );
+   connect(pFullAnalysis, SIGNAL(toggled(bool)), pWhiteSpaceDiffsEqual, SLOT(setEnabled(bool)));
+   pWhiteSpaceDiffsEqual->setEnabled(false);
+   ++line;
+
+   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(
+                 "When a file would be saved over an old file, then the old file\n"
+                 "will be renamed with a '.orig'-extension instead of being deleted."));
+   ++line;
+
+   topLayout->addStretch(10);
+}
+/*
+static void insertCodecs(OptionComboBox* p)
+{
+   std::multimap<QString,QString> m;  // Using the multimap for case-insensitive sorting.
+   int i;
+   for(i=0;;++i)
+   {
+      QTextCodec* pCodec = QTextCodec::codecForIndex ( i );
+      if ( pCodec != 0 )  m.insert( std::make_pair( QString(pCodec->mimeName()).upper(), pCodec->mimeName()) );
+      else                break;
+   }
+   
+   p->insertItem( i18n("Auto"), 0 );
+   std::multimap<QString,QString>::iterator mi;
+   for(mi=m.begin(), i=0; mi!=m.end(); ++mi, ++i)
+      p->insertItem(mi->second, i+1);
+}
+*/
+
+// UTF8-Codec that saves a BOM
+class Utf8BOMCodec : public QTextCodec
+{
+   public:
+   const char * name () const { return "UTF-8-BOM"; }
+   int mibEnum () const { return 2123; }
+   int heuristicContentMatch(const char*, int) const { return 0; }
+   QString toUnicode( const char* p, int len) const 
+   {
+      return QString::fromUtf8 ( p, len );
+   }
+   class UTF8BOMEncoder : public QTextEncoder
+   {
+      bool bBOMAdded;
+   public:
+      UTF8BOMEncoder(){bBOMAdded=false;}
+      QCString fromUnicode(const QString& uc, int& lenInOut )
+      {
+         QCString r;
+         if (!bBOMAdded)
+         {
+            r += "\xEF\xBB\xBF";
+            bBOMAdded=true; 
+         }
+         r += uc.utf8();
+         lenInOut = r.length();
+         return r;
+      }
+   };
+   QTextEncoder* makeEncoder() const
+   {
+      return new UTF8BOMEncoder;
+   }
+};
+
+void OptionDialog::setupRegionalPage( void )
+{
+   new Utf8BOMCodec();
+
+   QFrame *page = addPage( i18n("Regional Settings"), i18n("Regional Settings"),
+                           BarIcon("locale"/*"charset"*/, KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 3, 2 );
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   QLabel* label;
+
+#ifdef KREPLACEMENTS_H
+
+static char* countryMap[]={
+"af Afrikaans",
+"ar Arabic",
+"az Azerbaijani",
+"be Belarusian",
+"bg Bulgarian",
+"bn Bengali",
+"bo Tibetan",
+"br Breton",
+"bs Bosnian",
+"ca Catalan",
+"cs Czech",
+"cy Welsh",
+"da Danish",
+"de German",
+"el Greek",
+"en_GB British English",
+"eo Esperanto",
+"es Spanish",
+"et Estonian",
+"eu Basque",
+"fa Farsi (Persian)",
+"fi Finnish",
+"fo Faroese",
+"fr French",
+"ga Irish Gaelic",
+"gl Galician",
+"gu Gujarati",
+"he Hebrew",
+"hi Hindi",
+"hr Croatian",
+"hsb Upper Sorbian",
+"hu Hungarian",
+"id Indonesian",
+"is Icelandic",
+"it Italian",
+"ja Japanese",
+"ka Georgian",
+"ko Korean",
+"ku Kurdish",
+"lo Lao",
+"lt Lithuanian",
+"lv Latvian",
+"mi Maori",
+"mk Macedonian",
+"mn Mongolian",
+"ms Malay",
+"mt Maltese",
+"nb Norwegian Bookmal",
+"nds Low Saxon",
+"nl Dutch",
+"nn Norwegian Nynorsk",
+"nso Northern Sotho",
+"oc Occitan",
+"pl Polish",
+"pt Portuguese",
+"pt_BR Brazilian Portuguese",
+"ro Romanian",
+"ru Russian",
+"rw Kinyarwanda",
+"se Northern Sami",
+"sk Slovak",
+"sl Slovenian",
+"sq Albanian",
+"sr Serbian",
+"sr@Latn Serbian",
+"ss Swati",
+"sv Swedish",
+"ta Tamil",
+"tg Tajik",
+"th Thai",
+"tr Turkish",
+"uk Ukrainian",
+"uz Uzbek",
+"ven Venda",
+"vi Vietnamese",
+"wa Walloon",
+"xh Xhosa",
+"zh_CN Chinese Simplified",
+"zh_TW Chinese Traditional",
+"zu Zulu"
+};
+
+   label = new QLabel( i18n("Language (restart required)"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pLanguage = new OptionComboBox( 0, "Language", &m_language, page, this );
+   gbox->addWidget( pLanguage, line, 1 );
+   pLanguage->insertItem( "Auto", 0 );  // Must not translate, won't work otherwise!
+   pLanguage->insertItem( "en_orig" );
+      
+   // Read directory: Find all kdiff3_*.qm-files and insert the found files here selection   
+   FileAccess fa( getTranslationDir() );
+   t_DirectoryList dirList;
+   fa.listDir( &dirList, false, false, "kdiff3_*.qm", "", "*", false, false );
+   t_DirectoryList::iterator i;
+   for( i=dirList.begin(); i!=dirList.end(); ++i)
+   {      
+      QString fileName = i->fileName();
+      // Skip the "kdiff3_" and omit the .qm
+      QString languageId = fileName.mid(7, fileName.length()-10 );
+      
+      unsigned int countryIdx=0;
+      for(countryIdx=0; countryIdx< sizeof(countryMap)/sizeof(countryMap[0]); ++countryIdx )
+      {
+         QString fullName = countryMap[countryIdx];
+         if ( languageId+" " == fullName.left(languageId.length()+1) )
+         {
+            languageId += " (" + fullName.mid(languageId.length()+1) + ")";
+         }
+      }
+      
+      pLanguage->insertItem( languageId );
+   }
+   
+   QToolTip::add( label, i18n(
+      "Choose the language of the GUI-strings or \"Auto\".\n" 
+      "For a change of language to take place, quit and restart KDiff3.") 
+      );
+   ++line;
+/*
+   label = new QLabel( i18n("Codec for file contents"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionComboBox* pFileCodec = new OptionComboBox( 0, "FileCodec", &m_fileCodec, page, this );
+   gbox->addWidget( pFileCodec, line, 1 );
+   insertCodecs( pFileCodec );
+   QToolTip::add( label, i18n(
+      "Choose the codec that should be used for your input files\n"
+      "or \"Auto\" if unsure." ) 
+      );
+   ++line;
+*/      
+#endif
+
+   m_pSameEncoding = new OptionCheckBox( i18n("Use the same encoding for everything:"), true, "SameEncoding", &m_bSameEncoding, page, this );
+   gbox->addMultiCellWidget( m_pSameEncoding, line, line, 0, 1 );
+   QToolTip::add( m_pSameEncoding, i18n(
+                  "Enable this allows to change all encodings by changing the first only.\n"
+                  "Disable this if different individual settings are needed."
+                  ) );
+   ++line;
+
+   label = new QLabel( i18n("Note: Local Encoding is ") + "\"" + QTextCodec::codecForLocale()->name() + "\"", page );
+   gbox->addWidget( label, line, 0 );
+   ++line;
+
+   label = new QLabel( i18n("File Encoding for A:"), page );
+   gbox->addWidget( label, line, 0 );
+   m_pEncodingAComboBox = new OptionEncodingComboBox( "EncodingForA", &m_pEncodingA, page, this );
+   gbox->addWidget( m_pEncodingAComboBox, line, 1 );
+
+   QString autoDetectToolTip = i18n(
+      "If enabled then Unicode (UTF-16 or UTF-8) encoding will be detected.\n"
+      "If the file encoding is not detected then the selected encoding will be used as fallback.\n"
+      "(Unicode detection depends on the first bytes of a file - the byte order mark \"BOM\".)"
+      );
+   m_pAutoDetectUnicodeA = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeA", &m_bAutoDetectUnicodeA, page, this );
+   gbox->addWidget( m_pAutoDetectUnicodeA, line, 2 );
+   QToolTip::add( m_pAutoDetectUnicodeA, autoDetectToolTip );
+   ++line;
+
+   label = new QLabel( i18n("File Encoding for B:"), page );
+   gbox->addWidget( label, line, 0 );
+   m_pEncodingBComboBox = new OptionEncodingComboBox( "EncodingForB", &m_pEncodingB, page, this );
+   gbox->addWidget( m_pEncodingBComboBox, line, 1 );
+   m_pAutoDetectUnicodeB = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeB", &m_bAutoDetectUnicodeB, page, this );
+   gbox->addWidget( m_pAutoDetectUnicodeB, line, 2 );
+   QToolTip::add( m_pAutoDetectUnicodeB, autoDetectToolTip );
+   ++line;
+
+   label = new QLabel( i18n("File Encoding for C:"), page );
+   gbox->addWidget( label, line, 0 );
+   m_pEncodingCComboBox = new OptionEncodingComboBox( "EncodingForC", &m_pEncodingC, page, this );
+   gbox->addWidget( m_pEncodingCComboBox, line, 1 );
+   m_pAutoDetectUnicodeC = new OptionCheckBox( i18n("Auto Detect Unicode"), true, "AutoDetectUnicodeC", &m_bAutoDetectUnicodeC, page, this );
+   gbox->addWidget( m_pAutoDetectUnicodeC, line, 2 );
+   QToolTip::add( m_pAutoDetectUnicodeC, autoDetectToolTip );
+   ++line;
+
+   label = new QLabel( i18n("File Encoding for Merge Output and Saving:"), page );
+   gbox->addWidget( label, line, 0 );
+   m_pEncodingOutComboBox = new OptionEncodingComboBox( "EncodingForOutput", &m_pEncodingOut, page, this );
+   gbox->addWidget( m_pEncodingOutComboBox, line, 1 );
+   m_pAutoSelectOutEncoding = new OptionCheckBox( i18n("Auto Select"), true, "AutoSelectOutEncoding", &m_bAutoSelectOutEncoding, page, this );
+   gbox->addWidget( m_pAutoSelectOutEncoding, line, 2 );
+   QToolTip::add( m_pAutoSelectOutEncoding, i18n(
+      "If enabled then the encoding from the input files is used.\n"
+      "In ambiguous cases a dialog will ask the user to choose the encoding for saving."
+      ) );
+   ++line;
+   label = new QLabel( i18n("File Encoding for Preprocessor Files:"), page );
+   gbox->addWidget( label, line, 0 );
+   m_pEncodingPPComboBox = new OptionEncodingComboBox( "EncodingForPP", &m_pEncodingPP, page, this );
+   gbox->addWidget( m_pEncodingPPComboBox, line, 1 );   
+   ++line;
+
+   connect(m_pSameEncoding, SIGNAL(toggled(bool)), this, SLOT(slotEncodingChanged()));
+   connect(m_pEncodingAComboBox, SIGNAL(activated(int)), this, SLOT(slotEncodingChanged()));
+   connect(m_pAutoDetectUnicodeA, SIGNAL(toggled(bool)), this, SLOT(slotEncodingChanged()));
+   connect(m_pAutoSelectOutEncoding, SIGNAL(toggled(bool)), this, SLOT(slotEncodingChanged()));
+
+   OptionCheckBox* pRightToLeftLanguage = new OptionCheckBox( i18n("Right To Left Language"), false, "RightToLeftLanguage", &m_bRightToLeftLanguage, page, this );
+   gbox->addMultiCellWidget( pRightToLeftLanguage, line, line, 0, 1 );
+   QToolTip::add( pRightToLeftLanguage, i18n(
+                 "Some languages are read from right to left.\n"
+                 "This setting will change the viewer and editor accordingly."));
+   ++line;   
+
+
+   topLayout->addStretch(10);
+}
+
+void OptionDialog::setupIntegrationPage( void )
+{
+   QFrame *page = addPage( i18n("Integration"), i18n("Integration Settings"),
+                           BarIcon("launch"/*"charset"*/, KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 5, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 3, 2 );
+   gbox->setColStretch(1,5);
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   QLabel* label;
+   label = new QLabel( i18n("Command line options to ignore:"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionLineEdit* pIgnorableCmdLineOptions = new OptionLineEdit( "-u;-query;-html;-abort", "IgnorableCmdLineOptions", &m_ignorableCmdLineOptions, page, this );
+   gbox->addWidget( pIgnorableCmdLineOptions, line, 1 );
+   QToolTip::add( label, i18n(
+      "List of command line options that should be ignored when KDiff3 is used by other tools.\n"
+      "Several values can be specified if separated via ';'\n"
+      "This will suppress the \"Unknown option\"-error."
+      ));
+   ++line;
+
+   topLayout->addStretch(10);
+}
+
+
+void OptionDialog::slotEncodingChanged()
+{
+   if ( m_pSameEncoding->isChecked() )
+   {
+      m_pEncodingBComboBox->setEnabled( false );
+      m_pEncodingBComboBox->setCurrentItem( m_pEncodingAComboBox->currentItem() );
+      m_pEncodingCComboBox->setEnabled( false );
+      m_pEncodingCComboBox->setCurrentItem( m_pEncodingAComboBox->currentItem() );
+      m_pEncodingOutComboBox->setEnabled( false );
+      m_pEncodingOutComboBox->setCurrentItem( m_pEncodingAComboBox->currentItem() );
+      m_pEncodingPPComboBox->setEnabled( false );
+      m_pEncodingPPComboBox->setCurrentItem( m_pEncodingAComboBox->currentItem() );
+      m_pAutoDetectUnicodeB->setEnabled( false );
+      m_pAutoDetectUnicodeB->setChecked( m_pAutoDetectUnicodeA->isChecked() );
+      m_pAutoDetectUnicodeC->setEnabled( false );
+      m_pAutoDetectUnicodeC->setChecked( m_pAutoDetectUnicodeA->isChecked() );
+      m_pAutoSelectOutEncoding->setEnabled( false );
+      m_pAutoSelectOutEncoding->setChecked( m_pAutoDetectUnicodeA->isChecked() );
+   }
+   else
+   {
+      m_pEncodingBComboBox->setEnabled( true );
+      m_pEncodingCComboBox->setEnabled( true );
+      m_pEncodingOutComboBox->setEnabled( true );
+      m_pEncodingPPComboBox->setEnabled( true );
+      m_pAutoDetectUnicodeB->setEnabled( true );
+      m_pAutoDetectUnicodeC->setEnabled( true );
+      m_pAutoSelectOutEncoding->setEnabled( true );
+      m_pEncodingOutComboBox->setEnabled( !m_pAutoSelectOutEncoding->isChecked() );
+   }
+}
+
+void OptionDialog::setupKeysPage( void )
+{
+   //QVBox *page = addVBoxPage( i18n("Keys"), i18n("KeyDialog" ),
+   //                          BarIcon("fonts", KIcon::SizeMedium ) );
+
+   //QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+    //           new KFontChooser( page,"font",false/*onlyFixed*/,QStringList(),false,6 );
+   //m_pKeyDialog=new KKeyDialog( false, 0 );
+   //topLayout->addWidget( m_pKeyDialog );
+}
+
+void OptionDialog::slotOk( void )
+{
+   slotApply();
+
+   // My system returns variable width fonts even though I
+   // disabled this. Even QFont::fixedPitch() doesn't work.
+   QFontMetrics fm(m_font);
+   if ( fm.width('W')!=fm.width('i') )
+   {
+      int result = KMessageBox::warningYesNo(this, i18n(
+         "You selected a variable width font.\n\n"
+         "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 Own Risk"), i18n("Select Another Font"));
+      if (result==KMessageBox::No)
+         return;
+   }
+
+   accept();
+}
+
+
+/** Copy the values from the widgets to the public variables.*/
+void OptionDialog::slotApply( void )
+{
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->apply();
+   }
+
+   emit applyClicked();   
+
+#ifdef _WIN32
+   QString locale = m_language;
+   if ( locale == "Auto" || locale.isEmpty() )
+      locale = locale = QTextCodec::locale();
+   int spacePos = locale.find(' ');
+   if (spacePos>0) locale = locale.left(spacePos);
+   QSettings settings;
+   settings.setPath("KDiff3", "diff-ext", QSettings::User );
+   settings.writeEntry( "Language", locale );
+#endif
+}
+
+/** Set the default values in the widgets only, while the
+    public variables remain unchanged. */
+void OptionDialog::slotDefault()
+{
+   int result = KMessageBox::warningContinueCancel(this, i18n("This resets all options. Not only those of the current topic.") );
+   if ( result==KMessageBox::Cancel ) return;
+   else resetToDefaults();
+}
+
+void OptionDialog::resetToDefaults()
+{
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->setToDefault();
+   }
+
+   slotEncodingChanged();
+}
+
+/** Initialise the widgets using the values in the public varibles. */
+void OptionDialog::setState()
+{
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->setToCurrent();
+   }
+
+   slotEncodingChanged();
+}
+
+class ConfigValueMap : public ValueMap
+{
+private:
+   KConfig* m_pConfig;
+public:
+   ConfigValueMap( KConfig* pConfig ) { m_pConfig = pConfig; }
+
+   void writeEntry(const QString& s, const QFont&  v ){ m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, const QColor& v ){ m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, const QSize&  v ){ m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, const QPoint& v ){ m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, int v )          { m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, bool v )         { m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, const QStringList& v, char separator ){ m_pConfig->writeEntry(s,v,separator); }
+   void writeEntry(const QString& s, const QString& v ){ m_pConfig->writeEntry(s,v); }
+   void writeEntry(const QString& s, const char* v )   { m_pConfig->writeEntry(s,v); }
+
+   QFont       readFontEntry (const QString& s, QFont* defaultVal ) { return m_pConfig->readFontEntry(s,defaultVal); }
+   QColor      readColorEntry(const QString& s, QColor* defaultVal ){ return m_pConfig->readColorEntry(s,defaultVal); }
+   QSize       readSizeEntry (const QString& s, QSize* defaultVal ) { return m_pConfig->readSizeEntry(s,defaultVal); }
+   QPoint      readPointEntry(const QString& s, QPoint* defaultVal) { return m_pConfig->readPointEntry(s,defaultVal); }
+   bool        readBoolEntry (const QString& s, bool defaultVal )   { return m_pConfig->readBoolEntry(s,defaultVal); }
+   int         readNumEntry  (const QString& s, int defaultVal )    { return m_pConfig->readNumEntry(s,defaultVal); }
+   QStringList readListEntry (const QString& s, const QStringList& def, char separator )    { return m_pConfig->readListEntry(s.latin1(),def,separator); }
+   QString     readEntry     (const QString& s, const QString& defaultVal){ return m_pConfig->readEntry(s,defaultVal); }
+};
+
+void OptionDialog::saveOptions( KConfig* config )
+{
+   // No i18n()-Translations here!
+
+   config->setGroup("KDiff3 Options");
+
+   ConfigValueMap cvm(config);
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->write(&cvm);
+   }
+}
+
+void OptionDialog::readOptions( KConfig* config )
+{
+   // No i18n()-Translations here!
+
+   config->setGroup("KDiff3 Options");
+
+   ConfigValueMap cvm(config);
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->read(&cvm);
+   }
+
+   setState();
+}
+
+void OptionDialog::slotHelp( void )
+{
+   KDialogBase::slotHelp();
+}
+
+QString OptionDialog::parseOptions( const QCStringList& optionList )
+{
+   QString result;
+   QCStringList::const_iterator i;
+   for ( i=optionList.begin(); i!=optionList.end(); ++i )
+   {
+      QString s = *i;
+
+      int pos = s.find('=');
+      if( pos > 0 )                     // seems not to have a tag
+      {
+         QString key = s.left(pos);
+         QString val = s.mid(pos+1);
+         std::list<OptionItem*>::iterator j;
+         bool bFound = false;
+         for(j=m_optionItemList.begin(); j!=m_optionItemList.end(); ++j)
+         {
+            if ( (*j)->getSaveName()==key )
+            {
+               ValueMap config;
+               config.writeEntry( key, val );  // Write the value as a string and
+               (*j)->read(&config);       // use the internal conversion from string to the needed value.
+               bFound = true;
+               break;
+            }
+         }
+         if ( ! bFound )
+         {
+            result += "No config item named \"" + key + "\"\n";
+         }
+      }
+      else
+      {
+         result += "No '=' found in \"" + s + "\"\n";
+      }
+   }
+   return result;
+}
+
+QString OptionDialog::calcOptionHelp()
+{
+   ValueMap config;
+   std::list<OptionItem*>::iterator j;
+   for(j=m_optionItemList.begin(); j!=m_optionItemList.end(); ++j)
+   {
+      (*j)->write( &config );
+   }
+   return config.getAsString();
+}
+
+void OptionDialog::slotHistoryMergeRegExpTester()
+{
+   RegExpTester dlg(this, s_autoMergeRegExpToolTip, s_historyStartRegExpToolTip, 
+                          s_historyEntryStartRegExpToolTip, s_historyEntryStartSortKeyOrderToolTip );
+   dlg.init(m_pAutoMergeRegExpLineEdit->currentText(), m_pHistoryStartRegExpLineEdit->currentText(), 
+            m_pHistoryEntryStartRegExpLineEdit->currentText(), m_pHistorySortKeyOrderLineEdit->currentText());
+   if ( dlg.exec() )
+   {
+      m_pAutoMergeRegExpLineEdit->setCurrentText( dlg.autoMergeRegExp() );
+      m_pHistoryStartRegExpLineEdit->setCurrentText( dlg.historyStartRegExp() );
+      m_pHistoryEntryStartRegExpLineEdit->setCurrentText( dlg.historyEntryStartRegExp() );
+      m_pHistorySortKeyOrderLineEdit->setCurrentText( dlg.historySortKeyOrder() );
+   }
+}
+
+
+#include "optiondialog.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/optiondialog.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,223 @@
+
+/*
+ *   kdiff3 - Text Diff And Merge Tool
+ *   Copyright (C) 2002-2006  Joachim Eibl, joachim.eibl at gmx.de
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef OPTION_DIALOG_H
+#define OPTION_DIALOG_H
+
+class QCheckBox;
+class QLabel;
+class QLineEdit;
+class KColorButton;
+class KFontChooser;
+class KConfig;
+
+#include <kdialogbase.h>
+#include <qstringlist.h>
+#include <list>
+#include <kcmdlineargs.h>
+
+class OptionItem;
+class OptionCheckBox;
+class OptionEncodingComboBox;
+class OptionLineEdit;
+class KKeyDialog;
+
+enum e_LineEndStyle
+{
+   eLineEndUnix=0,
+   eLineEndDos
+};
+
+class OptionDialog : public KDialogBase
+{
+   Q_OBJECT
+
+public:
+
+    OptionDialog( bool bShowDirMergeSettings, QWidget *parent = 0, char *name = 0 );
+    ~OptionDialog( void );
+    QString parseOptions( const QCStringList& optionList );
+    QString calcOptionHelp();
+
+    // Some settings are not available in the option dialog:
+    QSize  m_geometry;
+    QPoint m_position;
+    bool   m_bMaximised; 
+    bool   m_bShowToolBar;
+    bool   m_bShowStatusBar;
+    int    m_toolBarPos;
+
+    // These are the results of the option dialog.
+    QFont m_font;
+    bool m_bItalicForDeltas;
+
+    QColor m_fgColor;
+    QColor m_bgColor;
+    QColor m_diffBgColor;
+    QColor m_colorA;
+    QColor m_colorB;
+    QColor m_colorC;
+    QColor m_colorForConflict;
+    QColor m_currentRangeBgColor;
+    QColor m_currentRangeDiffBgColor;
+    QColor m_oldestFileColor;
+    QColor m_midAgeFileColor;
+    QColor m_newestFileColor;
+    QColor m_missingFileColor;
+    QColor m_manualHelpRangeColor;
+
+    bool m_bWordWrap;
+
+    bool m_bReplaceTabs;
+    bool m_bAutoIndentation;
+    int  m_tabSize;
+    bool m_bAutoCopySelection;
+    bool m_bSameEncoding;
+    QTextCodec*  m_pEncodingA;
+    bool m_bAutoDetectUnicodeA;
+    QTextCodec*  m_pEncodingB;
+    bool m_bAutoDetectUnicodeB;
+    QTextCodec*  m_pEncodingC;
+    bool m_bAutoDetectUnicodeC;
+    QTextCodec*  m_pEncodingOut;
+    bool m_bAutoSelectOutEncoding;
+    QTextCodec*  m_pEncodingPP;
+    int  m_lineEndStyle;
+
+    bool m_bPreserveCarriageReturn;
+    bool m_bTryHard;
+    bool m_bShowWhiteSpaceCharacters;
+    bool m_bShowWhiteSpace;
+    bool m_bShowLineNumbers;
+    bool m_bHorizDiffWindowSplitting;
+
+    int  m_whiteSpace2FileMergeDefault;
+    int  m_whiteSpace3FileMergeDefault;
+    bool m_bIgnoreCase;
+    bool m_bIgnoreNumbers;
+    bool m_bIgnoreComments;
+    QString m_PreProcessorCmd;
+    QString m_LineMatchingPreProcessorCmd;
+    bool m_bRunRegExpAutoMergeOnMergeStart;
+    QString m_autoMergeRegExp;
+    bool m_bRunHistoryAutoMergeOnMergeStart;
+    QString m_historyStartRegExp;
+    QString m_historyEntryStartRegExp;
+    bool m_bHistoryMergeSorting;
+    QString m_historyEntryStartSortKeyOrder;
+    QString m_IrrelevantMergeCmd;
+
+    bool m_bAutoAdvance;
+    int  m_autoAdvanceDelay;
+
+    QStringList m_recentAFiles;
+    QStringList m_recentBFiles;
+    QStringList m_recentCFiles;
+
+    QStringList m_recentOutputFiles;
+
+    // Directory Merge options
+    bool m_bDmSyncMode;
+    bool m_bDmRecursiveDirs;
+    bool m_bDmFollowFileLinks;
+    bool m_bDmFollowDirLinks;
+    bool m_bDmFindHidden;
+    bool m_bDmCreateBakFiles;
+    bool m_bDmBinaryComparison;
+    bool m_bDmFullAnalysis;
+    bool m_bDmTrustDate;
+    bool m_bDmTrustSize;
+    bool m_bDmCopyNewer;
+    //bool m_bDmShowOnlyDeltas;
+    bool m_bDmShowIdenticalFiles;
+    bool m_bDmUseCvsIgnore;
+    bool m_bDmWhiteSpaceEqual;
+    bool m_bDmCaseSensitiveFilenameComparison;
+    QString m_DmFilePattern;
+    QString m_DmFileAntiPattern;
+    QString m_DmDirAntiPattern;
+
+    QString m_language;
+    bool m_bRightToLeftLanguage;
+
+    QString m_ignorableCmdLineOptions;
+
+    void saveOptions(KConfig* config);
+    void readOptions(KConfig* config);
+
+    void setState(); // Must be called before calling exec();
+
+    void addOptionItem(OptionItem*);
+    KKeyDialog* m_pKeyDialog;
+protected slots:
+    virtual void slotDefault( void );
+    virtual void slotOk( void );
+    virtual void slotApply( void );
+    virtual void slotHelp( void );
+
+    void slotEncodingChanged();
+    void slotHistoryMergeRegExpTester();
+private:
+    void resetToDefaults();
+
+    std::list<OptionItem*> m_optionItemList;
+
+    OptionCheckBox* m_pSameEncoding;
+    OptionEncodingComboBox* m_pEncodingAComboBox;
+    OptionCheckBox* m_pAutoDetectUnicodeA;
+    OptionEncodingComboBox* m_pEncodingBComboBox;
+    OptionCheckBox* m_pAutoDetectUnicodeB;
+    OptionEncodingComboBox* m_pEncodingCComboBox;
+    OptionCheckBox* m_pAutoDetectUnicodeC;
+    OptionEncodingComboBox* m_pEncodingOutComboBox;
+    OptionCheckBox* m_pAutoSelectOutEncoding;
+    OptionEncodingComboBox* m_pEncodingPPComboBox;
+    OptionCheckBox* m_pHistoryAutoMerge;
+    OptionLineEdit* m_pAutoMergeRegExpLineEdit;
+    OptionLineEdit* m_pHistoryStartRegExpLineEdit;
+    OptionLineEdit* m_pHistoryEntryStartRegExpLineEdit;
+    OptionCheckBox* m_pHistoryMergeSorting;
+    OptionLineEdit* m_pHistorySortKeyOrderLineEdit;
+
+private:
+    void setupFontPage();
+    void setupColorPage();
+    void setupEditPage();
+    void setupDiffPage();
+    void setupMergePage();
+    void setupDirectoryMergePage();
+    void setupKeysPage();
+    void setupRegionalPage();
+    void setupIntegrationPage();
+    void setupOtherOptions();
+};
+
+
+
+
+#endif
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/pdiff.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2257 @@
+/***************************************************************************
+                         pdiff.cpp  -  Implementation for class KDiff3App
+                         ---------------
+    begin                : Mon March 18 20:04:50 CET 2002
+    copyright            : (C) 2002-2005 by Joachim Eibl
+    email                : joachim.eibl at gmx.de
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "difftextwindow.h"
+#include "mergeresultwindow.h"
+#include "directorymergewindow.h"
+#include "smalldialogs.h"
+
+#include <iostream>
+#include <algorithm>
+#include <ctype.h>
+#include <qaccel.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfontdialog.h>
+#include <kstatusbar.h>
+#include <kkeydialog.h>
+
+#include <qclipboard.h>
+#include <qscrollbar.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qsplitter.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qvbuttongroup.h>
+#include <qdragobject.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <assert.h>
+
+#include "kdiff3.h"
+#include "optiondialog.h"
+#include "fileaccess.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "gnudiff_diff.h"
+
+bool g_bIgnoreWhiteSpace = true;
+bool g_bIgnoreTrivialMatches = true;
+
+
+bool KDiff3App::runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList )
+{
+   ProgressProxy pp;
+   static GnuDiff gnuDiff;  // All values are initialized with zeros.
+
+   pp.setCurrent(0);
+
+   diffList.clear();
+   if ( p1[0].pLine==0 || p2[0].pLine==0 || size1==0 || size2==0 )
+   {
+      Diff d( 0,0,0);
+      if ( p1[0].pLine==0 && p2[0].pLine==0 && size1 == size2 )
+         d.nofEquals = size1;
+      else
+      {
+         d.diff1=size1;
+         d.diff2=size2;
+      }
+
+      diffList.push_back(d);
+   }
+   else
+   {
+      GnuDiff::comparison comparisonInput;
+      memset( &comparisonInput, 0, sizeof(comparisonInput) );
+      comparisonInput.parent = 0;
+      comparisonInput.file[0].buffer = 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 = 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;
+      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() )
+      {
+         Diff d(0,0,0);
+         d.nofEquals = min2(size1,size2);
+         d.diff1 = size1 - d.nofEquals;
+         d.diff2 = size2 - d.nofEquals;
+         diffList.push_back(d);
+/*         Diff d(0,0,0);
+         d.nofEquals = equalLinesAtStart;
+         if ( gnuDiff.files[0].missing_newline != gnuDiff.files[1].missing_newline )
+         {
+            d.diff1 = gnuDiff.files[0].missing_newline ? 0 : 1;
+            d.diff2 = gnuDiff.files[1].missing_newline ? 0 : 1;
+            ++d.nofEquals;
+         }
+         else if ( !gnuDiff.files[0].missing_newline )
+         {
+            ++d.nofEquals;
+         }
+         diffList.push_back(d);
+*/
+      }
+      else
+      {
+         diffList.front().nofEquals += equalLinesAtStart;   
+         currentLine1 += equalLinesAtStart;
+         currentLine2 += equalLinesAtStart;
+
+         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);
+         }
+
+         /*
+         if ( gnuDiff.files[0].missing_newline != gnuDiff.files[1].missing_newline )
+         {
+            diffList.back().diff1 += gnuDiff.files[0].missing_newline ? 0 : 1;
+            diffList.back().diff2 += gnuDiff.files[1].missing_newline ? 0 : 1;
+         }
+         else if ( !gnuDiff.files[0].missing_newline )
+         {
+            ++ diffList.back().nofEquals;
+         }
+         */
+      }
+   }
+
+#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
+
+   pp.setCurrent(1.0);
+
+   return true;
+}
+
+bool KDiff3App::runDiff( const LineData* p1, int size1, const LineData* p2, int size2, DiffList& diffList,
+                         int winIdx1, int winIdx2 )
+{
+   diffList.clear();
+   DiffList diffList2;
+
+   int l1begin = 0;
+   int l2begin = 0;
+   ManualDiffHelpList::const_iterator i;
+   for( i = m_manualDiffHelpList.begin(); i!=m_manualDiffHelpList.end(); ++i )
+   {
+      const ManualDiffHelpEntry& mdhe = *i;
+
+      int l1end = winIdx1 == 1 ? mdhe.lineA1 : winIdx1==2 ? mdhe.lineB1 : mdhe.lineC1 ;
+      int l2end = winIdx2 == 1 ? mdhe.lineA1 : winIdx2==2 ? mdhe.lineB1 : mdhe.lineC1 ;
+
+      if ( l1end>=0 && l2end>=0 )
+      {
+         runDiff( p1+l1begin, l1end-l1begin, p2+l2begin, l2end-l2begin, diffList2 );
+         diffList.splice( diffList.end(), diffList2 );
+         l1begin = l1end;
+         l2begin = l2end;
+
+         l1end = winIdx1 == 1 ? mdhe.lineA2 : winIdx1==2 ? mdhe.lineB2 : mdhe.lineC2 ;
+         l2end = winIdx2 == 1 ? mdhe.lineA2 : winIdx2==2 ? mdhe.lineB2 : mdhe.lineC2 ;
+
+         if ( l1end>=0 && l2end>=0 )
+         {
+            ++l1end; // point to line after last selected line
+            ++l2end;
+            runDiff( p1+l1begin, l1end-l1begin, p2+l2begin, l2end-l2begin, diffList2 );
+            diffList.splice( diffList.end(), diffList2 );
+            l1begin = l1end;
+            l2begin = l2end;
+         }
+      }
+   }
+   runDiff( p1+l1begin, size1-l1begin, p2+l2begin, size2-l2begin, diffList2 );
+   diffList.splice( diffList.end(), diffList2 );
+   return true;
+}
+
+void KDiff3App::init( bool bAuto, TotalDiffStatus* pTotalDiffStatus, bool bLoadFiles )
+{
+   ProgressProxy pp;
+   // When doing a full analysis in the directory-comparison, then the statistics-results
+   // will be stored in the given TotalDiffStatus. Otherwise it will be 0.
+   bool bGUI = pTotalDiffStatus == 0;
+   if (pTotalDiffStatus==0) 
+      pTotalDiffStatus = &m_totalDiffStatus;
+
+   bool bPreserveCarriageReturn = m_pOptionDialog->m_bPreserveCarriageReturn;
+
+   bool bVisibleMergeResultWindow = ! m_outputFilename.isEmpty();
+   if ( bVisibleMergeResultWindow && bGUI )
+   {
+      bPreserveCarriageReturn = false;
+
+      QString msg;
+
+      if ( !m_pOptionDialog->m_PreProcessorCmd.isEmpty() )
+      {
+         msg += "- " + i18n("PreprocessorCmd: ") + m_pOptionDialog->m_PreProcessorCmd + "\n";
+      }
+      if ( !msg.isEmpty() )
+      {
+         int result = KMessageBox::warningYesNo( this,
+                               i18n("The following option(s) you selected might change data:\n") + msg + 
+                               i18n("\nMost likely this is not wanted during a merge.\n"
+                                    "Do you want to disable these settings or continue with these settings active?"),
+                               i18n("Option Unsafe for Merging"), 
+                               i18n("Use These Options During Merge"), i18n("Disable Unsafe Options")
+                               );
+
+         if (result == KMessageBox::No )
+         {
+            m_pOptionDialog->m_PreProcessorCmd = "";
+         }
+      }
+   }
+
+   // Because of the progressdialog paintevents can occur, but data is invalid,
+   // so painting must be suppressed.
+   if (m_pDiffTextWindow1) m_pDiffTextWindow1->setPaintingAllowed( false );
+   if (m_pDiffTextWindow2) m_pDiffTextWindow2->setPaintingAllowed( false );
+   if (m_pDiffTextWindow3) m_pDiffTextWindow3->setPaintingAllowed( false );
+   if (m_pOverview)        m_pOverview->setPaintingAllowed( false );
+   if (m_pMergeResultWindow) m_pMergeResultWindow->setPaintingAllowed( false );
+
+   m_diff3LineList.clear();
+
+   if ( bLoadFiles )
+   {
+      m_manualDiffHelpList.clear();
+
+      if( m_sd3.isEmpty() )
+         pp.setMaxNofSteps( 4 );  // Read 2 files, 1 comparison, 1 finediff
+      else
+         pp.setMaxNofSteps( 9 );  // Read 3 files, 3 comparisons, 3 finediffs
+
+      // First get all input data.
+      pp.setInformation(i18n("Loading A"));
+      m_sd1.readAndPreprocess(m_pOptionDialog->m_pEncodingA, m_pOptionDialog->m_bAutoDetectUnicodeA );
+      pp.step();
+
+      pp.setInformation(i18n("Loading B"));
+      m_sd2.readAndPreprocess(m_pOptionDialog->m_pEncodingB, m_pOptionDialog->m_bAutoDetectUnicodeB );
+      pp.step();
+   }
+   else
+   {
+      if( m_sd3.isEmpty() )
+         pp.setMaxNofSteps( 2 );  // 1 comparison, 1 finediff
+      else
+         pp.setMaxNofSteps( 6 );  // 3 comparisons, 3 finediffs
+   }
+
+   pTotalDiffStatus->reset();
+   // Run the diff.
+   if ( m_sd3.isEmpty() )
+   {
+      pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith( m_sd2 );
+      pp.setInformation(i18n("Diff: A <-> B"));
+
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12,1,2 );
+
+      pp.step();
+
+      pp.setInformation(i18n("Linediff: A <-> B"));
+      calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
+      fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay(), pTotalDiffStatus->bTextAEqB );
+      if ( m_sd1.getSizeBytes()==0 ) pTotalDiffStatus->bTextAEqB=false;
+
+      pp.step();
+   }
+   else
+   {
+      if (bLoadFiles)
+      {
+         pp.setInformation(i18n("Loading C"));
+         m_sd3.readAndPreprocess(m_pOptionDialog->m_pEncodingC, m_pOptionDialog->m_bAutoDetectUnicodeC );
+         pp.step();
+      }
+
+      pTotalDiffStatus->bBinaryAEqB = m_sd1.isBinaryEqualWith( m_sd2 );
+      pTotalDiffStatus->bBinaryAEqC = m_sd1.isBinaryEqualWith( m_sd3 );
+      pTotalDiffStatus->bBinaryBEqC = m_sd3.isBinaryEqualWith( m_sd2 );
+
+      pp.setInformation(i18n("Diff: A <-> B"));
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_diffList12,1,2 );
+      pp.step();
+      pp.setInformation(i18n("Diff: B <-> C"));
+      runDiff( m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList23,2,3 );
+      pp.step();
+      pp.setInformation(i18n("Diff: A <-> C"));
+      runDiff( m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(), m_sd3.getLineDataForDiff(), m_sd3.getSizeLines(), m_diffList13,1,3 );
+      pp.step();
+
+      calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
+      calcDiff3LineListUsingAC( &m_diffList13, m_diff3LineList );
+      correctManualDiffAlignment( m_diff3LineList, &m_manualDiffHelpList );
+      calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList );
+
+      calcDiff3LineListUsingBC( &m_diffList23, m_diff3LineList );
+      correctManualDiffAlignment( m_diff3LineList, &m_manualDiffHelpList );
+      calcDiff3LineListTrim( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff(), &m_manualDiffHelpList );
+      debugLineCheck( m_diff3LineList, m_sd1.getSizeLines(), 1 );
+      debugLineCheck( m_diff3LineList, m_sd2.getSizeLines(), 2 );
+      debugLineCheck( m_diff3LineList, m_sd3.getSizeLines(), 3 );
+
+      pp.setInformation(i18n("Linediff: A <-> B"));
+      fineDiff( m_diff3LineList, 1, m_sd1.getLineDataForDisplay(), m_sd2.getLineDataForDisplay(), pTotalDiffStatus->bTextAEqB );
+      pp.step();
+      pp.setInformation(i18n("Linediff: B <-> C"));
+      fineDiff( m_diff3LineList, 2, m_sd2.getLineDataForDisplay(), m_sd3.getLineDataForDisplay(), pTotalDiffStatus->bTextBEqC );
+      pp.step();
+      pp.setInformation(i18n("Linediff: A <-> C"));
+      fineDiff( m_diff3LineList, 3, m_sd3.getLineDataForDisplay(), m_sd1.getLineDataForDisplay(), pTotalDiffStatus->bTextAEqC );
+      pp.step();
+      if ( m_sd1.getSizeBytes()==0 ) { pTotalDiffStatus->bTextAEqB=false;  pTotalDiffStatus->bTextAEqC=false; }
+      if ( m_sd2.getSizeBytes()==0 ) { pTotalDiffStatus->bTextAEqB=false;  pTotalDiffStatus->bTextBEqC=false; }
+   }
+   m_diffBufferInfo.init( &m_diff3LineList, &m_diff3LineVector,
+      m_sd1.getLineDataForDiff(), m_sd1.getSizeLines(),
+      m_sd2.getLineDataForDiff(), m_sd2.getSizeLines(),
+      m_sd3.getLineDataForDiff(), m_sd3.getSizeLines() );
+   calcWhiteDiff3Lines( m_diff3LineList, m_sd1.getLineDataForDiff(), m_sd2.getLineDataForDiff(), m_sd3.getLineDataForDiff() );
+   calcDiff3LineVector( m_diff3LineList, m_diff3LineVector );
+
+   // Calc needed lines for display
+   m_neededLines = m_diff3LineList.size();
+
+   m_pDirectoryMergeWindow->allowResizeEvents(false);
+   initView();
+   if ( !bGUI )
+   {
+      m_pMainWidget->hide();
+   }
+   m_pDirectoryMergeWindow->allowResizeEvents(true);
+
+   m_bTripleDiff = ! m_sd3.isEmpty();
+
+   m_pMergeResultWindowTitle->setEncodings( m_sd1.getEncoding(), m_sd2.getEncoding(), m_sd3.getEncoding() );
+   if ( ! m_pOptionDialog->m_bAutoSelectOutEncoding )
+      m_pMergeResultWindowTitle->setEncoding( m_pOptionDialog->m_pEncodingOut );
+
+   if ( bGUI )
+   {
+      const ManualDiffHelpList* pMDHL = &m_manualDiffHelpList;
+      m_pDiffTextWindow1->init( m_sd1.getAliasName(),
+         m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff );
+      m_pDiffTextWindow2->init( m_sd2.getAliasName(),
+         m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff );
+      m_pDiffTextWindow3->init( m_sd3.getAliasName(),
+         m_sd3.getLineDataForDisplay(), m_sd3.getSizeLines(), &m_diff3LineVector, pMDHL, m_bTripleDiff );
+
+      if (m_bTripleDiff) m_pDiffTextWindowFrame3->show();
+      else               m_pDiffTextWindowFrame3->hide();
+   }
+
+   m_bOutputModified = bVisibleMergeResultWindow;
+
+   m_pMergeResultWindow->init(
+      m_sd1.getLineDataForDisplay(), m_sd1.getSizeLines(),
+      m_sd2.getLineDataForDisplay(), m_sd2.getSizeLines(),
+      m_bTripleDiff ? m_sd3.getLineDataForDisplay() : 0, m_sd3.getSizeLines(),
+      &m_diff3LineList,
+      pTotalDiffStatus      
+      );
+   m_pMergeResultWindowTitle->setFileName( m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename );
+
+   if ( !bGUI ) 
+   {
+      // We now have all needed information. The rest below is only for GUI-activation.
+      m_sd1.reset();
+      m_sd2.reset();
+      m_sd3.reset();
+      return;
+   }
+
+   m_pOverview->init(&m_diff3LineList, m_bTripleDiff );
+   m_pDiffVScrollBar->setValue( 0 );
+   m_pHScrollBar->setValue( 0 );
+   m_pMergeVScrollBar->setValue( 0 );
+
+   m_pDiffTextWindow1->setPaintingAllowed( true );
+   m_pDiffTextWindow2->setPaintingAllowed( true );
+   m_pDiffTextWindow3->setPaintingAllowed( true );
+   m_pOverview->setPaintingAllowed( true );
+   m_pMergeResultWindow->setPaintingAllowed( true );
+
+
+   if ( !bVisibleMergeResultWindow )
+      m_pMergeWindowFrame->hide();
+   else
+      m_pMergeWindowFrame->show();
+
+   // Calc max width for display
+   m_maxWidth = max2( m_pDiffTextWindow1->getNofColumns(), m_pDiffTextWindow2->getNofColumns() );
+   m_maxWidth = max2( m_maxWidth, m_pDiffTextWindow3->getNofColumns() );
+   m_maxWidth += 5;
+
+   // Try to create a meaningful but not too long caption
+   if ( !isPart() )
+   {
+      // 1. If the filenames are equal then show only one filename
+      QString caption;
+      QString a1 = m_sd1.getAliasName();
+      QString a2 = m_sd2.getAliasName();
+      QString a3 = m_sd3.getAliasName();
+      QString f1, f2, f3;
+      int p1,p2,p3;
+      if ( !a1.isEmpty() &&  (p1=a1.findRev('/'))>=0 )
+         f1 = a1.mid( p1+1 );
+      if ( !a2.isEmpty() &&  (p2=a2.findRev('/'))>=0 )
+         f2 = a2.mid( p2+1 );
+      if ( !a3.isEmpty() &&  (p3=a3.findRev('/'))>=0 )
+         f3 = a3.mid( p3+1 );
+      if ( !f1.isEmpty() ) 
+      {
+         if ( ( f2.isEmpty() && f3.isEmpty() ) || 
+              (f2.isEmpty() && f1==f3) || ( f3.isEmpty() && f1==f2 ) || (f1==f2 && f1==f3)) 
+            caption = ".../"+f1;
+      }
+      else if ( ! f2.isEmpty() ) 
+      {
+         if ( f3.isEmpty() || f2==f3 ) 
+            caption = ".../"+f2;
+      }
+      else if ( ! f3.isEmpty() ) 
+         caption = ".../"+f3;
+
+      // 2. If the files don't have the same name then show all names
+      if ( caption.isEmpty() && (!f1.isEmpty() || !f2.isEmpty() || !f3.isEmpty()) )
+      {
+         caption = ( f1.isEmpty()? QString("") : QString(".../")+f1 );
+         caption += QString(caption.isEmpty() || f2.isEmpty() ? "" : " <-> ") + ( f2.isEmpty()? QString("") : QString(".../")+f2 );
+         caption += QString(caption.isEmpty() || f3.isEmpty() ? "" : " <-> ") + ( f3.isEmpty()? QString("") : QString(".../")+f3 ) ;
+      }
+
+      m_pKDiff3Shell->setCaption( caption.isEmpty() ? QString("KDiff3") : caption+QString(" - KDiff3"));
+   }
+
+   if ( bLoadFiles )
+   {
+      if ( bVisibleMergeResultWindow && !bAuto )
+         m_pMergeResultWindow->showNrOfConflicts();
+      else if ( !bAuto && 
+         // Avoid showing this message during startup without parameters.
+         !( m_sd1.getAliasName().isEmpty() && m_sd2.getAliasName().isEmpty() && m_sd3.getAliasName().isEmpty() ) &&
+         ( m_sd1.isValid() && m_sd2.isValid() && m_sd3.isValid() )
+         )
+      {
+         QString totalInfo;
+         if ( pTotalDiffStatus->bBinaryAEqB && pTotalDiffStatus->bBinaryAEqC )
+            totalInfo += i18n("All input files are binary equal.");
+         else  if ( pTotalDiffStatus->bTextAEqB && pTotalDiffStatus->bTextAEqC )
+            totalInfo += i18n("All input files contain the same text, but are not binary equal.");
+         else {
+            if    ( pTotalDiffStatus->bBinaryAEqB ) totalInfo += i18n("Files %1 and %2 are binary equal.\n"                          ).arg("A").arg("B");
+            else if ( pTotalDiffStatus->bTextAEqB ) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n").arg("A").arg("B");
+            if    ( pTotalDiffStatus->bBinaryAEqC ) totalInfo += i18n("Files %1 and %2 are binary equal.\n"                          ).arg("A").arg("C");
+            else if ( pTotalDiffStatus->bTextAEqC ) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n").arg("A").arg("C");
+            if    ( pTotalDiffStatus->bBinaryBEqC ) totalInfo += i18n("Files %1 and %2 are binary equal.\n"                          ).arg("B").arg("C");
+            else if ( pTotalDiffStatus->bTextBEqC ) totalInfo += i18n("Files %1 and %2 have equal text, but are not binary equal. \n").arg("B").arg("C");
+         }
+
+         if ( !totalInfo.isEmpty() )
+            KMessageBox::information( this, totalInfo );
+      }
+
+      if ( bVisibleMergeResultWindow && (!m_sd1.isText() || !m_sd2.isText() || !m_sd3.isText()) )
+      {
+         KMessageBox::information( this, i18n(
+            "Some inputfiles don't seem to be pure textfiles.\n"
+            "Note that the KDiff3-merge was not meant for binary data.\n"
+            "Continue at your own risk.") );
+      }
+   }
+
+   QTimer::singleShot( 10, this, SLOT(slotAfterFirstPaint()) );
+
+   if ( bVisibleMergeResultWindow && m_pMergeResultWindow )
+   {
+      m_pMergeResultWindow->setFocus();
+   }
+   else if(m_pDiffTextWindow1)
+   {
+      m_pDiffTextWindow1->setFocus();
+   }
+}
+
+
+void KDiff3App::resizeDiffTextWindow(int newWidth, int newHeight)
+{
+   m_DTWHeight = newHeight;
+
+   recalcWordWrap();
+
+   m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines+1 - newHeight) );
+   m_pDiffVScrollBar->setPageStep( newHeight );
+   m_pOverview->setRange( m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep() );
+
+   // The second window has a somewhat inverse width
+
+   m_pHScrollBar->setRange(0, max2(0, m_maxWidth - newWidth) );
+   m_pHScrollBar->setPageStep( newWidth );
+}
+
+void KDiff3App::resizeMergeResultWindow()
+{
+   MergeResultWindow* p = m_pMergeResultWindow;
+   m_pMergeVScrollBar->setRange(0, max2(0, p->getNofLines() - p->getNofVisibleLines()) );
+   m_pMergeVScrollBar->setPageStep( p->getNofVisibleLines() );
+
+   // The second window has a somewhat inverse width
+//   m_pHScrollBar->setRange(0, max2(0, m_maxWidth - newWidth) );
+//   m_pHScrollBar->setPageStep( newWidth );
+}
+
+void KDiff3App::scrollDiffTextWindow( int deltaX, int deltaY )
+{
+   if ( deltaY!= 0 )
+   {
+      m_pDiffVScrollBar->setValue( m_pDiffVScrollBar->value() + deltaY );
+      m_pOverview->setRange( m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep() );
+   }
+   if ( deltaX!= 0)
+      m_pHScrollBar->QScrollBar::setValue( m_pHScrollBar->value() + deltaX );
+}
+
+void KDiff3App::scrollMergeResultWindow( int deltaX, int deltaY )
+{
+   if ( deltaY!= 0 )
+      m_pMergeVScrollBar->setValue( m_pMergeVScrollBar->value() + deltaY );
+   if ( deltaX!= 0)
+      m_pHScrollBar->setValue( m_pHScrollBar->value() + deltaX );
+}
+
+void KDiff3App::setDiff3Line( int line )
+{
+   m_pDiffVScrollBar->setValue( line );
+}
+
+void KDiff3App::sourceMask( int srcMask, int enabledMask )
+{
+   chooseA->setChecked( (srcMask & 1) != 0 );
+   chooseB->setChecked( (srcMask & 2) != 0 );
+   chooseC->setChecked( (srcMask & 4) != 0 );
+   chooseA->setEnabled( (enabledMask & 1) != 0 );
+   chooseB->setEnabled( (enabledMask & 2) != 0 );
+   chooseC->setEnabled( (enabledMask & 4) != 0 );
+}
+
+
+
+// Function uses setMinSize( sizeHint ) before adding the widget.
+// void addWidget(QBoxLayout* layout, QWidget* widget);
+template <class W, class L>
+void addWidget( L* layout, W* widget)
+{
+   QSize s = widget->sizeHint();
+   widget->setMinimumSize( QSize(max2(s.width(),0),max2(s.height(),0) ) );
+   layout->addWidget( widget );
+}
+
+void KDiff3App::initView()
+{
+   // set the main widget here
+   QValueList<int> oldHeights;
+   if ( m_pDirectoryMergeSplitter->isVisible() )
+   {
+      oldHeights = m_pMainSplitter->sizes();
+   }
+
+   if ( m_pMainWidget != 0 )
+   {
+      return;
+      //delete m_pMainWidget;
+   }
+   m_pMainWidget = new QWidget(m_pMainSplitter);
+
+   QVBoxLayout* pVLayout = new QVBoxLayout(m_pMainWidget,0,0);
+
+   QSplitter* pVSplitter = new QSplitter( m_pMainWidget );
+   pVSplitter->setOrientation( Qt::Vertical );
+   pVLayout->addWidget( pVSplitter );
+
+   QWidget* pDiffWindowFrame = new QWidget( pVSplitter );
+   QHBoxLayout* pDiffHLayout = new QHBoxLayout( pDiffWindowFrame,0,0 );
+
+   m_pDiffWindowSplitter = new QSplitter( pDiffWindowFrame );
+   m_pDiffWindowSplitter->setOrientation( m_pOptionDialog->m_bHorizDiffWindowSplitting ?  Qt::Horizontal : Qt::Vertical );
+   pDiffHLayout->addWidget( m_pDiffWindowSplitter );
+
+   m_pOverview = new Overview( pDiffWindowFrame, m_pOptionDialog );
+   pDiffHLayout->addWidget(m_pOverview);
+   connect( m_pOverview, SIGNAL(setLine(int)), this, SLOT(setDiff3Line(int)) );
+   //connect( m_pOverview, SIGNAL(afterFirstPaint()), this, SLOT(slotAfterFirstPaint()));
+
+   m_pDiffVScrollBar = new QScrollBar( Qt::Vertical, pDiffWindowFrame );
+   pDiffHLayout->addWidget( m_pDiffVScrollBar );
+
+   m_pDiffTextWindowFrame1 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog, 1 );
+   m_pDiffTextWindowFrame2 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog, 2 );
+   m_pDiffTextWindowFrame3 = new DiffTextWindowFrame( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog, 3 );
+   m_pDiffTextWindow1 = m_pDiffTextWindowFrame1->getDiffTextWindow();
+   m_pDiffTextWindow2 = m_pDiffTextWindowFrame2->getDiffTextWindow();
+   m_pDiffTextWindow3 = m_pDiffTextWindowFrame3->getDiffTextWindow();
+   connect(m_pDiffTextWindowFrame1, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int)));
+   connect(m_pDiffTextWindowFrame2, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int)));
+   connect(m_pDiffTextWindowFrame3, SIGNAL(fileNameChanged(const QString&,int)), this, SLOT(slotFileNameChanged(const QString&,int)));
+
+   // Merge window
+   m_pMergeWindowFrame = new QWidget( pVSplitter );
+   QHBoxLayout* pMergeHLayout = new QHBoxLayout( m_pMergeWindowFrame,0,0 );
+
+   QVBoxLayout* pMergeVLayout = new QVBoxLayout();
+   pMergeHLayout->addLayout( pMergeVLayout, 1 );
+
+   m_pMergeResultWindowTitle = new WindowTitleWidget(m_pOptionDialog, m_pMergeWindowFrame);
+   pMergeVLayout->addWidget( m_pMergeResultWindowTitle );
+
+   m_pMergeResultWindow = new MergeResultWindow( m_pMergeWindowFrame, m_pOptionDialog, statusBar() );
+   pMergeVLayout->addWidget( m_pMergeResultWindow, 1 );
+
+   m_pMergeVScrollBar = new QScrollBar( Qt::Vertical, m_pMergeWindowFrame );
+   pMergeHLayout->addWidget( m_pMergeVScrollBar );
+
+   autoAdvance->setEnabled(true);
+
+   QValueList<int> sizes = pVSplitter->sizes();
+   int total = sizes[0] + sizes[1];
+   sizes[0]=total/2; sizes[1]=total/2;
+   pVSplitter->setSizes( sizes );
+
+   m_pMergeResultWindow->installEventFilter( this );       // for Cut/Copy/Paste-shortcuts
+   m_pMergeResultWindow->installEventFilter( m_pMergeResultWindowTitle ); // for focus tracking
+
+   QHBoxLayout* pHScrollBarLayout = new QHBoxLayout( pVLayout );
+   m_pHScrollBar = new ReversibleScrollBar( Qt::Horizontal, m_pMainWidget, &m_pOptionDialog->m_bRightToLeftLanguage );
+   pHScrollBarLayout->addWidget( m_pHScrollBar );
+   m_pCornerWidget = new QWidget( m_pMainWidget );
+   pHScrollBarLayout->addWidget( m_pCornerWidget );
+
+
+   connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pOverview, SLOT(setFirstLine(int)));
+   connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow1, SLOT(setFirstLine(int)));
+   connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow1, SLOT(setFirstColumn(int)));
+   connect( m_pDiffTextWindow1, SIGNAL(newSelection()), this, SLOT(slotSelectionStart()));
+   connect( m_pDiffTextWindow1, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd()));
+   connect( m_pDiffTextWindow1, SIGNAL(scroll(int,int)), this, SLOT(scrollDiffTextWindow(int,int)));
+   m_pDiffTextWindow1->installEventFilter( this );
+
+   connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow2, SLOT(setFirstLine(int)));
+   connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow2, SLOT(setFirstColumn(int)));
+   connect( m_pDiffTextWindow2, SIGNAL(newSelection()), this, SLOT(slotSelectionStart()));
+   connect( m_pDiffTextWindow2, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd()));
+   connect( m_pDiffTextWindow2, SIGNAL(scroll(int,int)), this, SLOT(scrollDiffTextWindow(int,int)));
+   m_pDiffTextWindow2->installEventFilter( this );
+
+   connect( m_pDiffVScrollBar, SIGNAL(valueChanged(int)), m_pDiffTextWindow3, SLOT(setFirstLine(int)));
+   connect( m_pHScrollBar, SIGNAL(valueChanged2(int)), m_pDiffTextWindow3, SLOT(setFirstColumn(int)));
+   connect( m_pDiffTextWindow3, SIGNAL(newSelection()), this, SLOT(slotSelectionStart()));
+   connect( m_pDiffTextWindow3, SIGNAL(selectionEnd()), this, SLOT(slotSelectionEnd()));
+   connect( m_pDiffTextWindow3, SIGNAL(scroll(int,int)), this, SLOT(scrollDiffTextWindow(int,int)));
+   m_pDiffTextWindow3->installEventFilter( this );
+
+
+   MergeResultWindow* p = m_pMergeResultWindow;
+   connect( m_pMergeVScrollBar, SIGNAL(valueChanged(int)), p, SLOT(setFirstLine(int)));
+
+   connect( m_pHScrollBar,      SIGNAL(valueChanged2(int)), p, SLOT(setFirstColumn(int)));
+   connect( p, SIGNAL(scroll(int,int)), this, SLOT(scrollMergeResultWindow(int,int)));
+   connect( p, SIGNAL(sourceMask(int,int)), this, SLOT(sourceMask(int,int)));
+   connect( p, SIGNAL( resizeSignal() ),this, SLOT(resizeMergeResultWindow()));
+   connect( p, SIGNAL( selectionEnd() ), this, SLOT( slotSelectionEnd() ) );
+   connect( p, SIGNAL( newSelection() ), this, SLOT( slotSelectionStart() ) );
+   connect( p, SIGNAL( modifiedChanged(bool) ), this, SLOT( slotOutputModified(bool) ) );
+   connect( p, SIGNAL( modifiedChanged(bool) ), m_pMergeResultWindowTitle, SLOT( slotSetModified(bool) ) );
+   connect( p, SIGNAL( updateAvailabilities() ), this, SLOT( slotUpdateAvailabilities() ) );
+   connect( p, SIGNAL( showPopupMenu(const QPoint&) ), this, SLOT(showPopupMenu(const QPoint&)));
+   connect( p, SIGNAL( noRelevantChangesDetected() ), this, SLOT(slotNoRelevantChangesDetected()));
+   sourceMask(0,0);
+
+
+   connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow1, SLOT(setFastSelectorRange(int,int)));
+   connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow2, SLOT(setFastSelectorRange(int,int)));
+   connect( p, SIGNAL(setFastSelectorRange(int,int)), m_pDiffTextWindow3, SLOT(setFastSelectorRange(int,int)));
+   connect(m_pDiffTextWindow1, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int)));
+   connect(m_pDiffTextWindow2, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int)));
+   connect(m_pDiffTextWindow3, SIGNAL(setFastSelectorLine(int)), p, SLOT(slotSetFastSelectorLine(int)));
+   connect(m_pDiffTextWindow1, SIGNAL(gotFocus()), p, SLOT(updateSourceMask()));
+   connect(m_pDiffTextWindow2, SIGNAL(gotFocus()), p, SLOT(updateSourceMask()));
+   connect(m_pDiffTextWindow3, SIGNAL(gotFocus()), p, SLOT(updateSourceMask()));
+   connect(m_pDirectoryMergeInfo, SIGNAL(gotFocus()), p, SLOT(updateSourceMask()));
+
+   connect( m_pDiffTextWindow1, SIGNAL( resizeSignal(int,int) ),this, SLOT(resizeDiffTextWindow(int,int)));
+   // The following two connects cause the wordwrap to be recalced thrice, just to make sure. Better than forgetting one.
+   connect( m_pDiffTextWindow2, SIGNAL( resizeSignal(int,int) ),this, SLOT(slotRecalcWordWrap()));
+   connect( m_pDiffTextWindow3, SIGNAL( resizeSignal(int,int) ),this, SLOT(slotRecalcWordWrap()));
+
+   m_pDiffTextWindow1->setFocus();
+   m_pMainWidget->setMinimumSize(50,50);
+   if ( m_pDirectoryMergeSplitter->isVisible() )
+   {
+      if (oldHeights.count() < 2)
+         oldHeights.append(0);
+      if (oldHeights[1]==0)    // Distribute the available space evenly between the two widgets.
+      {
+         oldHeights[1] = oldHeights[0]/2;
+         oldHeights[0] -= oldHeights[1];
+      }
+      m_pMainSplitter->setSizes( oldHeights );
+   }
+   m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() );
+   //show();
+   m_pMainWidget->show();
+   showWindowA->setChecked( true );
+   showWindowB->setChecked( true );
+   showWindowC->setChecked( true );
+}
+
+static int calcManualDiffFirstDiff3LineIdx( const Diff3LineVector& d3lv, const ManualDiffHelpEntry& mdhe )
+{
+   unsigned int i;
+   for( i = 0; i<d3lv.size(); ++i )
+   {
+      const Diff3Line& d3l = *d3lv[i];
+      if ( mdhe.lineA1>=0  &&  mdhe.lineA1==d3l.lineA ||
+           mdhe.lineB1>=0  &&  mdhe.lineB1==d3l.lineB ||
+           mdhe.lineC1>=0  &&  mdhe.lineC1==d3l.lineC )
+         return i;
+   }
+   return -1;
+}
+
+void KDiff3App::slotAfterFirstPaint()
+{
+   int newHeight = m_pDiffTextWindow1->getNofVisibleLines();
+   int newWidth  = m_pDiffTextWindow1->getNofVisibleColumns();
+   m_DTWHeight = newHeight;
+
+   recalcWordWrap();
+
+   m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines+1 - newHeight) );
+   m_pDiffVScrollBar->setPageStep( newHeight );
+   m_pOverview->setRange( m_pDiffVScrollBar->value(), m_pDiffVScrollBar->pageStep() );
+
+   // The second window has a somewhat inverse width
+   m_pHScrollBar->setRange(0, max2(0, m_maxWidth - newWidth) );
+   m_pHScrollBar->setPageStep( newWidth );
+
+   int d3l=-1;
+   if ( ! m_manualDiffHelpList.empty() )
+      d3l = calcManualDiffFirstDiff3LineIdx( m_diff3LineVector, m_manualDiffHelpList.front() );
+   if ( d3l>=0 && m_pDiffTextWindow1 )
+   {
+      int line = m_pDiffTextWindow1->convertDiff3LineIdxToLine( d3l );
+      m_pDiffVScrollBar->setValue( max2(0,line-1) );
+   }
+   else
+   {
+      m_pMergeResultWindow->slotGoTop();
+   }
+
+   if (m_pCornerWidget)
+      m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() );
+
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::resizeEvent(QResizeEvent* e)
+{
+   QSplitter::resizeEvent(e);
+   if (m_pCornerWidget)
+      m_pCornerWidget->setFixedSize( m_pDiffVScrollBar->width(), m_pHScrollBar->height() );
+}
+
+
+bool KDiff3App::eventFilter( QObject* o, QEvent* e )
+{
+   if( o == m_pMergeResultWindow )
+   {
+      if ( e->type() == QEvent::KeyPress )
+      {  // key press
+         QKeyEvent *k = (QKeyEvent*)e;
+         if (k->key()==Qt::Key_Insert &&  (k->state() & Qt::ControlButton)!=0 )
+         {
+            slotEditCopy();
+            return true;
+         }
+         if (k->key()==Qt::Key_Insert &&  (k->state() & Qt::ShiftButton)!=0 )
+         {
+            slotEditPaste();
+            return true;
+         }
+         if (k->key()==Qt::Key_Delete &&  (k->state() & Qt::ShiftButton)!=0 )
+         {
+            slotEditCut();
+            return true;
+         }
+      }
+      return QSplitter::eventFilter( o, e );    // standard event processing
+   }
+
+   if ( e->type() == QEvent::KeyPress )   // key press
+   {
+       QKeyEvent *k = (QKeyEvent*)e;
+
+       bool bCtrl = (k->state() & Qt::ControlButton) != 0;
+       if (k->key()==Qt::Key_Insert &&  bCtrl )
+       {
+          slotEditCopy();
+          return true;
+       }
+       if (k->key()==Qt::Key_Insert &&  (k->state() & Qt::ShiftButton)!=0 )
+       {
+          slotEditPaste();
+          return true;
+       }
+       int deltaX=0;
+       int deltaY=0;
+       int pageSize =  m_DTWHeight;
+       switch( k->key() )
+       {
+       case Qt::Key_Down:     if (!bCtrl) 
+                                 ++deltaY; 
+                              break;
+       case Qt::Key_Up:       if (!bCtrl) --deltaY; break;
+       case Qt::Key_PageDown: if (!bCtrl) deltaY+=pageSize; break;
+       case Qt::Key_PageUp:   if (!bCtrl) deltaY-=pageSize; break;
+       case Qt::Key_Left:     if (!bCtrl) --deltaX;  break;
+       case Qt::Key_Right:    if (!bCtrl) ++deltaX;  break;
+       case Qt::Key_Home: if ( bCtrl )  m_pDiffVScrollBar->setValue( 0 );
+                      else          m_pHScrollBar->setValue( 0 );
+                      break;
+       case Qt::Key_End:  if ( bCtrl )  m_pDiffVScrollBar->setValue( m_pDiffVScrollBar->maxValue() );
+                      else          m_pHScrollBar->setValue( m_pHScrollBar->maxValue() );
+                      break;
+       default: break;
+       }
+
+       scrollDiffTextWindow( deltaX, deltaY );
+
+       return true;                        // eat event
+   }
+   else if (e->type() == QEvent::Wheel )   // wheel event
+   {
+       QWheelEvent *w = (QWheelEvent*)e;
+       w->accept();
+
+       int deltaX=0;
+
+       int d=w->delta();
+       int deltaY = -d/120 * QApplication::wheelScrollLines();
+
+       scrollDiffTextWindow( deltaX, deltaY );
+       return true;
+   }
+   else if (e->type() == QEvent::Drop )
+   {
+      QDropEvent* pDropEvent = static_cast<QDropEvent*>(e);
+      pDropEvent->accept();
+
+      if ( QUriDrag::canDecode(pDropEvent) )
+      {
+#ifdef KREPLACEMENTS_H
+         QStringList stringList;
+         QUriDrag::decodeLocalFiles( pDropEvent, stringList );
+         if ( canContinue() && !stringList.isEmpty() )
+         {
+            raise();
+            QString filename = stringList.first();
+            if      ( o == m_pDiffTextWindow1 ) m_sd1.setFilename( filename );
+            else if ( o == m_pDiffTextWindow2 ) m_sd2.setFilename( filename );
+            else if ( o == m_pDiffTextWindow3 ) m_sd3.setFilename( filename );
+            init();
+         }
+#else
+         KURL::List urlList;
+         KURLDrag::decode( pDropEvent, urlList );
+         if ( canContinue() && !urlList.isEmpty() )
+         {
+            raise();
+            FileAccess fa( urlList.first().url() );
+            if      ( o == m_pDiffTextWindow1 ) m_sd1.setFileAccess( fa );
+            else if ( o == m_pDiffTextWindow2 ) m_sd2.setFileAccess( fa );
+            else if ( o == m_pDiffTextWindow3 ) m_sd3.setFileAccess( fa );
+            init();
+         }
+#endif
+      }
+      else if ( QTextDrag::canDecode(pDropEvent) )
+      {
+         QString text;
+         bool bDecodeSuccess = QTextDrag::decode( pDropEvent, text );
+         if ( bDecodeSuccess && canContinue() )
+         {
+            raise();
+            if      ( o == m_pDiffTextWindow1 ) m_sd1.setData(text);
+            else if ( o == m_pDiffTextWindow2 ) m_sd2.setData(text);
+            else if ( o == m_pDiffTextWindow3 ) m_sd3.setData(text);
+            init();
+         }
+      }
+
+      return true;
+   }
+   return QSplitter::eventFilter( o, e );    // standard event processing
+}
+
+
+
+
+void KDiff3App::slotFileOpen()
+{
+   if ( !canContinue() ) return;
+
+   if ( m_pDirectoryMergeWindow->isDirectoryMergeInProgress() )
+   {
+      int result = KMessageBox::warningYesNo(this,
+         i18n("You are currently doing a directory merge. Are you sure, you want to abort?"),
+         i18n("Warning"), i18n("Abort"), i18n("Continue Merging") );
+      if ( result!=KMessageBox::Yes )
+         return;
+   }
+
+
+   slotStatusMsg(i18n("Opening files..."));
+
+   for(;;)
+   {
+      OpenDialog d(this,
+         m_sd1.isFromBuffer() ? QString("") : m_sd1.getAliasName(),
+         m_sd2.isFromBuffer() ? QString("") : m_sd2.getAliasName(),
+         m_sd3.isFromBuffer() ? QString("") : m_sd3.getAliasName(),
+         !m_outputFilename.isEmpty(),
+         m_bDefaultFilename ? QString("") : m_outputFilename,
+         SLOT(slotConfigure()), m_pOptionDialog );
+      int status = d.exec();
+      if ( status == QDialog::Accepted )
+      {
+         m_sd1.setFilename( d.m_pLineA->currentText() );
+         m_sd2.setFilename( d.m_pLineB->currentText() );
+         m_sd3.setFilename( d.m_pLineC->currentText() );
+
+         if( d.m_pMerge->isChecked() )
+         {
+            if ( d.m_pLineOut->currentText().isEmpty() )
+            {
+               m_outputFilename = "unnamed.txt";
+               m_bDefaultFilename = true;
+            }
+            else
+            {
+               m_outputFilename = d.m_pLineOut->currentText();
+               m_bDefaultFilename = false;
+            }
+         }
+         else
+            m_outputFilename = "";
+
+         bool bSuccess = improveFilenames(false);
+         if ( !bSuccess )
+            continue;
+
+         if ( m_bDirCompare )
+         {
+            m_pDirectoryMergeSplitter->show();
+            if ( m_pMainWidget!=0 )
+            {
+               m_pMainWidget->hide();
+            }
+            break;
+         }
+         else
+         {
+            m_pDirectoryMergeSplitter->hide();
+            init();
+
+            if ( ! m_sd1.isEmpty() && !m_sd1.hasData()  ||
+                 ! m_sd2.isEmpty() && !m_sd2.hasData()  ||
+                 ! m_sd3.isEmpty() && !m_sd3.hasData() )
+            {
+               QString text( i18n("Opening of these files failed:") );
+               text += "\n\n";
+               if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
+                  text += " - " + m_sd1.getAliasName() + "\n";
+               if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
+                  text += " - " + m_sd2.getAliasName() + "\n";
+               if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
+                  text += " - " + m_sd3.getAliasName() + "\n";
+
+               KMessageBox::sorry( this, text, i18n("File open error") );
+               continue;
+            }
+         }
+      }
+      break;
+   }
+
+   slotUpdateAvailabilities();
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotFileOpen2(QString fn1, QString fn2, QString fn3, QString ofn,
+                              QString an1, QString an2, QString an3, TotalDiffStatus* pTotalDiffStatus )
+{
+   if ( !canContinue() ) return;
+
+   if(fn1=="" && fn2=="" && fn3=="" && ofn=="" && m_pMainWidget!=0 )
+   {
+      m_pMainWidget->hide();
+      return;
+   }
+
+   slotStatusMsg(i18n("Opening files..."));
+
+   m_sd1.setFilename( fn1 );
+   m_sd2.setFilename( fn2 );
+   m_sd3.setFilename( fn3 );
+
+   m_sd1.setAliasName( an1 );
+   m_sd2.setAliasName( an2 );
+   m_sd3.setAliasName( an3 );
+
+   if ( ! ofn.isEmpty() )
+   {
+      m_outputFilename = ofn;
+      m_bDefaultFilename = false;
+   }
+   else
+   {
+      m_outputFilename = "";
+      m_bDefaultFilename = true;
+   }
+
+   bool bDirCompare = m_bDirCompare;
+   improveFilenames(true);  // Create new window for KDiff3 for directory comparison.
+
+   if( m_bDirCompare )
+   {
+   }
+   else
+   {
+      m_bDirCompare = bDirCompare;  // Don't allow this to change here.
+      init( false, pTotalDiffStatus );
+
+      if ( pTotalDiffStatus!=0 )
+         return;
+
+      if ( ! m_sd1.isEmpty() && ! m_sd1.hasData()  ||
+           ! m_sd2.isEmpty() && ! m_sd2.hasData()  ||
+           ! m_sd3.isEmpty() && ! m_sd3.hasData() )
+      {
+         QString text( i18n("Opening of these files failed:") );
+         text += "\n\n";
+         if ( ! m_sd1.isEmpty() && !m_sd1.hasData() )
+            text += " - " + m_sd1.getAliasName() + "\n";
+         if ( ! m_sd2.isEmpty() && !m_sd2.hasData() )
+            text += " - " + m_sd2.getAliasName() + "\n";
+         if ( ! m_sd3.isEmpty() && !m_sd3.hasData() )
+            text += " - " + m_sd3.getAliasName() + "\n";
+
+         KMessageBox::sorry( this, text, i18n("File open error") );
+      }
+      else
+      {
+         if ( m_pDirectoryMergeWindow!=0 && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() )
+         {
+            slotDirViewToggle();
+         }
+      }
+   }
+   slotStatusMsg(i18n("Ready."));
+}
+
+
+void KDiff3App::slotFileNameChanged(const QString& fileName, int winIdx)
+{
+   QString fn1 = m_sd1.getFilename();
+   QString an1 = m_sd1.getAliasName();
+   QString fn2 = m_sd2.getFilename();
+   QString an2 = m_sd2.getAliasName();
+   QString fn3 = m_sd3.getFilename();
+   QString an3 = m_sd3.getAliasName();
+   if (winIdx==1) { fn1 = fileName; an1 = ""; }
+   if (winIdx==2) { fn2 = fileName; an2 = ""; }
+   if (winIdx==3) { fn3 = fileName; an3 = ""; }
+
+   slotFileOpen2( fn1, fn2, fn3, m_outputFilename, an1, an2, an3, 0 );
+}
+
+
+void KDiff3App::slotEditCut()
+{
+   slotStatusMsg(i18n("Cutting selection..."));
+
+   QString s;
+   if ( m_pMergeResultWindow!=0 )
+   {
+      s = m_pMergeResultWindow->getSelection();
+      m_pMergeResultWindow->deleteSelection();
+
+      m_pMergeResultWindow->update();
+   }
+
+   if ( !s.isNull() )
+   {
+      QApplication::clipboard()->setText( s, QClipboard::Clipboard );
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotEditCopy()
+{
+   slotStatusMsg(i18n("Copying selection to clipboard..."));
+   QString s;
+   if (               m_pDiffTextWindow1!=0 )   s = m_pDiffTextWindow1->getSelection();
+   if ( s.isNull() && m_pDiffTextWindow2!=0 )   s = m_pDiffTextWindow2->getSelection();
+   if ( s.isNull() && m_pDiffTextWindow3!=0 )   s = m_pDiffTextWindow3->getSelection();
+   if ( s.isNull() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection();
+   if ( !s.isNull() )
+   {
+      QApplication::clipboard()->setText( s, QClipboard::Clipboard );
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotEditPaste()
+{
+   slotStatusMsg(i18n("Inserting clipboard contents..."));
+
+   if ( m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() )
+   {
+      m_pMergeResultWindow->pasteClipboard(false);
+   }
+   else if ( canContinue() )
+   {
+      if ( m_pDiffTextWindow1->hasFocus() )
+      {
+         m_sd1.setData( QApplication::clipboard()->text(QClipboard::Clipboard) );
+         init();
+      }
+      else if ( m_pDiffTextWindow2->hasFocus() )
+      {
+         m_sd2.setData( QApplication::clipboard()->text(QClipboard::Clipboard) );
+         init();
+      }
+      else if ( m_pDiffTextWindow3->hasFocus() )
+      {
+         m_sd3.setData( QApplication::clipboard()->text(QClipboard::Clipboard) );
+         init();
+      }
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotEditSelectAll()
+{
+   int l=0,p=0; // needed as dummy return values
+   if  ( m_pMergeResultWindow && m_pMergeResultWindow->hasFocus() ) { m_pMergeResultWindow->setSelection( 0,0,m_pMergeResultWindow->getNofLines(),0); }
+   else if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->hasFocus() ) { m_pDiffTextWindow1  ->setSelection( 0,0,m_pDiffTextWindow1->getNofLines(),0,l,p);   }
+   else if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->hasFocus() ) { m_pDiffTextWindow2  ->setSelection( 0,0,m_pDiffTextWindow2->getNofLines(),0,l,p);   }
+   else if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->hasFocus() ) { m_pDiffTextWindow3  ->setSelection( 0,0,m_pDiffTextWindow3->getNofLines(),0,l,p);   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotGoCurrent()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoCurrent();
+}
+void KDiff3App::slotGoTop()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoTop();
+}
+void KDiff3App::slotGoBottom()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoBottom();
+}
+void KDiff3App::slotGoPrevUnsolvedConflict()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoPrevUnsolvedConflict();
+}
+void KDiff3App::slotGoNextUnsolvedConflict()
+{
+   m_bTimerBlock = false;
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoNextUnsolvedConflict();
+}
+void KDiff3App::slotGoPrevConflict()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoPrevConflict();
+}
+void KDiff3App::slotGoNextConflict()
+{
+   m_bTimerBlock = false;
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoNextConflict();
+}
+void KDiff3App::slotGoPrevDelta()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoPrevDelta();
+}
+void KDiff3App::slotGoNextDelta()
+{
+   if (m_pMergeResultWindow)  m_pMergeResultWindow->slotGoNextDelta();
+}
+
+void KDiff3App::choose( int choice )
+{
+   if (!m_bTimerBlock )
+   {
+      if ( m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->hasFocus() )
+      {
+         if (choice==A) m_pDirectoryMergeWindow->slotCurrentChooseA();
+         if (choice==B) m_pDirectoryMergeWindow->slotCurrentChooseB();
+         if (choice==C) m_pDirectoryMergeWindow->slotCurrentChooseC();
+         
+         chooseA->setChecked(false);
+         chooseB->setChecked(false);
+         chooseC->setChecked(false);
+      }
+      else if ( m_pMergeResultWindow )
+      {
+         m_pMergeResultWindow->choose( choice );
+         if ( autoAdvance->isChecked() )
+         {
+            m_bTimerBlock = true;
+            QTimer::singleShot( m_pOptionDialog->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) );
+         }
+      }
+   }
+}
+
+void KDiff3App::slotChooseA() { choose( A ); }
+void KDiff3App::slotChooseB() { choose( B ); }
+void KDiff3App::slotChooseC() { choose( C ); }
+
+// bConflictsOnly automatically choose for conflicts only (true) or for everywhere
+static void mergeChooseGlobal( MergeResultWindow* pMRW, int selector, bool bConflictsOnly, bool bWhiteSpaceOnly )
+{
+   if ( pMRW )
+   {
+      pMRW->chooseGlobal(selector, bConflictsOnly, bWhiteSpaceOnly );
+   }
+}
+
+void KDiff3App::slotChooseAEverywhere() {  mergeChooseGlobal( m_pMergeResultWindow, A, false, false ); }
+void KDiff3App::slotChooseBEverywhere() {  mergeChooseGlobal( m_pMergeResultWindow, B, false, false ); }
+void KDiff3App::slotChooseCEverywhere() {  mergeChooseGlobal( m_pMergeResultWindow, C, false, false ); }
+void KDiff3App::slotChooseAForUnsolvedConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, A, true, false ); }
+void KDiff3App::slotChooseBForUnsolvedConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, B, true, false ); }
+void KDiff3App::slotChooseCForUnsolvedConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, C, true, false ); }
+void KDiff3App::slotChooseAForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, A, true, true ); }
+void KDiff3App::slotChooseBForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, B, true, true ); }
+void KDiff3App::slotChooseCForUnsolvedWhiteSpaceConflicts() {  mergeChooseGlobal( m_pMergeResultWindow, C, true, true ); }
+
+
+void KDiff3App::slotAutoSolve()
+{
+   if (m_pMergeResultWindow )
+   {
+      m_pMergeResultWindow->slotAutoSolve();
+      // m_pMergeWindowFrame->show(); incompatible with bPreserveCarriageReturn
+      m_pMergeResultWindow->showNrOfConflicts();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotUnsolve()
+{
+   if (m_pMergeResultWindow )
+   {
+      m_pMergeResultWindow->slotUnsolve();
+   }
+}
+
+void KDiff3App::slotMergeHistory()
+{
+   if (m_pMergeResultWindow )
+   {
+      m_pMergeResultWindow->slotMergeHistory();
+   }
+}
+
+void KDiff3App::slotRegExpAutoMerge()
+{
+   if (m_pMergeResultWindow )
+   {
+      m_pMergeResultWindow->slotRegExpAutoMerge();
+   }
+}
+
+void KDiff3App::slotSplitDiff()
+{
+   int firstLine = -1;
+   int lastLine = -1;
+   DiffTextWindow* pDTW=0;
+   if (                m_pDiffTextWindow1 ) { pDTW=m_pDiffTextWindow1; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( firstLine<0 && m_pDiffTextWindow2 ) { pDTW=m_pDiffTextWindow2; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( firstLine<0 && m_pDiffTextWindow3 ) { pDTW=m_pDiffTextWindow3; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( pDTW && firstLine>=0 && m_pMergeResultWindow)
+   {
+      pDTW->resetSelection();
+
+      m_pMergeResultWindow->slotSplitDiff( firstLine, lastLine );
+   }
+}
+
+void KDiff3App::slotJoinDiffs()
+{
+   int firstLine = -1;
+   int lastLine = -1;
+   DiffTextWindow* pDTW=0;
+   if (                m_pDiffTextWindow1 ) { pDTW=m_pDiffTextWindow1; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( firstLine<0 && m_pDiffTextWindow2 ) { pDTW=m_pDiffTextWindow2; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( firstLine<0 && m_pDiffTextWindow3 ) { pDTW=m_pDiffTextWindow3; pDTW->getSelectionRange(&firstLine, &lastLine, eD3LLineCoords); }
+   if ( pDTW && firstLine>=0 && m_pMergeResultWindow)
+   {
+      pDTW->resetSelection();
+
+      m_pMergeResultWindow->slotJoinDiffs( firstLine, lastLine );
+   }
+}
+
+void KDiff3App::slotConfigure()
+{
+   m_pOptionDialog->setState();
+   m_pOptionDialog->incInitialSize ( QSize(0,40) );
+   m_pOptionDialog->exec();
+   slotRefresh();
+}
+
+void KDiff3App::slotConfigureKeys()
+{
+    KKeyDialog::configure(actionCollection(), this);
+}
+
+void KDiff3App::slotRefresh()
+{
+   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();
+   }
+   if (m_pDiffTextWindow3!=0)
+   {
+      m_pDiffTextWindow3->setFont(m_pOptionDialog->m_font);
+      m_pDiffTextWindow3->update();
+   }
+   if (m_pMergeResultWindow!=0)
+   {
+      m_pMergeResultWindow->setFont(m_pOptionDialog->m_font);
+      m_pMergeResultWindow->update();
+   }
+   if (m_pHScrollBar!=0)
+   {
+      m_pHScrollBar->setAgain();
+   }
+   if ( m_pDiffWindowSplitter!=0 )
+   {
+      m_pDiffWindowSplitter->setOrientation( m_pOptionDialog->m_bHorizDiffWindowSplitting ? Qt::Horizontal : Qt::Vertical );
+   }
+   if ( m_pDirectoryMergeWindow )
+   {
+      m_pDirectoryMergeWindow->updateFileVisibilities();
+   }
+}
+
+void KDiff3App::slotSelectionStart()
+{
+   //editCopy->setEnabled( false );
+   //editCut->setEnabled( false );
+
+   const QObject* s = sender();
+   if (m_pDiffTextWindow1 && s!=m_pDiffTextWindow1)   m_pDiffTextWindow1->resetSelection();
+   if (m_pDiffTextWindow2 && s!=m_pDiffTextWindow2)   m_pDiffTextWindow2->resetSelection();
+   if (m_pDiffTextWindow3 && s!=m_pDiffTextWindow3)   m_pDiffTextWindow3->resetSelection();
+   if (m_pMergeResultWindow && s!=m_pMergeResultWindow) m_pMergeResultWindow->resetSelection();
+}
+
+void KDiff3App::slotSelectionEnd()
+{
+   //const QObject* s = sender();
+   //editCopy->setEnabled(true);
+   //editCut->setEnabled( s==m_pMergeResultWindow );
+   if ( m_pOptionDialog->m_bAutoCopySelection )
+   {
+      slotEditCopy();
+   }
+   else
+   {
+       QClipboard *clipBoard = QApplication::clipboard();
+
+       if (clipBoard->supportsSelection ())
+       {
+           QString s;
+           if (               m_pDiffTextWindow1!=0 )   s = m_pDiffTextWindow1->getSelection();
+           if ( s.isNull() && m_pDiffTextWindow2!=0 )   s = m_pDiffTextWindow2->getSelection();
+           if ( s.isNull() && m_pDiffTextWindow3!=0 )   s = m_pDiffTextWindow3->getSelection();
+           if ( s.isNull() && m_pMergeResultWindow!=0 ) s = m_pMergeResultWindow->getSelection();
+           if ( !s.isNull() )
+           {
+               clipBoard->setText( s, QClipboard::Selection );
+           }
+       }
+   }
+}
+
+void KDiff3App::slotClipboardChanged()
+{
+   QString s = QApplication::clipboard()->text();
+   //editPaste->setEnabled(!s.isEmpty());
+}
+
+void KDiff3App::slotOutputModified(bool bModified)
+{
+   if ( bModified && !m_bOutputModified )
+   {
+      m_bOutputModified=true;
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotAutoAdvanceToggled()
+{
+   m_pOptionDialog->m_bAutoAdvance = autoAdvance->isChecked();
+}
+
+void KDiff3App::slotWordWrapToggled()
+{
+   m_pOptionDialog->m_bWordWrap = wordWrap->isChecked();
+   recalcWordWrap();
+}
+
+void KDiff3App::slotRecalcWordWrap()
+{
+   recalcWordWrap();
+}
+
+void KDiff3App::recalcWordWrap(int nofVisibleColumns) // nofVisibleColumns is >=0 only for printing, otherwise the really visible width is used
+{
+   bool bPrinting = nofVisibleColumns>=0;
+   int firstD3LIdx = 0;
+   if( m_pDiffTextWindow1 ) 
+      firstD3LIdx = m_pDiffTextWindow1->convertLineToDiff3LineIdx( m_pDiffTextWindow1->getFirstLine() );
+
+   // Convert selection to D3L-coords (converting back happens in DiffTextWindow::recalcWordWrap()
+   if ( m_pDiffTextWindow1 )
+      m_pDiffTextWindow1->convertSelectionToD3LCoords();
+   if ( m_pDiffTextWindow2 )
+      m_pDiffTextWindow2->convertSelectionToD3LCoords();
+   if ( m_pDiffTextWindow3 )
+      m_pDiffTextWindow3->convertSelectionToD3LCoords();
+
+
+   if ( !m_diff3LineList.empty() && m_pOptionDialog->m_bWordWrap )
+   {
+      Diff3LineList::iterator i;
+      int sumOfLines=0;
+      for ( i=m_diff3LineList.begin(); i!=m_diff3LineList.end(); ++i )
+      {
+         Diff3Line& d3l = *i;
+         d3l.linesNeededForDisplay = 1;
+         d3l.sumLinesNeededForDisplay = sumOfLines;
+         sumOfLines += d3l.linesNeededForDisplay;
+      }
+
+      // Let every window calc how many lines will be needed.
+      if ( m_pDiffTextWindow1 )
+         m_pDiffTextWindow1->recalcWordWrap(true,0,nofVisibleColumns);
+      if ( m_pDiffTextWindow2 )
+         m_pDiffTextWindow2->recalcWordWrap(true,0,nofVisibleColumns);
+      if ( m_pDiffTextWindow3 )
+         m_pDiffTextWindow3->recalcWordWrap(true,0,nofVisibleColumns);
+
+      sumOfLines=0;
+      for ( i=m_diff3LineList.begin(); i!=m_diff3LineList.end(); ++i )
+      {
+         Diff3Line& d3l = *i;
+         d3l.sumLinesNeededForDisplay = sumOfLines;
+         sumOfLines += d3l.linesNeededForDisplay;
+      }
+
+      // Finish the initialisation:
+      if ( m_pDiffTextWindow1 )
+         m_pDiffTextWindow1->recalcWordWrap(true,sumOfLines,nofVisibleColumns);
+      if ( m_pDiffTextWindow2 )
+         m_pDiffTextWindow2->recalcWordWrap(true,sumOfLines,nofVisibleColumns);
+      if ( m_pDiffTextWindow3 )
+         m_pDiffTextWindow3->recalcWordWrap(true,sumOfLines,nofVisibleColumns);
+
+      m_neededLines = sumOfLines;
+   }
+   else
+   {
+      m_neededLines = m_diff3LineVector.size();
+      if ( m_pDiffTextWindow1 )
+         m_pDiffTextWindow1->recalcWordWrap(false,0,0);
+      if ( m_pDiffTextWindow2 )
+         m_pDiffTextWindow2->recalcWordWrap(false,0,0);
+      if ( m_pDiffTextWindow3 )
+         m_pDiffTextWindow3->recalcWordWrap(false,0,0);
+   }
+   if (bPrinting)
+      return;
+
+   m_pOverview->slotRedraw();
+   if ( m_pDiffTextWindow1 )
+   {
+      m_pDiffTextWindow1->setFirstLine( m_pDiffTextWindow1->convertDiff3LineIdxToLine( firstD3LIdx ) );
+      m_pDiffTextWindow1->update();
+   }
+   if ( m_pDiffTextWindow2 )
+   {
+      m_pDiffTextWindow2->setFirstLine( m_pDiffTextWindow2->convertDiff3LineIdxToLine( firstD3LIdx ) );
+      m_pDiffTextWindow2->update();
+   }
+   if ( m_pDiffTextWindow3 )
+   {
+      m_pDiffTextWindow3->setFirstLine( m_pDiffTextWindow3->convertDiff3LineIdxToLine( firstD3LIdx ) );
+      m_pDiffTextWindow3->update();
+   }
+
+   m_pDiffVScrollBar->setRange(0, max2(0, m_neededLines+1 - m_DTWHeight) );
+   if ( m_pDiffTextWindow1 )
+   {
+      m_pDiffVScrollBar->setValue( m_pDiffTextWindow1->convertDiff3LineIdxToLine( firstD3LIdx ) );
+
+      m_maxWidth = max3( m_pDiffTextWindow1->getNofColumns(), 
+                         m_pDiffTextWindow2->getNofColumns(),
+                         m_pDiffTextWindow3->getNofColumns() ) + (m_pOptionDialog->m_bWordWrap ? 0 : 5);
+
+      m_pHScrollBar->setRange(0, max2( 0, m_maxWidth - m_pDiffTextWindow1->getNofVisibleColumns() ) );
+      m_pHScrollBar->setPageStep( m_pDiffTextWindow1->getNofVisibleColumns() );
+      m_pHScrollBar->setValue(0);
+   }
+}
+
+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()
+{
+   m_pOptionDialog->m_bShowLineNumbers = showLineNumbers->isChecked();
+   if ( m_pDiffTextWindow1!=0 )
+      m_pDiffTextWindow1->update();
+   if ( m_pDiffTextWindow2!=0 )
+      m_pDiffTextWindow2->update();
+   if ( m_pDiffTextWindow3!=0 )
+      m_pDiffTextWindow3->update();
+}
+
+/// Return true for success, else false
+bool KDiff3App::improveFilenames( bool bCreateNewInstance )
+{
+   m_bDirCompare = false;
+
+   FileAccess f1(m_sd1.getFilename());
+   FileAccess f2(m_sd2.getFilename());
+   FileAccess f3(m_sd3.getFilename());
+   FileAccess f4(m_outputFilename);
+
+   if ( f1.isFile()  &&  f1.exists() )
+   {
+      if ( f2.isDir() )
+      {
+         f2.addPath( f1.fileName() );
+         if ( f2.isFile() && f2.exists() )
+            m_sd2.setFileAccess( f2 );
+      }
+      if ( f3.isDir() )
+      {
+         f3.addPath( f1.fileName() );
+         if ( f3.isFile() && f3.exists() )
+            m_sd3.setFileAccess( f3 );
+      }
+      if ( f4.isDir() )
+      {
+         f4.addPath( f1.fileName() );
+         if ( f4.isFile() && f4.exists() )
+            m_outputFilename = f4.absFilePath();
+      }
+   }
+   else if ( f1.isDir() )
+   {
+      m_bDirCompare = true;
+      if (bCreateNewInstance)
+      {
+         emit createNewInstance( f1.absFilePath(), f2.absFilePath(), f3.absFilePath() );
+      }
+      else
+      {
+         FileAccess destDir;
+         if (!m_bDefaultFilename) destDir = f4;
+         m_pDirectoryMergeSplitter->show();
+         if (m_pMainWidget!=0) m_pMainWidget->hide();
+
+         bool bSuccess = m_pDirectoryMergeWindow->init(
+            f1, f2, f3,
+            destDir,  // Destdirname
+            !m_outputFilename.isEmpty()
+            );
+   
+         m_bDirCompare = true;  // This seems redundant but it might have been reset during full analysis.
+   
+         if (bSuccess)
+         {
+            m_sd1.reset();
+            if (m_pDiffTextWindow1!=0) m_pDiffTextWindow1->init(0,0,0,0,0,false);
+            m_sd2.reset();
+            if (m_pDiffTextWindow2!=0) m_pDiffTextWindow2->init(0,0,0,0,0,false);
+            m_sd3.reset();
+            if (m_pDiffTextWindow3!=0) m_pDiffTextWindow3->init(0,0,0,0,0,false);
+         }
+         slotUpdateAvailabilities();
+         return bSuccess;
+      }
+   }
+   return true;
+}
+
+void KDiff3App::slotReload()
+{
+   if ( !canContinue() ) return;
+
+   init();
+}
+
+bool KDiff3App::canContinue()
+{
+   // First test if anything must be saved.
+   if(m_bOutputModified)
+   {
+      int result = KMessageBox::warningYesNoCancel(this,
+         i18n("The merge result hasn't been saved."),
+         i18n("Warning"), i18n("Save && Continue"), i18n("Continue Without Saving") );
+      if ( result==KMessageBox::Cancel )
+         return false;
+      else if ( result==KMessageBox::Yes )
+      {
+         slotFileSave();
+         if ( m_bOutputModified )
+         {
+            KMessageBox::sorry(this, i18n("Saving the merge result failed."), i18n("Warning") );
+            return false;
+         }
+      }
+   }
+
+   m_bOutputModified = false;
+   return true;
+}
+
+void KDiff3App::slotCheckIfCanContinue( bool* pbContinue )
+{
+   if (pbContinue!=0) *pbContinue = canContinue();
+}
+
+
+void KDiff3App::slotDirShowBoth()
+{
+   if( dirShowBoth->isChecked() )
+   {
+      if ( m_bDirCompare )
+         m_pDirectoryMergeSplitter->show();
+      else
+         m_pDirectoryMergeSplitter->hide();
+
+      if ( m_pMainWidget!=0 )
+         m_pMainWidget->show();
+   }
+   else
+   {
+      if ( m_pMainWidget!=0 )
+      {
+         m_pMainWidget->show();
+         m_pDirectoryMergeSplitter->hide();
+      }
+      else if ( m_bDirCompare )
+      {
+         m_pDirectoryMergeSplitter->show();
+      }
+   }
+
+   slotUpdateAvailabilities();
+}
+
+
+void KDiff3App::slotDirViewToggle()
+{
+   if ( m_bDirCompare )
+   {
+      if( ! m_pDirectoryMergeSplitter->isVisible() )
+      {
+         m_pDirectoryMergeSplitter->show();
+         if (m_pMainWidget!=0)
+            m_pMainWidget->hide();
+      }
+      else
+      {
+         if (m_pMainWidget!=0)
+         {
+            m_pDirectoryMergeSplitter->hide();
+            m_pMainWidget->show();
+         }
+      }
+   }
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::slotShowWindowAToggled()
+{
+   if ( m_pDiffTextWindow1!=0 )
+   {
+      if ( showWindowA->isChecked() ) m_pDiffTextWindowFrame1->show();
+      else                            m_pDiffTextWindowFrame1->hide();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotShowWindowBToggled()
+{
+   if ( m_pDiffTextWindow2!=0 )
+   {
+      if ( showWindowB->isChecked() ) m_pDiffTextWindowFrame2->show();
+      else                            m_pDiffTextWindowFrame2->hide();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotShowWindowCToggled()
+{
+   if ( m_pDiffTextWindow3!=0 )
+   {
+      if ( showWindowC->isChecked() ) m_pDiffTextWindowFrame3->show();
+      else                            m_pDiffTextWindowFrame3->hide();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotEditFind()
+{
+   m_pFindDialog->currentLine = 0;
+   m_pFindDialog->currentPos = 0;
+   m_pFindDialog->currentWindow = 1;
+   
+   if ( QDialog::Accepted == m_pFindDialog->exec() )
+   {
+      slotEditFindNext();
+   }
+}
+
+void KDiff3App::slotEditFindNext()
+{
+   QString s = m_pFindDialog->m_pSearchString->text();
+   if ( s.isEmpty() )
+   {
+      slotEditFind();
+      return;
+   }
+
+   bool bDirDown = true;
+   bool bCaseSensitive = m_pFindDialog->m_pCaseSensitive->isChecked();
+
+   int d3vLine = m_pFindDialog->currentLine;
+   int posInLine = m_pFindDialog->currentPos;
+   int l=0;
+   int p=0;
+   if ( m_pFindDialog->currentWindow == 1 )
+   {
+      if ( m_pFindDialog->m_pSearchInA->isChecked() && m_pDiffTextWindow1!=0  &&
+           m_pDiffTextWindow1->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) )
+      {
+         m_pDiffTextWindow1->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(), l, p );
+         m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2);
+         m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) );
+         m_pFindDialog->currentLine = d3vLine;
+         m_pFindDialog->currentPos = posInLine + 1;
+         return;
+      }
+      m_pFindDialog->currentWindow = 2;
+      m_pFindDialog->currentLine = 0;
+      m_pFindDialog->currentPos = 0;
+   }
+
+   d3vLine = m_pFindDialog->currentLine;
+   posInLine = m_pFindDialog->currentPos;
+   if ( m_pFindDialog->currentWindow == 2 )
+   {
+      if ( m_pFindDialog->m_pSearchInB->isChecked() && m_pDiffTextWindow2!=0 &&
+           m_pDiffTextWindow2->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) )
+      {
+         m_pDiffTextWindow2->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(),l,p );
+         m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2);
+         m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) );
+         m_pFindDialog->currentLine = d3vLine;
+         m_pFindDialog->currentPos = posInLine + 1;
+         return;
+      }
+      m_pFindDialog->currentWindow = 3;
+      m_pFindDialog->currentLine = 0;
+      m_pFindDialog->currentPos = 0;
+   }
+
+   d3vLine = m_pFindDialog->currentLine;
+   posInLine = m_pFindDialog->currentPos;
+   if ( m_pFindDialog->currentWindow == 3 )
+   {
+      if ( m_pFindDialog->m_pSearchInC->isChecked() && m_pDiffTextWindow3!=0 &&
+           m_pDiffTextWindow3->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) )
+      {
+         m_pDiffTextWindow3->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length(),l,p );
+         m_pDiffVScrollBar->setValue(l-m_pDiffVScrollBar->pageStep()/2);
+         m_pHScrollBar->setValue( max2( 0, p+(int)s.length()-m_pHScrollBar->pageStep()) );
+         m_pFindDialog->currentLine = d3vLine;
+         m_pFindDialog->currentPos = posInLine + 1;
+         return;
+      }
+      m_pFindDialog->currentWindow = 4;
+      m_pFindDialog->currentLine = 0;
+      m_pFindDialog->currentPos = 0;
+   }  
+
+   d3vLine = m_pFindDialog->currentLine;
+   posInLine = m_pFindDialog->currentPos;
+   if ( m_pFindDialog->currentWindow == 4 )
+   {
+      if ( m_pFindDialog->m_pSearchInOutput->isChecked() && m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() &&
+           m_pMergeResultWindow->findString( s, d3vLine, posInLine, bDirDown, bCaseSensitive ) )
+      {
+         m_pMergeResultWindow->setSelection( d3vLine, posInLine, d3vLine, posInLine+s.length() );
+         m_pMergeVScrollBar->setValue(d3vLine - m_pMergeVScrollBar->pageStep()/2);
+         m_pHScrollBar->setValue( max2( 0, posInLine+(int)s.length()-m_pHScrollBar->pageStep()) );
+         m_pFindDialog->currentLine = d3vLine;
+         m_pFindDialog->currentPos = posInLine + 1;
+         return;
+      }
+      m_pFindDialog->currentWindow = 5;
+      m_pFindDialog->currentLine = 0;
+      m_pFindDialog->currentPos = 0;
+   }
+
+   KMessageBox::information(this,i18n("Search complete."),i18n("Search Complete"));
+   m_pFindDialog->currentWindow = 1;
+   m_pFindDialog->currentLine = 0;
+   m_pFindDialog->currentPos = 0;
+}
+
+void KDiff3App::slotMergeCurrentFile()
+{
+   if ( m_bDirCompare  &&  m_pDirectoryMergeWindow->isVisible()  &&  m_pDirectoryMergeWindow->isFileSelected() )
+   {
+      m_pDirectoryMergeWindow->mergeCurrentFile();
+   }
+   else if ( m_pMainWidget != 0 && m_pMainWidget->isVisible() )
+   {
+      if ( !canContinue() ) return;
+      if ( m_outputFilename.isEmpty() )
+      {
+         if ( !m_sd3.isEmpty() && !m_sd3.isFromBuffer() )
+         {
+            m_outputFilename =  m_sd3.getFilename();
+         }
+         else if ( !m_sd2.isEmpty() && !m_sd2.isFromBuffer() )
+         {
+            m_outputFilename =  m_sd2.getFilename();
+         }
+         else if ( !m_sd1.isEmpty() && !m_sd1.isFromBuffer() )
+         {
+            m_outputFilename =  m_sd1.getFilename();
+         }
+         else
+         {
+            m_outputFilename = "unnamed.txt";
+            m_bDefaultFilename = true;
+         }
+      }
+      init();
+   }
+}
+
+void KDiff3App::slotWinFocusNext()
+{
+   QWidget* focus = qApp->focusWidget();
+   if ( focus == m_pDirectoryMergeWindow && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() )
+   {
+      slotDirViewToggle();
+   }
+
+   std::list<QWidget*> visibleWidgetList;
+   if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1);
+   if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2);
+   if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3);
+   if ( m_pMergeResultWindow && m_pMergeResultWindow->isVisible() ) visibleWidgetList.push_back(m_pMergeResultWindow);
+   if ( m_bDirCompare /*m_pDirectoryMergeWindow->isVisible()*/ ) visibleWidgetList.push_back(m_pDirectoryMergeWindow);
+   //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList());
+
+   std::list<QWidget*>::iterator i = std::find( visibleWidgetList.begin(),  visibleWidgetList.end(), focus);
+   ++i;
+   if ( i==visibleWidgetList.end() ) 
+      i = visibleWidgetList.begin();
+   if ( i!=visibleWidgetList.end() )
+   {
+      if ( *i == m_pDirectoryMergeWindow  && ! dirShowBoth->isChecked() )
+      {
+         slotDirViewToggle();
+      }
+      (*i)->setFocus();
+   }
+}
+
+void KDiff3App::slotWinFocusPrev()
+{
+   QWidget* focus = qApp->focusWidget();
+   if ( focus == m_pDirectoryMergeWindow  && m_pDirectoryMergeWindow->isVisible() && ! dirShowBoth->isChecked() )
+   {
+      slotDirViewToggle();
+   }
+
+   std::list<QWidget*> visibleWidgetList;
+   if ( m_pDiffTextWindow1 && m_pDiffTextWindow1->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1);
+   if ( m_pDiffTextWindow2 && m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2);
+   if ( m_pDiffTextWindow3 && m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3);
+   if ( m_pMergeResultWindow && m_pMergeResultWindow->isVisible() ) visibleWidgetList.push_back(m_pMergeResultWindow);
+   if (m_bDirCompare /* m_pDirectoryMergeWindow->isVisible() */ ) visibleWidgetList.push_back(m_pDirectoryMergeWindow);
+   //if ( m_pDirectoryMergeInfo->isVisible() ) visibleWidgetList.push_back(m_pDirectoryMergeInfo->getInfoList());
+
+   std::list<QWidget*>::iterator i = std::find( visibleWidgetList.begin(),  visibleWidgetList.end(), focus);
+   if ( i==visibleWidgetList.begin() )
+      i=visibleWidgetList.end();
+   --i;
+   if ( i!=visibleWidgetList.end() )
+   {
+      if ( *i == m_pDirectoryMergeWindow  && ! dirShowBoth->isChecked() )
+      {
+         slotDirViewToggle();
+      }
+      (*i)->setFocus();
+   }
+}
+
+void KDiff3App::slotWinToggleSplitterOrientation()
+{
+   if ( m_pDiffWindowSplitter!=0 )
+   {
+      m_pDiffWindowSplitter->setOrientation(
+            m_pDiffWindowSplitter->orientation()==Qt::Vertical ? Qt::Horizontal : Qt::Vertical
+         );
+
+      m_pOptionDialog->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation()==Qt::Horizontal;
+   }
+}
+
+void KDiff3App::slotOverviewNormal()
+{
+   m_pOverview->setOverviewMode( Overview::eOMNormal );
+   m_pMergeResultWindow->setOverviewMode( Overview::eOMNormal );
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::slotOverviewAB()
+{
+   m_pOverview->setOverviewMode( Overview::eOMAvsB );
+   m_pMergeResultWindow->setOverviewMode( Overview::eOMAvsB );
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::slotOverviewAC()
+{
+   m_pOverview->setOverviewMode( Overview::eOMAvsC );
+   m_pMergeResultWindow->setOverviewMode( Overview::eOMAvsC );
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::slotOverviewBC()
+{
+   m_pOverview->setOverviewMode( Overview::eOMBvsC );
+   m_pMergeResultWindow->setOverviewMode( Overview::eOMBvsC );
+   slotUpdateAvailabilities();
+}
+
+void KDiff3App::slotNoRelevantChangesDetected()
+{
+   if ( m_bTripleDiff &&  ! m_outputFilename.isEmpty() )
+   {
+      //KMessageBox::information( this, "No relevant changes detected", "KDiff3" );
+      if (!m_pOptionDialog->m_IrrelevantMergeCmd.isEmpty())
+      {
+         QString cmd = m_pOptionDialog->m_IrrelevantMergeCmd + " \"" + m_sd1.getAliasName()+ "\" \"" + m_sd2.getAliasName() + "\" \"" + m_sd3.getAliasName();
+         ::system( cmd.local8Bit() );
+      }
+   }
+}
+
+static void insertManualDiffHelp( ManualDiffHelpList* pManualDiffHelpList, int winIdx, int firstLine, int lastLine )
+{
+   // The manual diff help list must be sorted and compact.
+   // "Compact" means that upper items can't be empty if lower items contain data.
+
+   // First insert the new item without regarding compactness.
+   // If the new item overlaps with previous items then the previous items will be removed.
+
+   ManualDiffHelpEntry mdhe;
+   mdhe.firstLine( winIdx ) = firstLine;
+   mdhe.lastLine( winIdx ) = lastLine;
+
+   ManualDiffHelpList::iterator i;
+   for( i=pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i )
+   {
+      int& l1 = i->firstLine( winIdx );
+      int& l2 = i->lastLine( winIdx );
+      if (l1>=0 && l2>=0)
+      {
+         if ( firstLine<=l1 && lastLine>=l1  ||  firstLine <=l2 && lastLine>=l2 )
+         {
+            // overlap
+            l1 = -1;
+            l2 = -1;
+         }
+         if ( firstLine<l1 && lastLine<l1 )
+         {
+            // insert before this position
+            pManualDiffHelpList->insert( i, mdhe );
+            break;
+         }
+      }
+   }
+   if ( i == pManualDiffHelpList->end() )
+   {
+      pManualDiffHelpList->insert( i, mdhe );
+   }
+
+   // Now make the list compact
+   for( int wIdx=1; wIdx<=3; ++wIdx )
+   {
+      ManualDiffHelpList::iterator iEmpty = pManualDiffHelpList->begin();
+      for( i=pManualDiffHelpList->begin(); i!=pManualDiffHelpList->end(); ++i )
+      {
+         if ( iEmpty->firstLine(wIdx) >= 0 )
+         {
+            ++iEmpty;
+            continue;
+         }
+         if ( i->firstLine(wIdx)>=0 )  // Current item is not empty -> move it to the empty place
+         {
+            iEmpty->firstLine(wIdx) = i->firstLine(wIdx);
+            iEmpty->lastLine(wIdx) = i->lastLine(wIdx);
+            i->firstLine(wIdx) = -1;
+            i->lastLine(wIdx) = -1;
+            ++iEmpty;
+         }
+      }
+   }
+   pManualDiffHelpList->remove( ManualDiffHelpEntry() ); // Remove all completely empty items.
+}
+
+void KDiff3App::slotAddManualDiffHelp()
+{
+   int firstLine = -1;
+   int lastLine = -1;
+   int winIdx = -1;
+   if (                m_pDiffTextWindow1 ) { m_pDiffTextWindow1->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=1; }
+   if ( firstLine<0 && m_pDiffTextWindow2 ) { m_pDiffTextWindow2->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=2; }
+   if ( firstLine<0 && m_pDiffTextWindow3 ) { m_pDiffTextWindow3->getSelectionRange(&firstLine, &lastLine, eFileCoords); winIdx=3; }
+
+   if ( firstLine<0 || lastLine <0 || lastLine<firstLine )
+      KMessageBox::information( this, i18n("Nothing is selected in either diff input window."), i18n("Error while adding manual diff range") );
+   else
+   {
+   /*
+      ManualDiffHelpEntry mdhe;
+      if (!m_manualDiffHelpList.empty()) mdhe = m_manualDiffHelpList.front();
+      if ( winIdx==1 ) { mdhe.lineA1 = firstLine; mdhe.lineA2 = lastLine; }
+      if ( winIdx==2 ) { mdhe.lineB1 = firstLine; mdhe.lineB2 = lastLine; }
+      if ( winIdx==3 ) { mdhe.lineC1 = firstLine; mdhe.lineC2 = lastLine; }
+      m_manualDiffHelpList.clear();
+      m_manualDiffHelpList.push_back( mdhe );
+      */
+
+      insertManualDiffHelp( &m_manualDiffHelpList, winIdx, firstLine, lastLine );
+
+      init( false, 0, false ); // Init without reload
+      slotRefresh();
+   }
+}
+
+void KDiff3App::slotClearManualDiffHelpList()
+{
+   m_manualDiffHelpList.clear();
+   init( false, 0, false ); // Init without reload
+   slotRefresh();
+}
+
+void KDiff3App::slotUpdateAvailabilities()
+{
+   bool bTextDataAvailable = ( m_sd1.hasData() || m_sd2.hasData() || m_sd3.hasData() );
+
+   if( dirShowBoth->isChecked() )
+   {
+      if ( m_bDirCompare )
+         m_pDirectoryMergeSplitter->show();
+      else
+         m_pDirectoryMergeSplitter->hide();
+
+      if ( m_pMainWidget!=0 && !m_pMainWidget->isVisible() &&
+           bTextDataAvailable && !m_pDirectoryMergeWindow->isScanning()
+         )
+         m_pMainWidget->show();
+   }
+
+
+   bool bDiffWindowVisible = m_pMainWidget != 0 && m_pMainWidget->isVisible();
+   bool bMergeEditorVisible = m_pMergeWindowFrame !=0  &&  m_pMergeWindowFrame->isVisible();
+
+   m_pDirectoryMergeWindow->updateAvailabilities( m_bDirCompare, bDiffWindowVisible, chooseA, chooseB, chooseC );
+
+   dirShowBoth->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 )
+      );
+
+   bool bDirWindowHasFocus = m_pDirectoryMergeSplitter->isVisible() && m_pDirectoryMergeWindow->hasFocus();
+
+   showWhiteSpaceCharacters->setEnabled( bDiffWindowVisible );
+   autoAdvance->setEnabled( bMergeEditorVisible );
+   autoSolve->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   unsolve->setEnabled( bMergeEditorVisible );
+   if ( !bDirWindowHasFocus )
+   {
+      chooseA->setEnabled( bMergeEditorVisible );
+      chooseB->setEnabled( bMergeEditorVisible );
+      chooseC->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   }
+   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 );
+   mergeHistory->setEnabled( bMergeEditorVisible );
+   mergeRegExp->setEnabled( bMergeEditorVisible );
+   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() ) );
+   editFind->setEnabled( bDiffWindowVisible );
+   editFindNext->setEnabled( bDiffWindowVisible );
+   m_pFindDialog->m_pSearchInC->setEnabled( m_bTripleDiff );
+   m_pFindDialog->m_pSearchInOutput->setEnabled( bMergeEditorVisible );
+
+   bool bSavable = bMergeEditorVisible && m_pMergeResultWindow->getNrOfUnsolvedConflicts()==0;
+   fileSave->setEnabled( m_bOutputModified && bSavable );
+   fileSaveAs->setEnabled( bSavable );
+
+   goTop->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isDeltaAboveCurrent() );
+   goBottom->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isDeltaBelowCurrent() );
+   goCurrent->setEnabled( bDiffWindowVisible );
+   goPrevUnsolvedConflict->setEnabled( bMergeEditorVisible &&  m_pMergeResultWindow->isUnsolvedConflictAboveCurrent() );
+   goNextUnsolvedConflict->setEnabled( bMergeEditorVisible &&  m_pMergeResultWindow->isUnsolvedConflictBelowCurrent() );
+   goPrevConflict->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isConflictAboveCurrent() );
+   goNextConflict->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isConflictBelowCurrent() );
+   goPrevDelta->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isDeltaAboveCurrent() );
+   goNextDelta->setEnabled( bDiffWindowVisible &&  m_pMergeResultWindow->isDeltaBelowCurrent() );
+
+   overviewModeNormal->setEnabled( m_bTripleDiff && bDiffWindowVisible );
+   overviewModeAB->setEnabled( m_bTripleDiff && bDiffWindowVisible );
+   overviewModeAC->setEnabled( m_bTripleDiff && bDiffWindowVisible );
+   overviewModeBC->setEnabled( m_bTripleDiff && bDiffWindowVisible );
+   Overview::e_OverviewMode overviewMode = m_pOverview==0 ? Overview::eOMNormal : m_pOverview->getOverviewMode();
+   overviewModeNormal->setChecked( overviewMode == Overview::eOMNormal );
+   overviewModeAB->setChecked( overviewMode == Overview::eOMAvsB );
+   overviewModeAC->setChecked( overviewMode == Overview::eOMAvsC );
+   overviewModeBC->setChecked( overviewMode == Overview::eOMBvsC );
+
+   winToggleSplitOrientation->setEnabled( bDiffWindowVisible && m_pDiffWindowSplitter!=0 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/smalldialogs.cpp	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,579 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2006 by Joachim Eibl                               *
+ *   joachim.eibl at gmx.de                                                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#include "smalldialogs.h"
+#include "optiondialog.h"
+
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qdragobject.h>
+#include <qregexp.h>
+#include <qtooltip.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+
+
+#include <kfiledialog.h>
+#include <klocale.h>
+
+// OpenDialog **************************************************************
+
+OpenDialog::OpenDialog(
+   QWidget* pParent, const QString& n1, const QString& n2, const QString& n3,
+   bool bMerge, const QString& outputName, const char* slotConfigure, OptionDialog* pOptions )
+: QDialog( pParent, "OpenDialog", true /*modal*/ )
+{
+   m_pOptions = pOptions;
+
+   QVBoxLayout* v = new QVBoxLayout( this, 5 );
+   QGridLayout* h = new QGridLayout( v, 5, 4, 5 );
+   h->setColStretch( 1, 10 );
+
+   QLabel* label  = new QLabel( i18n("A (Base):"), this );
+
+   m_pLineA = new QComboBox( true, this );
+   m_pLineA->insertStringList( m_pOptions->m_recentAFiles );
+   m_pLineA->setEditText( KURL(n1).prettyURL() );
+   m_pLineA->setMinimumSize( 200, m_pLineA->size().height() );
+   QPushButton * button = new QPushButton( i18n("File..."), this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileA() ) );
+   QPushButton * button2 = new QPushButton( i18n("Dir..."), this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirA() ) );
+   connect( m_pLineA, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
+
+   h->addWidget( label,    0, 0 );
+   h->addWidget( m_pLineA,  0, 1 );
+   h->addWidget( button,   0, 2 );
+   h->addWidget( button2,  0, 3 );
+
+   label    = new QLabel( "B:", this );
+   m_pLineB  = new QComboBox( true, this );
+   m_pLineB->insertStringList( m_pOptions->m_recentBFiles );
+   m_pLineB->setEditText( KURL(n2).prettyURL() );
+   m_pLineB->setMinimumSize( 200, m_pLineB->size().height() );
+   button   = new QPushButton( i18n("File..."), this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileB() ) );
+   button2   = new QPushButton( i18n("Dir..."), this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirB() ) );
+   connect( m_pLineB, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
+
+   h->addWidget( label,     1, 0 );
+   h->addWidget( m_pLineB,   1, 1 );
+   h->addWidget( button,    1, 2 );
+   h->addWidget( button2,   1, 3 );
+
+   label  = new QLabel( i18n("C (Optional):"), this );
+   m_pLineC= new QComboBox( true, this );
+   m_pLineC->insertStringList( m_pOptions->m_recentCFiles );
+   m_pLineC->setEditText( KURL(n3).prettyURL() );
+   m_pLineC->setMinimumSize( 200, m_pLineC->size().height() );
+   button = new QPushButton( i18n("File..."), this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileC() ) );
+   button2   = new QPushButton( i18n("Dir..."), this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirC() ) );
+   connect( m_pLineC, SIGNAL(textChanged(const QString&)), this, SLOT(inputFilenameChanged() ) );
+
+   h->addWidget( label,     2, 0 );
+   h->addWidget( m_pLineC,   2, 1 );
+   h->addWidget( button,    2, 2 );
+   h->addWidget( button2,   2, 3 );
+
+   m_pMerge = new QCheckBox( i18n("Merge"), this );
+   h->addWidget( m_pMerge, 3, 0 );
+
+   QHBoxLayout* hl = new QHBoxLayout();
+   h->addLayout( hl, 3, 1 );
+   hl->addStretch(2);
+   button = new QPushButton(i18n("Swap/Copy Names ..."), this);
+   //button->setToggleButton(false);
+   hl->addWidget( button );
+
+   QPopupMenu* m = new QPopupMenu(this);
+   int id=0;
+   m->insertItem( i18n("Swap %1<->%2").arg("A").arg("B"), id++ );
+   m->insertItem( i18n("Swap %1<->%2").arg("B").arg("C"), id++ );
+   m->insertItem( i18n("Swap %1<->%2").arg("C").arg("A"), id++ );
+   m->insertItem( i18n("Copy %1->Output").arg("A"), id++ );
+   m->insertItem( i18n("Copy %1->Output").arg("B"), id++ );
+   m->insertItem( i18n("Copy %1->Output").arg("C"), id++  );
+   m->insertItem( i18n("Swap %1<->Output").arg("A"), id++  );
+   m->insertItem( i18n("Swap %1<->Output").arg("B"), id++  );
+   m->insertItem( i18n("Swap %1<->Output").arg("C"), id++  );
+   connect( m, SIGNAL(activated(int)), this, SLOT(slotSwapCopyNames(int)));
+   button->setPopup(m);
+
+
+   hl->addStretch(2);
+
+   label  = new QLabel( i18n("Output (optional):"), this );
+   m_pLineOut = new QComboBox( true, this );
+   m_pLineOut->insertStringList( m_pOptions->m_recentOutputFiles );
+   m_pLineOut->setEditText( KURL(outputName).prettyURL() );
+   m_pLineOut->setMinimumSize( 200, m_pLineOut->size().height() );
+   button = new QPushButton( i18n("File..."), this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectOutputName() ) );
+   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_pLineOut, SLOT(setEnabled(bool)) );
+   connect( this, SIGNAL(internalSignal(bool)), button, SLOT(setEnabled(bool)) );
+   connect( this, SIGNAL(internalSignal(bool)), button2, SLOT(setEnabled(bool)) );
+
+   m_pMerge->setChecked( !bMerge );
+   m_pMerge->setChecked( bMerge );
+//   m_pLineOutput->setEnabled( bMerge );
+
+//   button->setEnabled( bMerge );
+
+   h->addWidget( label,          4, 0 );
+   h->addWidget( m_pLineOut,      4, 1 );
+   h->addWidget( button,         4, 2 );
+   h->addWidget( button2,        4, 3 );
+
+   h->addColSpacing( 1, 200 );
+
+   QHBoxLayout* l = new QHBoxLayout( v, 5 );
+
+   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, 1 );
+
+   button = new QPushButton( i18n("&Cancel"), this );
+   connect( button, SIGNAL(clicked()), this, SLOT( reject() ) );
+   l->addWidget( button,1 );
+
+   QSize sh = sizeHint();
+   setFixedHeight( sh.height() );
+   m_bInputFileNameChanged = false;
+
+#ifdef KREPLACEMENTS_H
+   m_pLineA->lineEdit()->installEventFilter( this );
+   m_pLineB->lineEdit()->installEventFilter( this );
+   m_pLineC->lineEdit()->installEventFilter( this );
+   m_pLineOut->lineEdit()->installEventFilter( this );
+#endif
+}
+
+// Eventfilter: Only needed under Windows.
+// Without this, files dropped in the line edit have URL-encoding.
+// This eventfilter decodes the filenames as needed by KDiff3.
+bool OpenDialog::eventFilter(QObject* o, QEvent* e)
+{
+   if (e->type()==QEvent::Drop)
+   {
+      QDropEvent* d = static_cast<QDropEvent*>(e);
+
+      if ( !QUriDrag::canDecode( d ) ) {
+         return false;
+      }
+
+      QStringList lst;
+      QUriDrag::decodeLocalFiles( d, lst );
+
+      if ( lst.count() > 0 )
+      {
+         static_cast<QLineEdit*>(o)->setText( lst[0] );
+         static_cast<QLineEdit*>(o)->setFocus();
+      }
+       
+      return true;
+   }
+   return false;
+}
+
+
+void OpenDialog::selectURL( QComboBox* pLine, bool bDir, int i, bool bSave )
+{
+   QString current = pLine->currentText();
+   if (current.isEmpty() && i>3 ){  current = m_pLineC->currentText(); }
+   if (current.isEmpty()        ){  current = m_pLineB->currentText(); }
+   if (current.isEmpty()        ){  current = m_pLineA->currentText(); }
+   KURL newURL = bDir ? KFileDialog::getExistingURL( current, this)
+                      : bSave ? KFileDialog::getSaveURL( current, 0, this)
+                              : KFileDialog::getOpenURL( current, 0, this);
+   if ( !newURL.isEmpty() )
+   {
+      pLine->setEditText( newURL.url() );
+   }
+   // newURL won't be modified if nothing was selected.
+}
+
+void OpenDialog::selectFileA()     {  selectURL( m_pLineA,    false, 1, false );  }
+void OpenDialog::selectFileB()     {  selectURL( m_pLineB,    false, 2, false );  }
+void OpenDialog::selectFileC()     {  selectURL( m_pLineC,    false, 3, false );  }
+void OpenDialog::selectOutputName(){  selectURL( m_pLineOut,  false, 4, true );  }
+void OpenDialog::selectDirA()      {  selectURL( m_pLineA,    true,  1, false );  }
+void OpenDialog::selectDirB()      {  selectURL( m_pLineB,    true,  2, false );  }
+void OpenDialog::selectDirC()      {  selectURL( m_pLineC,    true,  3, false );  }
+void OpenDialog::selectOutputDir() {  selectURL( m_pLineOut,  true,  4, true );  }
+
+void OpenDialog::internalSlot(int i)
+{
+   emit internalSignal(i!=0);
+}
+
+// Clear the output-filename when any input-filename changed, 
+// because users forgot to change the output and accidently overwrote it with
+// wrong data during a merge.
+void OpenDialog::inputFilenameChanged()
+{
+   if(!m_bInputFileNameChanged)
+   {
+      m_bInputFileNameChanged=true;
+      m_pLineOut->clearEdit();
+   }
+}
+
+static void fixCurrentText( QComboBox* pCB )
+{
+   QString s = pCB->currentText();
+
+   int pos = s.find( '\n' );
+   if ( pos>=0 )
+      s=s.left(pos);
+   pos = s.find( '\r' );
+   if ( pos>=0 )
+      s=s.left(pos);
+
+   pCB->setCurrentText( s );
+}
+
+void OpenDialog::accept()
+{
+   unsigned int maxNofRecentFiles = 10;
+
+   fixCurrentText( m_pLineA );
+   QString s = m_pLineA->currentText();
+   s = KURL::fromPathOrURL(s).prettyURL();
+   QStringList* sl = &m_pOptions->m_recentAFiles;
+   // If an item exist, remove it from the list and reinsert it at the beginning.
+   sl->remove(s);
+   if ( !s.isEmpty() ) sl->prepend( s );
+   if (sl->count()>maxNofRecentFiles) sl->erase( sl->at(maxNofRecentFiles), sl->end() );
+
+   fixCurrentText( m_pLineB );
+   s = m_pLineB->currentText();
+   s = KURL::fromPathOrURL(s).prettyURL();
+   sl = &m_pOptions->m_recentBFiles;
+   sl->remove(s);
+   if ( !s.isEmpty() ) sl->prepend( s );
+   if (sl->count()>maxNofRecentFiles) sl->erase( sl->at(maxNofRecentFiles), sl->end() );
+
+   fixCurrentText( m_pLineC );
+   s = m_pLineC->currentText();
+   s = KURL::fromPathOrURL(s).prettyURL();
+   sl = &m_pOptions->m_recentCFiles;
+   sl->remove(s);
+   if ( !s.isEmpty() ) sl->prepend( s );
+   if (sl->count()>maxNofRecentFiles) sl->erase( sl->at(maxNofRecentFiles), sl->end() );
+
+   fixCurrentText( m_pLineOut );
+   s = m_pLineOut->currentText();
+   s = KURL::fromPathOrURL(s).prettyURL();
+   sl = &m_pOptions->m_recentOutputFiles;
+   sl->remove(s);
+   if ( !s.isEmpty() ) sl->prepend( s );
+   if (sl->count()>maxNofRecentFiles) sl->erase( sl->at(maxNofRecentFiles), sl->end() );
+
+   QDialog::accept();
+}
+
+void OpenDialog::slotSwapCopyNames( int id ) // id selected in the popup menu
+{
+   QComboBox* cb1=0;
+   QComboBox* cb2=0;
+   switch(id)
+   {
+   case 0:  cb1=m_pLineA; cb2=m_pLineB; break;
+   case 1:  cb1=m_pLineB; cb2=m_pLineC; break;
+   case 2:  cb1=m_pLineC; cb2=m_pLineA; break;
+   case 3:  cb1=m_pLineA; cb2=m_pLineOut; break;
+   case 4:  cb1=m_pLineB; cb2=m_pLineOut; break;
+   case 5:  cb1=m_pLineC; cb2=m_pLineOut; break;
+   case 6:  cb1=m_pLineA; cb2=m_pLineOut; break;
+   case 7:  cb1=m_pLineB; cb2=m_pLineOut; break;
+   case 8:  cb1=m_pLineC; cb2=m_pLineOut; break;
+   }
+   if ( cb1 && cb2 )
+   {
+      QString t1 = cb1->currentText();
+      QString t2 = cb2->currentText();
+      cb2->setCurrentText(t1);
+      if ( id<=2 || id>=6 )
+      {
+         cb1->setCurrentText( t2 );
+      }
+   }
+}
+
+// FindDialog *********************************************
+
+FindDialog::FindDialog(QWidget* pParent)
+: QDialog( pParent )
+{
+   QGridLayout* layout = new QGridLayout( this );
+   layout->setMargin(5);
+   layout->setSpacing(5);
+
+   int line=0;
+   layout->addMultiCellWidget( new QLabel(i18n("Search text:"),this), line,line,0,1 );
+   ++line;
+
+   m_pSearchString = new QLineEdit( this );
+   layout->addMultiCellWidget( m_pSearchString, line,line,0,1 );
+   ++line;
+
+   m_pCaseSensitive = new QCheckBox(i18n("Case sensitive"),this);
+   layout->addWidget( m_pCaseSensitive, line, 1 );
+
+   m_pSearchInA = new QCheckBox(i18n("Search A"),this);
+   layout->addWidget( m_pSearchInA, line, 0 );
+   m_pSearchInA->setChecked( true );
+   ++line;
+
+   m_pSearchInB = new QCheckBox(i18n("Search B"),this);
+   layout->addWidget( m_pSearchInB, line, 0 );
+   m_pSearchInB->setChecked( true );
+   ++line;
+
+   m_pSearchInC = new QCheckBox(i18n("Search C"),this);
+   layout->addWidget( m_pSearchInC, line, 0 );
+   m_pSearchInC->setChecked( true );
+   ++line;
+
+   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 );
+   layout->addWidget( pButton, line, 0 );
+   connect( pButton, SIGNAL(clicked()), this, SLOT(accept()));
+
+   pButton = new QPushButton( i18n("&Cancel"), this );
+   layout->addWidget( pButton, line, 1 );
+   connect( pButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+   hide();
+}
+
+
+RegExpTester::RegExpTester( QWidget* pParent, const QString& autoMergeRegExpToolTip,
+   const QString& historyStartRegExpToolTip, const QString& historyEntryStartRegExpToolTip, const QString& historySortKeyOrderToolTip )
+: QDialog( pParent)
+{
+   int line=0;
+   setCaption(i18n("Regular Expression Tester"));
+   QGridLayout* pGrid = new QGridLayout( this, 11, 2, 5, 5 );
+
+   QLabel* l = new QLabel(i18n("Auto merge regular expression:"), this);
+   pGrid->addWidget(l,line,0);
+   QToolTip::add( l, autoMergeRegExpToolTip );
+   m_pAutoMergeRegExpEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pAutoMergeRegExpEdit,line,1);
+   connect( m_pAutoMergeRegExpEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Example auto merge line:"), this);
+   pGrid->addMultiCellWidget(l,line,line,0,1);
+   QToolTip::add( l, i18n("For auto merge test copy a line as used in your files.") );
+   m_pAutoMergeExampleEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pAutoMergeExampleEdit,line,1);
+   connect( m_pAutoMergeExampleEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Match result:"), this);
+   pGrid->addWidget(l,line,0);
+   m_pAutoMergeMatchResult = new QLineEdit(this);
+   m_pAutoMergeMatchResult->setReadOnly(true);
+   pGrid->addWidget(m_pAutoMergeMatchResult,line,1);
+   ++line;
+
+   pGrid->addItem( new QSpacerItem(100,20), line, 0 );
+   pGrid->setRowStretch( line, 5);
+   ++line;
+
+   l = new QLabel(i18n("History start regular expression:"), this);
+   pGrid->addWidget(l,line,0);
+   QToolTip::add( l, historyStartRegExpToolTip );
+   m_pHistoryStartRegExpEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pHistoryStartRegExpEdit,line,1);
+   connect( m_pHistoryStartRegExpEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Example history start line (with leading comment):"), this);
+   pGrid->addMultiCellWidget(l,line,line,0,1);
+   ++line;
+   QToolTip::add( l, i18n("Copy a history start line as used in your files,\n"
+                          "including the leading comment.") );
+   m_pHistoryStartExampleEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pHistoryStartExampleEdit,line,1);
+   connect( m_pHistoryStartExampleEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Match result:"), this);
+   pGrid->addWidget(l,line,0);
+   m_pHistoryStartMatchResult = new QLineEdit(this);
+   m_pHistoryStartMatchResult->setReadOnly(true);
+   pGrid->addWidget(m_pHistoryStartMatchResult,line,1);
+   ++line;
+
+   pGrid->addItem( new QSpacerItem(100,20), line, 0 );
+   pGrid->setRowStretch( line, 5);
+   ++line;
+
+   l = new QLabel(i18n("History entry start regular expression:"), this);
+   pGrid->addWidget(l,line,0);
+   QToolTip::add( l, historyEntryStartRegExpToolTip );
+   m_pHistoryEntryStartRegExpEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pHistoryEntryStartRegExpEdit,line,1);
+   connect( m_pHistoryEntryStartRegExpEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("History sort key order:"), this);
+   pGrid->addWidget(l,line,0);
+   QToolTip::add( l, historySortKeyOrderToolTip );
+   m_pHistorySortKeyOrderEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pHistorySortKeyOrderEdit,line,1);
+   connect( m_pHistorySortKeyOrderEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Example history entry start line (without leading comment):"), this);
+   pGrid->addMultiCellWidget(l,line,line,0,1);
+   QToolTip::add( l, i18n("Copy a history entry start line as used in your files,\n"
+                          "but omit the leading comment.") );
+   ++line;
+   m_pHistoryEntryStartExampleEdit = new QLineEdit(this);
+   pGrid->addWidget(m_pHistoryEntryStartExampleEdit,line,1);
+   connect( m_pHistoryEntryStartExampleEdit, SIGNAL(textChanged(const QString&)), this, SLOT(slotRecalc()));
+   ++line;
+
+   l = new QLabel(i18n("Match result:"), this);
+   pGrid->addWidget(l,line,0);
+   m_pHistoryEntryStartMatchResult = new QLineEdit(this);
+   m_pHistoryEntryStartMatchResult->setReadOnly(true);
+   pGrid->addWidget(m_pHistoryEntryStartMatchResult,line,1);
+   ++line;
+
+   l = new QLabel(i18n("Sort key result:"), this);
+   pGrid->addWidget(l,line,0);
+   m_pHistorySortKeyResult = new QLineEdit(this);
+   m_pHistorySortKeyResult->setReadOnly(true);
+   pGrid->addWidget(m_pHistorySortKeyResult,line,1);
+   ++line;
+
+   QPushButton* pButton = new QPushButton(i18n("OK"), this);
+   pGrid->addWidget(pButton,line,0);
+   connect( pButton, SIGNAL(clicked()), this, SLOT(accept()));
+
+   pButton = new QPushButton(i18n("Cancel"), this);
+   pGrid->addWidget(pButton,line,1);
+   connect( pButton, SIGNAL(clicked()), this, SLOT(reject()));
+
+   resize( 800, sizeHint().height() );
+}
+
+void RegExpTester::init( const QString& autoMergeRegExp, const QString& historyStartRegExp, const QString& historyEntryStartRegExp, const QString historySortKeyOrder )
+{
+   m_pAutoMergeRegExpEdit->setText( autoMergeRegExp );
+   m_pHistoryStartRegExpEdit->setText( historyStartRegExp );
+   m_pHistoryEntryStartRegExpEdit->setText( historyEntryStartRegExp );
+   m_pHistorySortKeyOrderEdit->setText( historySortKeyOrder );
+}
+
+QString RegExpTester::autoMergeRegExp()
+{
+   return m_pAutoMergeRegExpEdit->text();
+}
+
+QString RegExpTester::historyStartRegExp()
+{
+   return m_pHistoryStartRegExpEdit->text();
+}
+
+QString RegExpTester::historyEntryStartRegExp()
+{
+   return m_pHistoryEntryStartRegExpEdit->text();
+}
+
+QString RegExpTester::historySortKeyOrder()
+{
+   return m_pHistorySortKeyOrderEdit->text();
+}
+
+void RegExpTester::slotRecalc()
+{
+   QRegExp autoMergeRegExp = m_pAutoMergeRegExpEdit->text();
+   if ( autoMergeRegExp.exactMatch( m_pAutoMergeExampleEdit->text() ) )
+   {
+      m_pAutoMergeMatchResult->setText( i18n("Match success.") );
+   }
+   else
+   {
+      m_pAutoMergeMatchResult->setText( i18n("Match failed.") );
+   }
+
+   QRegExp historyStartRegExp = m_pHistoryStartRegExpEdit->text();
+   if ( historyStartRegExp.exactMatch( m_pHistoryStartExampleEdit->text() ) )
+   {
+      m_pHistoryStartMatchResult->setText( i18n("Match success.") );
+   }
+   else
+   {
+      m_pHistoryStartMatchResult->setText( i18n("Match failed.") );
+   }
+
+
+   QStringList parenthesesGroups;
+   bool bSuccess = findParenthesesGroups( m_pHistoryEntryStartRegExpEdit->text(), parenthesesGroups );
+   if ( ! bSuccess )
+   {
+      m_pHistoryEntryStartMatchResult->setText( i18n("Opening and closing parentheses don't match in regular expression.") );
+      m_pHistorySortKeyResult->setText( i18n("") );
+      return;
+   }
+   QRegExp historyEntryStartRegExp = m_pHistoryEntryStartRegExpEdit->text();
+   QString s = m_pHistoryEntryStartExampleEdit->text();
+
+   if ( historyEntryStartRegExp.exactMatch( s ) )
+   {
+      m_pHistoryEntryStartMatchResult->setText( i18n("Match success.") );
+      QString key = calcHistorySortKey( m_pHistorySortKeyOrderEdit->text(),historyEntryStartRegExp,parenthesesGroups);
+      m_pHistorySortKeyResult->setText(key);
+   }
+   else
+   {
+      m_pHistoryEntryStartMatchResult->setText( i18n("Match failed.") );
+      m_pHistorySortKeyResult->setText( i18n("") );
+   }
+}
+
+#include "smalldialogs.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/smalldialogs.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,120 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Joachim Eibl                                    *
+ *   joachim.eibl at gmx.de                                                *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.           *
+ ***************************************************************************/
+
+#ifndef SMALLDIALOGS_H
+#define SMALLDIALOGS_H
+
+#include <qdialog.h>
+#include "diff.h"
+
+class OptionDialog;
+class QComboBox;
+class QCheckBox;
+class QLineEdit;
+class QLabel;
+
+class OpenDialog : public QDialog
+{
+   Q_OBJECT
+public:
+   OpenDialog(
+      QWidget* pParent, const QString& n1, const QString& n2, const QString& n3,
+      bool bMerge, const QString& outputName, const char* slotConfigure, OptionDialog* pOptions  );
+
+   QComboBox* m_pLineA;
+   QComboBox* m_pLineB;
+   QComboBox* m_pLineC;
+   QComboBox* m_pLineOut;
+
+   QCheckBox* m_pMerge;
+   virtual void accept();
+   virtual bool eventFilter(QObject* o, QEvent* e);
+private:
+   OptionDialog* m_pOptions;
+   void selectURL( QComboBox* pLine, bool bDir, int i, bool bSave );
+   bool m_bInputFileNameChanged;
+private slots:
+   void selectFileA();
+   void selectFileB();
+   void selectFileC();
+   void selectDirA();
+   void selectDirB();
+   void selectDirC();
+   void selectOutputName();
+   void selectOutputDir();
+   void internalSlot(int);
+   void inputFilenameChanged();
+   void slotSwapCopyNames(int);
+signals:
+   void internalSignal(bool);
+};
+
+class FindDialog : public QDialog
+{
+   Q_OBJECT
+public:
+   FindDialog(QWidget* pParent);
+
+signals:
+   void findNext();
+
+public:
+   QLineEdit* m_pSearchString;
+   QCheckBox* m_pSearchInA;
+   QCheckBox* m_pSearchInB;
+   QCheckBox* m_pSearchInC;
+   QCheckBox* m_pSearchInOutput;
+   QCheckBox* m_pCaseSensitive;
+
+   int currentLine;
+   int currentPos;
+   int currentWindow;
+};
+
+
+class RegExpTester : public QDialog
+{
+   Q_OBJECT
+private:
+   QLineEdit* m_pAutoMergeRegExpEdit;
+   QLineEdit* m_pAutoMergeMatchResult;
+   QLineEdit* m_pAutoMergeExampleEdit;
+   QLineEdit* m_pHistoryStartRegExpEdit;
+   QLineEdit* m_pHistoryStartMatchResult;
+   QLineEdit* m_pHistoryStartExampleEdit;
+   QLineEdit* m_pHistoryEntryStartRegExpEdit;
+   QLineEdit* m_pHistorySortKeyOrderEdit;
+   QLineEdit* m_pHistoryEntryStartExampleEdit;
+   QLineEdit* m_pHistoryEntryStartMatchResult;
+   QLineEdit* m_pHistorySortKeyResult;
+   OptionDialog* m_pOptionDialog;
+public:
+   RegExpTester( QWidget* pParent, const QString& autoMergeRegExpToolTip, const QString& historyStartRegExpToolTip, 
+                                   const QString& historyEntryStartRegExpToolTip, const QString& historySortKeyOrderToolTip  );
+   void init( const QString& autoMergeRegExp, const QString& historyStartRegExp, const QString& historyEntryStartRegExp, const QString sortKeyOrder );
+   QString autoMergeRegExp();
+   QString historyStartRegExp();
+   QString historyEntryStartRegExp();
+   QString historySortKeyOrder();
+public slots:
+   void slotRecalc();
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/version.h	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,2 @@
+#undef VERSION
+#define VERSION "0.9.91"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/autoadvance.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *autoadvance[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 3 1",
+". c #0080FF",
+"# c #000000",
+"  c None",
+/* pixels */
+" ##  # # ###  # ",
+"#  # # #  #  # #",
+"#  # # #  #  # #",
+"#### # #  #  # #",
+"#  # ###  #   # ",
+"                ",
+"                ",
+"    ########    ",
+"     #....#     ",
+"      #..#      ",
+"       ##       ",
+"    ########    ",
+"     #....#     ",
+"      #..#      ",
+"       ##       ",
+"                "
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/currentpos.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *currentpos[]={
+"16 16 3 1",
+"  c #0080FF",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+".#............#.",
+".##..........##.",
+".# #........# #.",
+".#  #..##..#  #.",
+".#   ##  ##   #.",
+".#   #    #   #.",
+".#   ##  ##   #.",
+".#  #..##..#  #.",
+".# #........# #.",
+".##..........##.",
+".#............#.",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/down1arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *down1arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 3 1",
+"  c #0080ff",
+"# c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+"................",
+"................",
+"................",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+".......##.......",
+"................",
+"................",
+"................",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/down2arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *down2arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 3 1",
+"  c #0080ff",
+"# c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+".......##.......",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+".......##.......",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/downend.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *downend[]={
+"16 16 3 1",
+"  c #0080ff",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+"................",
+"................",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+".......##.......",
+"..############..",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/equal.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *equal_pm[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #00d000",
+"################",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"################"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/file.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *file_pm[]={
+"16 16 5 1",
+". c None",
+"# c #000000",
+"c c #c0c0c0",
+"b c #dcdcdc",
+"a c #ffffff",
+"..#########.....",
+"..#aaaaaabb#....",
+"..#aaaaaacab#...",
+"..#aaaaaacaab#..",
+"..#aaaaaac####..",
+"..#aaaaaaaccc#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..############.."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/filenew.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char * filenew[] = {
+"10 14 5 1",
+" 	c None",
+".	c #000000",
+"+	c #FFFFFF",
+"@	c #DCDCDC",
+"#	c #C0C0C0",
+".......   ",
+".++++@@.  ",
+".++++#+@. ",
+".++++#++@.",
+".++++#....",
+".+++++###.",
+".++++++++.",
+".++++++++.",
+".++++++++.",
+".++++++++.",
+".++++++++.",
+".++++++++.",
+".++++++++.",
+".........."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/fileopen.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *fileopen[] = {
+"    16    13        5            1",
+". c #040404",
+"# c #808304",
+"a c None",
+"b c #f3f704",
+"c c #f3f7f3",
+"aaaaaaaaa...aaaa",
+"aaaaaaaa.aaa.a.a",
+"aaaaaaaaaaaaa..a",
+"a...aaaaaaaa...a",
+".bcb.......aaaaa",
+".cbcbcbcbc.aaaaa",
+".bcbcbcbcb.aaaaa",
+".cbcb...........",
+".bcb.#########.a",
+".cb.#########.aa",
+".b.#########.aaa",
+"..#########.aaaa",
+"...........aaaaa"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/fileprint.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *fileprint[] = {
+"    16    14        6            1",
+". c #000000",
+"# c #848284",
+"a c #c6c3c6",
+"b c #ffff00",
+"c c #ffffff",
+"d c None",
+"ddddd.........dd",
+"dddd.cccccccc.dd",
+"dddd.c.....c.ddd",
+"ddd.cccccccc.ddd",
+"ddd.c.....c....d",
+"dd.cccccccc.a.a.",
+"d..........a.a..",
+".aaaaaaaaaa.a.a.",
+".............aa.",
+".aaaaaa###aa.a.d",
+".aaaaaabbbaa...d",
+".............a.d",
+"d.aaaaaaaaa.a.dd",
+"dd...........ddd"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/filesave.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *filesave[] = {
+"    14    14        3            1",
+". c #040404",
+"# c #808304",
+"a c #bfc2bf",
+"..............",
+".#.aaaaaaaa.a.",
+".#.aaaaaaaa...",
+".#.aaaaaaaa.#.",
+".#.aaaaaaaa.#.",
+".#.aaaaaaaa.#.",
+".#.aaaaaaaa.#.",
+".##........##.",
+".############.",
+".##.........#.",
+".##......aa.#.",
+".##......aa.#.",
+".##......aa.#.",
+"a............."
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/folder.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *folder_pm[]={
+"16 16 5 1",
+". c None",
+"# c #040404",
+"c c #808304",
+"a c #f3f704",
+"b c #f3f7f3",
+"................",
+"................",
+"................",
+".###............",
+"#aba#######.....",
+"#babababab#.....",
+"#ababababa#.....",
+"#baba###########",
+"#aba#ccccccccc#.",
+"#ba#ccccccccc#..",
+"#a#ccccccccc#...",
+"##ccccccccc#....",
+"###########.....",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/iconA.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *iconA[]={
+"16 16 3 1",
+"  c #0080FF",
+"# c #000000",
+". c None",
+"................",
+"................",
+"......###.......",
+".....#   #......",
+"....#  #  #.....",
+"...#  #.#  #....",
+"...# #...# #....",
+"...# #...# #....",
+"...# ##### #....",
+"...#       #....",
+"...# ##### #....",
+"...# #...# #....",
+"...###...###....",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/iconB.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *iconB[]={
+"16 16 3 1",
+"  c #0080FF",
+"# c #000000",
+". c None",
+"................",
+"................",
+"...#######......",
+"...#      #.....",
+"...# ####  #....",
+"...# #...# #....",
+"...# ####  #....",
+"...#      #.....",
+"...# ####  #....",
+"...# #...# #....",
+"...# ####  #....",
+"...#      #.....",
+"...#######......",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/iconC.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *iconC[]={
+"16 16 3 1",
+"  c #0080FF",
+"# c #000000",
+". c None",
+"................",
+"................",
+"......####......",
+".....#    #.....",
+"....#  ### #....",
+"...#  #...##....",
+"...# #..........",
+"...# #..........",
+"...# #..........",
+"...# #..........",
+"...#  #...##....",
+"....#  ### #....",
+".....#    #.....",
+"......####......",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/left1arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *left1arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 2 1",
+"  c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+".......... .....",
+".........  .....",
+"........   .....",
+".......    .....",
+"......     .....",
+".....      .....",
+".....      .....",
+"......     .....",
+".......    .....",
+"........   .....",
+".........  .....",
+".......... .....",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/left2arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *left2arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 2 1",
+"  c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+"....... ..... ..",
+"......  ....  ..",
+".....   ...   ..",
+"....    ..    ..",
+"...     .     ..",
+"..            ..",
+"..            ..",
+"...     .     ..",
+"....    ..    ..",
+".....   ...   ..",
+"......  ....  ..",
+"....... ..... ..",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/leftend.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *leftend[]={
+"16 16 2 1",
+"# c #000000",
+". c None",
+"................",
+"................",
+"....#.....#.....",
+"....#....##.....",
+"....#...###.....",
+"....#..####.....",
+"....#.#####.....",
+"....#######.....",
+"....#######.....",
+"....#.#####.....",
+"....#..####.....",
+"....#...###.....",
+"....#....##.....",
+"....#.....#.....",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/link_arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *link_arrow[]={
+"16 16 5 1",
+". c None",
+"b c #000000",
+"# c #585858",
+"c c #dcdcdc",
+"a c #ffffff",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"########........",
+"#aaaaaab........",
+"#aabbbab........",
+"#aac#bab........",
+"#acbcbab........",
+"#abcaaab........",
+"#aaaaaab........",
+"#bbbbbbb........"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/nextunsolved.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *nextunsolved[]={
+"16 16 4 1",
+". c None",
+"  c #0080ff",
+"# c #000000",
+"a c #ff0000",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+"..############..",
+"...#        #...",
+"....#      #....",
+".....#    #.....",
+"......#  #......",
+"..############..",
+"...#aaaaaaaa#...",
+"....#aaaaaa#....",
+".....#aaaa#.....",
+"......#aa#......",
+".......##......."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/not_equal.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *not_equal_pm[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #f00000",
+"################",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"################"};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/not_everywhere.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *not_everywhere_pm[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #c0c000",
+"################",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"################"};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/not_there.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *not_there_pm[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #000000",
+"################",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"#aaaaaaaaaaaaaa#",
+"################"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/prevunsolved.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *prevunsolved[]={
+"16 16 4 1",
+"  c #0080ff",
+"# c #000000",
+"a c #ff0000",
+". c None",
+".......##.......",
+"......#aa#......",
+".....#aaaa#.....",
+"....#aaaaaa#....",
+"...#aaaaaaaa#...",
+"..############..",
+"......#  #......",
+".....#    #.....",
+"....#      #....",
+"...#        #...",
+"..############..",
+"......#  #......",
+".....#    #.....",
+"....#      #....",
+"...#        #...",
+"..############.."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/reload.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,74 @@
+/* XPM */
+static const char *reloadIcon[]={
+"16 16 55 1",
+". c None",
+"e c #25502a",
+"# c #25512b",
+"d c #25522b",
+"g c #26552c",
+"c c #27562e",
+"n c #27582f",
+"b c #28592e",
+"M c #285930",
+"a c #295a2f",
+"q c #295a30",
+"G c #295c31",
+"t c #2a5e31",
+"y c #2b6635",
+"U c #2b6636",
+"Q c #2f703a",
+"H c #327b3d",
+"0 c #36843f",
+"W c #388943",
+"u c #3f7046",
+"r c #42764a",
+"f c #44754b",
+"A c #488653",
+"N c #50995b",
+"K c #529d5f",
+"J c #529f60",
+"m c #53885c",
+"l c #55a161",
+"B c #57a863",
+"R c #5aaa66",
+"I c #5aad69",
+"v c #5baa67",
+"X c #5cb16b",
+"o c #5db469",
+"k c #5eb56c",
+"z c #5eb66b",
+"s c #5fb26d",
+"V c #64b171",
+"Y c #64c274",
+"j c #69c779",
+"Z c #6dc97d",
+"p c #729a77",
+"O c #73c782",
+"i c #7ace89",
+"w c #7bce89",
+"C c #7ecb8b",
+"L c #80d191",
+"h c #80d193",
+"S c #8dd49b",
+"P c #95d8a1",
+"D c #a7ddb1",
+"x c #bde3c2",
+"T c #c0e5c5",
+"E c #daf0de",
+"F c #f9fdf9",
+"................",
+"..#abcde#df.....",
+"..ghhhijklm.....",
+"..nhoooooop.....",
+"..qho....rso....",
+"..tho...uvwxo...",
+"..yhz..ABCDEFo..",
+"gGHhIJJAAKLooo..",
+"MNOPEFo..Qho....",
+".eRSTo...Uho....",
+"..eV.....Uho....",
+"...W.....Qho....",
+"....nXYZihho....",
+"....0ooooooo....",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/right1arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *right1arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 2 1",
+"  c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+"..... ..........",
+".....  .........",
+".....   ........",
+".....    .......",
+".....     ......",
+".....      .....",
+".....      .....",
+".....     ......",
+".....    .......",
+".....   ........",
+".....  .........",
+"..... ..........",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/right2arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *right2arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 2 1",
+"  c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+".. ..... .......",
+"..  ....  ......",
+"..   ...   .....",
+"..    ..    ....",
+"..     .     ...",
+"..            ..",
+"..            ..",
+"..     .     ...",
+"..    ..    ....",
+"..   ...   .....",
+"..  ....  ......",
+".. ..... .......",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/rightend.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *rightend[]={
+"16 16 2 1",
+"# c #000000",
+". c None",
+"................",
+"................",
+".....#.....#....",
+".....##....#....",
+".....###...#....",
+".....####..#....",
+".....#####.#....",
+".....#######....",
+".....#######....",
+".....#####.#....",
+".....####..#....",
+".....###...#....",
+".....##....#....",
+".....#.....#....",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showequalfiles.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *showequalfiles[]={
+"16 16 4 1",
+"# c None",
+"a c None",
+". c #000000",
+"b c #00ff00",
+"...........##aaa",
+".bbbb.bbbb.##aaa",
+".bbbb.bbbb.##aaa",
+".bbbb.bbbb.##aaa",
+".bbbb.bbbb.##aaa",
+"...........##aaa",
+"aaaaaaaaaaaaaaaa",
+"................",
+"aaaaaaaaaaaaaaaa",
+"................",
+".bbbb.bbbb.bbbb.",
+".bbbb.bbbb.bbbb.",
+".bbbb.bbbb.bbbb.",
+".bbbb.bbbb.bbbb.",
+"................",
+"aaaaaaaaaaaaaaaa"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showfilesonlyina.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *showfilesonlyina[]={
+"16 16 4 1",
+"# c None",
+"a c None",
+". c #000000",
+"b c #00ff00",
+"...........##aaa",
+".bbbb......##aaa",
+".bbbb......##aaa",
+".bbbb......##aaa",
+".bbbb......##aaa",
+"...........##aaa",
+"aaaaaaaaaaaaaaaa",
+"................",
+"aaaaaaaaaaaaaaaa",
+"................",
+".bbbb...........",
+".bbbb...........",
+".bbbb...........",
+".bbbb...........",
+"................",
+"aaaaaaaaaaaaaaaa"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showfilesonlyinb.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,23 @@
+/* XPM */
+static const char *showfilesonlyinb[]={
+"16 16 4 1",
+"# c None",
+"a c None",
+". c #000000",
+"b c #00ff00",
+"...........##aaa",
+"......bbbb.##aaa",
+"......bbbb.##aaa",
+"......bbbb.##aaa",
+"......bbbb.##aaa",
+"...........##aaa",
+"aaaaaaaaaaaaaaaa",
+"................",
+"aaaaaaaaaaaaaaaa",
+"................",
+"......bbbb......",
+"......bbbb......",
+"......bbbb......",
+"......bbbb......",
+"................",
+"aaaaaaaaaaaaaaaa"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showfilesonlyinc.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *showfilesonlyinc[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #00ff00",
+"................",
+"................",
+"................",
+"................",
+"................",
+"################",
+"###########aaaa#",
+"###########aaaa#",
+"###########aaaa#",
+"###########aaaa#",
+"################",
+"................",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showlinenumbers.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *showlinenumbers[]={
+"16 16 2 1",
+". c None",
+"# c #000040",
+"................",
+"................",
+"................",
+"................",
+"...#...##..###..",
+"..##..#..#....#.",
+"...#.....#....#.",
+"...#....#...##..",
+"...#...#......#.",
+"...#..#.......#.",
+"..###.####.###..",
+"................",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showwhitespace.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *showwhitespace[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #ffffff",
+"................",
+"................",
+"..############..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..#aaaaaaaaaa#..",
+"..############..",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/showwhitespacechars.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *showwhitespacechars[]={
+"16 16 2 1",
+". c None",
+"# c #000040",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+".####.####.####.",
+".####.####.####.",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/startmerge.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *startmerge[]={
+"16 16 6 1",
+". c None",
+"# c #000000",
+"b c #0000ff",
+"c c #00ffff",
+"d c #ff0000",
+"a c #ffff00",
+".......##.......",
+"......#aa#......",
+"......#aa#......",
+"...b.b.##.b.b...",
+"...bb......bb...",
+"...bbb....bbb...",
+".##..........##.",
+"#cc#........#cc#",
+"#cc#........#cc#",
+".##.b.b..b.b.##.",
+".....bb..bb.....",
+"....bbb..bbb....",
+".......##.......",
+"......#dd#......",
+"......#dd#......",
+".......##......."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/up1arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *up1arrow[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #0080ff",
+"................",
+"................",
+"................",
+"................",
+"................",
+".......##.......",
+"......#aa#......",
+".....#aaaa#.....",
+"....#aaaaaa#....",
+"...#aaaaaaaa#...",
+"..############..",
+"................",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/up2arrow.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,25 @@
+/* XPM */
+static const char *up2arrow[] = {
+/* columns rows colors chars-per-pixel */
+"16 16 3 1",
+"  c #0080ff",
+"# c #000000",
+". c None",
+/* pixels */
+"................",
+"................",
+".......##.......",
+"......#  #......",
+".....#    #.....",
+"....#      #....",
+"...#        #...",
+"..############..",
+".......##.......",
+"......#  #......",
+".....#    #.....",
+"....#      #....",
+"...#        #...",
+"..############..",
+"................",
+"................"
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/upend.xpm	Sat Nov 04 00:36:16 2006 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *upend[]={
+"16 16 3 1",
+"  c #0080ff",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+"................",
+"..############..",
+".......##.......",
+"......#  #......",
+".....#    #.....",
+"....#      #....",
+"...#        #...",
+"..############..",
+"................",
+"................",
+"................",
+"................",
+"................"};