changeset 8:86d21651c8db

KDiff3 version 0.9.70
author joachim99
date Mon, 06 Oct 2003 18:50:45 +0000
parents ff98a43bbfea
children b6b488467677
files kdiff3/src/.cvsignore kdiff3/src/Makefile.am kdiff3/src/Makefile.qt kdiff3/src/Makefile.win_qt230 kdiff3/src/common.h kdiff3/src/diff.cpp kdiff3/src/diff.h kdiff3/src/difftextwindow.cpp kdiff3/src/directorymergewindow.cpp kdiff3/src/directorymergewindow.h kdiff3/src/fileaccess.cpp kdiff3/src/fileaccess.h kdiff3/src/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.pro kdiff3/src/kdiff3.rc 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/kdiff3_tmake.pro kdiff3/src/kdiff3part.desktop kdiff3/src/kreplacements/README kdiff3/src/kreplacements/diff.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/kparts/factory.h kdiff3/src/kreplacements/kparts/mainwindow.h kdiff3/src/kreplacements/kparts/part.h kdiff3/src/kreplacements/kpopupmenu.h kdiff3/src/kreplacements/kprogress.h kdiff3/src/kreplacements/kreplacements.cpp kdiff3/src/kreplacements/kreplacements.h kdiff3/src/kreplacements/kreplacements.moc 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/optiondialog.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/optiondialog.cpp kdiff3/src/optiondialog.h kdiff3/src/pdiff.cpp 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/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/showlinenumbers.xpm kdiff3/src/xpm/showwhitespace.xpm kdiff3/src/xpm/startmerge.xpm kdiff3/src/xpm/up1arrow.xpm kdiff3/src/xpm/up2arrow.xpm kdiff3/src/xpm/upend.xpm
diffstat 105 files changed, 17514 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/.cvsignore	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/Makefile.am	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,57 @@
+
+# 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
+
+# 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
+libkdiff3part_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libkdiff3part_la_LIBADD  = $(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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,315 @@
+#############################################################################
+# Makefile for building: kdiff3
+# Generated by qmake (1.05a) (Qt 3.1.2-snapshot-20030618) on: Thu Oct  2 22:13:20 2003
+# 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 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT
+CXXFLAGS = -pipe -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -Wall -W -O2 -march=i586 -mcpu=i686 -fmessage-length=0 -fPIC -DNO_DEBUG -D_REENTRANT  -DQT_NO_DEBUG -DQT_THREAD_SUPPORT
+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) -p
+COPY_DIR = $(COPY) -pR
+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 = diff.h \
+		kdiff3.h \
+		merger.h \
+		optiondialog.h \
+		kreplacements/kreplacements.h \
+		directorymergewindow.h \
+		fileaccess.h \
+		kdiff3_shell.h \
+		kdiff3_part.h
+SOURCES = diff.cpp \
+		difftextwindow.cpp \
+		kdiff3.cpp \
+		main.cpp \
+		merger.cpp \
+		mergeresultwindow.cpp \
+		optiondialog.cpp \
+		pdiff.cpp \
+		directorymergewindow.cpp \
+		fileaccess.cpp \
+		kdiff3_shell.cpp \
+		kdiff3_part.cpp \
+		kreplacements/kreplacements.cpp
+OBJECTS = diff.o \
+		difftextwindow.o \
+		kdiff3.o \
+		main.o \
+		merger.o \
+		mergeresultwindow.o \
+		optiondialog.o \
+		pdiff.o \
+		directorymergewindow.o \
+		fileaccess.o \
+		kdiff3_shell.o \
+		kdiff3_part.o \
+		kreplacements.o
+FORMS = 
+UICDECLS = 
+UICIMPLS = 
+SRCMOC   = moc_diff.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
+OBJMOC = moc_diff.o \
+		moc_kdiff3.o \
+		moc_optiondialog.o \
+		moc_kreplacements.o \
+		moc_directorymergewindow.o \
+		moc_fileaccess.o \
+		moc_kdiff3_shell.o \
+		moc_kdiff3_part.o
+DIST	   = kdiff3.pro
+QMAKE_TARGET = kdiff3
+DESTDIR  = 
+TARGET   = kdiff3
+
+first: all
+####### Implicit rules
+
+.SUFFIXES: .c .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) $(LIBS)
+
+mocables: $(SRCMOC)
+
+$(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
+
+diff.o: diff.cpp diff.h \
+		fileaccess.h \
+		common.h
+
+difftextwindow.o: difftextwindow.cpp diff.h \
+		merger.h \
+		optiondialog.h \
+		common.h \
+		fileaccess.h
+
+kdiff3.o: kdiff3.cpp diff.h \
+		kdiff3.h \
+		optiondialog.h \
+		fileaccess.h \
+		kdiff3_part.h \
+		directorymergewindow.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/showlinenumbers.xpm \
+		xpm/startmerge.xpm \
+		common.h
+
+main.o: main.cpp kdiff3_shell.h
+
+merger.o: merger.cpp merger.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+mergeresultwindow.o: mergeresultwindow.cpp diff.h \
+		optiondialog.h \
+		common.h \
+		fileaccess.h
+
+optiondialog.o: optiondialog.cpp optiondialog.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+pdiff.o: pdiff.cpp diff.h \
+		directorymergewindow.h \
+		kdiff3.h \
+		optiondialog.h \
+		fileaccess.h \
+		common.h
+
+directorymergewindow.o: directorymergewindow.cpp directorymergewindow.h \
+		optiondialog.h \
+		common.h \
+		fileaccess.h
+
+fileaccess.o: fileaccess.cpp fileaccess.h \
+		optiondialog.h \
+		common.h
+
+kdiff3_shell.o: kdiff3_shell.cpp kdiff3_shell.h \
+		kdiff3.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+kdiff3_part.o: kdiff3_part.cpp kdiff3_part.h \
+		kdiff3.h \
+		fileaccess.h \
+		diff.h \
+		common.h
+
+kreplacements.o: kreplacements/kreplacements.cpp kreplacements/kreplacements.h \
+		kreplacements/kreplacements.moc
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -o kreplacements.o kreplacements/kreplacements.cpp
+
+moc_diff.o: moc_diff.cpp diff.h common.h \
+		fileaccess.h
+
+moc_kdiff3.o: moc_kdiff3.cpp kdiff3.h diff.h \
+		common.h \
+		fileaccess.h
+
+moc_optiondialog.o: moc_optiondialog.cpp optiondialog.h 
+
+moc_kreplacements.o: kreplacements/moc_kreplacements.cpp kreplacements/kreplacements.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
+
+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_diff.cpp: $(MOC) diff.h
+	$(MOC) diff.h -o moc_diff.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
+
+####### Install
+
+install_documentation: 
+	@$(CHK_DIR_EXISTS) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/" || $(MKDIR) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+	-$(COPY_DIR) "../doc/en" "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3"
+
+uninstall_documentation: 
+	-$(DEL_FILE) -r "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/en"
+	-$(DEL_DIR) "$(INSTALL_ROOT)/usr/local/share/doc/kdiff3/"
+
+
+install_target: 
+	@$(CHK_DIR_EXISTS) "$(INSTALL_ROOT)/usr/local/bin/" || $(MKDIR) "$(INSTALL_ROOT)/usr/local/bin/"
+	-$(COPY) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
+	-strip "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
+
+uninstall_target: 
+	-$(DEL_FILE) "$(INSTALL_ROOT)/usr/local/bin/$(QMAKE_TARGET)"
+	-$(DEL_DIR) "$(INSTALL_ROOT)/usr/local/bin/"
+
+
+install: all install_documentation install_target 
+
+uninstall: uninstall_documentation uninstall_target 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/Makefile.win_qt230	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,308 @@
+#############################################################################
+# Makefile for building kdiff3
+# Generated by tmake at 22:40, 2003/10/01
+#     Project: kdiff3_tmake
+#    Template: app
+#############################################################################
+
+####### Compiler, tools and options
+
+CC	=	cl
+CXX	=	cl
+CFLAGS	=	-nologo -W3 -MD -O1 -DQT_DLL -DQT_THREAD_SUPPORT -DNO_DEBUG -GX -GR
+CXXFLAGS=	-nologo -W3 -MD -O1 -DQT_DLL -DQT_THREAD_SUPPORT -DNO_DEBUG -GX -GR
+INCPATH	=	-I"." -I".\kreplacements" -I"$(QTDIR)\include"
+LINK	=	link
+LFLAGS	=	/NOLOGO /SUBSYSTEM:windows
+LIBS	=	$(QTDIR)\lib\qt-mt230nc.lib $(QTDIR)\lib\qtmain.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib kdiff3.res
+MOC	=	$(QTDIR)\bin\moc
+UIC	=	uic
+
+ZIP	=	zip -r -9
+
+####### Files
+
+HEADERS =	diff.h \
+		kdiff3.h \
+		merger.h \
+		optiondialog.h \
+		kreplacements\kreplacements.h \
+		directorymergewindow.h \
+		fileaccess.h \
+		kdiff3_shell.h \
+		kdiff3_part.h
+SOURCES =	diff.cpp \
+		difftextwindow.cpp \
+		kdiff3.cpp \
+		main.cpp \
+		merger.cpp \
+		mergeresultwindow.cpp \
+		optiondialog.cpp \
+		pdiff.cpp \
+		directorymergewindow.cpp \
+		fileaccess.cpp \
+		kdiff3_shell.cpp \
+		kdiff3_part.cpp \
+		kreplacements\kreplacements.cpp
+OBJECTS =	diff.obj \
+		difftextwindow.obj \
+		kdiff3.obj \
+		main.obj \
+		merger.obj \
+		mergeresultwindow.obj \
+		optiondialog.obj \
+		pdiff.obj \
+		directorymergewindow.obj \
+		fileaccess.obj \
+		kdiff3_shell.obj \
+		kdiff3_part.obj \
+		kreplacements\kreplacements.obj
+INTERFACES =	
+UICDECLS =	
+UICIMPLS =	
+SRCMOC	=	moc_diff.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
+OBJMOC	=	moc_diff.obj \
+		moc_kdiff3.obj \
+		moc_optiondialog.obj \
+		kreplacements\moc_kreplacements.obj \
+		moc_directorymergewindow.obj \
+		moc_fileaccess.obj \
+		moc_kdiff3_shell.obj \
+		moc_kdiff3_part.obj
+DIST	=	
+TARGET	=	kdiff3.exe
+INTERFACE_DECL_PATH = .
+
+####### Implicit rules
+
+.SUFFIXES: .cpp .cxx .cc .c
+
+.cpp.obj:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $<
+
+.cxx.obj:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $<
+
+.cc.obj:
+	$(CXX) -c $(CXXFLAGS) $(INCPATH) -Fo$@ $<
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $(INCPATH) -Fo$@ $<
+
+####### Build rules
+
+all: $(TARGET)
+
+$(TARGET): $(UICDECLS) $(OBJECTS) $(OBJMOC) kdiff3.res
+	$(LINK) $(LFLAGS) /OUT:$(TARGET) @<<
+	    $(OBJECTS) $(OBJMOC) $(LIBS)
+<<
+
+kdiff3.res: kdiff3.rc
+	rc kdiff3.rc
+
+moc: $(SRCMOC)
+
+
+dist:
+	$(ZIP) kdiff3_tmake.zip kdiff3_tmake.pro $(SOURCES) $(HEADERS) $(DIST) $(INTERFACES)
+
+clean:
+	-del diff.obj
+	-del difftextwindow.obj
+	-del kdiff3.obj
+	-del main.obj
+	-del merger.obj
+	-del mergeresultwindow.obj
+	-del optiondialog.obj
+	-del pdiff.obj
+	-del directorymergewindow.obj
+	-del fileaccess.obj
+	-del kdiff3_shell.obj
+	-del kdiff3_part.obj
+	-del kreplacements\kreplacements.obj
+	-del moc_diff.cpp
+	-del moc_kdiff3.cpp
+	-del moc_optiondialog.cpp
+	-del kreplacements\moc_kreplacements.cpp
+	-del moc_directorymergewindow.cpp
+	-del moc_fileaccess.cpp
+	-del moc_kdiff3_shell.cpp
+	-del moc_kdiff3_part.cpp
+	-del moc_diff.obj
+	-del moc_kdiff3.obj
+	-del moc_optiondialog.obj
+	-del kreplacements\moc_kreplacements.obj
+	-del moc_directorymergewindow.obj
+	-del moc_fileaccess.obj
+	-del moc_kdiff3_shell.obj
+	-del moc_kdiff3_part.obj
+	-del $(TARGET)
+
+####### Compile
+
+diff.obj: diff.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+difftextwindow.obj: difftextwindow.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		merger.h \
+		optiondialog.h
+
+kdiff3.obj: kdiff3.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		kdiff3.h \
+		optiondialog.h \
+		kdiff3_part.h \
+		directorymergewindow.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\showlinenumbers.xpm \
+		xpm\startmerge.xpm
+
+main.obj: main.cpp \
+		kdiff3_shell.h
+
+merger.obj: merger.cpp \
+		merger.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+mergeresultwindow.obj: mergeresultwindow.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h
+
+optiondialog.obj: optiondialog.cpp \
+		optiondialog.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+pdiff.obj: pdiff.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h \
+		directorymergewindow.h \
+		kdiff3.h \
+		optiondialog.h
+
+directorymergewindow.obj: directorymergewindow.cpp \
+		directorymergewindow.h \
+		common.h \
+		fileaccess.h \
+		optiondialog.h \
+		xpm\equal.xpm \
+		xpm\not_equal.xpm \
+		xpm\not_everywhere.xpm \
+		xpm\not_there.xpm \
+		xpm\link_arrow.xpm \
+		xpm\file.xpm \
+		xpm\folder.xpm
+
+fileaccess.obj: fileaccess.cpp \
+		fileaccess.h \
+		optiondialog.h \
+		common.h
+
+kdiff3_shell.obj: kdiff3_shell.cpp \
+		kdiff3_shell.h \
+		kdiff3.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+kdiff3_part.obj: kdiff3_part.cpp \
+		kdiff3_part.h \
+		kdiff3.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+kreplacements\kreplacements.obj: kreplacements\kreplacements.cpp \
+		kreplacements\kreplacements.h \
+		kreplacements\..\xpm\fileopen.xpm \
+		kreplacements\..\xpm\filesave.xpm
+
+moc_diff.obj: moc_diff.cpp \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+moc_kdiff3.obj: moc_kdiff3.cpp \
+		kdiff3.h \
+		diff.h \
+		common.h \
+		fileaccess.h
+
+moc_optiondialog.obj: moc_optiondialog.cpp \
+		optiondialog.h
+
+kreplacements\moc_kreplacements.obj: kreplacements\moc_kreplacements.cpp \
+		kreplacements\kreplacements.h
+
+moc_directorymergewindow.obj: moc_directorymergewindow.cpp \
+		directorymergewindow.h \
+		common.h \
+		fileaccess.h
+
+moc_fileaccess.obj: moc_fileaccess.cpp \
+		fileaccess.h
+
+moc_kdiff3_shell.obj: moc_kdiff3_shell.cpp \
+		kdiff3_shell.h
+
+moc_kdiff3_part.obj: moc_kdiff3_part.cpp \
+		kdiff3_part.h
+
+moc_diff.cpp: diff.h
+	$(MOC) diff.h -o moc_diff.cpp
+
+moc_kdiff3.cpp: kdiff3.h
+	$(MOC) kdiff3.h -o moc_kdiff3.cpp
+
+moc_optiondialog.cpp: optiondialog.h
+	$(MOC) optiondialog.h -o moc_optiondialog.cpp
+
+kreplacements\moc_kreplacements.cpp: kreplacements\kreplacements.h
+	$(MOC) kreplacements\kreplacements.h -o kreplacements\moc_kreplacements.cpp
+
+moc_directorymergewindow.cpp: directorymergewindow.h
+	$(MOC) directorymergewindow.h -o moc_directorymergewindow.cpp
+
+moc_fileaccess.cpp: fileaccess.h
+	$(MOC) fileaccess.h -o moc_fileaccess.cpp
+
+moc_kdiff3_shell.cpp: kdiff3_shell.h
+	$(MOC) kdiff3_shell.h -o moc_kdiff3_shell.cpp
+
+moc_kdiff3_part.cpp: kdiff3_part.h
+	$(MOC) kdiff3_part.h -o moc_kdiff3_part.cpp
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/common.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,73 @@
+/***************************************************************************
+                          common.h  -  Things that are needed often
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#ifndef _COMMON_H
+#define _COMMON_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;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/diff.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,1081 @@
+/***************************************************************************
+                          diff.cpp  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <iostream>
+
+#include "diff.h"
+#include "fileaccess.h"
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+
+#include <map>
+#include <assert.h>
+#include <ctype.h>
+//using namespace std;
+
+
+int LineData::width()
+{
+   int w=0;
+   int j=0;
+   for( int i=0; i<size; ++i )
+   {
+      if ( pLine[i]=='\t' )
+      {
+         for(j %= g_tabSize; j<g_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 char* p1 = l1.pLine;
+   const char* p1End = p1 + l1.size;
+
+   const char* p2 = l2.pLine;
+   const char* 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;
+   }
+}
+
+
+// class needed during preprocess phase
+class LineDataRef
+{
+   const LineData* m_pLd;
+public:
+   LineDataRef(const LineData* pLd){ m_pLd = pLd; }
+
+   bool operator<(const LineDataRef& ldr2) const
+   {
+      const LineData* pLd1 = m_pLd;
+      const LineData* pLd2 = ldr2.m_pLd;
+      const char* p1 = pLd1->pFirstNonWhiteChar;
+      const char* p2 = pLd2->pFirstNonWhiteChar;
+      int i1=pLd1->pFirstNonWhiteChar - pLd1->pLine;
+      int i2=pLd2->pFirstNonWhiteChar - pLd2->pLine;
+
+      int size1=pLd1->size;
+      int size2=pLd2->size;
+      for(;;)
+      {
+         while( i1<size1 && isWhite( p1[i1] ) ) ++i1;
+         while( i2<size2 && isWhite( p2[i2] ) ) ++i2;
+         if ( i1==size1 || i2==size2 )
+         {
+            if ( i1==size1 && i2==size2 ) return false;  // Equal
+            if ( i1==size1 ) return true;  // String 1 is shorter than string 2
+            if ( i2==size2 ) return false; // String 1 is longer than string 2
+         }
+         if ( p1[i1]==p2[i2] ) { ++i1; ++i2; continue; }
+         return  p1[i1]<p2[i2];
+      }
+   }
+};
+
+void SourceData::reset()
+{
+   delete (char*)m_pBuf;
+   m_pBuf = 0;
+   m_v.clear();
+   m_size = 0;
+   m_vSize = 0;
+   m_bIsText = false;
+   m_bPreserve = false;
+   m_fileAccess = FileAccess("");
+}
+
+/** Prepare the linedata vector for every input line.*/
+void SourceData::preprocess( bool bPreserveCR )
+{
+   const char* p = m_pBuf;
+   m_bIsText = true;
+   int lines = 1;
+
+   int i;
+   for( i=0; i<m_size; ++i )
+   {
+      if (p[i]=='\n')
+      {
+         ++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<=m_size; ++i )
+   {
+      // For WIN32
+      if ( i==m_size || (!bPreserveCR  &&  p[i]=='\r' && p[i+1]=='\n' ) || p[i]=='\n' )        // The last line does not end with a linefeed.
+      {
+         m_v[lineIdx].pLine = &p[ i-lineLength ];
+         m_v[lineIdx].pFirstNonWhiteChar = m_v[lineIdx].pLine + whiteLength;
+         m_v[lineIdx].size = lineLength;
+         lineLength = 0;
+         bNonWhiteFound = false;
+         whiteLength = 0;
+         ++lineIdx;
+         if ( i<m_size && p[i]=='\r') ++i;
+      }
+      else
+      {
+         ++lineLength;
+
+         if ( ! bNonWhiteFound && isWhite( p[i] ) )
+            ++whiteLength;
+         else
+            bNonWhiteFound = true;
+      }
+   }
+   assert( lineIdx == lines );
+
+   m_vSize = lines;
+}
+
+// read and prepocess file for line matching input data
+void SourceData::readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase )
+{
+   if ( ppCmd.isEmpty() || pOrigSource->m_bPreserve )
+   {
+      reset();
+   }
+   else
+   {
+      m_fileName = pOrigSource->m_fileAccess.absFilePath();
+      readPPFile( false, ppCmd, bUpCase );
+      if ( m_vSize < pOrigSource->m_vSize )
+      {
+         m_v.resize( pOrigSource->m_vSize );
+         m_vSize = pOrigSource->m_vSize;
+      }
+   }
+}
+
+
+void SourceData::readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase )
+{
+   if ( !m_bPreserve )
+   {
+      if ( ! ppCmd.isEmpty() && !m_fileName.isEmpty() && FileAccess::exists( m_fileName ) )
+      {
+         QString fileNameOut = FileAccess::tempFileName();
+#ifdef _WIN32
+         QString cmd = QString("type ") + m_fileName + " | " + ppCmd  + " >" + fileNameOut;
+#else
+         QString cmd = QString("cat ") + m_fileName + " | " + ppCmd  + " >" + fileNameOut;
+#endif
+         ::system( cmd.ascii() );
+         readFile( fileNameOut, true, bUpCase );
+         FileAccess::removeFile( fileNameOut );
+      }
+      else
+      {
+         readFile( m_fileAccess.absFilePath(), true, bUpCase );
+      }
+   }
+   preprocess( bPreserveCR );
+}
+
+void SourceData::readFile( const QString& filename, bool bFollowLinks, bool bUpCase )
+{
+   delete (char*)m_pBuf;
+   m_size = 0;
+   m_pBuf = 0;
+   char* pBuf = 0;
+   if ( filename.isEmpty() )   { return; }
+
+   if ( !bFollowLinks )
+   {
+      FileAccess fi( filename );
+      if ( fi.isSymLink() )
+      {
+         QString s = fi.readLink();
+         m_size = s.length();
+         m_pBuf = pBuf = new char[m_size+100];
+         memcpy( pBuf, s.ascii(), m_size );
+         return;
+      }
+   }
+
+
+   FileAccess fa( filename );
+   m_size = fa.sizeForReading();
+   m_pBuf = pBuf = new char[m_size+100];
+   bool bSuccess = fa.readFile( pBuf, m_size );
+   if ( !bSuccess )
+   {
+      delete pBuf;
+      m_pBuf = 0;
+      m_size = 0;
+      return;
+   }
+
+   /*
+
+   FILE* f = fopen( filename, "rb" );
+   if ( f==0 )
+   {
+      std::cerr << "File open error for file: '"<< filename <<"': ";
+      perror("");
+      return;
+   }
+
+   fseek( f, 0, SEEK_END );
+
+   m_size =  ftell(f);
+
+   fseek( f, 0, SEEK_SET );
+
+   m_pBuf = pBuf = new char[m_size+100];
+   int bytesRead = fread( pBuf, 1, m_size, f );
+   if( bytesRead != m_size )
+   {
+      std::cerr << "File read error for file: '"<< filename <<"': ";
+
+      perror("");
+      fclose(f);
+      m_size = 0;
+      delete pBuf;
+      m_pBuf = 0;
+      return;
+   }
+   fclose( f );
+   */
+
+   if ( bUpCase )
+   {
+      int i;
+      for(i=0; i<m_size; ++i)
+      {
+         pBuf[i] = toupper(pBuf[i]);
+      }
+   }
+
+}
+
+void SourceData::setData( const QString& data, bool bUpCase )
+{
+   delete (char*)m_pBuf;
+   m_size = data.length();
+   m_pBuf = 0;
+
+   char* pBuf = 0;
+   m_pBuf = pBuf = new char[m_size+100];
+
+   memcpy( pBuf, data.ascii(), m_size );
+   if ( bUpCase )
+   {
+      int i;
+      for(i=0; i<m_size; ++i)
+      {
+         pBuf[i] = toupper(pBuf[i]);
+      }
+   }
+   m_bPreserve = true;
+   m_fileName="";
+   m_aliasName = i18n("From Clipboard");
+   m_fileAccess = FileAccess("");
+}
+
+void SourceData::setFilename( const QString& filename )
+{
+   FileAccess fa( filename );
+   setFileAccess( fa );
+}
+
+QString SourceData::getFilename()
+{
+   return m_fileName;
+}
+
+QString SourceData::getAliasName()
+{
+   return m_aliasName.isEmpty() ? m_fileAccess.prettyAbsPath() : m_aliasName;
+}
+
+void SourceData::setAliasName( const QString& name )
+{
+   m_aliasName = name;
+}
+
+void SourceData::setFileAccess( const FileAccess& fileAccess )
+{
+   m_fileAccess = fileAccess;
+   m_aliasName = QString();
+   m_bPreserve = false;
+   m_fileName = m_fileAccess.absFilePath();
+}
+
+void prepareOccurances( LineData* p, int size )
+{
+   // Special analysis: Find out how often this line occurs
+   // Only problem: A simple search will cost O(N^2).
+   // To avoid this we will use a map. Then the cost will only be
+   // O(N*log N). (A hash table would be even better.)
+
+   std::map<LineDataRef,int> occurancesMap;
+   int i;
+   for( i=0; i<size; ++i )
+   {
+      ++occurancesMap[ LineDataRef( &p[i] ) ];
+   }
+
+   for( i=0; i<size; ++i )
+   {
+      p[i].occurances = occurancesMap[ LineDataRef( &p[i] ) ];
+   }
+}
+
+// First step
+void calcDiff3LineListUsingAB(
+   const DiffList* pDiffListAB,
+   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 //if ( !(*i3b).bAEqB )
+         {
+            // 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 )
+               {
+                  // 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;
+                  //(*i3b).lineC = -1;
+                  (*i3c).lineB = lineB;
+
+                  (*i3c).bBEqC = true;
+
+               }
+
+            }
+
+            else if( i3b1==i3c  &&  !(*i3b).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 )
+               {
+                  // Move the disturbing lines up, out of sight.
+                  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;
+                  //(*i3c).lineB = -1;
+                  (*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 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
+
+// Fourth step
+void calcDiff3LineListTrim(       
+   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
+   )
+{
+   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;
+   int lineA=0;
+   int lineB=0;
+   int lineC=0;
+
+   // 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( line>lineA && (*i3).lineA != -1 && (*i3A).lineB!=-1 && (*i3A).bBEqC  &&
+          ::equal( pldA[(*i3).lineA], pldB[(*i3A).lineB], false ))
+      {
+         // 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 ))
+      {
+         // 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 ))
+      {
+         // 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 )
+      {
+         // 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 )
+      {
+         // 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 )
+      {
+         // 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;
+
+         (*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;
+         (*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;
+         (*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 calcWhiteDiff3Lines(       
+   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC
+   )
+{
+   Diff3LineList::iterator i3 = d3ll.begin();
+
+   for( ; i3!=d3ll.end(); ++i3 )
+   {
+      i3->bWhiteLineA = ( (*i3).lineA == -1  ||  pldA[(*i3).lineA].whiteLine() );
+      i3->bWhiteLineB = ( (*i3).lineB == -1  ||  pldB[(*i3).lineB].whiteLine() );
+      i3->bWhiteLineC = ( (*i3).lineC == -1  ||  pldC[(*i3).lineC].whiteLine() );
+   }
+}
+
+// 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;
+      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"
+               ), "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"
+         ), "Severe internal Error" );
+      assert(false);
+      std::cerr << "Severe Internal Error.\n";
+      ::exit(-1);
+   }
+}
+
+
+void fineDiff(
+   Diff3LineList& diff3LineList,
+   int selector,
+   LineData* v1,
+   LineData* v2,
+   int maxSearchLength,
+   bool& bTextsTotalEqual
+   )
+{
+   // Finetuning: Diff each line with deltas
+   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)!=0 )
+         {
+            bTextsTotalEqual = false;
+            DiffList* pDiffList = new DiffList;
+//            std::cout << std::string( v1[k1].pLine, v1[k1].size ) << "\n";
+            calcDiff( v1[k1].pLine, v1[k1].size, v2[k2].pLine, v2[k2].size, *pDiffList, 2, maxSearchLength );
+
+            // Optimize the diff list.
+            DiffList::iterator dli;
+            for( dli = pDiffList->begin(); dli!=pDiffList->end(); ++dli)
+            {
+               if( dli->nofEquals < 4  &&  (dli->diff1>0 || dli->diff2>0)  )
+               {
+                  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);
+         }
+      }
+      ++listIdx;
+      g_pProgressDialog->setSubCurrent(double(listIdx)/listSize);
+   }
+}
+
+
+// Convert the list to a vector of pointers
+void calcDiff3LineVector( const Diff3LineList& d3ll, Diff3LineVector& d3lv )
+{
+   d3lv.resize( d3ll.size() );
+   Diff3LineList::const_iterator i;
+   int j=0;
+   for( i= d3ll.begin(); i!= d3ll.end(); ++i, ++j)
+   {
+      d3lv[j] = &(*i);
+   }
+   assert( j==(int)d3lv.size() );   
+}
+
+
+#include "diff.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/diff.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,813 @@
+/***************************************************************************
+                          diff.h  -  description
+                             -------------------
+    begin                : Mon Mar 18 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#ifndef DIFF_H
+#define DIFF_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#include <qframe.h>
+#include <list>
+#include <vector>
+#include <assert.h>
+#include "common.h"
+#include "fileaccess.h"
+
+
+
+// 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 Diff3Line
+{
+   int lineA;
+   int lineB;
+   int lineC;
+
+   bool bAEqC;                 // These are true if equal or only white-space changes exist.
+   bool bBEqC;
+   bool bAEqB;
+
+   DiffList* pFineAB;          // These are 0 only if completely equal. 
+   DiffList* pFineBC;
+   DiffList* pFineCA;
+   
+   bool bWhiteLineA;
+   bool bWhiteLineB;
+   bool bWhiteLineC;
+
+   Diff3Line()
+   {
+      lineA=-1; lineB=-1; lineC=-1;
+      bAEqC=false; bAEqB=false; bBEqC=false;
+      pFineAB=0; pFineBC=0; pFineCA=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;
+   }
+};
+
+typedef std::list<Diff3Line> Diff3LineList;
+typedef std::vector<const Diff3Line*> Diff3LineVector;
+
+class TotalDiffStatus
+{
+public:
+   void reset() {bBinaryAEqC=false; bBinaryBEqC=false; bBinaryAEqB=false;
+                 bTextAEqC=false;   bTextBEqC=false;   bTextAEqB=false;}
+   bool bBinaryAEqC;
+   bool bBinaryBEqC;
+   bool bBinaryAEqB;
+
+   bool bTextAEqC;
+   bool bTextBEqC;
+   bool bTextAEqB;
+};
+
+void calcDiff3LineListUsingAB(       
+   const DiffList* pDiffListAB,
+   Diff3LineList& d3ll
+   );
+
+void calcDiff3LineListUsingAC(
+   const DiffList* pDiffListBC,
+   Diff3LineList& d3ll
+   );
+
+void calcDiff3LineListUsingBC(       
+   const DiffList* pDiffListBC,
+   Diff3LineList& d3ll
+   );
+
+struct LineData
+{
+   const char* pLine;
+   const char* pFirstNonWhiteChar;
+   int size;
+
+   LineData(){ pLine=0; size=0; occurances=0; }
+   int width();  // Calcs width considering tabs.
+   int occurances;
+   bool whiteLine(){ return pFirstNonWhiteChar-pLine == size; }
+};
+
+void prepareOccurances( LineData* p, int size );
+
+
+class SourceData
+{
+public:
+   SourceData(){ m_pBuf=0;m_size=0;m_vSize=0;m_bIsText=false;m_bPreserve=false; }
+   const char* m_pBuf;
+   int m_size;
+   int m_vSize; // Nr of lines in m_pBuf1 and size of m_v1, m_dv12 and m_dv13
+   std::vector<LineData> m_v;
+   bool m_bIsText;
+   bool m_bPreserve;
+   void reset();
+   void readPPFile( bool bPreserveCR, const QString& ppCmd, bool bUpCase );
+   void readLMPPFile( SourceData* pOrigSource, const QString& ppCmd, bool bUpCase );
+   void readFile(const QString& filename, bool bFollowLinks, bool bUpCase );
+   void preprocess(bool bPreserveCR );
+   void setData( const QString& data, bool bUpCase );
+   void setFilename(const QString& filename);
+   void setFileAccess( const FileAccess& fa );
+   FileAccess& getFileAccess();
+   QString getFilename();
+   void setAliasName(const QString& a);
+   QString getAliasName();
+   bool isEmpty() { return getFilename().isEmpty(); }
+private:
+   QString m_fileName;
+   QString m_aliasName;
+   FileAccess m_fileAccess;
+};
+
+void calcDiff3LineListTrim( Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC );
+void calcWhiteDiff3Lines(   Diff3LineList& d3ll, LineData* pldA, LineData* pldB, LineData* pldC );
+
+void calcDiff3LineVector( const 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;
+      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(){ return min2(firstLine,lastLine); }
+   int endLine(){ return max2(firstLine,lastLine); }
+   int beginPos() { return firstLine==lastLine ? min2(firstPos,lastPos) :
+                           firstLine<lastLine ? firstPos : lastPos;      }
+   int endPos()   { return firstLine==lastLine ? max2(firstPos,lastPos) :
+                           firstLine<lastLine ? lastPos : firstPos;      }
+};
+
+class OptionDialog;
+
+class DiffTextWindow : public QWidget
+{
+   Q_OBJECT
+public:
+   DiffTextWindow(
+      QWidget* pParent,
+      QStatusBar* pStatusBar,
+      OptionDialog* pOptionDialog
+      );
+   void init(
+      const QString& fileName,
+      LineData* pLineData,
+      int size,
+      const Diff3LineVector* pDiff3LineVector,
+      int winIdx,
+      bool bTriple
+      );
+   virtual void mousePressEvent ( QMouseEvent * );
+   virtual void mouseReleaseEvent ( QMouseEvent * );
+   virtual void mouseMoveEvent ( QMouseEvent * );
+   virtual void mouseDoubleClickEvent ( QMouseEvent * e );
+   void convertToLinePos( int x, int y, int& line, int& pos );
+
+   virtual void paintEvent( QPaintEvent*  );
+   virtual void dragEnterEvent( QDragEnterEvent* e );
+   //void setData( const char* pText);
+
+   virtual void resizeEvent( QResizeEvent* );
+
+   QString getSelection();
+   int getFirstLine() { return m_firstLine; }
+
+   int getNofColumns();
+   int getNofLines();
+   int getNofVisibleLines();
+   int getNofVisibleColumns();
+
+   bool findString( const QCString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive );
+   void setSelection( int firstLine, int startPos, int lastLine, int endPos );
+
+   void setPaintingAllowed( bool bAllowPainting );
+signals:
+   void resizeSignal( int nofVisibleColumns, int nofVisibleLines );
+   void scroll( int deltaX, int deltaY );
+   void newSelection();
+   void selectionEnd();
+   void setFastSelectorLine( int line );
+
+public slots:
+   void setFirstLine( int line );
+   void setFirstColumn( int col );
+   void resetSelection();
+   void setFastSelectorRange( int line1, int nofLines );
+
+private:
+   bool m_bPaintingAllowed;
+   LineData* m_pLineData;
+   int m_size;
+   QString m_filename;
+
+   const Diff3LineVector* m_pDiff3LineVector;
+
+   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  );
+
+   QCString getString( int line );
+
+   void writeLine(
+      QPainter& p, const LineData* pld,
+      const DiffList* pLineDiff1, const DiffList* pLineDiff2, int line,
+      int whatChanged, int whatChanged2, int srcLineNr );
+
+   QStatusBar* m_pStatusBar;
+
+   Selection selection;
+
+   int m_scrollDeltaX;
+   int m_scrollDeltaY;
+   virtual void timerEvent(QTimerEvent*);
+   bool m_bMyUpdate;
+   void myUpdate(int afterMilliSecs );
+
+   QRect m_invalidRect;
+};
+
+
+
+class Overview : public QWidget
+{
+   Q_OBJECT
+public:
+   Overview( QWidget* pParent, OptionDialog* pOptions );
+             
+   void init( Diff3LineList* pDiff3LineList, bool bTripleDiff );
+   void setRange( int firstLine, int pageHeight );
+   void setPaintingAllowed( bool bAllowPainting );
+
+public slots:
+   void setFirstLine(int firstLine);
+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;
+
+   virtual void paintEvent( QPaintEvent* e );
+   virtual void mousePressEvent( QMouseEvent* e );
+   virtual void mouseMoveEvent( QMouseEvent* e );
+};
+
+
+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 );
+
+
+class MergeResultWindow : public QWidget
+{
+   Q_OBJECT
+public:
+   MergeResultWindow(
+      QWidget* pParent,
+      OptionDialog* pOptionDialog
+      );
+
+   void init(
+      const LineData* pLineDataA,
+      const LineData* pLineDataB,
+      const LineData* pLineDataC,
+      const Diff3LineList* pDiff3LineList,
+      const TotalDiffStatus* pTotalDiffStatus,
+      QString fileName
+      );
+
+   bool saveDocument( const QString& fileName );
+   int getNrOfUnsolvedConflicts();
+   void choose(int selector);
+
+   int getNofColumns();
+   int getNofLines();
+   int getNofVisibleColumns();
+   int getNofVisibleLines();
+   virtual void resizeEvent( QResizeEvent* e );
+   virtual void keyPressEvent( QKeyEvent* e );
+   virtual void wheelEvent( QWheelEvent* e );
+   QString getSelection();
+   void resetSelection();
+   void showNrOfConflicts();
+   bool isDeltaAboveCurrent();
+   bool isDeltaBelowCurrent();
+   bool isConflictAboveCurrent();
+   bool isConflictBelowCurrent();
+   bool isUnsolvedConflictAboveCurrent();
+   bool isUnsolvedConflictBelowCurrent();
+   bool findString( const QCString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive );
+   void setSelection( int firstLine, int startPos, int lastLine, int endPos );
+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 slotChooseA();
+   void slotChooseB();
+   void slotChooseC();
+   void slotChooseAEverywhere();
+   void slotChooseBEverywhere();
+   void slotChooseCEverywhere();
+   void slotAutoSolve();
+   void slotUnsolve();
+   void slotSetFastSelectorLine(int);
+
+signals:
+   void scroll( int deltaX, int deltaY );
+   void modified();
+   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 );
+
+private:
+   void merge(bool bAutoSolve, int defaultSelector);
+   QCString getString( int lineIdx );
+
+   OptionDialog* m_pOptionDialog;
+
+   const LineData* m_pldA;
+   const LineData* m_pldB;
+   const LineData* m_pldC;
+
+   const Diff3LineList* m_pDiff3LineList;
+   const TotalDiffStatus* m_pTotalDiffStatus;
+
+private:
+   class MergeEditLine
+   {
+   public:
+      MergeEditLine(){ m_src=0; m_bLineRemoved=false; }
+      void setConflict() { m_src=0; m_bLineRemoved=false; m_str=QCString(); }
+      bool isConflict()  { return  m_src==0 && !m_bLineRemoved && m_str.isNull(); }
+      void setRemoved(int src=0)  { m_src=src; m_bLineRemoved=true; m_str=QCString(); }
+      bool isRemoved()   { return m_bLineRemoved; }
+      bool isEditableText() { return !isConflict() && !isRemoved(); }
+      void setString( const QCString& s ){ m_str=s; m_bLineRemoved=false; m_src=0; }
+      const char* getString( const MergeResultWindow*, int& size );
+      bool isModified() { return ! m_str.isNull() ||  (m_bLineRemoved && m_src==0); }
+
+      void setSource( int src, Diff3LineList::const_iterator i, bool bLineRemoved )
+      {
+         m_src=src; m_id3l=i; 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.
+      QCString 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;
+   public:
+      typedef std::list<MergeEditLine>::iterator iterator;
+      typedef std::list<MergeEditLine>::const_iterator const_iterator;
+      MergeEditLineList(){m_size=0;}
+      void clear()                             { m_size=0; BASE::clear();          }
+      void push_back( const MergeEditLine& m)  { ++m_size; BASE::push_back(m);     }
+      void push_front( const MergeEditLine& m) { ++m_size; BASE::push_front(m);    }
+      iterator erase( iterator i )             { --m_size; return BASE::erase(i);  }
+      iterator insert( iterator i, const MergeEditLine& m ) { ++m_size; return BASE::insert(i,m); }
+      int size(){ /*assert(int(BASE::size())==m_size);*/ return m_size;}
+      iterator begin(){return BASE::begin();}
+      iterator end(){return BASE::end();}
+      bool empty() { return m_size==0; }
+   };
+
+   friend class MergeEditLine;
+
+   struct MergeLine
+   {
+      MergeLine()
+      { srcSelect=0; mergeDetails=eDefault; d3lLineIdx = -1; srcRangeLength=0; bConflict=false; bDelta=false;}
+      Diff3LineList::const_iterator id3l;
+      e_MergeDetails mergeDetails;
+      int d3lLineIdx;  // Needed to show the correct window pos.
+      int srcRangeLength; // how many src-lines have this properties
+      bool bConflict;
+      bool bDelta;
+      int srcSelect;
+      MergeEditLineList mergeEditLineList;
+   };
+
+private:
+   static bool sameKindCheck( const MergeLine& ml1, const MergeLine& ml2 );
+
+   typedef std::list<MergeLine> MergeLineList;
+   MergeLineList m_mergeLineList;
+   MergeLineList::iterator m_currentMergeLineIt;
+   int m_currentPos;
+
+   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
+      );
+
+   virtual void paintEvent( QPaintEvent* e );
+
+
+   void myUpdate(int afterMilliSecs);
+   virtual void timerEvent(QTimerEvent*);
+   void writeLine(
+      QPainter& p, int line, const char* pStr, int size,
+      int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved
+      );
+   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 * );
+
+   QPixmap m_pixmap;
+   int m_firstLine;
+   int m_firstColumn;
+   int m_nofColumns;
+   int m_nofLines;
+   bool m_bMyUpdate;
+   bool m_bInsertMode;
+   QString m_fileName;
+   bool m_bModified;
+   void setModified();
+
+   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;
+
+   Selection m_selection;
+
+   bool deleteSelection2( const char*& ps, int& stringLength, int& x, int& y,
+                    MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt );
+public slots:
+   void deleteSelection();
+   void pasteClipboard();
+private slots:
+   void slotCursorUpdate();
+};
+
+void fineDiff(
+   Diff3LineList& diff3LineList,
+   int selector,
+   LineData* v1,
+   LineData* v2,
+   int maxSearchLength,
+   bool& bTextsTotalEqual
+   );
+
+
+bool equal( const LineData& l1, const LineData& l2, bool bStrict );
+
+inline bool equal( char c1, char c2, bool /*bStrict*/ )
+{
+   // If bStrict then white space doesn't match
+
+   //if ( bStrict &&  ( c1==' ' || c1=='\t' ) )
+   //   return false;
+
+   return c1==c2;
+}
+
+
+// My own diff-invention:
+template <class T>
+void calcDiff( const T* p1, int size1, const T* p2, int size2, DiffList& diffList, int match, int maxSearchRange )
+{
+   diffList.clear();
+
+   const T* p1start = p1;
+   const T* p2start = p2;
+   const T* p1end=p1+size1;
+   const T* p2end=p2+size2;
+   for(;;)
+   {
+      int nofEquals = 0;
+      while( p1!=p1end &&  p2!=p2end && equal(*p1, *p2, false) )
+      {
+
+
+         ++p1;
+         ++p2;
+         ++nofEquals;
+      }
+
+      bool bBestValid=false;
+      int bestI1=0;
+      int bestI2=0;
+      int i1=0;
+      int i2=0;
+      for( i1=0; ; ++i1 )
+      {
+         if ( &p1[i1]==p1end || ( bBestValid && i1>= bestI1+bestI2))
+         {
+            break;
+         }
+         for(i2=0;i2<maxSearchRange;++i2)
+         {
+            if( &p2[i2]==p2end ||  ( bBestValid && i1+i2>=bestI1+bestI2) )
+            {
+               break;
+            }
+            else if(  equal( p2[i2], p1[i1], true ) &&
+                      ( match==1 ||  abs(i1-i2)<3  || ( &p2[i2+1]==p2end  &&  &p1[i1+1]==p1end ) ||
+                         ( &p2[i2+1]!=p2end  &&  &p1[i1+1]!=p1end  && equal( p2[i2+1], p1[i1+1], false ))
+                      )
+                   )
+            {
+               if ( i1+i2 < bestI1+bestI2 || bBestValid==false )
+               {
+                  bestI1 = i1;
+                  bestI2 = i2;
+                  bBestValid = true;
+                  break;
+               }
+            }
+         }
+      }
+
+      // The match was found using the strict search. Go back if there are non-strict
+      // matches.
+      while( bestI1>=1 && bestI2>=1 && equal( p1[bestI1-1], p2[bestI2-1], false ) )
+      {
+         --bestI1;
+         --bestI2;
+      }
+
+
+      bool bEndReached = false;
+      if (bBestValid)
+      {
+         // continue somehow
+         Diff d(nofEquals, bestI1, bestI2);
+         diffList.push_back( d );
+
+         p1 += bestI1;
+         p2 += bestI2;
+      }
+      else
+      {
+         // Nothing else to match.
+         Diff d(nofEquals, p1end-p1, p2end-p2);
+         diffList.push_back( d );
+
+         bEndReached = true; //break;
+      }
+
+      // Sometimes the algorithm that chooses the first match unfortunately chooses
+      // a match where later actually equal parts don't match anymore.
+      // A different match could be achieved, if we start at the end.
+      // Do it, if it would be a better match.
+      int nofUnmatched = 0;
+      const T* pu1 = p1-1;
+      const T* pu2 = p2-1;
+      while ( pu1>=p1start && pu2>=p2start && equal( *pu1, *pu2, false ) )
+      {
+         ++nofUnmatched;
+         --pu1;
+         --pu2;
+      }
+
+      Diff d = diffList.back();
+      if ( nofUnmatched > 0 )
+      {
+         // We want to go backwards the nofUnmatched elements and redo
+         // the matching
+         d = diffList.back();
+         Diff origBack = d;
+         diffList.pop_back();
+
+         while (  nofUnmatched > 0 )
+         {
+            if ( d.diff1 > 0  &&  d.diff2 > 0 )
+            {
+               --d.diff1;
+               --d.diff2;
+               --nofUnmatched;
+            }
+            else if ( d.nofEquals > 0 )
+            {
+               --d.nofEquals;
+               --nofUnmatched;
+            }
+
+            if ( d.nofEquals==0 && (d.diff1==0 || d.diff2==0) &&  nofUnmatched>0 )
+            {
+               if ( diffList.empty() )
+                  break;
+               d.nofEquals += diffList.back().nofEquals;
+               d.diff1 += diffList.back().diff1;
+               d.diff2 += diffList.back().diff2;
+               diffList.pop_back();
+               bEndReached = false;
+            }
+         }
+
+         if ( bEndReached )
+            diffList.push_back( origBack );
+         else
+         {
+
+            p1 = pu1 + 1 + nofUnmatched;
+            p2 = pu2 + 1 + nofUnmatched;
+            diffList.push_back( d );
+         }
+      }
+      if ( bEndReached )
+         break;
+   }
+
+#ifndef NDEBUG
+   // Verify difflist
+   {
+      int l1=0;
+      int l2=0;
+      DiffList::iterator i;
+      for( i = diffList.begin(); i!=diffList.end(); ++i )
+      {
+         l1+= i->nofEquals + i->diff1;
+         l2+= i->nofEquals + i->diff2;
+      }
+
+      //if( l1!=p1-p1start || l2!=p2-p2start )
+      if( l1!=size1 || l2!=size2 )
+         assert( false );
+   }
+#endif
+}
+
+
+
+inline bool isWhite( char 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 int g_tabSize;
+extern bool g_bIgnoreWhiteSpace;
+extern bool g_bIgnoreTrivialMatches;
+extern int g_bAutoSolve;
+
+// Cursor conversions that consider g_tabSize.
+int convertToPosInText( const char* p, int size, int posOnScreen );
+int convertToPosOnScreen( const char* p, int posInText );
+void calcTokenPos( const char* p, int size, int posOnScreen, int& pos1, int& pos2 );
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/difftextwindow.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,1025 @@
+/***************************************************************************
+                          difftextwindow.cpp  -  description
+                             -------------------
+    begin                : Mon Apr 8 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include <iostream>
+#include "diff.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 <optiondialog.h>
+#include <math.h>
+#include <qdragobject.h>
+
+#define leftInfoWidth (4+m_lineNumberWidth)   // Nr of information columns on left side
+
+//using namespace std;
+
+DiffTextWindow::DiffTextWindow(
+   QWidget* pParent,
+   QStatusBar* pStatusBar,
+   OptionDialog* pOptionDialog
+   )
+: QWidget(pParent, 0, WRepaintNoErase)
+{
+   setFocusPolicy( QWidget::ClickFocus );
+   setAcceptDrops( true );
+
+   m_pOptionDialog = pOptionDialog;
+   init( 0, 0, 0, 0, 0, false );
+
+   setBackgroundMode( PaletteBase );
+   setMinimumSize(QSize(20,20));
+
+   m_pStatusBar = pStatusBar;
+   m_bPaintingAllowed = true;
+}
+
+
+void DiffTextWindow::init(
+   const QString& filename,
+   LineData* pLineData,
+   int size,
+   const Diff3LineVector* pDiff3LineVector,
+   int winIdx,
+   bool bTriple
+   )
+{
+   m_filename = filename;
+   m_pLineData = pLineData;
+   m_size = size;
+   m_pDiff3LineVector = pDiff3LineVector;
+   m_winIdx = winIdx;
+
+   m_firstLine = 0;
+   m_oldFirstLine = -1;
+   m_firstColumn = 0;
+   m_oldFirstColumn = -1;
+   m_bTriple = bTriple;
+   m_scrollDeltaX=0;
+   m_scrollDeltaY=0;
+   m_bMyUpdate = false;
+   m_fastSelectorLine1 = 0;
+   m_fastSelectorNofLines = 0;
+   m_lineNumberWidth = 0;
+   selection.reset();
+   selection.oldFirstLine = -1; // reset is not enough here.
+   selection.oldLastLine = -1;
+   selection.lastLine = -1;
+
+   QToolTip::remove(this);
+   QToolTip::add( this, QRect( 0,0, 1024, fontMetrics().height() ), m_filename );
+   update();
+}
+
+void DiffTextWindow::setPaintingAllowed( bool bAllowPainting )
+{
+   if (m_bPaintingAllowed != bAllowPainting)
+   {
+      m_bPaintingAllowed = bAllowPainting;
+      if ( m_bPaintingAllowed ) update();
+   }
+}
+
+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)
+{
+   m_firstLine = max2(0,firstLine);
+   myUpdate(0); // Immediately
+}
+
+void DiffTextWindow::setFirstColumn(int firstCol)
+{
+   m_firstColumn = max2(0,firstCol);
+   myUpdate(0); // Immediately
+}
+
+int DiffTextWindow::getNofColumns()
+{
+   int nofColumns = 0;
+   for( int i = 0; i< m_size; ++i )
+   {
+      if ( m_pLineData[i].width() > nofColumns )
+         nofColumns = m_pLineData[i].width();
+   }
+   return nofColumns;
+}
+
+int DiffTextWindow::getNofLines()
+{
+   return m_pDiff3LineVector->size();
+}
+
+/** 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 )
+{
+   m_fastSelectorLine1 = line1;
+   m_fastSelectorNofLines = nofLines;
+
+   if ( isVisible() )
+   {
+      int newFirstLine = getBestFirstLine( line1, nofLines, m_firstLine, getNofVisibleLines() );
+      if ( newFirstLine != m_firstLine )
+      {
+         scroll( 0, newFirstLine - m_firstLine );
+      }
+
+      update();
+   }
+}
+
+
+static void showStatusLine(int line, int winIdx, const QString& filename, const Diff3LineVector& d3lv, QStatusBar* sb)
+{
+   int l=0;
+   const Diff3Line* pD3l = d3lv[line];
+   if(line >= 0 && line<(int)d3lv.size() && pD3l != 0 )
+   {
+      if      ( winIdx==1 ) l = pD3l->lineA;
+      else if ( winIdx==2 ) l = pD3l->lineB;
+      else if ( winIdx==3 ) l = pD3l->lineC;
+      else assert(false);
+
+      QString s;
+      if ( l!=-1 )
+         s.sprintf("File %s: Line %d", filename.ascii(), l+1 );
+      else
+         s.sprintf("File %s: Line not available", filename.ascii() );
+      if (sb!=0) sb->message(s);
+   }
+}
+
+
+void DiffTextWindow::mousePressEvent ( QMouseEvent* e )
+{
+   if ( e->button() == LeftButton )
+   {
+      int line;
+      int pos;
+      convertToLinePos( e->x(), e->y(), line, pos );
+      if ( pos < m_firstColumn )
+      {
+         emit setFastSelectorLine( line );
+         selection.firstLine = -1;     // Disable current selection
+      }
+      else
+      {  // Selection
+         resetSelection();
+         selection.start( line, pos );
+         selection.end( line, pos );
+
+         showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar );
+      }
+   }
+}
+
+bool isCTokenChar( char 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 char* p, int size, int posOnScreen, int& pos1, int& pos2 )
+{
+   // Cursor conversions that consider g_tabSize
+   int pos = convertToPosInText( p, size, max2( 0, posOnScreen ) );
+   if ( pos>=size )
+   {
+      pos1=size;
+      pos2=size;
+      return;
+   }
+
+   pos1 = pos;
+   pos2 = pos+1;
+
+   if( isCTokenChar( p[pos1] ) )
+   {
+      while( pos1>=0 && isCTokenChar( p[pos1] ) )
+         --pos1;
+      ++pos1;
+
+      while( pos2<size && isCTokenChar( p[pos2] ) )
+         ++pos2;
+   }
+}
+
+void DiffTextWindow::mouseDoubleClickEvent( QMouseEvent* e )
+{
+   if ( e->button() == LeftButton )
+   {
+      int line;
+      int pos;
+      convertToLinePos( e->x(), e->y(), line, pos );
+
+      // Get the string data of the current line
+      QCString s = getString( line );
+
+      if ( ! s.isEmpty() )
+      {
+         int pos1, pos2;
+         calcTokenPos( s, s.length(), pos, pos1, pos2 );
+
+         resetSelection();
+         selection.start( line, convertToPosOnScreen( s, pos1 ) );
+         selection.end( line, convertToPosOnScreen( s, pos2 ) );
+         update();
+         // emit selectionEnd() happens in the mouseReleaseEvent.
+         showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar );
+      }
+   }
+}
+
+void DiffTextWindow::mouseReleaseEvent ( QMouseEvent * /*e*/ )
+{
+   //if ( e->button() == LeftButton )
+   {
+      killTimers();
+      if (selection.firstLine != -1 )
+      {
+         emit selectionEnd();
+      }
+   }
+   m_scrollDeltaX=0;
+   m_scrollDeltaY=0;
+}
+
+void DiffTextWindow::mouseMoveEvent ( QMouseEvent * e )
+{
+   int line;
+   int pos;
+   convertToLinePos( e->x(), e->y(), line, pos );
+   if (selection.firstLine != -1 )
+   {
+      selection.end( line, pos );
+      myUpdate(0);
+
+      showStatusLine( line, m_winIdx, m_filename, *m_pDiff3LineVector, m_pStatusBar );
+
+      // Scroll because mouse moved out of the window
+      const QFontMetrics& fm = fontMetrics();
+      int fontHeight = fm.height();
+      int fontWidth = fm.width('W');
+      int topLineYOffset = fontHeight + 3;
+      int deltaX=0;
+      int deltaY=0;
+      if ( e->x() < leftInfoWidth*fontWidth )       deltaX=-1;
+      if ( e->x() > width()     )       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 DiffTextWindow::myUpdate(int afterMilliSecs)
+{
+   killTimers();
+   m_bMyUpdate = true;
+   startTimer( afterMilliSecs );
+}
+
+void DiffTextWindow::timerEvent(QTimerEvent*)
+{
+   killTimers();
+
+   if ( m_bMyUpdate )
+   {
+      paintEvent( 0 );
+      m_bMyUpdate = false;
+   }
+
+   if ( m_scrollDeltaX != 0 || m_scrollDeltaY != 0 )
+   {
+      selection.end( selection.lastLine + m_scrollDeltaY, selection.lastPos +  m_scrollDeltaX );
+      emit scroll( m_scrollDeltaX, m_scrollDeltaY );
+      killTimers();
+      startTimer(50);
+   }
+}
+
+void DiffTextWindow::resetSelection()
+{
+   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 = (leftInfoWidth-m_firstColumn)*fontWidth;
+
+   int topLineYOffset = fontHeight + 3;
+
+   int yOffset = topLineYOffset - m_firstLine * fontHeight;
+
+   line = ( y - yOffset ) / fontHeight;
+   pos  = ( 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 DiffTextWindow::writeLine(
+   QPainter& p,
+   const LineData* pld,
+   const DiffList* pLineDiff1,
+   const DiffList* pLineDiff2,
+   int line,
+   int whatChanged,
+   int whatChanged2,
+   int srcLineNr
+   )
+{
+   QFont normalFont = font();
+   QFont diffFont = normalFont;
+   diffFont.setItalic( m_pOptionDialog->m_bItalicForDeltas );
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontAscent = fm.ascent();
+   int fontDescent = fm.descent();
+   int fontWidth = fm.width('W');
+   int topLineYOffset = fontHeight + 3;
+
+   int xOffset = (leftInfoWidth - m_firstColumn)*fontWidth;
+   int yOffset = (line-m_firstLine) * fontHeight + topLineYOffset;
+
+   QRect lineRect( 0, yOffset, width(), fontHeight );
+   if ( ! m_invalidRect.intersects( lineRect ) )
+      return;
+
+   int fastSelectorLine2 = m_fastSelectorLine1+m_fastSelectorNofLines - 1;
+   bool bFastSelectionRange = (line>=m_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;
+   }
+
+//   QRect winRect = rect(); //p.window();
+   if ( yOffset+fontHeight<0  ||  height() + fontHeight < yOffset )
+      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, width(), 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();
+         }
+      }
+
+      QCString s=" ";
+      // Convert tabs
+      int outPos = 0;
+      for( i=0; i<pld->size; ++i )
+      {
+         int spaces = 1;
+
+         if ( pld->pLine[i]=='\t' )
+         {
+            spaces = tabber( outPos, g_tabSize );
+            s[0] = ' ';
+         }
+         else
+         {
+            s[0] = pld->pLine[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;
+         }
+
+         QRect outRect( xOffset + fontWidth*outPos, yOffset, fontWidth*spaces, fontHeight );
+         if ( m_invalidRect.intersects( outRect ) )
+         {
+            if( !selection.within( line, outPos ) )
+            {
+               if( c!=m_pOptionDialog->m_fgColor )
+               {
+                  QColor lightc = diffBgColor;
+                  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_bShowWhiteSpace )
+                  {
+                     p.fillRect( xOffset + fontWidth*outPos, yOffset+fontAscent,
+                                 fontWidth*spaces-1, fontDescent+1, c );
+                  }
+               }
+               else
+               {
+                  p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) );
+               }
+               p.setFont(normalFont);
+            }
+            else
+            {
+
+               p.fillRect( xOffset + fontWidth*outPos, yOffset,
+                           fontWidth*(spaces), fontHeight, colorGroup().highlight() );
+
+               p.setPen( colorGroup().highlightedText() );
+               p.drawText( xOffset + fontWidth*outPos, yOffset + fontAscent, QString::fromUtf8(s) );
+
+               selection.bSelectionContainsData = true;
+            }
+         }
+
+         outPos += spaces;
+      }
+
+      if( selection.lineWithin( line ) && selection.lineWithin( line+1 ) )
+      {
+         p.fillRect( xOffset + fontWidth*outPos, yOffset,
+                     width(), fontHeight, 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 )
+      {
+         QString num;
+         num.sprintf( "%0*d", m_lineNumberWidth, srcLineNr);
+         p.drawText( 0, yOffset + fontAscent, num );
+         //p.drawLine( xLeft -1, yOffset, xLeft -1, yOffset+fontHeight-1 );
+      }
+      p.drawLine( xOffset +1, yOffset, xOffset +1, yOffset+fontHeight-1 );
+   }
+   if ( c!=m_pOptionDialog->m_fgColor && whatChanged2==0 )//&& whatChanged==0 )
+   {
+      p.setBrushOrigin(0,0);
+      p.fillRect( xLeft, yOffset, fontWidth*2-1, fontHeight, QBrush(c,Dense5Pattern) );
+   }
+   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 );
+/*      p.drawLine( xOffset + fontWidth-1, yOffset, xOffset + fontWidth-1, yOffset+fontHeight-1 );
+      if ( line == m_fastSelectorLine1 )
+      {
+         p.drawLine( xOffset + fontWidth-1, yOffset, xOffset + fontWidth+2, yOffset );
+      }
+      if ( line == fastSelectorLine2 )
+      {
+         p.drawLine( xOffset + fontWidth-1, yOffset+fontHeight-1, xOffset + fontWidth+2, yOffset+fontHeight-1 );
+      }*/
+   }
+}
+
+void DiffTextWindow::paintEvent( QPaintEvent* e )
+{
+   if ( m_pDiff3LineVector==0 || ! m_bPaintingAllowed ) return;
+
+   m_lineNumberWidth =  m_pOptionDialog->m_bShowLineNumbers ? (int)log10((double)m_size)+1 : 0;
+
+   if (e!=0)
+   {
+      m_invalidRect |= e->rect();
+   }
+
+   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
+
+   if (font() != m_pOptionDialog->m_font )
+   {
+      setFont(m_pOptionDialog->m_font);
+   }
+
+   bool bOldSelectionContainsData = selection.bSelectionContainsData;
+   selection.bSelectionContainsData = false;
+
+   int fontHeight = fontMetrics().height();
+   int fontAscent = fontMetrics().ascent();
+//   int fontDescent = fontMetrics().descent();
+   int fontWidth = fontMetrics().width('W');
+
+   int topLineYOffset = fontHeight + 3;
+   int xOffset = leftInfoWidth * fontWidth;
+
+   int firstLineToDraw = 0;
+   int lastLineToDraw = (height() - topLineYOffset ) / fontHeight;
+   if ( abs(m_oldFirstLine - m_firstLine)>=lastLineToDraw )
+   {
+      m_oldFirstLine = -1;
+      m_invalidRect |= QRect( 0, topLineYOffset, width(), height() );
+   }
+
+   if ( m_oldFirstLine != -1 && m_oldFirstLine != m_firstLine )
+   {
+      int deltaY = fontHeight * ( m_oldFirstLine - m_firstLine );
+      if ( deltaY > 0 )
+      {  // Move down
+         bitBlt( this, 0, deltaY + topLineYOffset /*dy*/, this, 0, topLineYOffset /*sy*/, width(), height()- (deltaY + topLineYOffset), CopyROP, true);
+         lastLineToDraw = firstLineToDraw + ( m_oldFirstLine - m_firstLine);
+         m_invalidRect |= QRect( 0, topLineYOffset, width(), deltaY );
+      }
+      else
+      {  // Move up
+         bitBlt( this, 0, topLineYOffset /*dy*/, this, 0, -deltaY+topLineYOffset /*sy*/, width(), height()-(-deltaY+topLineYOffset), CopyROP, true);
+         firstLineToDraw = lastLineToDraw + ( m_oldFirstLine - m_firstLine);
+         m_invalidRect |= QRect( 0, height()+deltaY, width(), -deltaY );
+      }
+   }
+
+   if ( m_oldFirstColumn != -1  && m_oldFirstColumn != m_firstColumn )
+   {
+      int deltaX = fontWidth * ( m_oldFirstColumn - m_firstColumn );
+      if ( deltaX > 0 )
+      {  // Move right, scroll left
+         bitBlt( this, deltaX+xOffset, topLineYOffset, this, xOffset, topLineYOffset, width(), height(), CopyROP, true);
+         m_invalidRect |=
+            QRect( xOffset, topLineYOffset, deltaX, height() - topLineYOffset );
+      }
+      else
+      {  // Move left, scroll right
+         bitBlt( this, xOffset, topLineYOffset, this, xOffset-deltaX, topLineYOffset, width()-(xOffset-deltaX), height()-topLineYOffset, CopyROP, true);
+         m_invalidRect |=
+            QRect( width() + deltaX, topLineYOffset, -deltaX, height() - topLineYOffset );
+      }
+   }
+
+   if ( selection.oldLastLine != -1 )
+   {
+      int lastLine;
+      int firstLine;
+      if ( selection.oldFirstLine != -1 )
+      {
+         firstLine = min3( selection.oldFirstLine, selection.lastLine, selection.oldLastLine );
+         lastLine = max3( selection.oldFirstLine, selection.lastLine, selection.oldLastLine );
+      }
+      else
+      {
+         firstLine = min2( selection.lastLine, selection.oldLastLine );
+         lastLine = max2( selection.lastLine, selection.oldLastLine );
+      }
+      int y1 = topLineYOffset + ( firstLine - m_firstLine  ) * fontHeight;
+      int y2 = min2( height(),
+                     topLineYOffset + ( lastLine  - m_firstLine +1 ) * fontHeight );
+
+      if ( y1<height() && y2>topLineYOffset )
+      {
+         m_invalidRect |= QRect( 0, y1, width(), y2-y1 );
+      }
+   }
+
+   if ( m_invalidRect.isEmpty() )
+      return;
+
+   QPainter painter(this);
+   //QPainter& p=painter;
+   QPixmap pixmap( m_invalidRect.size() );
+   QPainter p( &pixmap );
+   p.translate( -m_invalidRect.x(), -m_invalidRect.y() );
+
+   p.fillRect( m_invalidRect, m_pOptionDialog->m_bgColor );
+
+   firstLineToDraw += m_firstLine;
+   lastLineToDraw += m_firstLine;
+
+   p.setFont( font() );
+
+   p.setPen( m_cThis );
+   if( m_invalidRect.intersects( QRect(0,0,width(), topLineYOffset ) )
+      || m_firstLine != m_oldFirstLine )
+   {
+      int l=-1;
+      for ( int i = m_firstLine; i<(int)m_pDiff3LineVector->size(); ++i )
+      {
+         const Diff3Line* d3l = (*m_pDiff3LineVector)[i];
+         if      ( m_winIdx==1 ) l=d3l->lineA;
+         else if ( m_winIdx==2 ) l=d3l->lineB;
+         else if ( m_winIdx==3 ) l=d3l->lineC;
+         else assert(false);
+         if (l!=-1) break;
+      }
+
+      const char* winId = (   m_winIdx==1 ? (m_bTriple?"A (Base)":"A") :
+                            ( m_winIdx==2 ? "B" : "C" ) );
+
+      QString s;
+      if ( l!=-1 )
+         s.sprintf(" %s : %s : Topline %d", winId, m_filename.ascii(), l+1 );
+      else
+         s.sprintf(" %s : %s: End", winId, m_filename.ascii() );
+
+      if (hasFocus())
+      {
+         painter.fillRect( 0, 0, width(), topLineYOffset, m_cThis );
+         painter.setPen( m_pOptionDialog->m_bgColor );
+         painter.drawText( 0, fontAscent+1, s );
+      }
+      else
+      {
+         painter.fillRect( 0, 0, width(), topLineYOffset, m_pOptionDialog->m_bgColor );
+         painter.setPen( m_cThis );
+         painter.drawLine( 0, fontHeight + 2, width(), fontHeight + 2 );
+         painter.drawText( 0, fontAscent+1, s );
+      }
+   }
+
+   int lastVisibleLine = min2( m_firstLine + getNofVisibleLines()+2, (int)m_pDiff3LineVector->size() );
+
+   for ( int line = m_firstLine; line<lastVisibleLine; ++line )
+   {
+      const Diff3Line* d3l = (*m_pDiff3LineVector)[line];
+      DiffList* pFineDiff1;
+      DiffList* pFineDiff2;
+      int changed=0;
+      int changed2=0;
+      int lineIdx;
+
+      getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 );
+
+      writeLine(
+         p,                         // QPainter
+         lineIdx == -1 ? 0 : &m_pLineData[lineIdx],     // Text in this line
+         pFineDiff1,
+         pFineDiff2,
+         line,                      // Line on the screen
+         changed,
+         changed2,
+         lineIdx+1
+         );
+   }
+   
+   // p.drawLine( m_invalidRect.x(), m_invalidRect.y(), m_invalidRect.right(), m_invalidRect.bottom() );
+   p.end();
+
+   painter.setClipRect ( 0, topLineYOffset, width(), height()-topLineYOffset );
+
+   painter.drawPixmap( m_invalidRect.x(), m_invalidRect.y(), pixmap );
+
+   m_oldFirstLine = m_firstLine;
+   m_oldFirstColumn = m_firstColumn;
+   m_invalidRect = QRect(0,0,0,0);
+   selection.oldLastLine = -1;
+   if ( selection.oldFirstLine !=-1 )
+      selection.oldFirstLine = -1;
+   if( !bOldSelectionContainsData  &&  selection.bSelectionContainsData )
+      emit newSelection();
+
+}
+
+QCString DiffTextWindow::getString( int line )
+{
+   const Diff3Line* d3l = (*m_pDiff3LineVector)[line];
+   DiffList* pFineDiff1;
+   DiffList* pFineDiff2;
+   int changed=0;
+   int changed2=0;
+   int lineIdx;
+   getLineInfo( *d3l, lineIdx, pFineDiff1, pFineDiff2, changed, changed2 );
+
+   if (lineIdx==-1) return QCString();
+   else
+   {
+      LineData* ld = &m_pLineData[lineIdx];
+      return QCString( ld->pLine, ld->size + 1 );
+   }
+   return QCString();
+}
+
+
+void DiffTextWindow::getLineInfo(
+   const Diff3Line& d,
+   int& lineIdx,
+   DiffList*& pFineDiff1, DiffList*& pFineDiff2,   // return values
+   int& changed, int& changed2
+   )
+{
+   changed=0;
+   changed2=0;
+   bool bAEqB = d.bAEqB || ( d.bWhiteLineA && d.bWhiteLineB );
+   bool bAEqC = d.bAEqC || ( d.bWhiteLineA && d.bWhiteLineC );
+   bool bBEqC = d.bBEqC || ( d.bWhiteLineB && d.bWhiteLineC );
+   if      ( m_winIdx == 1 ) {
+      lineIdx=d.lineA;
+      pFineDiff1=d.pFineAB;
+      pFineDiff2=d.pFineCA;
+      changed |= ((d.lineB==-1)!=(lineIdx==-1) ? 1 : 0) +
+                 ((d.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 2 : 0);
+      changed2 |= ( bAEqB ? 0 : 1 ) + (bAEqC || !m_bTriple ? 0 : 2);
+   }
+   else if ( m_winIdx == 2 ) {
+      lineIdx=d.lineB;
+      pFineDiff1=d.pFineBC;
+      pFineDiff2=d.pFineAB;
+      changed |= ((d.lineC==-1)!=(lineIdx==-1) && m_bTriple ? 1 : 0) +
+                 ((d.lineA==-1)!=(lineIdx==-1) ? 2 : 0);
+      changed2 |= ( bBEqC || !m_bTriple ? 0 : 1 ) + (bAEqB ? 0 : 2);
+   }
+   else if ( m_winIdx == 3 ) {
+      lineIdx=d.lineC;
+      pFineDiff1=d.pFineCA;
+      pFineDiff2=d.pFineBC;
+      changed |= ((d.lineA==-1)!=(lineIdx==-1) ? 1 : 0) +
+                 ((d.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')-leftInfoWidth;
+   emit resizeSignal( visibleColumns, visibleLines );
+   QWidget::resizeEvent(e);
+}
+
+int DiffTextWindow::getNofVisibleLines()
+{
+   QFontMetrics fm = fontMetrics();
+   int fmh = fm.height();
+   int h = height();
+   return h/fmh -2;//height()/fm.height()-2;
+}
+
+int DiffTextWindow::getNofVisibleColumns()
+{
+   QFontMetrics fm = fontMetrics();
+   return width()/fm.width('W')-leftInfoWidth;
+}
+
+QString DiffTextWindow::getSelection()
+{
+   QString selectionString;
+
+   int line=0;
+   int lineIdx=0;
+
+   int it;
+   for( it=0; it<(int)m_pDiff3LineVector->size(); ++it )
+   {
+      const Diff3Line* d = (*m_pDiff3LineVector)[it];
+      if      ( m_winIdx == 1 ) {    lineIdx=d->lineA;     }
+      else if ( m_winIdx == 2 ) {    lineIdx=d->lineB;     }
+      else if ( m_winIdx == 3 ) {    lineIdx=d->lineC;     }
+      else assert(false);
+
+      if( lineIdx != -1 )
+      {
+         const char* pLine = m_pLineData[lineIdx].pLine;
+         int size = m_pLineData[lineIdx].size;
+
+         // Consider tabs
+         int outPos = 0;
+         for( int i=0; i<size; ++i )
+         {
+            int spaces = 1;
+            if ( pLine[i]=='\t' )
+            {
+
+               spaces = tabber( outPos, g_tabSize );
+            }
+
+            if( selection.within( line, outPos ) )
+            {
+              selectionString += pLine[i];
+            }
+
+            outPos += spaces;
+         }
+
+         if( selection.within( line, outPos ) )
+         {
+            #ifdef _WIN32
+            selectionString += '\r';
+            #endif
+            selectionString += '\n';
+         }
+      }
+
+
+
+      ++line;
+   }
+
+   return selectionString;
+}
+
+bool DiffTextWindow::findString( const QCString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive )
+{
+   int it = d3vLine;
+   int endIt = bDirDown ? (int)m_pDiff3LineVector->size() : -1;
+   int step =  bDirDown ? 1 : -1;
+   int startPos = posInLine;
+
+   for( ; it!=endIt; it+=step )
+   {
+      QCString 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 DiffTextWindow::setSelection( int firstLine, int startPos, int lastLine, int endPos )
+{
+   selection.reset();
+   selection.start( firstLine, convertToPosOnScreen( getString(firstLine), startPos ) );
+   selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos ) );
+   update();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/directorymergewindow.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2070 @@
+/***************************************************************************
+                          directorymergewindow.cpp
+                             -------------------
+    begin                : Sat Oct 19 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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 <qregexp.h>
+#include <qmessagebox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtable.h>
+#include <qsplitter.h>
+#include <qprogressdialog.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <iostream>
+#include <assert.h>
+
+
+class StatusInfo : public QListView
+{
+public:
+   StatusInfo(QWidget* pParent) : QListView( pParent )
+   {
+      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 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::removeFile(m_name);
+}
+
+void DirectoryMergeWindow::fastFileComparison(
+   FileAccess& fi1, FileAccess& fi2,
+   bool& bEqual, bool& bError, QString& status )
+{
+   status = "";
+   bEqual = false;
+   bError = true;
+
+   if ( !m_bFollowFileLinks )
+   {
+      if ( fi1.isSymLink() != fi2.isSymLink() )
+      {
+         status = "Mix of links and normal files.";
+         return;
+      }
+      else if ( fi1.isSymLink() && fi2.isSymLink() )
+      {
+         bError = false;
+         bEqual = fi1.readLink() == fi2.readLink();
+         status = "Link: ";
+         return;
+      }
+   }
+
+   if ( fi1.size()!=fi2.size() )
+   {
+      bEqual = false;
+      status = "Size. ";
+      return;
+   }
+
+   if ( m_pOptions->m_bDmTrustDate )
+   {
+      bEqual = ( fi1.lastModified() == fi2.lastModified()  &&  fi1.size()==fi2.size() );
+      bError = false;
+      status = "Date&Size: ";
+      return;
+   }
+
+   QString fileName1 = fi1.absFilePath();
+   QString fileName2 = fi2.absFilePath();
+   TempRemover tr1( fileName1, fi1 );
+   if ( !tr1.success() )
+   {
+      status = "Creating temp copy of " + fileName1 + " failed.";
+      return;
+   }
+   TempRemover tr2( fileName2, fi2 );
+   if ( !tr2.success() )
+   {
+      status = "Creating temp copy of " + fileName2 + " failed.";
+      return;
+   }
+
+   std::vector<char> buf1(100000);
+   std::vector<char> buf2(buf1.size());
+
+   QFile file1( tr1.name() );
+
+   if ( ! file1.open(IO_ReadOnly) )
+   {
+      status = "Opening " + fileName1 + " failed.";
+      return;
+   }
+
+   QFile file2( tr2.name() );
+
+   if ( ! file2.open(IO_ReadOnly) )
+   {
+      status = "Opening " + fileName2 + " failed.";
+      return;
+   }
+
+#if QT_VERSION==230
+   typedef int t_FileSize;
+#else
+   typedef QFile::Offset t_FileSize;
+#endif
+   t_FileSize size = file1.size();
+
+   while( size>0 )
+   {
+      int len = min2( size, (t_FileSize)buf1.size() );
+      if( len != file1.readBlock( &buf1[0], len ) )
+      {
+         status = "Error reading from " + fileName1;
+         return;
+      }
+
+      if( len != file2.readBlock( &buf2[0], len ) )
+      {
+         status = "Error reading from " + fileName2;
+         return;
+      }
+
+      if ( memcmp( &buf1[0], &buf2[0], len ) != 0 )
+      {
+         bError = false;
+         return;
+      }
+      size-=len;
+   }
+
+   // 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;
+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( pressed(QListViewItem*,const QPoint&, int)),
+            this, SLOT(   onClick(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_bSingleFileOperationStarted=false;
+   m_bError = false;
+   m_bSyncMode = false;
+   m_pStatusInfo = new StatusInfo(0);
+   m_pStatusInfo->hide();
+   
+   addColumn("Name");
+   addColumn("A");
+   addColumn("B");
+   addColumn("C");
+   addColumn("Operation");
+   addColumn("Status");
+}
+
+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("Yes - Rescan"), i18n("No - 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 );
+}
+
+bool DirectoryMergeWindow::init
+   (
+   FileAccess& dirA,
+   FileAccess& dirB,
+   FileAccess& dirC,
+   FileAccess& dirDest,
+   bool bDirectoryMerge
+   )
+{
+   m_bFollowDirLinks = m_pOptions->m_bDmFollowDirLinks;
+   m_bFollowFileLinks = m_pOptions->m_bDmFollowFileLinks;
+   m_bSimulatedMergeStarted=false;
+   m_bRealMergeStarted=false;
+   m_bError=false;
+   m_bDirectoryMerge = bDirectoryMerge;
+
+   clear();
+
+   m_pCurrentItemForOperation = 0;
+
+   m_dirA = dirA;
+   m_dirB = dirB;
+   m_dirC = dirC;
+   m_dirDest = dirDest;
+
+   // 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 += "Dir A \"" + m_dirA.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+
+       if ( !dirB.isDir() )
+       {  text += "Dir B \"" + m_dirB.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+
+       if ( m_dirC.isValid() && !m_dirC.isDir() )
+       {  text += "Dir C \"" + m_dirC.prettyAbsPath() + "\" does not exist or is not a directory.\n"; }
+
+       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."),
+         "KDiff3: Parameter warning");
+      return false;
+   }
+
+   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();
+
+   g_pProgressDialog->start();
+
+   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;
+
+   bool bListDirSuccessA = true;
+   bool bListDirSuccessB = true;
+   bool bListDirSuccessC = true;
+   if ( m_dirA.isValid() )
+   {
+      g_pProgressDialog->setInformation("Reading Directory A");
+      g_pProgressDialog->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[i->filePath()];
+         //std::cout <<i->filePath()<<std::endl;
+         mfi.m_bExistsInA = true;
+         mfi.m_fileInfoA = *i;
+      }
+   }
+
+   if ( m_dirB.isValid() )
+   {
+      g_pProgressDialog->setInformation("Reading Directory B");
+      g_pProgressDialog->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[i->filePath()];
+         mfi.m_bExistsInB = true;
+         mfi.m_fileInfoB = *i;
+      }
+   }
+
+   e_MergeOperation eDefaultMergeOp;
+   if ( m_dirC.isValid() )
+   {
+      g_pProgressDialog->setInformation("Reading Directory C");
+      g_pProgressDialog->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[i->filePath()];
+         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();
+      g_pProgressDialog->hide();
+
+      for( QListViewItem* p = firstChild();  p!=0; p = p->nextSibling() )
+      {
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>( p );
+         calcSuggestedOperation( *pDMI->m_pMFI, eDefaultMergeOp );
+      }
+   }
+   else
+   {
+      g_pProgressDialog->hide();
+      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 );
+   }
+
+   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 );
+}
+
+void DirectoryMergeWindow::setAllMergeOperations( e_MergeOperation eDefaultOperation )
+{
+   if ( KMessageBox::Yes == KMessageBox::warningYesNo(this,
+        i18n("This affects all merge operations."),
+        i18n("KDiff3: Changing all merge operations"),i18n("Continue"), i18n("Cancel") ) )
+   {
+      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;
+   }
+
+   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 void setOnePixmap( QListViewItem* pLVI, int col, e_Age eAge, bool bLink, bool bDir )
+{
+   #include "xpm/equal.xpm"
+   #include "xpm/not_equal.xpm"
+   #include "xpm/not_everywhere.xpm"
+   #include "xpm/not_there.xpm"
+   #include "xpm/link_arrow.xpm"
+
+   static QPixmap pmLink( link_arrow );
+
+   static QPixmap pmDirLink( pixCombiner( *s_pm_dir, pmLink) );
+   static QPixmap pmFileLink( pixCombiner( *s_pm_file, pmLink ) );
+
+   static QPixmap pmNotThere( not_there_pm );
+
+   static QPixmap pmNew( equal_pm );
+   static QPixmap pmOld( not_equal_pm );
+   static QPixmap pmMiddle( not_everywhere_pm );
+
+   static QPixmap pmNewLink( pixCombiner( pmNew, pmLink) );
+   static QPixmap pmOldLink( pixCombiner( pmOld, pmLink) );
+   static QPixmap pmMiddleLink( pixCombiner( pmMiddle, pmLink) );
+
+   static QPixmap pmNewDir( pixCombiner2( pmNew, *s_pm_dir) );
+   static QPixmap pmMiddleDir( pixCombiner2( pmMiddle, *s_pm_dir) );
+   static QPixmap pmOldDir( pixCombiner2( pmOld, *s_pm_dir) );
+
+   static QPixmap pmNewDirLink( pixCombiner( pmNewDir, pmLink) );
+   static QPixmap pmMiddleDirLink( pixCombiner( pmMiddleDir, pmLink) );
+   static QPixmap pmOldDirLink( pixCombiner( pmOldDir, pmLink) );
+
+   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 )
+{
+   if( p!=0 )
+   {
+      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();             }
+         }
+      }
+   }
+   return p;
+}
+
+void DirectoryMergeWindow::prepareListView()
+{
+   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();
+
+   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 )
+   {
+      const QString& fileName = j->first;
+      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() : "";
+
+      g_pProgressDialog->setInformation(
+         "Processing " + QString::number(currentIdx) +" / "+ QString::number(nrOfFiles)
+         +"\n" + fileName, double(currentIdx) / nrOfFiles, false );
+      if ( g_pProgressDialog->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[dirPart]; // 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;
+
+   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( eNoOperation );  // All is well, nothing to do.
+         }
+         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( eCopyCToDest );
+         }
+         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( 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 ) return;
+
+   bool bThreeDirs = m_dirC.isValid();
+
+   //bool bImmediate = (button==Qt::LeftButton);
+
+   KPopupMenu m(this);
+   //if (bImmediate ) m.insertItem("Immediate Mode", eTitleId );
+   //else             m.insertItem("Postponed Mode", eTitleId );
+   //m.setItemEnabled ( eTitleId, false );
+   if ( bThreeDirs )
+   {
+      m.insertItem("Do nothing", eNoOperation );
+      int count=0;
+      if ( mfi.m_bExistsInA ) { m.insertItem("A", eCopyAToDest );  ++count;  }
+      if ( mfi.m_bExistsInB ) { m.insertItem("B", eCopyBToDest );  ++count;  }
+      if ( mfi.m_bExistsInC ) { m.insertItem("C", eCopyCToDest );  ++count;  }
+      if ( !conflictingFileTypes(mfi) && count>1 ) m.insertItem("Merge", eMergeABCToDest );
+      m.insertItem("Delete (if exists)", eDeleteFromDest );
+   }
+   else if ( m_bSyncMode )
+   {
+      m.insertItem("Do nothing", eNoOperation );
+      if ( mfi.m_bExistsInA ) m.insertItem("Copy A to B", eCopyAToB );
+      if ( mfi.m_bExistsInB ) m.insertItem("Copy B to A", eCopyBToA );
+      if ( mfi.m_bExistsInA ) m.insertItem("Delete A", eDeleteA );
+      if ( mfi.m_bExistsInB ) m.insertItem("Delete B", eDeleteB );
+      if ( mfi.m_bExistsInA && mfi.m_bExistsInB )
+      {
+         m.insertItem("Delete A and B", eDeleteAB );
+         if ( !conflictingFileTypes(mfi))
+         {
+            m.insertItem("Merge to A",    eMergeToA );
+            m.insertItem("Merge to B",    eMergeToB );
+            m.insertItem("Merge to A and B",    eMergeToAB );
+         }
+      }
+   }
+   else
+   {
+      m.insertItem("Do nothing", eNoOperation );
+      if ( mfi.m_bExistsInA ) m.insertItem("A", eCopyAToDest );
+      if ( mfi.m_bExistsInB ) m.insertItem("B", eCopyBToDest );
+      if ( mfi.m_bExistsInA  &&  mfi.m_bExistsInB  && !conflictingFileTypes(mfi) )
+         m.insertItem("Merge", eMergeABToDest );
+      m.insertItem("Delete (if exists)", eDeleteFromDest );
+   }
+
+   int result = m.exec( p );
+   if (result>=0 )
+      mfi.setMergeOperation( (e_MergeOperation)result );
+}
+
+// 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 ), "","","", "To do." )
+{
+   pMFI->m_pDMI = this;
+   m_pMFI = pMFI;
+}
+
+DirMergeItem::DirMergeItem( DirMergeItem* pParent, const QString& fileName, MergeFileInfos* pMFI )
+: QListViewItem( pParent, DIRSORT( fileName ), "","","", "To do." )
+{
+   pMFI->m_pDMI = this;
+   m_pMFI = pMFI;
+}
+
+DirMergeItem::~DirMergeItem()
+{
+   m_pMFI->m_pDMI = 0;
+}
+
+void MergeFileInfos::setMergeOperation( e_MergeOperation eMOp )
+{
+   m_eMergeOperation = eMOp;
+   const char* s=0;
+   bool bDir = m_bDirA || m_bDirB || m_bDirC;
+   if( m_pDMI!=0 )
+   {
+      switch( m_eMergeOperation )
+      {
+      case eNoOperation:      s=""; m_pDMI->setText(s_OpCol,""); break;
+      case eCopyAToB:         s="Copy A to B";     break;
+      case eCopyBToA:         s="Copy B to A";     break;
+      case eDeleteA:          s="Delete A";        break;
+      case eDeleteB:          s="Delete B";        break;
+      case eDeleteAB:         s="Delete A and B";  break;
+      case eMergeToA:         s="Merge to A";      break;
+      case eMergeToB:         s="Merge to B";      break;
+      case eMergeToAB:        s="Merge to A and B";  break;
+      case eCopyAToDest:      s="A";    break;
+      case eCopyBToDest:      s="B";    break;
+      case eCopyCToDest:      s="C";    break;
+      case eDeleteFromDest:   s="Delete (if exists)";  break;
+      case eMergeABCToDest:   s= bDir ? "Merge" : "Merge (manual)";  break;
+      case eMergeABToDest:    s= bDir ? "Merge" : "Merge (manual)";  break;
+      case eConflictingFileTypes: s="Error: Conflicting File Types"; break;
+      case eConflictingAges:  s="Error: Dates are equal but files are not."; break;
+      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,"This operation is currently not possible.","KDiff3");
+      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(""),
+            "",
+            "","",""
+            );
+      }
+   }
+   emit updateAvailabilities();
+}
+
+void DirectoryMergeWindow::mergeCurrentFile()
+{
+   if (!canContinue()) return;
+
+   if ( m_bRealMergeStarted )
+   {
+      KMessageBox::sorry(this,"This operation is currently not possible because diff merge currently runs.","KDiff3");
+      return;
+   }
+
+   if ( isFileSelected() )
+   {
+      DirMergeItem* pDMI = static_cast<DirMergeItem*>( selectedItem() );
+      if ( pDMI != 0 )
+      {
+         MergeFileInfos& mfi = *pDMI->m_pMFI;
+         m_bSingleFileOperationStarted = true;
+         emit startDiffMerge(
+            mfi.m_bExistsInA ? mfi.m_fileInfoA.absFilePath() : QString(""),
+            mfi.m_bExistsInB ? mfi.m_fileInfoB.absFilePath() : QString(""),
+            mfi.m_bExistsInC ? mfi.m_fileInfoC.absFilePath() : QString(""),
+            fullNameDest(mfi),
+            "","",""
+            );
+         m_pCurrentItemForOperation = pDMI;
+         m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
+      }
+   }
+   emit updateAvailabilities();
+}
+
+
+bool DirectoryMergeWindow::isFileSelected()
+{
+   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)
+{
+   m_bSingleFileOperationStarted = false;
+   if ( m_pCurrentItemForOperation!=0 && m_pCurrentItemForOperation->m_pMFI==0 )
+   {
+      KMessageBox::error( this, "This should never happen: \n\nmergeResultSaved: m_pMFI=0\n\nIf you know how to reproduce this, please contact the program author.","Program Error" );
+      return;
+   }
+   if ( m_pCurrentItemForOperation!=0 && fileName == fullNameDest(*m_pCurrentItemForOperation->m_pMFI) )
+   {
+      if ( m_pCurrentItemForOperation->m_pMFI->m_eMergeOperation==eMergeToAB )
+      {
+         MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
+         bool bSuccess = copyFLD( fullNameB(mfi), fullNameA(mfi) );
+         if (!bSuccess)
+         {
+            KMessageBox::error(this, i18n("An error occurred while copying.\n"), "KDiff3: Error" );
+            m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+            m_pStatusInfo->show();
+            if ( m_pStatusInfo->firstChild()!=0 )
+               m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
+            m_bError = true;
+            m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+            mfi.m_eMergeOperation = eCopyBToA;
+            return;
+         }
+      }
+      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Done." );
+      m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+   }
+
+   emit updateAvailabilities();
+}
+
+bool DirectoryMergeWindow::canContinue()
+{
+   bool bCanContinue=false;
+   checkIfCanContinue( &bCanContinue );
+   if ( bCanContinue && !m_bError )
+   {
+      if ( m_bRealMergeStarted && m_pCurrentItemForOperation!=0  && ! m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+      {
+         m_pCurrentItemForOperation->setText( s_OpStatusCol, "Not saved." );
+         m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+      }
+   }
+   return bCanContinue;
+}
+
+void DirectoryMergeWindow::mergeContinue()
+{
+   if ( ! canContinue() ) return;
+
+   m_bSingleFileOperationStarted = false;
+
+   int nrOfItems = 0;
+   int nrOfCompletedItems = 0;
+   int nrOfCompletedSimItems = 0;
+
+   if ( !m_bSimulatedMergeStarted && !m_bRealMergeStarted )
+   {
+      // First check if an invalid merge operations exist.
+      for( QListViewItem* p=firstChild(); p!=0; p = treeIterator( p ) )
+      {
+         DirMergeItem* pDMI = static_cast<DirMergeItem*>(p);
+         if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingFileTypes )
+         {
+            ensureItemVisible( pDMI );
+            setSelected( pDMI, true );
+            KMessageBox::error(this, i18n("The highlighted item has a different type in the different directories. Select what to do."), "Error");
+            return;
+         }
+         if (pDMI!=0 && pDMI->m_pMFI->m_eMergeOperation == eConflictingAges )
+         {
+            ensureItemVisible( pDMI );
+            setSelected( pDMI, true );
+            KMessageBox::error(this, i18n("The modification dates of the file are equal but the files are not. Select what to do."), "Error");
+            return;
+         }
+         ++nrOfItems;
+         if ( pDMI->m_pMFI->m_bSimOpComplete )
+            ++nrOfCompletedSimItems;
+         if ( pDMI->m_pMFI->m_bOperationComplete )
+            ++nrOfCompletedItems;
+      }
+
+      int status = KMessageBox::warningYesNoCancel(this,
+         i18n("The merge is about to begin.\n\n"
+         "Choose \"Do it\" if you have read the instructions and know what you are doing.\n"
+         "Choosing \"Simulate it\" will tell you what would happen.\n\n"
+         "Be aware that this program still has beta status "
+         "and there is NO WARRANTY whatsoever! Make backups of your vital data!"),
+         i18n("KDiff3: Starting the Merge"), i18n("Do it"), i18n("Simulate it") );
+      if (status==KMessageBox::Yes) m_bRealMergeStarted = true;
+      else if (status==KMessageBox::No ) m_bSimulatedMergeStarted = true;
+      else return;
+
+      m_pStatusInfo->hide();
+      m_pStatusInfo->clear();
+   }
+
+   bool bContinueWithCurrentItem = false;
+   bool bSkipItem = false;
+   if ( m_bError && m_pCurrentItemForOperation!=0 )
+   {
+      int status = KMessageBox::warningYesNoCancel(this,
+         i18n("There was an error in the last step.\n"
+         "Do you want to continue with the item that caused the error or do you want to skip this item?"),
+         i18n("KDiff3: Continue merge after an error"), i18n("Continue with last item"), i18n("Skip item") );
+      if (status==KMessageBox::Yes) bContinueWithCurrentItem = true;
+      else if (status==KMessageBox::No ) bSkipItem = true;
+      else return;
+      m_bError = false;
+   }
+
+   g_pProgressDialog->start();
+
+   bool bSuccess = true;
+   bool bSingleFileMerge = false;
+   bool bSim = m_bSimulatedMergeStarted;
+   while( bSuccess )
+   {
+      if ( m_pCurrentItemForOperation!=0 && !bContinueWithCurrentItem )
+      {
+         if ( bSim )
+         {
+            if( m_pCurrentItemForOperation->firstChild()==0 )
+            {
+               m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete = true;
+            }
+         }
+         else
+         {
+            if( m_pCurrentItemForOperation->firstChild()==0 )
+            {
+               if( !m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete )
+               {
+                  m_pCurrentItemForOperation->setText( s_OpStatusCol, bSkipItem ? "Skipped." : "Done." );
+                  m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete = true;
+                  bSkipItem = false;
+               }
+            }
+            else
+            {
+               m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
+            }
+         }
+      }
+
+      if ( m_pCurrentItemForOperation==0 )
+      {
+         m_pCurrentItemForOperation = static_cast<DirMergeItem*>( firstChild() );
+      }
+      else
+      {
+         if ( ! bContinueWithCurrentItem )
+         {
+            // Depth first
+            QListViewItem* pNextItem = m_pCurrentItemForOperation->firstChild();
+            QListViewItem* pCurrentItem = m_pCurrentItemForOperation;
+            while( pCurrentItem!=0 && pNextItem==0 )
+            {
+               // Find an item on this level that hasn't been operated yet. (Always start at beginning.)
+               if ( pCurrentItem->parent()==0 )
+                  pNextItem = firstChild();
+               else
+                  pNextItem = pCurrentItem->parent()->firstChild();
+
+               while( pNextItem!=0 && ( static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bOperationComplete ||
+                               ( bSim && static_cast<DirMergeItem*>(pNextItem)->m_pMFI->m_bSimOpComplete ) ) )
+               {
+                  pNextItem = pNextItem->nextSibling();
+               }
+
+               if ( pNextItem == 0 )
+               {
+                  pCurrentItem = pCurrentItem->parent();
+                  if ( pCurrentItem!=0 )
+                  {
+                     if (bSim)
+                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bSimOpComplete = true;
+                     else
+                     {
+                        pCurrentItem->setText( s_OpStatusCol, "Done." );
+                        static_cast<DirMergeItem*>(pCurrentItem)->m_pMFI->m_bOperationComplete = true;
+                     }
+                  }
+               }
+            }
+            m_pCurrentItemForOperation = static_cast<DirMergeItem*>(pNextItem);
+         }
+      }
+
+      if( m_pCurrentItemForOperation !=0 &&
+         (bSim ? m_pCurrentItemForOperation->m_pMFI->m_bSimOpComplete :
+                 m_pCurrentItemForOperation->m_pMFI->m_bOperationComplete ))
+         m_pCurrentItemForOperation = 0;
+
+      if ( m_pCurrentItemForOperation==0 )
+      {
+         if ( m_bRealMergeStarted )
+         {
+            KMessageBox::information( this, "Merge operation complete.", "The merge is complete." );
+            m_bRealMergeStarted = false;
+            m_pStatusInfo->setCaption("KDiff3: 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("KDiff3: Simulated merge complete: Check if you agree with the proposed operations.");
+            m_pStatusInfo->show();
+         }
+         g_pProgressDialog->hide();
+         return;
+      }
+
+      MergeFileInfos& mfi = *m_pCurrentItemForOperation->m_pMFI;
+      bool bCreateBackups = m_pOptions->m_bDmCreateBakFiles;
+
+      g_pProgressDialog->setInformation( mfi.m_subPath,
+         bSim ? double(nrOfCompletedSimItems)/nrOfItems : double(nrOfCompletedItems)/nrOfItems,
+         true
+         );
+      g_pProgressDialog->show();
+
+      // First decide destname
+      QString destName;
+      switch( mfi.m_eMergeOperation )
+      {
+      case eNoOperation: break;
+      case eMergeToAB:   // let the user save in B. In mergeResultSaved() the file will be copied to A.
+      case eMergeToB:
+      case eDeleteB:
+      case eCopyAToB:    destName = fullNameB(mfi); break;
+      case eMergeToA:
+      case eDeleteA:
+      case eCopyBToA:    destName = fullNameA(mfi); break;
+      case eMergeABToDest:
+      case eMergeABCToDest:
+      case eCopyAToDest:
+      case eCopyBToDest:
+      case eCopyCToDest:
+      case eDeleteFromDest: destName = fullNameDest(mfi); break;
+      default:
+         KMessageBox::error( this, "Unknown merge operation.(This must never happen!)", "Error" );
+         assert(false);
+      }
+
+      bSuccess = false;
+      bSingleFileMerge = false;
+      switch( mfi.m_eMergeOperation )
+      {
+      case eNoOperation: bSuccess = true; break;
+      case eCopyAToDest:
+      case eCopyAToB:    bSuccess = copyFLD( fullNameA(mfi), destName ); break;
+      case eCopyBToDest:
+      case eCopyBToA:    bSuccess = copyFLD( fullNameB(mfi), destName ); break;
+      case eCopyCToDest: bSuccess = copyFLD( fullNameC(mfi), destName ); break;
+      case eDeleteFromDest:
+      case eDeleteA:
+      case eDeleteB:     bSuccess = deleteFLD( destName, bCreateBackups ); break;
+      case eDeleteAB:    bSuccess = deleteFLD( fullNameA(mfi), bCreateBackups ) &&
+                                    deleteFLD( fullNameB(mfi), bCreateBackups ); break;
+      case eMergeABToDest:
+      case eMergeToA:
+      case eMergeToAB:
+      case eMergeToB:      bSuccess = mergeFLD( fullNameA(mfi), fullNameB(mfi), "",
+                                                destName, bSingleFileMerge );
+                           break;
+      case eMergeABCToDest:bSuccess = mergeFLD(
+                                         mfi.m_bExistsInA ? fullNameA(mfi) : QString(""),
+                                         mfi.m_bExistsInB ? fullNameB(mfi) : QString(""),
+                                         mfi.m_bExistsInC ? fullNameC(mfi) : QString(""),
+                                         destName, bSingleFileMerge );
+                           break;
+      default:
+         KMessageBox::error( this, "Unknown merge operation.", "Error" );
+         assert(false);
+      }
+      if ( bSuccess )
+      {
+         if(bSim) ++nrOfCompletedSimItems;
+         else     ++nrOfCompletedItems;
+         bContinueWithCurrentItem = false;
+      }
+   }  // end while
+
+   g_pProgressDialog->hide();
+
+   setCurrentItem( m_pCurrentItemForOperation );
+   ensureItemVisible( m_pCurrentItemForOperation );
+   if ( !bSuccess &&  !bSingleFileMerge )
+   {
+      KMessageBox::error(this, i18n("An error occurred. Press OK to see detailed information.\n"), "KDiff3: Error" );
+      m_pStatusInfo->setCaption("KDiff3: Merge-Error");
+      m_pStatusInfo->show();
+      if ( m_pStatusInfo->firstChild()!=0 )
+         m_pStatusInfo->ensureItemVisible( m_pStatusInfo->last() );
+      m_bError = true;
+      m_pCurrentItemForOperation->setText( s_OpStatusCol, "Error." );
+   }
+   else
+   {
+      m_bError = false;
+   }
+   emit updateAvailabilities();
+}
+
+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( "Error: While deleting "+name+": Creating backup failed." );
+         return false;
+      }
+   }
+   else
+   {
+      if ( fi.isDir() && !fi.isSymLink() )
+         m_pStatusInfo->addText("delete directory recursively( "+name+" )");
+      else
+         m_pStatusInfo->addText("delete( "+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( "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( "Error: rmdir( "+name+" ) operation failed." );
+               return false;
+            }
+         }
+      }
+      else
+      {
+         bool bSuccess = FileAccess::removeFile( name );
+         if ( !bSuccess )
+         {
+            m_pStatusInfo->addText( "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("manual merge( "+nameA+ ", "+nameB+","+nameC+" -> " + nameDest +" )" );
+   if ( m_bSimulatedMergeStarted )
+   {
+      m_pStatusInfo->addText("     Note: After a manual merge the user should continue via F5." );
+      return true;
+   }
+
+   bSingleFileMerge = true;
+   m_pCurrentItemForOperation->setText( s_OpStatusCol, "In progress ..." );
+   ensureItemVisible( m_pCurrentItemForOperation );
+
+   emit startDiffMerge( nameA, nameB, nameC, nameDest, "","","" );
+
+   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("Error: copy( "+srcName+ " -> " + destName +" ) failed."
+            "Deleting existing destination failed.");
+         return false;
+      }
+   }
+
+   FileAccess fi( srcName );
+
+   if ( fi.isSymLink() && (fi.isDir() && !m_bFollowDirLinks  ||  !fi.isDir() && !m_bFollowDirLinks) )
+   {
+      m_pStatusInfo->addText("copyLink( "+srcName+ " -> " + destName +" )");
+#ifdef _WIN32
+      // What are links?
+#else
+      if ( m_bSimulatedMergeStarted )
+      {
+         return true;
+      }
+      FileAccess destFi(destName);
+      if ( !destFi.isLocal() || !fi.isLocal() )
+      {
+         m_pStatusInfo->addText("Error: copyLink failed: Remote links are not yet supported.");
+         return false;
+      }
+      QString linkTarget = fi.readLink();
+      bool bSuccess = FileAccess::symLink( linkTarget, destName );
+      if (!bSuccess)
+         m_pStatusInfo->addText("Error: copyLink failed.");
+      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("copy( "+srcName+ " -> " + 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( "Error during rename( "+srcName+" -> " + destName + " ): "
+                             "Cannot delete existing destination." );
+         return false;
+      }
+   }
+
+   m_pStatusInfo->addText("rename( "+srcName+ " -> " + destName +" )");
+   if ( m_bSimulatedMergeStarted )
+   {
+      return true;
+   }
+
+   bool bSuccess = FileAccess( srcName ).rename( destName );
+   if (!bSuccess)
+   {
+      m_pStatusInfo->addText( "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( "Error during makeDir of "+name+
+                             "Cannot delete existing file." );
+         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("makeDir( " + name + " )");
+
+   if ( m_bSimulatedMergeStarted )
+   {
+      return true;
+   }
+
+   bool bSuccess = FileAccess::makeDir( name );
+   if ( bSuccess == false )
+   {
+      m_pStatusInfo->addText( "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("Dest",this);  grid->addWidget( m_pDest,line, 0 );
+   m_pInfoDest = new QLabel(this);     grid->addWidget( m_pInfoDest,line,1 ); ++line;
+
+   m_pInfoList = new QListView(this);  topLayout->addWidget( m_pInfoList );
+   m_pInfoList->addColumn("Dir");
+   m_pInfoList->addColumn("Type");
+   m_pInfoList->addColumn("Size");
+   m_pInfoList->addColumn("Attr");
+   m_pInfoList->addColumn("Last Modification");
+   m_pInfoList->addColumn("Link-Destination");
+   setMinimumSize( 100,100 );
+}
+
+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() ? "Dir" : "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,
+            "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( "A (Dest): " );  bHideDest=true;
+   }
+   else
+      m_pA->setText( !dirC.isValid() ? "A:    " : "A (Base): ");
+
+   m_pInfoA->setText( dirA.prettyAbsPath() );
+
+   if ( dirB.absFilePath()==dirDest.absFilePath() )
+   {
+      m_pB->setText( "B (Dest): " );  bHideDest=true;
+   }
+   else
+      m_pB->setText( "B:    " );
+   m_pInfoB->setText( dirB.prettyAbsPath() );
+
+   if ( dirC.absFilePath()==dirDest.absFilePath() )
+   {
+      m_pC->setText( "C (Dest): " );  bHideDest=true;
+   }
+   else
+      m_pC->setText( "C:    " );
+   m_pInfoC->setText( dirC.prettyAbsPath() );
+
+   m_pDest->setText( "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, "Dest", dirDest.prettyAbsPath(), fiDest );
+   }
+}
+
+#include "directorymergewindow.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/directorymergewindow.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,253 @@
+/***************************************************************************
+                          directorymergewindow.h
+                             -------------------
+    begin                : Sat Oct 19 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#ifndef DIRECTORY_MERGE_WINDOW_H
+#define DIRECTORY_MERGE_WINDOW_H
+
+#include <qfileinfo.h>
+#include <qlistview.h>
+#include <qtimer.h>
+#include <qdir.h>
+#include <list>
+#include <map>
+#include "common.h"
+#include "fileaccess.h"
+
+class OptionDialog;
+class KIconLoader;
+class StatusMessageBox;
+class StatusInfo;
+class DirectoryMergeInfo;
+class OneDirectoryInfo;
+class QLabel;
+
+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;
+};
+
+class DirMergeItem : public QListViewItem
+{
+public:
+   DirMergeItem( QListView* pParent, const QString&, MergeFileInfos*);
+   DirMergeItem( DirMergeItem* pParent, const QString&, MergeFileInfos*);
+   ~DirMergeItem();
+   MergeFileInfos* m_pMFI;
+#if QT_VERSION!=230
+   virtual int 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 )
+         return QListViewItem::compare( i, col, ascending );
+      else
+         return bDir1 ? -1 : 1;
+   }
+#endif
+};
+
+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; }
+
+public slots:
+   void mergeContinue();
+   void reload();
+   void mergeCurrentFile();
+   void compareCurrentFile();
+   void mergeResultSaved(const QString& fileName);
+   void slotChooseAEverywhere();
+   void slotChooseBEverywhere();
+   void slotChooseCEverywhere();
+   void slotAutoChooseEverywhere();
+   void slotNoOpEverywhere();
+   void slotFoldAllSubdirs();
+   void slotUnfoldAllSubdirs();
+
+protected:
+   void resizeEvent(QResizeEvent* e);
+   bool m_bAllowResizeEvents;
+
+   void prepareListView();
+   void calcSuggestedOperation( MergeFileInfos& mfi, e_MergeOperation eDefaultOperation );
+   void setAllMergeOperations( e_MergeOperation eDefaultOperation );
+   friend class MergeFileInfos;
+
+   bool canContinue();
+
+   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 mfi.m_fileInfoA.absFilePath(); }
+   QString fullNameB( const MergeFileInfos& mfi )
+   { return mfi.m_fileInfoB.absFilePath(); }
+   QString fullNameC( const MergeFileInfos& mfi )
+   { return mfi.m_fileInfoC.absFilePath(); }
+   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;
+
+   std::map<QString, MergeFileInfos> m_fileMergeMap;
+
+   bool m_bFollowDirLinks;
+   bool m_bFollowFileLinks;
+   bool m_bSimulatedMergeStarted;
+   bool m_bRealMergeStarted;
+   bool m_bSingleFileOperationStarted;
+   bool m_bError;
+   bool m_bSyncMode;
+   bool m_bDirectoryMerge; // if true, then merge is the default operation, otherwise it's diff.
+
+   OptionDialog* m_pOptions;
+   KIconLoader* m_pIconLoader;
+   DirMergeItem* m_pCurrentItemForOperation;
+   StatusMessageBox* m_pStatusMessageBox;
+   DirectoryMergeInfo* m_pDirectoryMergeInfo;
+   StatusInfo* m_pStatusInfo;
+signals:
+   void startDiffMerge(QString fn1,QString fn2, QString fn3, QString ofn, QString,QString,QString);
+   void checkIfCanContinue( bool* pbContinue );
+   void updateAvailabilities();
+protected slots:
+   void onDoubleClick( QListViewItem* lvi );
+   void onClick( QListViewItem* lvi, const QPoint&, int c );
+   void onSelectionChanged(QListViewItem* lvi);
+};
+
+class DirectoryMergeInfo : public QFrame
+{
+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;}
+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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,1530 @@
+/***************************************************************************
+ *   Copyright (C) 2003 by Joachim Eibl                                    *
+ *   joachim.eibl@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>
+#if QT_VERSION==230
+#else
+#include <qeventloop.h>
+#endif
+#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>
+#else
+#include <unistd.h>          // Needed for creating symbolic links via symlink().
+#include <utime.h>
+#endif
+
+
+ProgressDialog* g_pProgressDialog;
+
+
+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() )
+   {
+      removeFile( 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;
+
+   // 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() )
+   {
+      if ( m_url.isLocalFile() || !m_url.isValid() ) // assuming that malformed means relative
+      {
+         QString localName = name;
+         if ( m_url.isLocalFile() && name.left(5).lower()=="file:" )
+         {
+            localName = m_url.path(); // I want the path without preceding "file:"
+         }
+         QFileInfo fi( localName );
+         m_bReadable    = fi.isReadable();
+         m_bWritable    = fi.isWritable();
+         m_bExecutable  = fi.isExecutable();
+#if QT_VERSION==230
+         m_creationTime = fi.lastModified();
+         m_bHidden    = false;
+#else
+         m_creationTime = fi.created();
+         m_bHidden    = fi.isHidden();
+#endif
+         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 );
+         }
+      }
+      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;
+      }
+   }
+}
+
+void FileAccess::addPath( const QString& txt )
+{
+   m_url.addPath( txt );
+   setFile( m_url.url() );  // reinitialise
+}
+
+/*     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
+*/
+
+void FileAccess::setUdsEntry( const KIO::UDSEntry& e )
+{
+#ifndef KREPLACEMENTS_H
+   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 )
+{
+   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;
+
+      g_pProgressDialog->setSubCurrent( double(i)/maxLength );
+      if ( g_pProgressDialog->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( void* pSrcBuffer, unsigned long length )
+{
+   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;
+
+            g_pProgressDialog->setSubCurrent( double(i)/length );
+            if ( g_pProgressDialog->wasCancelled() ) return false;
+         }
+         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");
+         for(int i=0; ;++i)
+         {
+            // short filenames for WIN98 because for system() the command must not exceed 120 characters.
+            fileName = tmpDir + "/" + QString::number(i);
+            if ( ! FileAccess::exists(fileName) )
+               break;
+         }
+      #else
+         QString tmpDir = "/tmp";
+         for(int i=0; ;++i)
+         {
+            fileName = tmpDir + "/kdiff3_" + QString::number(i) +".tmp";
+            if ( ! FileAccess::exists(fileName) )
+               break;
+         }
+      #endif
+
+      return QDir::convertSeparators(fileName);
+
+   #else  // using KDE
+
+      KTempFile tmpFile;
+      tmpFile.setAutoDelete( true );  // We only want the name. Delete the precreated file immediately.
+      return tmpFile.name();
+
+   #endif
+}
+
+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 )
+{
+   return 0==::symlink( linkTarget.ascii(), linkLocation.ascii() );
+   //FileAccessJobHandler fh(0);
+   //return fh.symLink( linkTarget, linkLocation );
+}
+
+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();
+
+   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 )
+{
+   if ( maxLength>0 )
+   {
+      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();
+      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(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();
+      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();
+      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();
+      return m_bSuccess;
+   }
+}
+
+bool FileAccessJobHandler::removeFile( const QString& fileName )
+{
+   if ( fileName.isEmpty() )
+      return false;
+   else
+   {
+      m_bSuccess = false;
+      KIO::SimpleJob* pJob = KIO::file_delete( fileName, false );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop();
+      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( linkTarget, linkLocation, false );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+
+      g_pProgressDialog->enterEventLoop();
+      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.url(), permissions, bOverwrite, bResume, bShowProgress );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+      connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
+
+      g_pProgressDialog->enterEventLoop();
+      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 )
+{
+   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.url(), permissions, bOverwrite, bResume, bShowProgress );
+      connect( pJob, SIGNAL(result(KIO::Job*)), this, SLOT(slotSimpleJobResult(KIO::Job*)));
+      connect( pJob, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(slotPercent(KIO::Job*, unsigned long)));
+      g_pProgressDialog->enterEventLoop();
+
+      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 = "Error during file copy operation: Opening file for reading failed. Filename: " + srcName;
+      return false;
+   }
+   bool bWriteSuccess = destFile.open( IO_WriteOnly );
+   if ( bWriteSuccess == false )
+   {
+      m_pFileAccess->m_statusText = "Error during file copy operation: Opening file for writing failed. Filename: " + destName;
+      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 )
+   {
+      Q_LONG readSize = srcFile.readBlock( &buffer[0], min2( srcSize, bufSize ) );
+      if ( readSize==-1 )
+      {
+         m_pFileAccess->m_statusText = "Error during file copy operation: Reading failed. Filename: "+srcName;
+         return false;
+      }
+      srcSize -= readSize;
+      while ( readSize > 0 )
+      {
+         Q_LONG writeSize = destFile.writeBlock( &buffer[0], readSize );
+         if ( writeSize==-1 )
+         {
+            m_pFileAccess->m_statusText = "Error during file copy operation: Writing failed. Filename: "+destName;
+            return false;
+         }
+         readSize -= writeSize;
+      }
+      destFile.flush();
+   }
+   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;
+}
+
+static 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 QT_VERSION==230
+      int len=0;
+      if ( pattern.match( testString, 0, &len )!=-1 && len==testString.length())
+         return true;
+#else
+      if ( pattern.exactMatch( testString ) )
+         return true;
+#endif
+   }
+
+   return false;
+}
+
+
+// class CvsIgnoreList from Cervisia cvsdir.cpp
+//    Copyright (C) 1999-2002 Bernd Gehrmann <bernd@mail.berlios.de>
+// with elements from class StringMatcher
+//    Copyright (c) 2003 André Wöbbeking <Woebbeking@web.de>
+// Modifications for KDiff3 by Joachim Eibl
+class CvsIgnoreList
+{
+public:
+    CvsIgnoreList(){}
+    void init(FileAccess& dir, bool bUseLocalCvsIgnore );
+    bool matches(const QString& fileName) 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)
+                  {
+                     QCString entry( &buf[pos1], pos-pos1+1 );
+                     addEntry( entry );
+                  }
+                  pos1=pos+1;
+               }
+            }
+            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 != QChar('!'))
+   {
+      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) 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, true /*CaseSensitive*/, 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 )
+{
+   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 ( g_pProgressDialog->wasCancelled() )
+      return true; // Cancelled is not an error.
+
+   g_pProgressDialog->setSubInformation( i18n("Reading directory: ") + m_pFileAccess->absFilePath(), 0, false );
+
+   if( m_pFileAccess->isLocal() )
+   {
+      m_bSuccess = QDir::setCurrent( m_pFileAccess->absFilePath() );
+      if ( m_bSuccess )
+      {
+         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
+   {
+      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();
+      }
+   }
+
+   CvsIgnoreList cvsIgnoreList;
+   if ( bUseCvsIgnore )
+   {
+      cvsIgnoreList.init( *m_pFileAccess, cvsIgnoreExists(pDirList) );
+   }
+
+   // 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(), true ) ||
+                 wildcardMultiMatch( fileAntiPattern, i->fileName(), true ) ) )
+            ||
+            (i->isDir() && wildcardMultiMatch( dirAntiPattern, i->fileName(), true ) )
+            ||
+            cvsIgnoreList.matches(i->fileName())
+         )
+      {
+         // 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;
+}
+
+
+// Return value false means that the directory or some subdirectories
+// were not readable. Probably because of missing permissions.
+bool FileAccessJobHandler::scanLocalDirectory( const QString& dirName, t_DirectoryList* pDirList )
+{
+   bool bSuccess = true;
+   QDir dir( dirName );
+   g_pProgressDialog->setInformation( "Scanning directory: " + dirName, 0, false );
+
+   // First search subdirectorys
+   bool bHidden =  m_bFindHidden;
+   dir.setSorting( QDir::Name | QDir::DirsFirst );
+   dir.setFilter( QDir::Dirs | (bHidden ? QDir::Hidden : 0) );
+   dir.setMatchAllDirs( true );
+
+   const QFileInfoList *fiList = dir.entryInfoList();
+   if ( fiList == 0 )
+   {
+      // No Permission to read directory or other error.
+      return false;
+   }
+
+   QFileInfoListIterator it( *fiList );      // create list iterator
+
+   for ( ; it.current() != 0; ++it )       // for each file...
+   {
+      if ( g_pProgressDialog->wasCancelled() )
+         return true;
+
+      QFileInfo *fi = it.current();
+      if ( fi->isDir() )
+      {
+         if ( fi->fileName() == "." ||  fi->fileName()==".." ||
+            wildcardMultiMatch( m_dirAntiPattern, fi->fileName(), true/*case sensitive*/ ) )
+            continue;
+         else
+         {
+            if ( m_bRecursive )
+               if ( ! fi->isSymLink()  ||  m_bFollowDirLinks  )
+               {
+                  bool bLocalSuccess = scanLocalDirectory( fi->filePath(), pDirList );
+                  if ( ! bLocalSuccess )
+                     bSuccess = false;
+               }
+         }
+      }
+   }
+
+   dir.setFilter( QDir::Files | QDir::Dirs | (bHidden ? QDir::Hidden : 0) );
+   dir.setMatchAllDirs( true );
+   dir.setNameFilter( m_filePattern );
+
+   fiList = dir.entryInfoList();
+   it = *fiList;
+
+   QString sizeString;
+
+   for ( ; it.current() != 0; ++it )       // for each file...
+   {
+      QFileInfo* fi = it.current();
+
+      if ( fi->fileName() == "." ||  fi->fileName()==".."  ||
+           wildcardMultiMatch( fi->isDir() ? m_dirAntiPattern : m_fileAntiPattern, fi->fileName(), true/*case sensitive*/ ) )
+         continue;
+
+      pDirList->push_back( FileAccess( nicePath(*fi) ) );
+   }
+   return bSuccess;
+}
+
+void FileAccessJobHandler::slotListDirProcessNewEntries( KIO::Job *, const KIO::UDSEntryList& l )
+{
+   KURL parentUrl( m_pFileAccess->m_absFilePath );
+
+   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->setSubInformation( msg, 0 );
+}
+
+void FileAccessJobHandler::slotPercent( KIO::Job*, unsigned long percent )
+{
+   g_pProgressDialog->setSubCurrent( 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_dCurrent = 0.0;
+   m_dSubMax = 1.0;
+   m_dSubMin = 0.0;
+   m_dSubCurrent = 0.0;
+   resize( 400, 100 );
+   m_t1.start();
+   m_t2.start();
+   m_bWasCancelled = false;
+}
+
+
+void ProgressDialog::setInformation(const QString& info, double dCurrent, bool bRedrawUpdate )
+{
+   m_pInformation->setText( info );
+   m_dCurrent = dCurrent;
+   m_dSubCurrent=0;
+   m_dSubMin = 0;
+   m_dSubMax = 1;
+   m_pSubInformation->setText("");
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setInformation(const QString& info, bool bRedrawUpdate )
+{
+   m_pInformation->setText( info );
+   m_dSubCurrent = 0;
+   m_dSubMin = 0;
+   m_dSubMax = 1;
+   m_pSubInformation->setText("");
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setMaximum( int maximum )
+{
+   m_maximum = maximum;
+   m_dCurrent = 0;
+}
+
+void ProgressDialog::step( bool bRedrawUpdate )
+{
+   m_dCurrent += 1.0/m_maximum;
+   m_dSubCurrent=0;
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setSubInformation(const QString& info, double dSubCurrent, bool bRedrawUpdate )
+{
+   m_pSubInformation->setText(info);
+   m_dSubCurrent = dSubCurrent;
+   recalc(bRedrawUpdate);
+}
+
+void ProgressDialog::setSubCurrent( double dSubCurrent, bool bRedrawUpdate )
+{
+   m_dSubCurrent = dSubCurrent;
+   recalc( bRedrawUpdate );
+}
+
+
+void qt_enter_modal(QWidget*);
+void qt_leave_modal(QWidget*);
+
+void ProgressDialog::enterEventLoop()
+{
+   // 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()
+{
+#if QT_VERSION==230
+   //qApp->exit_loop();
+#else
+   qApp->eventLoop()->exitLoop();
+#endif
+}
+
+void ProgressDialog::recalc( bool bUpdate )
+{
+   if( (bUpdate && m_dSubCurrent == 0) || m_t1.elapsed()>200 )
+   {
+      m_pProgressBar->setProgress( int( 1000.0 * m_dCurrent ) );
+      m_pSubProgressBar->setProgress( int( 1000.0 * ( m_dSubCurrent * (m_dSubMax - m_dSubMin) + m_dSubMin ) ) );
+      if ( !isVisible() ) show();
+      qApp->processEvents();
+      m_t1.restart();
+   }
+}
+
+void ProgressDialog::start()
+{
+   setInformation("",0, true);
+   setSubInformation("",0);
+   m_bWasCancelled = false;
+   m_t1.restart();
+   m_t2.restart();
+   show();
+}
+
+#include <qtimer.h>
+void ProgressDialog::show()
+{
+#if QT_VERSION==230
+   QWidget::show();
+#else
+   QDialog::show();
+#endif
+}
+
+void ProgressDialog::hide()
+{
+   // Calling QDialog::hide() directly doesn't always work. (?)
+   QTimer::singleShot( 100, this, SLOT(delayedHide()) );
+}
+
+void ProgressDialog::delayedHide()
+{
+   QDialog::hide();
+}
+
+void ProgressDialog::reject()
+{
+   m_bWasCancelled = true;
+   QDialog::reject();
+}
+
+bool ProgressDialog::wasCancelled()
+{
+   if( m_t2.elapsed()>100 )
+   {
+      qApp->processEvents();
+      m_t2.restart();
+   }
+   return m_bWasCancelled;
+}
+
+// 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::setSubRangeTransformation( double dMin, double dMax )
+{
+   m_dSubMin = dMin;
+   m_dSubMax = dMax;
+   m_dSubCurrent = 0;
+}
+
+
+#include "fileaccess.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/fileaccess.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,223 @@
+/***************************************************************************
+ *   Copyright (C) 2003 by Joachim Eibl                                    *
+ *   joachim.eibl@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>
+
+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(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();
+   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( 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 step( bool bRedrawUpdate=true);
+   void setMaximum( int maximum );
+
+   void setSubInformation(const QString& info, double dSubCurrent, bool bRedrawUpdate=true );
+   void setSubCurrent( double dSubCurrent, 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 setSubRangeTransformation( double dMin, double dMax );
+
+   void exitEventLoop();
+   void enterEventLoop();
+
+   void start();
+
+   bool wasCancelled();
+   void show();
+   void hide();
+private:
+   KProgress* m_pProgressBar;
+   KProgress* m_pSubProgressBar;
+   QLabel* m_pInformation;
+   QLabel* m_pSubInformation;
+   int m_maximum;
+   double m_dCurrent;
+   double m_dSubCurrent;
+   double m_dSubMin;
+   double m_dSubMax;
+   void recalc(bool bRedrawUpdate);
+   QTime m_t1;
+   QTime m_t2;
+   bool m_bWasCancelled;
+
+protected:
+   virtual void reject();
+private slots:
+   void delayedHide();
+};
+
+extern ProgressDialog* g_pProgressDialog;
+
+
+
+#endif
+
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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,691 @@
+/***************************************************************************
+                          kdiff3.cpp  -  description
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include "diff.h"
+
+#include <iostream>
+
+// include files for QT
+#include <qdir.h>
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qsplitter.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qpopupmenu.h>
+#include <qlabel.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 <kkeydialog.h>
+
+// application specific includes
+#include "kdiff3.h"
+#include "optiondialog.h"
+#include "fileaccess.h"
+#include "kdiff3_part.h"
+#include "directorymergewindow.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;
+}
+
+
+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_pDiffWindowSplitter = 0;
+   m_pOverview        = 0;
+   m_bTripleDiff = false;
+   m_pMergeResultWindow = 0;
+   m_pMergeWindowFrame = 0;
+   m_bOutputModified = false;
+   m_bTimerBlock = false;
+
+   // Option handling: Only when pParent==0 (no parent)
+   KCmdLineArgs *args = isPart() ? 0 : KCmdLineArgs::parsedArgs();
+
+   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->arg(0) );
+         if ( args->count() > 1 ) m_sd2.setFilename( args->arg(1) );
+         if ( args->count() > 2 ) m_sd3.setFilename( args->arg(2) );
+      }
+      else
+      {
+         if ( args->count() > 0 ) m_sd2.setFilename( args->arg(0) );
+         if ( args->count() > 1 ) m_sd3.setFilename( args->arg(1) );
+      }
+
+      QCStringList aliasList = args->getOptionList("fname");
+      QCStringList::Iterator ali = aliasList.begin();
+      if ( ali != aliasList.end() ) { m_sd1.setAliasName(*ali); ++ali; }
+      if ( ali != aliasList.end() ) { m_sd2.setAliasName(*ali); ++ali; }
+      if ( ali != aliasList.end() ) { m_sd3.setAliasName(*ali); ++ali; }
+   }
+   g_pProgressDialog = new ProgressDialog(this);
+   ///////////////////////////////////////////////////////////////////
+   // call inits to invoke all other construction parts
+   initActions(actionCollection());
+   initStatusBar();
+
+   m_pFindDialog = new FindDialog( this );
+   connect( m_pFindDialog, SIGNAL(findNext()), this, SLOT(slotEditFindNext()));
+
+   // All default values must be set before calling readOptions().
+   m_pOptionDialog = new OptionDialog( m_pKDiff3Shell!=0, this );
+   connect( m_pOptionDialog, SIGNAL(applyClicked()), this, SLOT(slotRefresh()) );
+
+   readOptions( isPart() ? m_pKDiff3Part->instance()->config() : kapp->config() );
+
+   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)),
+            this, SLOT( slotFileOpen2(QString,QString,QString,QString,QString,QString,QString)));
+   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()));
+
+   initDirectoryMergeActions();
+
+   if ( args!=0 )  args->clear(); // Free up some memory.
+
+   if (m_pKDiff3Shell==0)
+   {
+      completeInit();
+   }
+}
+
+
+void KDiff3App::completeInit()
+{
+   if (m_pKDiff3Shell!=0)
+   {
+      QSize size=kapp->config()->readSizeEntry("Geometry");
+      QPoint pos=kapp->config()->readPointEntry("Position");
+      if(!size.isEmpty())
+      {
+         m_pKDiff3Shell->resize( size );
+         m_pKDiff3Shell->move( pos );
+      }
+   }
+
+   m_bDirCompare = improveFilenames();
+   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 )
+      {
+         const char* pBuf = 0;
+         unsigned int size = 0;
+         if ( m_sd3.isEmpty() )
+         {
+            if ( m_totalDiffStatus.bBinaryAEqB ){ pBuf=m_sd1.m_pBuf; size=m_sd1.m_size; }
+         }
+         else
+         {
+            if      ( m_totalDiffStatus.bBinaryBEqC ){ pBuf=m_sd3.m_pBuf; size=m_sd3.m_size; }
+            else if ( m_totalDiffStatus.bBinaryAEqB ){ pBuf=m_sd3.m_pBuf; size=m_sd3.m_size; }
+            else if ( m_totalDiffStatus.bBinaryAEqC ){ pBuf=m_sd2.m_pBuf; size=m_sd2.m_size; }
+         }
+
+         if ( pBuf!=0 )
+         {
+            // Save this file directly, not via the merge result window.
+            bool bSuccess = false;
+            if ( m_pOptionDialog->m_bDmCreateBakFiles && QDir().exists( m_outputFilename ) )
+            {
+               QString newName = m_outputFilename + ".orig";
+               if ( QDir().exists( newName ) ) QFile::remove(newName);
+               if ( !QDir().exists( newName ) ) QDir().rename( m_outputFilename, newName );
+            }
+            QFile file( m_outputFilename );
+            if ( file.open( IO_WriteOnly ) )
+            {
+               bSuccess = (long)size == file.writeBlock ( pBuf, size );
+               file.close();
+            }
+            if ( bSuccess ) ::exit(0);
+            else KMessageBox::error( this, i18n("Saving failed.") );
+         }
+         else if ( m_pMergeResultWindow->getNrOfUnsolvedConflicts() == 0 )
+         {
+            bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename );
+            if ( bSuccess ) ::exit(0);
+         }
+      }
+   }
+
+   if (statusBar() !=0 )
+      statusBar()->setSizeGripEnabled(false);
+
+   slotClipboardChanged(); // For initialisation.
+
+   slotUpdateAvailabilities();
+
+   if ( ! m_bDirCompare  &&  m_pKDiff3Shell!=0 )
+   {
+      bool bFileOpenError = false;
+      if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0  ||
+         ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
+         ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+      {
+         QString text( i18n("Opening of these files failed:") );
+         text += "\n\n";
+         if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+            text += " - " + m_sd1.getAliasName() + "\n";
+         if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+            text += " - " + m_sd2.getAliasName() + "\n";
+         if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+            text += " - " + m_sd3.getAliasName() + "\n";
+
+         KMessageBox::sorry( this, text, i18n("File open error") );
+         bFileOpenError = true;
+      }
+
+      if ( m_sd1.isEmpty() || m_sd2.isEmpty() || bFileOpenError )
+         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 ..."));
+   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..."));
+   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"));
+   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("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/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");
+   goPrevDelta = new KAction(i18n("Go to PrevDelta"), QIconSet(QPixmap(up1arrow)), CTRL+Key_Up, this, SLOT(slotGoPrevDelta()), ac, "go_prev_delta");
+   goNextDelta = new KAction(i18n("Go to NextDelta"), QIconSet(QPixmap(down1arrow)), CTRL+Key_Down, this, SLOT(slotGoNextDelta()), ac, "go_next_delta");
+   goPrevConflict = new KAction(i18n("Go to Previous Conflict"), QIconSet(QPixmap(up2arrow)), CTRL+Key_PageUp, this, SLOT(slotGoPrevConflict()), ac, "go_prev_conflict");
+   goNextConflict = new KAction(i18n("Go to Next Conflict"), QIconSet(QPixmap(down2arrow)), CTRL+Key_PageDown, this, SLOT(slotGoNextConflict()), ac, "go_next_conflict");
+   goPrevUnsolvedConflict = new KAction(i18n("Go to Previous Unsolved Conflict"), QIconSet(QPixmap(prevunsolved)), 0, this, SLOT(slotGoPrevUnsolvedConflict()), ac, "go_prev_unsolved_conflict");
+   goNextUnsolvedConflict = new KAction(i18n("Go to Next Unsolved Conflict"), QIconSet(QPixmap(nextunsolved)), 0, this, SLOT(slotGoNextUnsolvedConflict()), ac, "go_next_unsolved_conflict");
+   chooseA = new KToggleAction(i18n("Select line(s) from A"), QIconSet(QPixmap(iconA)), CTRL+Key_1, this, SLOT(slotChooseA()), ac, "merge_choose_a");
+   chooseB = new KToggleAction(i18n("Select line(s) from B"), QIconSet(QPixmap(iconB)), CTRL+Key_2, this, SLOT(slotChooseB()), ac, "merge_choose_b");
+   chooseC = new KToggleAction(i18n("Select line(s) from C"), QIconSet(QPixmap(iconC)), CTRL+Key_3, this, SLOT(slotChooseC()), ac, "merge_choose_c");
+   autoAdvance = new KToggleAction(i18n("Automatically go to next unsolved conflict after source selection"), QIconSet(QPixmap(autoadvance)), 0, this, SLOT(slotAutoAdvanceToggled()), ac, "merge_autoadvance");
+   showWhiteSpace = new KToggleAction(i18n("Show space and tabulator characters for differences"), QIconSet(QPixmap(showwhitespace)), 0, this, SLOT(slotShowWhiteSpaceToggled()), ac, "merge_showwhitespace");
+   showLineNumbers = new KToggleAction(i18n("Show line numbers"), QIconSet(QPixmap(showlinenumbers)), 0, this, SLOT(slotShowLineNumbersToggled()), ac, "merge_showlinenumbers");
+   chooseAEverywhere = new KAction(i18n("Choose A Everywhere"), CTRL+SHIFT+Key_1, this, SLOT(slotChooseAEverywhere()), ac, "merge_choose_a_everywhere");
+   chooseBEverywhere = new KAction(i18n("Choose B Everywhere"), CTRL+SHIFT+Key_2, this, SLOT(slotChooseBEverywhere()), ac, "merge_choose_b_everywhere");
+   chooseCEverywhere = new KAction(i18n("Choose C Everywhere"), CTRL+SHIFT+Key_3, this, SLOT(slotChooseCEverywhere()), ac, "merge_choose_c_everywhere");
+   autoSolve = new KAction(i18n("Automatically solve simple conflicts"), 0, this, SLOT(slotAutoSolve()), ac, "merge_autosolve");
+   unsolve = new KAction(i18n("Set deltas to conflicts"), 0, this, SLOT(slotUnsolve()), actionCollection(), "merge_autounsolve");
+   fileReload  = new KAction(i18n("Reload"), /*QIconSet(QPixmap(reloadIcon)),*/ 0, this, SLOT(slotReload()), ac, "file_reload");
+   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");
+   winFocusPrev = new KAction(i18n("Focus Prev Window"), ALT+Key_Left, this, SLOT(slotWinFocusPrev()), ac, "win_focus_prev");
+   winToggleSplitOrientation = new KAction(i18n("Toggle Split Orientation"), 0, this, SLOT(slotWinToggleSplitterOrientation()), ac, "win_toggle_split_orientation");
+}
+
+void KDiff3App::initDirectoryMergeActions()
+{
+#include "xpm/startmerge.xpm"
+   //dirOpen = new KAction(i18n("Open directories ..."), 0, this, SLOT(slotDirOpen()), actionCollection(), "dir_open");
+   dirStartOperation = new KAction(i18n("Start/Continue directory merge"), Key_F5, m_pDirectoryMergeWindow, SLOT(mergeContinue()), actionCollection(), "dir_start_operation");
+   dirCompareCurrent = new KAction(i18n("Compare selected file"), 0, m_pDirectoryMergeWindow, SLOT(compareCurrentFile()), actionCollection(), "dir_compare_current");
+   dirMergeCurrent = new KAction(i18n("Merge current file"), QIconSet(QPixmap(startmerge)), 0, this, SLOT(slotMergeCurrentFile()), actionCollection(), "merge_current");
+   dirShowBoth = new KToggleAction(i18n("Dir and Text Split Screen View"), 0, this, SLOT(slotDirShowBoth()), actionCollection(), "win_dir_show_both");
+   dirShowBoth->setChecked( true );
+   dirViewToggle = new KAction(i18n("Toggle between Dir and Text View"), 0, this, SLOT(slotDirViewToggle()), actionCollection(), "win_dir_view_toggle");
+   dirFoldAll = new KAction(i18n("Fold all subdirs"), 0, m_pDirectoryMergeWindow, SLOT(slotFoldAllSubdirs()), actionCollection(), "dir_fold_all");
+   dirUnfoldAll = new KAction(i18n("Unfold all subdirs"), 0, m_pDirectoryMergeWindow, SLOT(slotUnfoldAllSubdirs()), actionCollection(), "dir_unfold_all");
+   dirRescan = new KAction(i18n("Rescan"), 0, m_pDirectoryMergeWindow, SLOT(reload()), actionCollection(), "dir_rescan");
+   dirChooseAEverywhere = new KAction(i18n("Choose A for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseAEverywhere()), actionCollection(), "dir_choose_a_everywhere");
+   dirChooseBEverywhere = new KAction(i18n("Choose B for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseBEverywhere()), actionCollection(), "dir_choose_b_everywhere");
+   dirChooseCEverywhere = new KAction(i18n("Choose C for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotChooseCEverywhere()), actionCollection(), "dir_choose_c_everywhere");
+   dirAutoChoiceEverywhere = new KAction(i18n("Auto-choose operation for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotAutoChooseEverywhere()), actionCollection(), "dir_autochoose_everywhere");
+   dirDoNothingEverywhere = new KAction(i18n("No operation for all items"), 0, m_pDirectoryMergeWindow, SLOT(slotNoOpEverywhere()), actionCollection(), "dir_nothing_everywhere");
+   // choose A/B/C/Suggestion/NoOp everywhere
+
+
+   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() )
+   {
+      config->setGroup("General Options");
+      config->writeEntry("Geometry", m_pKDiff3Shell->size());
+      config->writeEntry("Position", m_pKDiff3Shell->pos());
+      config->writeEntry("Show Toolbar", viewToolBar->isChecked());
+      config->writeEntry("Show Statusbar",viewStatusBar->isChecked());
+      if(toolBar("mainToolBar")!=0)
+         config->writeEntry("ToolBarPos", (int) toolBar("mainToolBar")->barPos());
+   }
+   m_pOptionDialog->m_bAutoAdvance = autoAdvance->isChecked();
+   m_pOptionDialog->m_bShowWhiteSpace = showWhiteSpace->isChecked();
+   m_pOptionDialog->m_bShowLineNumbers = showLineNumbers->isChecked();
+
+   if ( m_pDiffWindowSplitter!=0 )
+   {
+      m_pOptionDialog->m_bHorizDiffWindowSplitting = m_pDiffWindowSplitter->orientation()==Horizontal;
+   }
+
+   m_pOptionDialog->saveOptions( config );
+}
+
+
+void KDiff3App::readOptions( KConfig* config )
+{
+   if( !isPart() )
+   {
+      config->setGroup("General Options");
+
+      // bar status settings
+      bool bViewToolbar = config->readBoolEntry("Show Toolbar", true);
+      viewToolBar->setChecked(bViewToolbar);
+      slotViewToolBar();
+
+      bool bViewStatusbar = config->readBoolEntry("Show Statusbar", true);
+      viewStatusBar->setChecked(bViewStatusbar);
+      slotViewStatusBar();
+
+
+      // bar position settings
+      KToolBar::BarPosition toolBarPos;
+      toolBarPos=(KToolBar::BarPosition) config->readNumEntry("ToolBarPos", KToolBar::Top);
+      if( toolBar("mainToolBar")!=0 )
+         toolBar("mainToolBar")->setBarPos(toolBarPos);
+
+      QSize size=config->readSizeEntry("Geometry");
+      QPoint pos=config->readPointEntry("Position");
+      if(!size.isEmpty())
+      {
+         m_pKDiff3Shell->resize( size );
+         m_pKDiff3Shell->move( pos );
+      }
+   }
+   m_pOptionDialog->readOptions( config );
+
+   slotRefresh();
+}
+
+
+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 and 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("Yes - Quit"), i18n("No - 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 );
+      if ( bSuccess )
+      {
+         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;
+     bool bSuccess = m_pMergeResultWindow->saveDocument( m_outputFilename );
+     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 KDiff3App::slotFileQuit()
+{
+   slotStatusMsg(i18n("Exiting..."));
+
+   if( !queryClose() )
+       return;      // Don't quit
+
+   KApplication::exit(0);
+}
+
+
+
+void KDiff3App::slotViewToolBar()
+{
+   slotStatusMsg(i18n("Toggling toolbar..."));
+   ///////////////////////////////////////////////////////////////////
+   // turn Toolbar on or off
+   if ( toolBar("mainToolBar") !=0 )
+   {
+      if(!viewToolBar->isChecked())
+      {
+         toolBar("mainToolBar")->hide();
+      }
+      else
+      {
+         toolBar("mainToolBar")->show();
+      }
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotViewStatusBar()
+{
+   slotStatusMsg(i18n("Toggle the statusbar..."));
+   ///////////////////////////////////////////////////////////////////
+   //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 );
+   }
+}
+
+
+
+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("Searchtext:"),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();
+}
+
+#include "kdiff3.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.desktop	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,15 @@
+
+[Desktop Entry]
+Encoding=UTF-8
+Name=KDiff3
+Name[xx]=xxkdiff3xx
+Exec=kdiff3 %i %m -caption "%c"
+Icon=kdiff3
+Type=Application
+DocPath=kdiff3/kdiff3.html
+Comment=A KDE KPart Application
+Comment[hu]=KPart-alapú KDE-alkalmazás
+Comment[pt_BR]=Um Aplicativo KPart do KDE
+Comment[sv]=Ett KDE Kpart-program
+Comment[xx]=xxA KDE KPart Applicationxx
+Terminal=0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,386 @@
+/***************************************************************************
+                          kdiff3.h  -  description
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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 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 QScrollBar;
+class QComboBox;
+class QLineEdit;
+class QCheckBox;
+class QSplitter;
+
+
+class KDiff3Part;
+class DirectoryMergeWindow;
+class DirectoryMergeInfo;
+
+
+class KDiff3App : public QSplitter
+{
+  Q_OBJECT
+
+  public:
+    /** construtor 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();
+
+    /** 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();
+
+  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 );
+
+    /** save a document */
+    void slotFileSave();
+    /** save a document by a new filename*/
+    void slotFileSaveAs();
+
+    /** 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* fileQuit;
+    KAction* fileReload;
+    KAction* editCut;
+    KAction* editCopy;
+    KAction* editPaste;
+    KToggleAction* viewToolBar;
+    KToggleAction* viewStatusBar;
+
+////////////////////////////////////////////////////////////////////////
+// Special KDiff3 specific stuff starts here
+    KAction *editFind;
+    KAction *editFindNext;
+    KAction *dirOpen;
+    KAction *dirStartOperation;
+    KAction *dirCompareCurrent;
+    KAction *dirMergeCurrent;
+    KToggleAction *dirShowBoth;
+    KAction *dirViewToggle;
+    KAction *dirRescan;
+    KAction* dirChooseAEverywhere;
+    KAction* dirChooseBEverywhere;
+    KAction* dirChooseCEverywhere;
+    KAction* dirAutoChoiceEverywhere;
+    KAction* dirDoNothingEverywhere;
+    KAction* dirFoldAll;
+    KAction* dirUnfoldAll;
+
+    KAction *goCurrent;
+    KAction *goTop;
+    KAction *goBottom;
+    KAction *goPrevUnsolvedConflict;
+    KAction *goNextUnsolvedConflict;
+    KAction *goPrevConflict;
+    KAction *goNextConflict;
+    KAction *goPrevDelta;
+    KAction *goNextDelta;
+    KToggleAction *chooseA;
+    KToggleAction *chooseB;
+    KToggleAction *chooseC;
+    KToggleAction *autoAdvance;
+    KToggleAction *showWhiteSpace;
+    KToggleAction *showLineNumbers;
+    KAction *chooseAEverywhere;
+    KAction *chooseBEverywhere;
+    KAction *chooseCEverywhere;
+    KAction *autoSolve;
+    KAction *unsolve;
+    KToggleAction *showWindowA;
+    KToggleAction *showWindowB;
+    KToggleAction *showWindowC;
+    KAction *winFocusNext;
+    KAction *winFocusPrev;
+    KAction* winToggleSplitOrientation;
+
+    QPopupMenu* m_pMergeEditorPopupMenu;
+
+    QSplitter*  m_pMainSplitter;
+    QFrame*     m_pMainWidget;
+    QFrame*     m_pMergeWindowFrame;
+    QScrollBar* m_pHScrollBar;
+    QScrollBar* m_pDiffVScrollBar;
+    QScrollBar* m_pMergeVScrollBar;
+
+    DiffTextWindow* m_pDiffTextWindow1;
+    DiffTextWindow* m_pDiffTextWindow2;
+    DiffTextWindow* m_pDiffTextWindow3;
+    QSplitter* m_pDiffWindowSplitter;
+
+    MergeResultWindow* m_pMergeResultWindow;
+    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;
+
+    SourceData m_sdlm1;  // SourceData for Line Matching only.
+    SourceData m_sdlm2;
+    SourceData m_sdlm3;
+
+   QString m_outputFilename;
+   bool m_bDefaultFilename;
+
+   DiffList m_diffList12;
+   DiffList m_diffList23;
+   DiffList m_diffList13;
+
+   Diff3LineList m_diff3LineList;
+   Diff3LineVector m_diff3LineVector;
+
+   int m_neededLines;
+   int m_maxWidth;
+   int m_DTWHeight;
+   bool m_bOutputModified;
+   bool m_bTimerBlock;      // Synchronisation
+
+   OptionDialog* m_pOptionDialog;
+   FindDialog*   m_pFindDialog;
+
+   void init( bool bAuto=false );
+
+   virtual bool eventFilter( QObject* o, QEvent* e );
+   virtual void resizeEvent(QResizeEvent*);
+
+   bool improveFilenames();
+
+   bool runDiff( LineData* p1, int size1, LineData* p2, int size2, DiffList& diffList );
+   bool canContinue();
+
+
+   KActionCollection* actionCollection();
+   KStatusBar*        statusBar();
+   KToolBar*          toolBar(const char*);
+   KDiff3Part*        m_pKDiff3Part;
+   KParts::MainWindow*       m_pKDiff3Shell;
+   bool m_bAuto;
+
+private slots:
+   void resizeDiffTextWindow(int newWidth, int newHeight);
+   void resizeMergeResultWindow();
+
+   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 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 slotChooseAEverywhere();
+   void slotChooseBEverywhere();
+   void slotChooseCEverywhere();
+   void slotConfigure();
+   void slotConfigureKeys();
+   void slotRefresh();
+   void slotSelectionEnd();
+   void slotSelectionStart();
+   void slotClipboardChanged();
+   void slotOutputModified();
+   void slotAfterFirstPaint();
+   void slotMergeCurrentFile();
+   void slotReload();
+   void slotCheckIfCanContinue( bool* pbContinue );
+   void slotShowWhiteSpaceToggled();
+   void slotShowLineNumbersToggled();
+   void slotAutoAdvanceToggled();
+   void slotShowWindowAToggled();
+   void slotShowWindowBToggled();
+   void slotShowWindowCToggled();
+   void slotWinFocusNext();
+   void slotWinFocusPrev();
+   void slotWinToggleSplitterOrientation();
+};
+
+
+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_lineA;
+   QComboBox* m_lineB;
+   QComboBox* m_lineC;
+   QComboBox* m_lineOut;
+
+   QCheckBox* m_pMerge;
+   virtual void accept();
+private:
+   OptionDialog* m_pOptions;
+   void selectURL( QComboBox* pLine, bool bDir, int i, bool bSave );
+private slots:
+   void selectFileA();
+   void selectFileB();
+   void selectFileC();
+   void selectDirA();
+   void selectDirB();
+   void selectDirC();
+   void selectOutputName();
+   void selectOutputDir();
+   void internalSlot(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;
+};
+#endif // KDIFF3_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3.pro	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,26 @@
+TEMPLATE = app
+CONFIG  += qt warn_on thread release
+HEADERS  = diff.h kdiff3.h merger.h optiondialog.h kreplacements/kreplacements.h \
+                  directorymergewindow.h fileaccess.h kdiff3_shell.h kdiff3_part.h
+SOURCES  = diff.cpp difftextwindow.cpp kdiff3.cpp main.cpp merger.cpp mergeresultwindow.cpp \
+                  optiondialog.cpp pdiff.cpp directorymergewindow.cpp fileaccess.cpp \
+                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp
+TARGET   = kdiff3
+INCLUDEPATH += . ./kreplacements
+
+win32 {
+   QMAKE_CXXFLAGS_DEBUG  -= -Zi
+   QMAKE_CXXFLAGS_DEBUG  += -GX -GR -Z7
+   QMAKE_LFLAGS_DEBUG  += /PDB:NONE
+   QMAKE_CXXFLAGS_RELEASE  += -GX -GR -DNDEBUG
+   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	Mon Oct 06 18:50:45 2003 +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_part.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2003 Joachim Eibl <joachim.eibl@gmx.de>
+ */
+
+#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>
+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);
+*/
+}
+
+bool KDiff3Part::openFile()
+{
+   // m_file is always local so we can use QFile on it
+   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";
+      if ( str.left(4)=="--- " && fileName1.isEmpty() )
+      {
+         int pos = str.find("\t");
+         fileName1 = str.mid( 4, pos-4 );
+         int vpos = str.findRev("\t", -1);
+         if ( pos>0 && vpos>0 && vpos>pos )
+         {
+            version1 = str.mid( vpos+1 );
+            while( !version1.right(1)[0].isLetterOrNumber() )
+               version1.truncate( version1.length()-1 );
+         }
+      }
+      if ( str.left(4)=="+++ " && fileName2.isEmpty() )
+      {
+         int pos = str.find("\t");
+         fileName2 = str.mid( 4, pos-4 );
+         int vpos = str.findRev("\t", -1);
+         if ( pos>0 && vpos>0 && vpos>pos )
+         {
+            version2 = str.mid( vpos+1 );
+            while( !version2.right(1)[0].isLetterOrNumber() )
+               version2.truncate( version2.length()-1 );
+         }
+      }
+   }
+
+   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, "", "", "", "", "" );
+      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, "" ); // alias names
+      FileAccess::removeFile( 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, "", "" ); // alias name
+      FileAccess::removeFile( tempFileName );
+   }
+   else if ( !version1.isEmpty() && !version2.isEmpty() )
+   {
+      // 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,
+         ""
+      );
+
+      FileAccess::removeFile( tempFileName1 );
+      FileAccess::removeFile( 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"), "0.9.70");
+        s_about->addAuthor("Joachim Eibl", 0, "joachim.eibl@gmx.de");
+        s_instance = new KInstance(s_about);
+    }
+    return s_instance;
+}
+
+extern "C"
+{
+    void* init_libkdiff3part()
+    {
+        return new KDiff3PartFactory;
+    }
+};
+
+#include "kdiff3_part.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_part.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2003 Joachim Eibl <joachim.eibl@gmx.de>
+ */
+
+#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@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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,23 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kdiff3_part" version="0.9.70">
+<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="merge_showwhitespace"/>
+    <Action name="merge_showlinenumbers"/>
+    <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="merge_showwhitespace"/>
+  <Action name="merge_showlinenumbers"/>
+</ToolBar>
+</kpartgui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_shell.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2003 Joachim Eibl <joachim@gmx.de>
+ */
+
+#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()
+    : 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());
+
+            show();
+
+            ((KDiff3App*)m_part->widget())->completeInit();
+        }
+    }
+    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();
+        // 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::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
+}
+
+#include "kdiff3_shell.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_shell.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2003 Joachim Eibl <joachim.eibl@gmx.de>
+ */
+
+#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@gmx.de>
+ */
+class KDiff3Shell : public KParts::MainWindow
+{
+    Q_OBJECT
+public:
+    /**
+     * Default Constructor
+     */
+    KDiff3Shell();
+
+    /**
+     * Default Destructor
+     */
+    virtual ~KDiff3Shell();
+
+    bool queryClose();
+    bool queryExit();
+
+private slots:
+    void optionsShowToolbar();
+    void optionsShowStatusbar();
+    void optionsConfigureKeys();
+    void optionsConfigureToolbars();
+
+    void applyNewToolbarConfig();
+
+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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,73 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kdiff3_shell" version="0.9.70">
+<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_compare_current"/>
+    <Action name="dir_rescan"/>
+    <Action name="dir_fold_all"/>
+    <Action name="dir_unfold_all"/>
+    <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"/>
+  </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="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_autosolve"/>
+    <Action name="merge_autounsolve"/>
+    <Action name="merge_showwhitespace"/>
+    <Action name="merge_showlinenumbers"/>
+  </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="merge_showwhitespace"/>
+  <Action name="merge_showlinenumbers"/>
+</ToolBar>
+</kpartgui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3_tmake.pro	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,13 @@
+TEMPLATE	= app
+CONFIG		+= qt warn-on release
+HEADERS  = diff.h kdiff3.h merger.h optiondialog.h kreplacements/kreplacements.h \
+                  directorymergewindow.h fileaccess.h kdiff3_shell.h kdiff3_part.h
+SOURCES  = diff.cpp difftextwindow.cpp kdiff3.cpp main.cpp merger.cpp mergeresultwindow.cpp \
+                  optiondialog.cpp pdiff.cpp directorymergewindow.cpp fileaccess.cpp \
+                  kdiff3_shell.cpp kdiff3_part.cpp kreplacements/kreplacements.cpp
+TARGET		= kdiff3
+INCLUDEPATH	+= . ./kreplacements
+REQUIRES             = full-config
+win32:RC_FILE        = kdiff3.rc
+win32:TMAKE_CFLAGS   = -GX -GR
+win32:TMAKE_CXXFLAGS = -GX -GR
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kdiff3part.desktop	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=KDiff3Part
+Name[sv]=kdiff3-del
+Name[xx]=xxkdiff3Partxx
+MimeType=text/x-diff
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
+X-KDE-Library=libkdiff3part
+Type=Service
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/README	Mon Oct 06 18:50:45 2003 +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/kaboutdata.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kaccel.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kaction.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kapplication.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kcmdlineargs.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kcolorbtn.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kconfig.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kdialogbase.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kedittoolbar.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kfiledialog.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kfontdialog.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kiconloader.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kinstance.h	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kkeydialog.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/klibloader.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/klocale.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmainwindow.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmenubar.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kmessagebox.h	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kpopupmenu.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kprogress.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,1201 @@
+/***************************************************************************
+                          kreplacements.cpp  -  description
+                             -------------------
+    begin                : Sat Aug 3 2002
+    copyright            : (C) 2002-2003 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:48:54  joachim99
+ * KDiff3 version 0.9.70
+ *
+ ***************************************************************************/
+
+#include "kreplacements.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 <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;
+
+#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() )
+         {
+            QMessageBox::warning( 0, "KDiff3 Helpfile not found", 
+               "Couldn't find the helpfile at: \n\n    "
+               + helpFile.absFilePath() + "\n\n"
+               "The documentation can also be found at the homepage:\n\n " 
+               "    http://kdiff3.sourceforge.net/");   
+            return;
+         }
+      }
+
+      HINSTANCE hi = FindExecutableA( helpFile.fileName(), helpFile.dirPath(true), 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(), prog.fileName(), (const char*)helpFile.absFilePath(), 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
+}
+
+
+// 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 ) ? 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, "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 QString& 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);
+   addTab( p, name );
+   return p;
+}
+
+QFrame* KDialogBase::addPage(  const QString& name, const QString& /*info*/, int )
+{
+   QFrame* p = new QFrame( this, name );
+   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, 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, caption);
+   return KURL(s);
+}
+
+KURL KFileDialog::getExistingURL( const QString &  startDir,
+                               QWidget *  parent,
+                               const QString &  caption)
+{
+   QString s = QFileDialog::getExistingDirectory(startDir, parent, caption);
+   return KURL(s);
+}
+
+
+KToolBar::BarPosition KToolBar::barPos()
+{
+   return Top;
+}
+
+void KToolBar::setBarPos(BarPosition)
+{
+}
+
+KToolBar::KToolBar( QMainWindow* parent )
+: QToolBar( parent )
+{
+}
+
+
+KMainWindow::KMainWindow( QWidget* parent, const QString& name )
+: QMainWindow( parent, name ), m_actionCollection(this)
+{
+   fileMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&File"), fileMenu);
+   editMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Edit"), editMenu);
+   directoryMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Directory"), directoryMenu);
+   movementMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Movement"), movementMenu);
+   mergeMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Merge"), mergeMenu);
+   windowsMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Windows"), windowsMenu);
+   settingsMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Settings"), settingsMenu);
+   helpMenu = new QPopupMenu();
+   menuBar()->insertItem(tr("&Help"), helpMenu);
+
+   m_pToolBar = new KToolBar(this);
+      
+   memberList = new QList<KMainWindow>;
+   memberList->append(this);
+   connect( qApp, SIGNAL(lastWindowClosed()), this, SLOT(quit())); 
+}
+
+void KMainWindow::closeEvent(QCloseEvent*e)
+{
+   if ( queryClose() )
+   {
+      e->accept();
+   }
+   else
+      e->ignore();
+}
+
+bool KMainWindow::event( QEvent* e )
+{
+   return QMainWindow::event(e);
+}
+
+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());
+}
+
+void KMainWindow::quit()
+{
+   if ( queryExit() )
+   {
+      qApp->quit();
+   }
+}
+
+void KMainWindow::slotAbout()
+{
+   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();
+}
+
+KConfig::KConfig()
+{
+   QString home = QDir::homeDirPath();
+   m_fileName = home + "/.kdiff3rc";
+
+   QFile f( m_fileName );
+   if ( f.open(IO_ReadOnly) )
+   {                               // file opened successfully
+      QTextStream t( &f );        // use a text stream
+      while ( !t.eof() )
+      {                                 // until end of file...	   
+         QString s = t.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;
+         }	   
+      }
+      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
+       std::map<QString,QString>::iterator i;
+       for( i=m_map.begin(); i!=m_map.end(); ++i)
+       {
+          QString key = i->first;
+          QString val = i->second;
+          t << key << "=" << val << "\n";
+       }
+       f.close();
+   }
+}
+
+void KConfig::setGroup(const QString&)
+{
+}
+
+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();
+
+   //return s.section(',', idx, idx).toInt();
+}
+
+void KConfig::writeEntry(const QString& k, const QFont& v )
+{
+   //m_map[k] = v.toString();
+   m_map[k] = v.family() + "," + QString::number(v.pointSize());
+}
+
+void KConfig::writeEntry(const QString& k, const QColor& v )
+{
+   m_map[k] = numStr(v.red()) + "," + numStr(v.green()) + "," + numStr(v.blue());
+}
+
+void KConfig::writeEntry(const QString& k, const QSize& v )
+{
+   m_map[k] = numStr(v.width()) + "," + numStr(v.height());
+}
+
+void KConfig::writeEntry(const QString& k, const QPoint& v )
+{
+   m_map[k] = numStr(v.x()) + "," + numStr(v.y());
+}
+
+void KConfig::writeEntry(const QString& k, int v )
+{
+   m_map[k] = numStr(v);
+}
+
+void KConfig::writeEntry(const QString& k, bool v )
+{
+   m_map[k] = numStr(v);
+}
+
+void KConfig::writeEntry(const QString& k, const QString& v )
+{
+   m_map[k] = v;
+}
+
+void KConfig::writeEntry(const QString& k, const QStringList& v, char separator )
+{
+   QString s;
+
+   QStringList::ConstIterator i = v.begin();
+   for( i=v.begin(); i!= v.end(); ++i )
+   {
+      s += *i;
+
+      if ( !(*i).isEmpty() )
+         s += separator;
+   }
+
+   m_map[k] = s;
+}
+
+
+QFont KConfig::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.fromString(i->second);
+   }
+
+   return f;
+}
+
+QColor KConfig::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 KConfig::readSizeEntry(const QString& k)
+{
+   QSize size(640,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 KConfig::readPointEntry(const QString& k)
+{
+   QPoint point(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 KConfig::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 KConfig::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 KConfig::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 KConfig::readListEntry(const QString& k, char /*separator*/ )
+{
+   QStringList strList;
+
+   std::map<QString,QString>::iterator i = m_map.find( k );
+   if ( i!=m_map.end() )
+   {
+      QString s = i->second;
+      int idx=0;
+      for(;;)
+      {
+         QString sec = subSection( s, idx, '|' ); //s.section('|',idx,idx);
+         if ( sec.isEmpty() )
+            break;
+         else
+            strList.append(sec);
+         ++idx;
+      }
+   }
+   return strList;
+}
+
+
+KAction::KAction(const QString& text, const QIconSet& icon, int accel,
+ QWidget* receiver, const char* slot, KActionCollection* actionCollection,
+ const QString& name, bool bToggle, bool bMenu
+ )
+: QAction ( text, icon, text, accel, actionCollection->m_pMainWindow, name, bToggle )
+{
+   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 ( !icon.isNull() && p ) this->addTo( p->m_pToolBar );
+
+   if (bMenu)
+   {
+      if( name[0]=='g')       addTo( p->movementMenu );
+      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, int accel,
+ QWidget* receiver, const char* slot, KActionCollection* actionCollection,
+ const QString& name, bool bToggle, bool bMenu
+ )
+: QAction ( text, text, accel, actionCollection->m_pMainWindow, name, bToggle )
+{
+   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( name[0]=='g') addTo( p->movementMenu );
+      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 );
+   }
+}
+
+void KAction::setStatusText(const QString&)
+{
+}
+
+void KAction::plug(QPopupMenu* menu)
+{
+   addTo(menu);
+}
+
+
+KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
+: KAction( text, icon, accel, parent, slot, actionCollection, name, true, bMenu)
+{
+}
+
+KToggleAction::KToggleAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu)
+: KAction( text, accel, parent, slot, actionCollection, name, true, bMenu)
+{
+}
+
+KToggleAction::KToggleAction(const QString& text, const QIconSet& icon, int accel, KActionCollection* actionCollection, const QString& 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( "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( "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( "SaveAs", 0, parent, slot, actionCollection, "saveas", 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( "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( "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( "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( "Paste", Qt::CTRL+Qt::Key_V, parent, slot, actionCollection, "paste", 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( "ShowToolBar", 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( "ShowStatusBar", 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( "Settings ...", 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( "About", 0, parent, slot, actionCollection, "about", 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( "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( "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( "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("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();
+}
+
+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 QString& /*name*/, int, const QString& /*email*/)
+{
+}
+
+/*  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* )  // static
+{
+   s_argc = argc;
+   s_argv = argv;
+}
+
+void KCmdLineArgs::addCmdLineOptions( KCmdLineOptions* options ) // static
+{
+   s_pOptions = options;
+}
+
+int KCmdLineArgs::count()
+{
+   return s_vArg.size();
+}
+
+QString KCmdLineArgs::arg(int idx)
+{
+   return QString(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].shortName;
+      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].shortName;
+      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].shortName;
+      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].shortName != 0 )
+   {
+      if ( s_pOptions[i].shortName[0]=='[' )
+         nofArgs++;
+      else
+         nofOptions++;
+
+      ++i;
+   }
+
+   s_vOption.resize(nofOptions);
+
+   for( i=1; i<s_argc; ++i )
+   {
+      if ( s_argv[i][0]=='-' )  // An option
+      {
+         // Find the option
+         int j=0;
+         for( j=0; j<nofOptions; ++j )
+         {
+            const char* optName = s_pOptions[j].shortName;
+            const char* pos = strchr( optName,' ' );
+            int len = pos==0 ? strlen( optName ) : pos - optName;
+
+            if( len>0 && ( s_argv[i][1]=='-' && memcmp( &s_argv[i][2], optName, len )==0  ||
+                                                memcmp( &s_argv[i][1], optName, len )==0  ))
+            {
+               if (s_pOptions[j].longName == 0)  // alias, because without description.
+               {
+                  ++j;
+                  optName = s_pOptions[j].shortName;
+                  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)
+         {
+            using std::cerr;
+            using std::endl;
+            cerr << "Unknown option: " << s_argv[i] << endl<<endl;
+
+            cerr << "Usage when starting via commandline: "                      << endl;
+            cerr << "- Comparing 2 files:     kdiff3 file1 file2  "              << endl;
+            cerr << "- Merging 2 files:       kdiff3 file1 file2 -o outputfile " << endl;
+            cerr << "- Comparing 3 files:     kdiff3 file1 file2 file3         " << endl;
+            cerr << "- Merging 3 files:       kdiff3 file1 file2 file3 -o outputfile " << endl;
+            cerr << "     Note that file1 will be treated as base of file2 and file3." << endl;
+            cerr << endl;
+            cerr << "If you start without arguments, then a dialog will appear"        << endl;
+            cerr << "where you can select your files via a filebrowser."               << endl;
+            cerr << endl;
+            cerr << "For more documentation, see the help-menu or the subdirectory doc. " << endl;
+            ::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, QString const& name, QString const& classname )
+{
+   KParts::Factory* f = dynamic_cast<KParts::Factory*>(this);
+   if (f!=0)
+      return f->createPartObject( (QWidget*)pParent, name,
+                                            pParent, name,
+                                            classname,  QStringList() );
+   else
+      return 0;
+}
+
+
+
+#include "kreplacements.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kreplacements.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,478 @@
+/***************************************************************************
+                          kreplacements.h  -  description
+                             -------------------
+    begin                : Sat Aug 3 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:48:54  joachim99
+ * KDiff3 version 0.9.70
+ *
+ ***************************************************************************/
+
+#ifndef KREPLACEMENTS_H
+#define KREPLACEMENTS_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 <map>
+
+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 QString& 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 );
+};
+
+typedef QStatusBar KStatusBar;
+
+class KToolBar : public QToolBar
+{
+public:
+   KToolBar(QMainWindow* parent);
+
+   enum BarPosition {Top};
+   BarPosition barPos();
+   void setBarPos(BarPosition);
+};
+
+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:
+   void closeEvent(QCloseEvent* e);
+   virtual bool queryClose() = 0;
+   virtual bool queryExit() = 0;
+   bool event( QEvent* e );
+public:
+   QPopupMenu* fileMenu;
+   QPopupMenu* editMenu;
+   QPopupMenu* directoryMenu;
+   QPopupMenu* movementMenu;
+   QPopupMenu* mergeMenu;
+   QPopupMenu* windowsMenu;
+   QPopupMenu* settingsMenu;
+   QPopupMenu* helpMenu;
+
+   KToolBar*  m_pToolBar;
+
+   KMainWindow( QWidget* parent, const QString& name );
+   KToolBar* toolBar(const QString& s = QString::null);
+   KActionCollection* actionCollection();
+   void createGUI();
+   void createGUI(KParts::ReadWritePart*){createGUI();}
+
+   QList<KMainWindow>* memberList;
+public slots:
+   void quit();
+   void slotHelp();
+   void slotAbout();
+};
+
+class KConfig
+{
+   QString m_fileName;
+   std::map<QString,QString> m_map;
+public:
+   KConfig();
+   ~KConfig();
+
+   void setGroup(const QString&);
+
+   void writeEntry(const QString&, const QFont& );
+   void writeEntry(const QString&, const QColor& );
+   void writeEntry(const QString&, const QSize& );
+   void writeEntry(const QString&, const QPoint& );
+   void writeEntry(const QString&, int );
+   void writeEntry(const QString&, bool );
+   void writeEntry(const QString&, const QStringList&, char separator );
+   void writeEntry(const QString&, const QString& );
+
+   QFont readFontEntry(const QString&, QFont* defaultVal );
+   QColor readColorEntry(const QString&, QColor* defaultVal );
+   QSize readSizeEntry(const QString& );
+   QPoint readPointEntry(const QString& );
+   bool readBoolEntry(const QString&, bool bDefault );
+   int readNumEntry(const QString&, int iDefault );
+   QStringList readListEntry(const QString&, char separator );
+   QString readEntry(const QString&, const QString& );
+};
+
+class KAction : public QAction
+{
+public:
+   KAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
+   KAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bToggle=false, bool bMenu=true);
+   void setStatusText(const QString&);
+   void plug(QPopupMenu*);
+};
+
+class KToggleAction : public KAction
+{
+public:
+   KToggleAction(const QString& text, const QIconSet& icon, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
+   KToggleAction(const QString& text, int accel, QWidget* parent, const char* slot, KActionCollection* actionCollection, const QString& name, bool bMenu=true);
+   KToggleAction(const QString& text, const QIconSet& icon, int accel, KActionCollection* actionCollection, const QString& 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* 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 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* 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();
+};
+
+struct KCmdLineOptions
+{
+   const char* shortName;
+   const char* longName;
+   int whatever;
+};
+
+
+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 QString& name, int, const QString& email);
+   enum { License_GPL };
+};
+
+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);
+   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:
+      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 QString& 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/kstatusbar.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kstdaction.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/ktempfile.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kunload.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kurl.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2 @@
+#include "kreplacements.h"      
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/kreplacements/kurldrag.h	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,126 @@
+/***************************************************************************
+                          main.cpp  -  Where everything starts.
+                             -------------------
+    begin                : Don Jul 11 12:31:29 CEST 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "kdiff3_shell.h"
+
+
+static const char *description =
+   I18N_NOOP("Text Diff and Merge Tool");
+
+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 },
+  { "fname alias",  I18N_NOOP("Visible name replacement. Supply this once for every input."), 0 },
+#ifdef _WIN32
+  { "query",       I18N_NOOP("For compatibility with certain tools."), 0 },
+#endif
+  { "+[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 },
+  { 0, 0, 0 }
+};
+
+#undef VERSION
+#define VERSION "0.9.70"
+
+#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.
+
+      The installation is very simple:
+      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]);
+   fclose(f);
+   */
+
+   // 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-2003 Joachim Eibl", 0, "http://kdiff3.sourceforge.net/", "joachim.eibl@gmx.de");
+   aboutData.addAuthor("Joachim Eibl",0, "joachim.eibl@gmx.de");
+   KCmdLineArgs::init( argc, argv, &aboutData );
+   KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+  KApplication app;
+
+  if (app.isRestored())
+  {
+     RESTORE(KDiff3Shell);
+  }
+  else
+  {
+     new KDiff3Shell();
+  }
+
+  return app.exec();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/merger.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,94 @@
+/***************************************************************************
+                          merger.cpp  -  description
+                             -------------------
+    begin                : Sun Mar 24 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,68 @@
+/***************************************************************************
+                          merger.h  -  description
+                             -------------------
+    begin                : Sun Mar 24 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,2246 @@
+/***************************************************************************
+                          mergeresultwindow.cpp  -  description
+                             -------------------
+    begin                : Sun Apr 14 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include "diff.h"
+#include <stdio.h>
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qcursor.h>
+#include <qpopupmenu.h>
+#include <optiondialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+int g_bAutoSolve = true;
+
+#define leftInfoWidth 3
+
+MergeResultWindow::MergeResultWindow(
+   QWidget* pParent,
+   OptionDialog* pOptionDialog
+   )
+: QWidget( pParent, 0, WRepaintNoErase )
+{
+   setFocusPolicy( QWidget::ClickFocus );
+
+   m_firstLine = 0;
+   m_firstColumn = 0;
+   m_nofColumns = 0;
+   m_nofLines = 0;
+   m_bMyUpdate = false;
+   m_bInsertMode = true;
+   m_scrollDeltaX = 0;
+   m_scrollDeltaY = 0;
+   m_bModified = false;
+
+   m_fileName = "";
+   m_pldA = 0;
+   m_pldB = 0;
+   m_pldC = 0;
+
+   m_pDiff3LineList = 0;
+   m_pTotalDiffStatus = 0;
+   
+   m_pOptionDialog = pOptionDialog;
+
+   m_cursorXPos=0;
+   m_cursorOldXPos=0;
+   m_cursorYPos=0;
+   m_bCursorOn = true;
+   connect( &m_cursorTimer, SIGNAL(timeout()), this, SLOT( slotCursorUpdate() ) );
+   m_cursorTimer.start( 500 /*ms*/, true /*single shot*/ );
+   m_selection.reset();
+
+   setMinimumSize( QSize(20,20) );
+}
+
+void MergeResultWindow::init(
+   const LineData* pLineDataA,
+   const LineData* pLineDataB,
+   const LineData* pLineDataC,
+   const Diff3LineList* pDiff3LineList,
+   const TotalDiffStatus* pTotalDiffStatus,
+   QString fileName
+   )
+{
+   m_firstLine = 0;
+   m_firstColumn = 0;
+   m_nofColumns = 0;
+   m_nofLines = 0;
+   m_bMyUpdate = false;
+   m_bInsertMode = true;
+   m_scrollDeltaX = 0;
+   m_scrollDeltaY = 0;
+   m_bModified = false;
+   
+   m_fileName = fileName;
+   m_pldA = pLineDataA;
+   m_pldB = pLineDataB;
+   m_pldC = pLineDataC;
+
+   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();
+}
+
+const int A=1, B=2, C=3;
+
+// Calculate the merge information for the given Diff3Line.
+// Results will be stored in mergeDetails, bConflict, bLineRemoved and src.
+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 )
+   {
+      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)
+{   
+   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("Continue"), i18n("Cancel"));
+      if ( result==KMessageBox::No )
+         return;
+   }
+   
+   m_mergeLineList.clear();
+   int lineIdx = 0;
+   Diff3LineList::const_iterator it;
+   for( it=m_pDiff3LineList->begin(); it!=m_pDiff3LineList->end(); ++it, ++lineIdx )
+   {
+      const Diff3Line& d = *it;
+
+      MergeLine ml;
+      bool bLineRemoved;
+      mergeOneLine( d, ml.mergeDetails, ml.bConflict, bLineRemoved, ml.srcSelect, m_pldC==0 );
+      
+      ml.d3lLineIdx   = lineIdx;
+      ml.bDelta       = ml.srcSelect != A;
+      ml.id3l         = it;
+      ml.srcRangeLength = 1;
+
+      MergeLine* back = m_mergeLineList.empty() ? 0 : &m_mergeLineList.back();
+
+      bool bSame = back!=0 && sameKindCheck( ml, *back );
+      if( bSame )
+      {
+         ++back->srcRangeLength;
+      }
+      else
+      {
+         m_mergeLineList.push_back( ml );
+      }
+
+      if ( ! ml.bConflict )
+      {
+         MergeLine& tmpBack = m_mergeLineList.back();
+         MergeEditLine mel;
+         mel.setSource( ml.srcSelect, ml.id3l, bLineRemoved );
+         tmpBack.mergeEditLineList.push_back(mel);
+      }
+      else if ( back==0  || ! back->bConflict || !bSame )
+      {
+         MergeLine& tmpBack = m_mergeLineList.back();
+         MergeEditLine mel;
+         mel.setConflict();
+         tmpBack.mergeEditLineList.push_back(mel);
+      }
+   }
+
+   if ( !bAutoSolve )
+   {
+      // Change all auto selections
+      MergeLineList::iterator mlIt;
+      for( mlIt=m_mergeLineList.begin(); mlIt!=m_mergeLineList.end(); ++mlIt )
+      {
+         MergeLine& ml = *mlIt;
+         if ( ml.bDelta )
+         {
+            ml.mergeEditLineList.clear();
+            if ( defaultSelector==-1 && ml.bDelta )
+            {
+               MergeEditLine mel;
+               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;
+                  mel.setSource( defaultSelector, d3llit, false );
+                  
+                  int srcLine = defaultSelector==1 ? d3llit->lineA :
+                                defaultSelector==2 ? d3llit->lineB :
+                                defaultSelector==3 ? d3llit->lineC : -1;
+                                
+                  if ( srcLine != -1 )
+                  {
+                     ml.mergeEditLineList.push_back(mel);
+                  }
+
+                  ++d3llit;
+               }
+
+               if ( ml.mergeEditLineList.empty() ) // Make a line nevertheless
+               {
+                  MergeEditLine mel;
+                  mel.setSource( defaultSelector, ml.id3l, false );
+                  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 = melsrc==1 ? mel.id3l()->lineA :
+                       melsrc==2 ? mel.id3l()->lineB :
+                       melsrc==3 ? mel.id3l()->lineC : -1;
+
+         if ( srcLine == -1 && oldSrcLine==-1 && oldSrc == melsrc )
+
+            melIt = ml.mergeEditLineList.erase( melIt );
+         else
+            ++melIt;
+
+         oldSrcLine = srcLine;
+         oldSrc = melsrc;
+      }
+   }
+
+   m_currentMergeLineIt = m_mergeLineList.begin();
+   m_cursorXPos=0;
+   m_cursorOldXPos=0;
+   m_cursorYPos=0;
+   m_firstLine = 0;
+   m_firstColumn = 0;
+   
+   m_bModified = false;
+   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_nofLines;
+}
+
+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();
+}
+
+// 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;
+   if( eEndPoint==eEnd )
+   {
+      if (eDir==eUp) i = m_mergeLineList.begin();     // first mergeline
+      else           i = --m_mergeLineList.end();     // last mergeline
+
+      while ( ! i->bDelta   &&   i!=m_mergeLineList.end() )
+      {
+         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->bDelta == false  &&  i!=m_mergeLineList.end() );
+   }
+   else if ( eEndPoint == eConflict  &&  i!=m_mergeLineList.end())
+   {
+      do
+      {
+         if ( eDir==eUp )  --i;
+         else              ++i;
+      }
+      while ( i->bConflict == false  &&  i!=m_mergeLineList.end() );
+   }
+   else if ( eEndPoint == eUnsolvedConflict  &&  i!=m_mergeLineList.end())
+   {
+      do
+      {
+         if ( eDir==eUp )  --i;
+         else              ++i;
+      }
+      while ( i!=m_mergeLineList.end() && ! i->mergeEditLineList.begin()->isConflict() );
+   }
+
+   setFastSelector( i );
+}
+
+bool MergeResultWindow::isDeltaAboveCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   --i;
+   for( ; i!=m_mergeLineList.end(); --i )
+   {
+      if ( i->bDelta ) return true;
+   }
+   return false;
+}
+
+bool MergeResultWindow::isDeltaBelowCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   ++i;
+   for( ; i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->bDelta ) return true;
+   }
+   return false;
+}
+
+bool MergeResultWindow::isConflictAboveCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   --i;
+   for( ; i!=m_mergeLineList.end(); --i )
+   {
+      if ( i->bConflict ) return true;
+   }
+   return false;
+}
+
+bool MergeResultWindow::isConflictBelowCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   ++i;
+   for( ; i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->bConflict ) return true;
+   }
+   return false;   
+}
+
+bool MergeResultWindow::isUnsolvedConflictAboveCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   --i;
+   for( ; i!=m_mergeLineList.end(); --i )
+   {
+      if ( i->mergeEditLineList.begin()->isConflict() ) return true;
+   }
+   return false;
+}
+
+bool MergeResultWindow::isUnsolvedConflictBelowCurrent()
+{
+   MergeLineList::iterator i = m_currentMergeLineIt;
+   ++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 nrOfUnsolvedConflicts = 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;
+   }
+
+   return nrOfUnsolvedConflicts;
+}
+
+void MergeResultWindow::showNrOfConflicts()
+{
+   int nrOfSolvedConflicts = 0;
+   int nrOfUnsolvedConflicts = 0;
+
+   MergeLineList::iterator i;
+   for ( i = m_mergeLineList.begin();  i!=m_mergeLineList.end(); ++i )
+   {
+      if ( i->bConflict )
+         ++nrOfUnsolvedConflicts;
+      else if ( i->bDelta )
+         ++nrOfSolvedConflicts;
+   }
+   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");
+   }
+   KMessageBox::information( this,
+      i18n("Total number of conflicts: ") + QString::number(nrOfSolvedConflicts + nrOfUnsolvedConflicts) +
+      i18n("\nNr of automatically solved conflicts: ") + QString::number(nrOfSolvedConflicts) +
+      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();
+   emit updateAvailabilities();
+}
+
+void MergeResultWindow::choose( int selector )
+{
+   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;
+         mel.setSource( selector, d3llit, 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;
+
+      if ( bActive )  mel.setConflict();         // All src entries deleted => conflict
+      else            mel.setRemoved(selector);  // No lines in corresponding src found.
+
+      ml.mergeEditLineList.push_back(mel);
+   }
+
+   update();
+   emit updateAvailabilities();
+}
+
+void MergeResultWindow::slotChooseA()
+{
+   choose( A );
+}
+
+void MergeResultWindow::slotChooseB()
+{
+   choose( B );
+}
+
+void MergeResultWindow::slotChooseC()
+{
+   choose( C );
+}
+void MergeResultWindow::slotChooseAEverywhere()
+{
+   resetSelection();
+   merge( false, A );
+   emit modified();
+   update();
+}
+
+void MergeResultWindow::slotChooseBEverywhere()
+{
+   resetSelection();
+   merge( false, B );
+   emit modified();
+   update();
+}
+
+void MergeResultWindow::slotChooseCEverywhere()
+{
+   resetSelection();
+   merge( false, C );
+   emit modified();
+   update();
+}
+
+void MergeResultWindow::slotAutoSolve()
+{
+   resetSelection();
+   merge( true, -1 );
+   emit modified();
+   update();
+}
+
+void MergeResultWindow::slotUnsolve()
+{
+   resetSelection();
+   merge( false, -1 );
+   emit modified();
+   update();
+}
+
+void MergeResultWindow::myUpdate(int afterMilliSecs)
+{
+   killTimers();
+   m_bMyUpdate = true;
+   startTimer( afterMilliSecs );
+}
+
+void MergeResultWindow::timerEvent(QTimerEvent*)
+{
+   killTimers();
+
+   if ( m_bMyUpdate )
+   {
+      update();//paintEvent( 0 );
+      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 );
+      killTimers();
+      startTimer(50);
+   }
+}
+
+const char* MergeResultWindow::MergeEditLine::getString( const MergeResultWindow* mrw, int& size )
+{
+   size=-1;
+   if ( isRemoved() )   { size=0; return ""; }
+
+   if ( ! isModified() )
+   {
+      int src = m_src;
+      const Diff3Line& d3l = *m_id3l;
+      if ( src == 0 )   { size=0; return ""; }
+
+      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.
+         size = 0;
+         return "";
+      }
+
+      size = pld->size;
+      return pld->pLine;
+   }
+   else
+   {
+      size = m_str.length();
+      return m_str;
+   }
+   return 0;
+}
+
+/// Converts the cursor-posOnScreen into a text index, considering tabulators.
+int convertToPosInText( const char* p, int size, int posOnScreen )
+{
+   int localPosOnScreen = 0;
+   for ( int i=0; i<size; ++i )
+   {
+      if ( localPosOnScreen>=posOnScreen )
+         return i;
+
+      // All letters except tabulator have width one.
+      int letterWidth = p[i]!='\t' ? 1 : tabber( localPosOnScreen, g_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 char* p, int posInText )
+{
+   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, g_tabSize );
+
+      posOnScreen += letterWidth;
+   }
+   return posOnScreen;
+}
+
+void MergeResultWindow::writeLine(
+   QPainter& p, int line, const char* pStr, int size,
+   int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved
+   )
+{
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width("W");
+   int fontAscent = fm.ascent();
+
+   int topLineYOffset = fontHeight + 3;
+   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;
+      QCString s;
+      for ( int i=0; i<size; ++i )
+      {
+         int spaces = 1;
+         if ( pStr[i]=='\t' )
+         {
+            spaces = tabber( outPos, g_tabSize );
+            for( int j=0; j<spaces; ++j )
+               s+=' ';
+         }
+         else
+         {
+            s+=pStr[i];
+         }
+         outPos += spaces;
+      }
+
+      if ( m_selection.lineWithin( line ) )
+      {
+         int firstPosInLine = convertToPosOnScreen( pStr, convertToPosInText( pStr, size, m_selection.firstPosInLine(line) ) );
+         int lastPosInLine  = convertToPosOnScreen( pStr, convertToPosInText( pStr, size, m_selection.lastPosInLine(line) ) );
+         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,  QString::fromUtf8( s.mid(m_firstColumn) ) );
+         }
+         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
+            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,
+            QString::fromUtf8( s.mid(firstPosInLine2,lengthInLine2) ) );
+      }
+      else
+      {
+         p.setPen( m_pOptionDialog->m_fgColor );
+         p.drawText( xOffset, yOffset+fontAscent, QString::fromUtf8( s.mid(m_firstColumn) ) );
+      }
+
+      p.setPen( m_pOptionDialog->m_fgColor );
+      if ( m_cursorYPos==line )
+      {
+         m_cursorXPos = minMaxLimiter( m_cursorXPos, 0, outPos );
+         m_cursorXPos = convertToPosOnScreen( pStr, convertToPosInText( pStr, size, m_cursorXPos ) );
+      }
+
+      p.drawText( 1, yOffset+fontAscent, srcName );
+   }
+   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 );
+      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::paintEvent( QPaintEvent* e )
+{
+   if (m_pDiff3LineList==0) return;
+
+   bool bOldSelectionContainsData = m_selection.bSelectionContainsData;
+   if (font() != m_pOptionDialog->m_font )
+   {
+      setFont( m_pOptionDialog->m_font );
+   }
+   const QFontMetrics& fm = fontMetrics();
+   int fontHeight = fm.height();
+   int fontWidth = fm.width("W");
+   int fontAscent = fm.ascent();
+
+   if ( e!= 0 )  // e==0 for blinking cursor
+   {
+      m_selection.bSelectionContainsData = false;
+      if ( size() != m_pixmap.size() )
+         m_pixmap.resize(size());
+
+      QPainter p(&m_pixmap);
+      p.setFont( font() );
+      p.fillRect( rect(), m_pOptionDialog->m_bgColor );
+
+      //int visibleLines = height() / fontHeight;
+
+      {  // Draw the topline
+         QString s;
+         s.sprintf(" Output : %s ", m_fileName.ascii() );
+         // s.sprintf(" Output : %s : Line %d",(const char*) m_fileName, m_firstLine+1 );
+         if (m_bModified)
+            s += i18n("[Modified]");
+
+         int topLineYOffset = fontHeight + 3;
+
+         if (hasFocus())
+         {
+            p.fillRect( 0, 0, width(), topLineYOffset, lightGray /*m_pOptionDialog->m_diffBgColor*/ );
+         }
+         else
+         {
+            p.fillRect( 0, 0, width(), topLineYOffset, m_pOptionDialog->m_bgColor );
+         }
+         p.setPen( m_pOptionDialog->m_fgColor );
+         p.drawText( 0, fontAscent+1, s );
+         p.drawLine( 0, fontHeight + 2, width(), fontHeight + 2 );
+      }
+
+      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
+
+                  const char* s;
+                  int size;
+                  s = mel.getString( this, size );
+                  if (size>nofColumns)
+                     nofColumns = size;
+
+                  writeLine( p, line, s, size, mel.src(), ml.mergeDetails, rangeMark,
+                     mel.isModified(), mel.isRemoved() );
+               }
+               ++line;
+            }
+         }
+      }
+
+      if ( line != m_nofLines || nofColumns != m_nofColumns )
+      {
+         m_nofLines = line;
+
+         m_nofColumns = nofColumns;
+         emit resizeSignal();
+      }
+
+      if( m_currentMergeLineIt == m_mergeLineList.end() )
+         emit sourceMask( 0, 0 );
+      else
+      {
+         int enabledMask = m_pldC==0 ? 3 : 7;
+         MergeLine& ml = *m_currentMergeLineIt;
+
+         int 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 ) emit sourceMask( 0, bModified ? 1 : 0 );
+         else                                emit sourceMask( srcMask, enabledMask );
+      }
+      p.end();
+   }
+
+   QPainter painter(this);
+   if ( e!= 0 )
+   {
+      painter.drawPixmap(0,0, m_pixmap);
+   }
+
+   int topLineYOffset = fontHeight + 3;
+   int xOffset = fontWidth * leftInfoWidth;
+   int yOffset = ( m_cursorYPos - m_firstLine ) * fontHeight + topLineYOffset;
+   int xCursor = ( m_cursorXPos - m_firstColumn ) * fontWidth + xOffset;
+
+   if ( e!= 0 )
+      painter.drawPixmap(0,0, m_pixmap);
+   else
+      painter.drawPixmap(xCursor-2, yOffset, m_pixmap,
+                         xCursor-2, yOffset, 5, fontAscent+2 );
+
+
+   if ( m_bCursorOn && hasFocus() && m_cursorYPos>=m_firstLine )
+   {
+      int topLineYOffset = fontHeight + 3;
+      int xOffset = fontWidth * leftInfoWidth;
+
+      int yOffset = ( m_cursorYPos-m_firstLine ) * fontHeight + topLineYOffset;
+
+      int xCursor = ( m_cursorXPos - m_firstColumn ) * fontWidth + xOffset;
+      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::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 = fontHeight + 3;
+
+   int yOffset = topLineYOffset - m_firstLine * fontHeight;
+
+   line = min2( ( y - yOffset ) / fontHeight, m_nofLines-1 );
+   pos  = ( 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() == LeftButton;
+   bool bMMB = e->button() == MidButton;
+   bool bRMB = e->button() == 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() & 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();
+   }
+}
+
+void MergeResultWindow::mouseDoubleClickEvent( QMouseEvent* e )
+{
+   if ( e->button() == 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
+
+      int size;
+      MergeLineList::iterator mlIt;
+      MergeEditLineList::iterator melIt;
+      calcIteratorFromLineNr( line, mlIt, melIt );
+      const char* s = melIt->getString( this, size );
+
+      if ( s!=0 && size>0 )
+      {
+         int pos1, pos2;
+
+         calcTokenPos( s, size, pos, pos1, pos2 );
+
+         resetSelection();
+         m_selection.start( line, convertToPosOnScreen( s, pos1 ) );
+         m_selection.end( line, convertToPosOnScreen( s, pos2 ) );
+
+         update();
+         // emit selectionEnd() happens in the mouseReleaseEvent.
+      }
+   }
+}
+
+void MergeResultWindow::mouseReleaseEvent ( QMouseEvent * e )
+{
+   if ( e->button() == LeftButton )
+   {
+      killTimers();
+
+      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 fontHeight = fm.height();
+      int fontWidth = fm.width('W');
+      int topLineYOffset = fontHeight + 3;
+      int deltaX=0;
+      int deltaY=0;
+      if ( e->x() < leftInfoWidth*fontWidth )       deltaX=-1;
+      if ( e->x() > width()     )       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() )
+      paintEvent(0);
+
+   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 );
+
+   int stringLength;
+   const char* ps = melIt->getString( this, stringLength );
+   int x = convertToPosInText( ps, stringLength, m_cursorXPos );
+
+   bool bCtrl  = ( e->state() & ControlButton ) != 0 ;
+   bool bShift = ( e->state() & ShiftButton   ) != 0 ;
+   #ifdef _WIN32
+   bool bAlt   = ( e->state() & AltButton     ) != 0 ;
+   if ( bCtrl && bAlt ){ bCtrl=false; bAlt=false; }  // AltGr-Key pressed.
+   #endif
+
+   bool bYMoveKey = false;
+   // Special keys
+   switch ( e->key() )
+   {
+      case  Key_Escape:       break;
+      //case  Key_Tab:          break;
+      case  Key_Backtab:      break;
+      case  Key_Delete:
+      {
+         if ( deleteSelection2( ps, stringLength, x, y, mlIt, melIt )) break;
+         if( !melIt->isEditableText() )  break;
+         if (x>=stringLength)
+         {
+            if ( y<m_nofLines-1 )
+            {
+               setModified();
+               QCString s1( ps, stringLength+1 );
+               MergeLineList::iterator mlIt1;
+               MergeEditLineList::iterator melIt1;
+               calcIteratorFromLineNr( y+1, mlIt1, melIt1 );
+               if ( melIt1->isEditableText() )
+               {
+                  int stringLength1;
+                  ps = melIt1->getString( this, stringLength1 );
+                  assert(ps!=0);
+                  QCString s2( ps, stringLength1+1 );
+                  melIt->setString( s1 + s2 );
+
+                  // Remove the line
+                  if ( mlIt1->mergeEditLineList.size()>1 )
+                     mlIt1->mergeEditLineList.erase( melIt1 );
+                  else
+                     melIt1->setRemoved();
+               }
+            }
+         }
+         else
+         {
+            QCString s( ps, x+1 );
+            s += QCString( ps+x+1, stringLength - x );
+            melIt->setString( s );
+            setModified();
+         }
+         break;
+      }
+      case  Key_Backspace:
+      {
+         if ( deleteSelection2( ps, stringLength, x, y, mlIt, melIt )) break;
+         if( !melIt->isEditableText() )  break;
+         if (x==0)
+         {
+            if ( y>0 )
+            {
+               setModified();
+               QCString s2( ps, stringLength+1 );
+               MergeLineList::iterator mlIt1;
+               MergeEditLineList::iterator melIt1;
+               calcIteratorFromLineNr( y-1, mlIt1, melIt1 );
+               if ( melIt1->isEditableText() )
+               {
+                  int stringLength1;
+                  ps = melIt1->getString( this, stringLength1 );
+                  QCString s1( ps, stringLength1+1 );
+                  melIt1->setString( s1 + s2 );
+
+                  // Remove the previous line
+                  if ( mlIt->mergeEditLineList.size()>1 )
+                     mlIt->mergeEditLineList.erase( melIt );
+                  else
+                     melIt->setRemoved();
+
+                  --y;
+                  x=stringLength1;
+               }
+            }
+         }
+         else
+         {
+            QCString s( ps, x );
+            s += QCString( ps+x, stringLength - x + 1 );
+            --x;
+            melIt->setString( s );
+            setModified();
+         }
+         break;
+      }
+      case  Key_Return:
+      case  Key_Enter:
+      {
+         if( !melIt->isEditableText() )  break;
+         deleteSelection2( ps, stringLength, x, y, mlIt, melIt );
+         setModified();
+         QCString indentation;
+         if ( m_pOptionDialog->m_bAutoIndentation )
+         {  // calc last indentation
+            MergeLineList::iterator mlIt1 = mlIt;
+            MergeEditLineList::iterator melIt1 = melIt;
+            for(;;) {
+               int size;
+               const char* s = melIt1->getString(this, size);
+               if ( s!=0 ) {
+                  int i;
+                  for( i=0; i<size; ++i ){ if(s[i]!=' ' && s[i]!='\t') break; }
+                  if (i<size) {
+                     indentation = QCString( s, i+1 );
+                     break;
+                  }
+               }
+               --melIt1;
+               if ( melIt1 == mlIt1->mergeEditLineList.end() ) {
+                  --mlIt1;
+                  if ( mlIt1 == m_mergeLineList.end() ) break;
+                  melIt1 = mlIt1->mergeEditLineList.end();
+                  --melIt1;
+               }
+            }
+         }
+         MergeEditLine mel;
+         mel.setString( indentation + QCString( ps+x, stringLength - x + 1 ) );
+
+         if ( x<stringLength ) // Cut off the old line.
+         {
+            // Since ps possibly points into melIt->str, first copy it into a temporary.
+            QCString temp = QCString( ps, x + 1 );
+            melIt->setString( temp );
+         }
+
+         ++melIt;
+         mlIt->mergeEditLineList.insert( melIt, mel );
+         x=indentation.length();
+         ++y;
+         break;
+      }
+      case  Key_Insert:   m_bInsertMode = !m_bInsertMode;    break;
+      case  Key_Pause:        break;
+      case  Key_Print:        break;
+      case  Key_SysReq:       break;
+      case  Key_Home:     x=0;        if(bCtrl){y=0;      }  break;   // cursor movement
+      case  Key_End:      x=INT_MAX;  if(bCtrl){y=INT_MAX;}  break;
+
+      case  Key_Left:
+         if ( !bCtrl )
+         {
+            --x;
+            if(x<0 && y>0){--y; x=INT_MAX;}
+         }
+         else
+         {
+            while( x>0  &&  (ps[x-1]==' ' || ps[x-1]=='\t') ) --x;
+            while( x>0  &&  (ps[x-1]!=' ' && ps[x-1]!='\t') ) --x;
+         }
+         break;
+
+      case  Key_Right:
+         if ( !bCtrl )
+         {
+            ++x;  if(x>stringLength && y<m_nofLines-1){ ++y; x=0; }
+         }
+
+         else
+         {
+            while( x<stringLength  &&  (ps[x]==' ' || ps[x]=='\t') ) ++x;
+            while( x<stringLength  &&  (ps[x]!=' ' && ps[x]!='\t') ) ++x;
+         }
+         break;
+
+      case  Key_Up:       --y;                     bYMoveKey=true;   break;
+      case  Key_Down:     ++y;                     bYMoveKey=true;    break;
+      case  Key_PageUp:   y-=getNofVisibleLines(); bYMoveKey=true;    break;
+      case  Key_PageDown: 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( ps, stringLength, x, y, mlIt, melIt );
+
+               setModified();
+               // Characters to insert
+               QCString s( ps, stringLength+1 );
+               if ( t[0]=='\t' && m_pOptionDialog->m_bReplaceTabs )
+               {
+                  int spaces = (m_cursorXPos / g_tabSize + 1)*g_tabSize - m_cursorXPos;
+                  t.fill( ' ', spaces );
+               }
+               if ( m_bInsertMode )
+                  s.insert( x, t.ascii() );
+               else
+                  s.replace( x, t.length(), t.ascii() );
+
+               melIt->setString( s );
+               x += t.length();
+               bShift = false;
+            }
+         }
+      }
+   }
+
+   y = minMaxLimiter( y, 0, m_nofLines-1 );
+
+   calcIteratorFromLineNr( y, mlIt, melIt );
+   ps = melIt->getString( this, stringLength );
+
+   x = minMaxLimiter( x, 0, stringLength );
+
+   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( ps, stringLength, m_cursorOldXPos );
+
+   int xOnScreen = convertToPosOnScreen( ps, x );
+   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())
+            {
+               int size;
+               const char* pLine = mel.getString( this, size );
+
+               // Consider tabs
+
+               for( int i=0; i<size; ++i )
+               {
+                  int spaces = 1;
+                  if ( pLine[i]=='\t' )
+                  {
+                     spaces = tabber( outPos, g_tabSize );
+                  }
+
+                  if( m_selection.within( line, outPos ) )
+                  {
+                    selectionString += pLine[i];
+                  }
+
+                  outPos += spaces;
+               }
+            }
+            else if ( mel.isConflict() )
+            {
+               selectionString += "<Merge Conflict>";
+            }
+            
+            if( m_selection.within( line, outPos ) )
+            {
+               #ifdef _WIN32
+               selectionString += '\r';
+               #endif
+               selectionString += '\n';
+            }
+         }
+
+         ++line;
+      }
+   }
+
+   return selectionString;
+}
+
+bool MergeResultWindow::deleteSelection2( const char*& ps, int& stringLength, 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 );
+      ps = melIt->getString( this, stringLength );
+      x = convertToPosInText( ps, stringLength, m_cursorXPos );
+      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;
+   QCString 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) )
+         {
+            int size;
+            const char* pLine = mel.getString( this, size );
+
+            int firstPosInLine = m_selection.firstPosInLine(line);
+            int lastPosInLine = m_selection.lastPosInLine(line);
+
+            if ( line==firstLine )
+            {
+               mlItFirst = mlIt;
+               melItFirst = melIt;
+               int pos = convertToPosInText( pLine, size, firstPosInLine );
+               firstLineString = QCString( pLine, pos+1 );
+            }
+
+            if ( line==lastLine )
+            {
+               // This is the last line in the selection
+               int pos = convertToPosInText( pLine, size, lastPosInLine );
+               firstLineString += QCString( pLine+pos, 1+max2( 0,size-pos));
+               melItFirst->setString( firstLineString );
+            }
+
+            if ( line!=firstLine )
+            {
+               // Remove the line
+               if ( mlIt->mergeEditLineList.size()>1 )
+               {   mlIt->mergeEditLineList.erase( melIt ); --m_nofLines; }
+               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()
+{
+   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;
+   int stringLength;
+   const char* ps = melIt->getString( this, stringLength );
+   int x = convertToPosInText( ps, stringLength, m_cursorXPos );
+
+   QString clipBoard = QApplication::clipboard()->text();
+
+   QCString currentLine = QCString( ps, x+1 );
+   QCString endOfLine = QCString( ps+x, stringLength-x+1 );
+   int i;
+   for( i=0; i<(int)clipBoard.length(); ++i )
+   {
+      QChar uc = clipBoard[i];
+      char c = uc;
+      if ( c == '\r' ) continue;
+      if ( c == '\n' )
+      {
+         melIt->setString( currentLine );
+
+         melIt = mlIt->mergeEditLineList.insert( melItAfter, MergeEditLine() );
+         currentLine = "";
+         x=0;
+         ++y;
+      }
+      else
+      {
+         currentLine += c;
+         ++x;
+      }
+   }
+
+   currentLine += endOfLine;
+   melIt->setString( currentLine );
+
+   m_cursorYPos = y;
+   m_cursorXPos = convertToPosOnScreen( currentLine, x );
+   m_cursorOldXPos = m_cursorXPos;
+
+   update();
+}
+
+void MergeResultWindow::resetSelection()
+{
+   m_selection.reset();
+   update();
+}
+
+void MergeResultWindow::setModified()
+{
+   if (!m_bModified)
+   {
+      m_bModified = true;
+      emit modified();
+   }
+}
+
+/// Saves and returns true when successful.
+bool MergeResultWindow::saveDocument( const QString& fileName )
+{
+   m_fileName = fileName;
+
+   // Are still conflicts somewhere?
+   if ( getNrOfUnsolvedConflicts()>0 )
+   {
+      KMessageBox::error( this,
+         i18n("Not all conflicts are solved yet.\n"
+              "File not saved.\n"),
+         i18n("There are 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\nFile not saved."), i18n("File save error.") );
+         return false;
+      }
+   }
+
+   // Loop twice over all data: First to calculate the needed size,
+   // then alloc memory and in the second loop copy the data into the memory.
+   long neededBufferSize = 0;
+   long dataIndex = 0;
+   QByteArray dataArray;
+   for ( int i=0; i<2; ++i )
+   {
+      if(i==1)
+      {
+         if ( ! dataArray.resize(neededBufferSize) )
+         {
+            KMessageBox::error(this, i18n("Out of memory while preparing to save.") );
+            return false;
+         }
+      }
+
+      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() )
+            {
+               int size;
+               const char* pLine = mel.getString( this, size );
+
+               QCString s(pLine, size+1);
+
+               if (line>0) // Prepend line feed, but not for first line
+               {
+                  #ifdef _WIN32
+                  s.prepend("\r\n"); size+=2;
+                  #else
+                  s.prepend("\n");   size+=1;
+                  #endif
+               }
+
+               if (i==0) neededBufferSize += size;
+               else
+               {
+                  memcpy( dataArray.data() + dataIndex, s, size );
+                  dataIndex+=size;
+               }
+            }
+
+            ++line;
+         }
+      }
+   }
+   bool bSuccess = file.writeFile( dataArray.data(), neededBufferSize );
+   if ( ! bSuccess )
+   {
+      KMessageBox::error( this, i18n("Error while writing."), i18n("File save error.") );
+      return false;
+   }
+   g_pProgressDialog->hide();
+
+   m_bModified = false;
+   update();
+
+   return true;
+}
+
+QCString MergeResultWindow::getString( int lineIdx )
+{
+   MergeResultWindow::MergeLineList::iterator mlIt;
+   MergeResultWindow::MergeEditLineList::iterator melIt;
+   calcIteratorFromLineNr( lineIdx, mlIt, melIt );
+   int length=0;   
+   const char* p = melIt->getString( this, length );
+   QCString line( p, length+1 );
+   return line;
+}
+
+bool MergeResultWindow::findString( const QCString& 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 )
+   {
+      QCString 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 )
+{
+   m_selection.reset();
+   m_selection.start( firstLine, convertToPosOnScreen( getString(firstLine), startPos ) );
+   m_selection.end( lastLine, convertToPosOnScreen( getString(lastLine), endPos ) );
+   update();
+}
+
+
+Overview::Overview( QWidget* pParent, OptionDialog* pOptions )
+: QWidget( pParent, 0, WRepaintNoErase )
+{
+   m_pDiff3LineList = 0;
+   m_pOptions = pOptions;
+   m_bTripleDiff = 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::setRange( int firstLine, int pageHeight )
+{
+   m_firstLine = firstLine;
+   m_pageHeight = pageHeight;
+   update();
+}
+void Overview::setFirstLine( int firstLine )
+{
+   m_firstLine = firstLine;
+   update();
+}
+
+void Overview::mousePressEvent( QMouseEvent* e )
+{
+   int h = height()-1;
+   int nofLines = m_pDiff3LineList->size();
+   int h1 = h * m_pageHeight / nofLines+3;
+   if ( h>0 )
+      emit setLine( ( e->y() - h1/2 )*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();
+   }
+}
+
+void Overview::paintEvent( QPaintEvent* )
+{
+   if (m_pDiff3LineList==0 || !m_bPaintingAllowed ) return;
+   int h = height()-1;
+   int w = width();
+   int nofLines = m_pDiff3LineList->size();
+
+   if ( m_pixmap.size() != size() )
+   {
+      m_pixmap.resize( size() );
+
+      QPainter p(&m_pixmap);
+
+      p.fillRect( rect(), m_pOptions->m_bgColor );
+      p.setPen(black);
+      p.drawLine( 0, 0, 0, h );
+
+      if (nofLines==0) return;
+
+      int line = 0;
+      int oldY = 0;
+      int oldConflictY = -1;
+      Diff3LineList::const_iterator i;
+      for( i = m_pDiff3LineList->begin(); i!= m_pDiff3LineList->end(); ++i )
+      {
+         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;
+         bool bWhiteSpaceChange = false;
+         //if( bConflict )  c=m_pOptions->m_colorForConflict;
+         //else
+         {
+            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;
+            }
+         }
+
+         // Make sure that lines with conflict are not overwritten.
+         if (  c == m_pOptions->m_colorForConflict )
+         {
+            p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
+            oldConflictY = oldY;
+         }
+         else if ( c!=m_pOptions->m_bgColor  &&  oldY>oldConflictY )
+         {
+            p.fillRect(1, oldY, w, max2(1,y-oldY), bWhiteSpaceChange ? QBrush(c,Dense4Pattern) : c );
+         }
+
+         oldY = y;
+
+         ++line;
+      }
+   }
+
+   QPainter painter( this );
+   painter.drawPixmap( 0,0, m_pixmap );
+
+   int y1 = h * m_firstLine / nofLines-1;
+   int h1 = h * m_pageHeight / nofLines+3;
+   painter.setPen(black);
+   painter.drawRect( 1, y1, w-1, h1 );
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/optiondialog.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,720 @@
+/*
+ *   kdiff3 - Text Diff And Merge Tool
+ *   This file only: Copyright (C) 2002  Joachim Eibl, joachim.eibl@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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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 <kapplication.h>
+#include <kcolorbtn.h>
+#include <kfontdialog.h> // For KFontChooser
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+//#include <kkeydialog.h>
+
+#include "optiondialog.h"
+#include "diff.h"
+
+void OptionDialog::addOptionItem(OptionItem* p)
+{
+   m_optionItemList.push_back(p);
+}
+
+class OptionItem
+{
+public:
+   OptionItem( OptionDialog* pOptionDialog, 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(KConfig*)=0;
+   virtual void read(KConfig*)=0;
+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(KConfig* config){ config->writeEntry(m_saveName, *m_pbVar );   }
+   void read (KConfig* 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 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(KConfig* config){ config->writeEntry(m_saveName, *m_pVar );   }
+   void read (KConfig* 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 QLineEdit, public OptionItem
+{
+public:
+   OptionLineEdit( const QString& defaultVal, const QString& saveName, QString* pVar,
+                   QWidget* pParent, OptionDialog* pOD )
+   : QLineEdit( pParent ), OptionItem( pOD, saveName )
+   {
+      m_pVar = pVar;
+      m_defaultVal = defaultVal;
+   }
+   void setToDefault(){ setText( m_defaultVal );      }
+   void setToCurrent(){ setText( *m_pVar );           }
+   void apply()       { *m_pVar = text();                              }
+   void write(KConfig* config){ config->writeEntry(m_saveName, *m_pVar );   }
+   void read (KConfig* config){ *m_pVar = config->readEntry( m_saveName, *m_pVar ); }
+private:
+   OptionLineEdit( const OptionLineEdit& ); // private copy constructor without implementation
+   QString* m_pVar;
+   QString m_defaultVal;
+};
+
+#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(KConfig* config){ config->writeEntry(m_saveName, *m_pVar );   }
+   void read (KConfig* config){ *m_pVar = config->readNumEntry( m_saveName, *m_pVar ); }
+private:
+   OptionIntEdit( const OptionIntEdit& ); // private copy constructor without implementation
+   int* m_pVar;
+   int m_defaultVal;
+};
+
+
+OptionDialog::OptionDialog( bool bShowDirMergeSettings, QWidget *parent, char *name )
+  :KDialogBase( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel,
+                Ok, parent, name, true /*modal*/, true )
+{
+  setHelp( "kdiff3/index.html", QString::null );
+
+  setupFontPage();
+  setupColorPage();
+  setupEditPage();
+  setupDiffPage();
+  if (bShowDirMergeSettings)
+     setupDirectoryMergePage();
+  //setupKeysPage();
+
+  // Initialize all values in the dialog
+  resetToDefaults();
+  slotApply();
+}
+
+OptionDialog::~OptionDialog( void )
+{
+}
+
+
+void OptionDialog::setupFontPage( void )
+{
+   QFrame *page = addPage( i18n("Font"), i18n("Editor and diff output font" ),
+                             BarIcon("fonts", KIcon::SizeMedium ) );
+
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+   
+   m_fontChooser = new KFontChooser( page,"font",true/*onlyFixed*/,QStringList(),false,6 );
+   topLayout->addWidget( m_fontChooser );
+
+   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 in editor and diff output"),
+     BarIcon("colorize", KIcon::SizeMedium ) );
+  QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+  QGridLayout *gbox = new QGridLayout( 7, 2 );
+  topLayout->addLayout(gbox);
+
+  QLabel* label;
+  int line = 0;
+
+  int depth = QColor::numBitPlanes();
+  bool bLowColor = depth<=8;
+
+  OptionColorButton* pFgColor = new OptionColorButton( 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( 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( lightGray, "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( 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;
+
+  topLayout->addStretch(10);
+}
+
+
+void OptionDialog::setupEditPage( void )
+{
+   QFrame *page = addPage( i18n("Editor Settings"), i18n("Editor behaviour"),
+                           BarIcon("edit", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 4, 2 );
+   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;
+
+   topLayout->addStretch(10);
+}
+
+
+void OptionDialog::setupDiffPage( void )
+{
+   QFrame *page = addPage( i18n("Diff & Merge Settings"), i18n("Diff & Merge Settings"),
+                           BarIcon("misc", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 3, 2 );
+   topLayout->addLayout( gbox );
+   int line=0;
+
+   OptionCheckBox* pIgnoreWhiteSpace = new OptionCheckBox( i18n("Ignore white space"), true, "IgnoreWhiteSpace", &m_bIgnoreWhiteSpace, page, this );
+   gbox->addMultiCellWidget( pIgnoreWhiteSpace, line, line, 0, 1 );
+   QToolTip::add( pIgnoreWhiteSpace, i18n(
+      "On: Text that differs only in white space will match and\n"
+      "be shown on the same line in the different output windows.\n"
+      "Off is useful when whitespace is very important.\n"
+      "On is good for C/C++ and similar languages." )
+      );
+   ++line;
+
+   OptionCheckBox* pPreserveCarriageReturn = new OptionCheckBox( i18n("Preserve Carriage Return"), false, "PreserveCarriageReturn", &m_bPreserveCarriageReturn, page, this );
+   gbox->addMultiCellWidget( pPreserveCarriageReturn, line, line, 0, 1 );
+   QToolTip::add( pPreserveCarriageReturn,
+      "Show carriage return characters '\\r' if they exist.\n"
+      "Helps to compare files that were modified under different operating systems."
+      );
+   ++line;
+
+   OptionCheckBox* pIgnoreNumbers = new OptionCheckBox( i18n("Ignore Numbers"), false, "IgnoreNumbers", &m_bIgnoreNumbers, page, this );
+   gbox->addMultiCellWidget( pIgnoreNumbers, line, line, 0, 1 );
+   QToolTip::add( pIgnoreNumbers,
+      "Ignore number characters during line matching phase. (Similar to Ignore white space.)\n"
+      "Might help to compare files with numeric data."
+      );
+   ++line;
+
+   OptionCheckBox* pUpCase = new OptionCheckBox( i18n("Convert to Upper Case"), false, "UpCase", &m_bUpCase, page, this );
+   gbox->addMultiCellWidget( pUpCase, line, line, 0, 1 );
+   QToolTip::add( pUpCase,
+      "Turn all lower case characters to upper case on reading. (e.g.: 'a'->'A')"
+      );
+   ++line;
+
+   QLabel* 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* pUseExternalDiff = new OptionCheckBox( i18n("Use external diff"), true, "UseExternalDiff", &m_bUseExternalDiff, page, this );
+   gbox->addMultiCellWidget( pUseExternalDiff, line, line, 0, 1 );
+   QToolTip::add( pUseExternalDiff,
+      "Since for complicated files the internal algorithm is not so good yet,\n"
+      "you probably want to use the normal diff tool as line matcher."
+      );
+   ++line;
+
+   OptionCheckBox* pTryHard = new OptionCheckBox( i18n("Try Hard (slow)"), true, "TryHard", &m_bTryHard, page, this );
+   gbox->addMultiCellWidget( pTryHard, line, line, 0, 1 );
+   QToolTip::add( pTryHard,
+      "Enables the --minimal option for the external diff.\n"
+      "The analysis of big files will be much slower."
+      );
+   ++line;
+
+   OptionCheckBox* pIgnoreTrivialMatches = new OptionCheckBox( i18n("Ignore trivial matches"), true, "IgnoreTrivialMatches", &m_bIgnoreTrivialMatches, page, this );
+   gbox->addMultiCellWidget( pIgnoreTrivialMatches, line, line, 0, 1 );
+   QToolTip::add( pIgnoreTrivialMatches, i18n(
+      "When a difference was found, the algorithm searches for matching lines\n"
+      "Short or trivial lines match even when the differences still continue.\n"
+      "Ignoring trivial lines avoids this. Good for C/C++ and similar languages." )
+      );
+   ++line;
+
+   label = new QLabel( i18n("Max search length"), page );
+   gbox->addWidget( label, line, 0 );
+   OptionIntEdit* pMaxSearchLength = new OptionIntEdit( 1000, "MaxSearchLength", &m_maxSearchLength, 100, 100000, page, this );
+   gbox->addWidget( pMaxSearchLength, line, 1 );
+   QToolTip::add( label, i18n(
+      "Diff might fail for too small values but might take too long for big values.\n" )
+      );
+   ++line;
+
+   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pTryHard, SLOT(setEnabled(bool)));
+   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pMaxSearchLength, SLOT(setDisabled(bool)));
+
+   connect( pUseExternalDiff, SIGNAL( toggled(bool)), label, SLOT(setDisabled(bool)));
+   connect( pUseExternalDiff, SIGNAL( toggled(bool)), pIgnoreTrivialMatches, SLOT(setDisabled(bool)));
+
+   label = new QLabel( i18n("Auto Advance Delay (ms)"), page );
+   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::setupDirectoryMergePage( void )
+{
+   QFrame *page = addPage( i18n("Directory Merge Settings"), i18n("Directory Merge"),
+                           BarIcon("folder", KIcon::SizeMedium ) );
+   QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+
+   QGridLayout *gbox = new QGridLayout( 11, 2 );
+   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", "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", "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 CVS-Ignore"), 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;
+
+   OptionCheckBox* pTrustDate = new OptionCheckBox( i18n("Trust the modification date. (Unsafe)."), false, "TrustDate", &m_bDmTrustDate, page, this );
+   gbox->addMultiCellWidget( pTrustDate, line, line, 0, 1 );
+   QToolTip::add( pTrustDate, i18n("Assume that files are equal if the modification date and file length are equal.\n"
+                                     "Useful for big directories or slow networks.") );
+   ++line;
+
+   // 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;
+
+   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);
+}
+
+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 my 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();
+   }
+
+   // FontConfigDlg
+   m_font = m_fontChooser->font();
+   
+   emit applyClicked();   
+}
+
+/** 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();
+   }
+
+   m_fontChooser->setFont( QFont("Courier", 10 ), true /*only fixed*/ );
+    
+   m_bAutoAdvance = false;
+   m_bShowWhiteSpace = true;
+   m_bShowLineNumbers = false;
+   m_bHorizDiffWindowSplitting = true;
+}
+
+/** 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();
+   }
+
+   m_fontChooser->setFont( m_font, true /*only fixed*/ );
+}
+
+void OptionDialog::saveOptions( KConfig* config )
+{
+   // No i18n()-Translations here!
+
+   config->setGroup("KDiff3 Options");
+
+   std::list<OptionItem*>::iterator i;
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->write(config);
+   }
+
+   // FontConfigDlg
+   config->writeEntry("Font",  m_font );
+
+   config->writeEntry("AutoAdvance", m_bAutoAdvance );
+   config->writeEntry("ShowWhiteSpace", m_bShowWhiteSpace );
+   config->writeEntry("ShowLineNumbers", m_bShowLineNumbers );
+   config->writeEntry("HorizDiffWindowSplitting", m_bHorizDiffWindowSplitting );
+
+   // Recent files (selectable in the OpenDialog)
+   config->writeEntry( "RecentAFiles", m_recentAFiles, '|' );
+   config->writeEntry( "RecentBFiles", m_recentBFiles, '|' );
+   config->writeEntry( "RecentCFiles", m_recentCFiles, '|' );
+   config->writeEntry( "RecentOutputFiles", m_recentOutputFiles, '|' );
+}
+
+void OptionDialog::readOptions( KConfig* config )
+{
+   // No i18n()-Translations here!
+
+   config->setGroup("KDiff3 Options");
+
+   std::list<OptionItem*>::iterator i;
+
+   for(i=m_optionItemList.begin(); i!=m_optionItemList.end(); ++i)
+   {
+      (*i)->read(config);
+   }
+
+   // Use the current values as default settings.
+
+   // FontConfigDlg
+   m_font = config->readFontEntry( "Font", &m_font);
+
+   // DiffConfigDlg
+
+   m_bAutoAdvance = config->readBoolEntry("AutoAdvance", m_bAutoAdvance );
+   m_bShowWhiteSpace = config->readBoolEntry("ShowWhiteSpace", m_bShowWhiteSpace );
+   m_bShowLineNumbers = config->readBoolEntry("ShowLineNumbers", m_bShowLineNumbers );
+   m_bHorizDiffWindowSplitting = config->readBoolEntry("HorizDiffWindowSplitting", m_bHorizDiffWindowSplitting);
+
+   // Recent files (selectable in the OpenDialog)
+   m_recentAFiles = config->readListEntry( "RecentAFiles", '|' );
+   m_recentBFiles = config->readListEntry( "RecentBFiles", '|' );
+   m_recentCFiles = config->readListEntry( "RecentCFiles", '|' );
+   m_recentOutputFiles = config->readListEntry( "RecentOutputFiles", '|' );
+
+   setState();
+}
+
+void OptionDialog::slotHelp( void )
+{
+   KDialogBase::slotHelp();
+}
+
+
+#include "optiondialog.moc"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/optiondialog.h	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,151 @@
+/*
+ *   kdiff3 - Text Diff And Merge Tool
+ *   This file only: Copyright (C) 2002  Joachim Eibl, joachim.eibl@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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#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>
+
+class OptionItem;
+class KKeyDialog;
+
+class OptionDialog : public KDialogBase
+{
+   Q_OBJECT
+
+public:
+
+    OptionDialog( bool bShowDirMergeSettings, QWidget *parent = 0, char *name = 0 );
+    ~OptionDialog( void );
+
+    // 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;
+
+    bool m_bReplaceTabs;
+    bool m_bAutoIndentation;
+    int  m_tabSize;
+    bool m_bAutoCopySelection;
+
+    bool m_bIgnoreTrivialMatches;
+    int  m_maxSearchLength;
+    bool m_bPreserveCarriageReturn;
+    bool m_bUseExternalDiff;
+    bool m_bTryHard;
+    bool m_bShowWhiteSpace;
+    bool m_bShowLineNumbers;
+    bool m_bHorizDiffWindowSplitting;
+
+    bool m_bIgnoreWhiteSpace;
+    bool m_bUpCase;
+    bool m_bIgnoreNumbers;
+    QString m_PreProcessorCmd;
+    QString m_LineMatchingPreProcessorCmd;
+
+    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_bDmTrustDate;
+    bool m_bDmCopyNewer;
+    bool m_bDmShowOnlyDeltas;
+    bool m_bDmUseCvsIgnore;
+    QString m_DmFilePattern;
+    QString m_DmFileAntiPattern;
+    QString m_DmDirAntiPattern;
+
+    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 );
+
+private:
+    void resetToDefaults();
+    
+    std::list<OptionItem*> m_optionItemList;
+    
+    // FontConfigDlg
+    KFontChooser *m_fontChooser;
+
+private:
+    void setupFontPage();
+    void setupColorPage();
+    void setupEditPage();
+    void setupDiffPage();
+    void setupDirectoryMergePage();
+    void setupKeysPage();
+};
+
+
+
+#endif
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/pdiff.cpp	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,1974 @@
+/***************************************************************************
+                          kdiff.cpp  -  description
+                             -------------------
+    begin                : Mon Mär 18 20:04:50 CET 2002
+    copyright            : (C) 2002 by Joachim Eibl
+    email                : joachim.eibl@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.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * $Log$
+ * Revision 1.1  2003/10/06 18:38:48  joachim99
+ * KDiff3 version 0.9.70
+ *                                                                   *
+ ***************************************************************************/
+
+#include "diff.h"
+#include "directorymergewindow.h"
+
+#include <iostream>
+#include <algorithm>
+#include <ctype.h>
+#include <qaccel.h>
+
+#include <kfiledialog.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 <qsplitter.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qvbuttongroup.h>
+#include <qradiobutton.h>
+#include <qdragobject.h>
+#include <assert.h>
+
+#include "kdiff3.h"
+#include "optiondialog.h"
+#include "fileaccess.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+//using namespace std;
+
+int g_tabSize = 8;
+bool g_bIgnoreWhiteSpace = true;
+bool g_bIgnoreTrivialMatches = true;
+
+
+QString createTempFile( const LineData* p, int size, bool bIgnoreWhiteSpace, bool bIgnoreNumbers )
+{
+   QString fileName = FileAccess::tempFileName();
+
+   QFile file( fileName );
+   bool bSuccess = file.open( IO_WriteOnly );
+   if ( !bSuccess ) return "";
+   for (int l=0; l<size; ++l)
+   {
+      // We don't want any white space in the diff output
+      QCString s( p[l].size+1 );
+      int is=0;
+      for(int j=0; j<p[l].size; ++j )
+      {
+         char c = p[l].pLine[j];
+         if ( !( bIgnoreWhiteSpace && isWhite( c )  ||
+                 bIgnoreNumbers    && (isdigit( c ) || c=='-' || c=='.' )
+               )
+            )
+         {
+            if ( c=='\0' )  // Replace zeros with something else.
+               s[is]=(char)0xFF;
+            else
+               s[is]=c;
+            ++is;
+         }
+      }
+      s[is]='\n';
+      ++is;
+      if( is != file.writeBlock( &s[0], is ) )
+         return "";
+   }
+   return fileName;
+}
+
+bool KDiff3App::runDiff( LineData* p1, int size1, LineData* p2, int size2, DiffList& diffList )
+{
+   diffList.clear();
+   //QString errorString;
+
+   if ( m_pOptionDialog->m_bUseExternalDiff )
+   {
+      bool bSuccess=false;
+
+      bool bIgnoreWhiteSpace = m_pOptionDialog->m_bIgnoreWhiteSpace;
+      bool bIgnoreNumbers = m_pOptionDialog->m_bIgnoreNumbers;
+
+      // Create two temp files (Remove all white spaces and carriage returns here)
+      // (Make sure that no existing files are overwritten.)
+      g_pProgressDialog->setSubCurrent(0);
+      QString fileName1 = createTempFile( p1, size1, bIgnoreWhiteSpace, bIgnoreNumbers );
+      g_pProgressDialog->setSubCurrent(0.25);
+      QString fileName2 = createTempFile( p2, size2, bIgnoreWhiteSpace, bIgnoreNumbers );
+      g_pProgressDialog->setSubCurrent(0.5);
+      QString fileNameOut = FileAccess::tempFileName();
+
+      if ( !fileName1.isEmpty() && !fileName2.isEmpty() )
+      {
+         QString cmd;
+#ifdef _WIN32
+         // Under Windows it's better to search for diff.exe
+         char buf[200];
+         int r= SearchPathA( 0, "diff.exe",  0, sizeof(buf), buf, 0 );
+
+         if (r!=0) { cmd = buf; }
+#else
+         // under Un*x I assume that a diff command is in the PATH
+         cmd = "diff";
+#endif
+         if ( !cmd.isEmpty() )
+         {
+            cmd += " -a ";     // -a = treat all files as text
+            if ( m_pOptionDialog->m_bTryHard )
+               cmd += "--minimal ";
+            //if ( m_pOptionDialog->m_bIgnoreWhiteSpace ) This I do myself, see below
+            //   cmd += "--ignore-all-space ";
+            cmd += fileName1+" "+fileName2+" >"+fileNameOut;
+            // Run diff
+            //int status1 = ::system( 0 ); // ==0 if shell not found
+            int status = ::system( cmd.ascii() );
+#ifdef WEXITSTATUS
+            status = WEXITSTATUS(status);
+#endif
+            //if (status<0)
+            //{
+            //   errorString = strerror( errno );
+            //}
+            bSuccess = status>=0 && status!=127;
+         }
+      }
+
+      g_pProgressDialog->setSubCurrent(0.75);
+
+      int currentLine1 = 0;
+      int currentLine2 = 0;
+      if ( bSuccess )
+      {
+         // Parse the output and create the difflist
+         QFile f( fileNameOut );
+         bSuccess = f.open(IO_ReadOnly);
+         if (bSuccess)
+         {
+            const QByteArray buf = f.readAll();
+            unsigned int bufSize=buf.size();
+            unsigned int pos=0;
+            for(pos=0;pos<bufSize;++pos)
+            {
+               unsigned int lineStart = pos;
+               // Find end of line
+               while( buf.at(pos)!='\n' && pos<bufSize )
+                  ++pos;
+
+               // parse it
+               char c = buf.at(lineStart);
+               if ( c == '>' || c == '-' || c=='<' )
+                  continue;  // Not interested in the data
+               else
+               {
+                  QCString line( &buf.at(lineStart), pos-lineStart+1 );
+                  int pa = line.find('a'); // add
+                  int pc = line.find('c'); // change
+                  int pd = line.find('d'); // delete
+                  int p = pa>0 ? pa : (pc > 0 ? pc : pd);
+                  if (p<0) break; // Unexpected error
+                  QCString left = line.left(p);
+                  QCString right = line.mid(p+1);
+                  int pcommaleft = left.find(',');
+                  int pcommaright = right.find(',');
+                  int l1top=-1, l1bottom=-1, l2top=-1, l2bottom=-1;
+                  if (pcommaleft>0)
+                  {
+                     l1top    = left.left(pcommaleft).toInt();
+                     l1bottom = left.mid(pcommaleft+1).toInt();
+                  }
+                  else
+                  {
+                     l1top    = left.toInt();
+                     l1bottom = l1top;
+                  }
+                  if (pcommaright>0)
+                  {
+                     l2top    = right.left(pcommaright).toInt();
+                     l2bottom = right.mid(pcommaright+1).toInt();
+                  }
+                  else
+                  {
+                     l2top    = right.toInt();
+                     l2bottom = l2top;
+                  }
+
+                  Diff d(0,0,0);
+
+                  if ( pa>0 )
+                  {
+                     d.nofEquals = l1top - currentLine1;
+                     d.diff1 = 0;
+                     d.diff2 = l2bottom - l2top + 1;
+                     assert( d.nofEquals == l2top - 1 - currentLine2 );
+                  }
+                  else if ( pd>0 )
+                  {
+                     d.nofEquals = l2top - currentLine2;
+                     d.diff1 = l1bottom - l1top + 1;
+                     d.diff2 = 0;
+                     assert( d.nofEquals == l1top - 1 - currentLine1 );
+                  }
+                  else if ( pc>0 )
+                  {
+                     d.nofEquals = l1top - 1 - currentLine1;
+                     d.diff1 = l1bottom - l1top + 1;
+                     d.diff2 = l2bottom - l2top + 1;
+                     assert( d.nofEquals == l2top - 1 - currentLine2 );
+                  }
+                  else
+                     assert(false);
+
+                  currentLine1 += d.nofEquals + d.diff1;
+                  currentLine2 += d.nofEquals + d.diff2;
+                  diffList.push_back(d);
+               }
+            }
+            if (size1-currentLine1==size2-currentLine2 )
+            {
+               Diff d( size1-currentLine1,0,0);
+               diffList.push_back(d);
+               currentLine1=size1;
+               currentLine2=size2;
+            }
+
+            if ( currentLine1 == size1 && currentLine2 == size2 )
+               bSuccess = true;
+         }
+      }
+      if ( currentLine1==0 && currentLine2==0 )
+      {
+         Diff d( 0, size1, size2 );
+         diffList.push_back(d);
+      }
+
+      FileAccess::removeFile( fileName1 );
+      FileAccess::removeFile( fileName2 );
+      FileAccess::removeFile( fileNameOut );
+      g_pProgressDialog->setSubCurrent(1.0);
+
+      if ( !bSuccess )
+      {
+         KMessageBox::sorry(this,
+            i18n("Running the external diff failed.\n"
+                 "Check if the diff works, if the program can write in the temp folder or if the disk is full.\n"
+                 "The external diff option will be disabled now and the internal diff will be used."),
+            i18n("KDiff3 Warning"));
+         m_pOptionDialog->m_bUseExternalDiff = false;
+      }
+   }
+
+   if ( ! m_pOptionDialog->m_bUseExternalDiff )
+   {
+      g_pProgressDialog->setSubCurrent(0.0);
+      if ( size1>0 && p1!=0 && p1->occurances==0 )
+      {
+         prepareOccurances( p1, size1 );
+      }
+      g_pProgressDialog->setSubCurrent(0.25);
+
+      if ( size2>0 && p2!=0 && p2->occurances==0 )
+      {
+         prepareOccurances( p2, size2 );
+      }
+      g_pProgressDialog->setSubCurrent(0.5);
+
+      calcDiff( p1, size1, p2, size2, diffList, 2, m_pOptionDialog->m_maxSearchLength );
+
+      g_pProgressDialog->setSubCurrent(1.0);
+   }
+   return true;
+}
+
+
+void KDiff3App::init( bool bAuto )
+{
+   bool bPreserveCarriageReturn = m_pOptionDialog->m_bPreserveCarriageReturn;
+
+   bool bVisibleMergeResultWindow = ! m_outputFilename.isEmpty();
+   if ( bVisibleMergeResultWindow )
+   {
+      bPreserveCarriageReturn = false;
+   }
+
+   g_bIgnoreWhiteSpace = m_pOptionDialog->m_bIgnoreWhiteSpace;
+   g_bIgnoreTrivialMatches = m_pOptionDialog->m_bIgnoreTrivialMatches;
+
+   m_diff3LineList.clear();
+
+   bool bUseLineMatchingPP = !m_pOptionDialog->m_LineMatchingPreProcessorCmd.isEmpty();
+   bool bUpCase = m_pOptionDialog->m_bUpCase;
+
+   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_sd3.isEmpty() )
+      g_pProgressDialog->setMaximum( 4 );  // Read 2 files, 1 comparison, 1 finediff
+   else
+      g_pProgressDialog->setMaximum( 9 );  // Read 3 files, 3 comparisons, 3 finediffs
+
+   g_pProgressDialog->start();
+
+   // First get all input data.
+   g_pProgressDialog->setInformation(i18n("Loading A"));
+   m_sd1.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
+   m_sdlm1.readLMPPFile( &m_sd1, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase );
+   g_pProgressDialog->step();
+
+   g_pProgressDialog->setInformation(i18n("Loading B"));
+   m_sd2.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
+   m_sdlm2.readLMPPFile( &m_sd2, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase );
+   g_pProgressDialog->step();
+
+   m_sd3.m_bIsText = true;
+   int maxSearchLength = m_pOptionDialog->m_maxSearchLength;
+   m_totalDiffStatus.reset();
+   // Run the diff.
+   if ( m_sd3.isEmpty() )
+   {
+      m_totalDiffStatus.bBinaryAEqB = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd2.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd2.m_pBuf,m_sd1.m_size)==0);
+      g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
+      if ( !bUseLineMatchingPP )
+         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd2.m_v[0], m_sd2.m_vSize, m_diffList12 );
+      else
+         runDiff( &m_sdlm1.m_v[0], m_sdlm1.m_vSize, &m_sdlm2.m_v[0], m_sdlm2.m_vSize, m_diffList12 );
+
+      g_pProgressDialog->step();
+
+      g_pProgressDialog->setInformation(i18n("Linediff: A <-> B"));
+      calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
+      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], maxSearchLength, m_totalDiffStatus.bTextAEqB );
+      if ( m_sd1.m_size==0 ) m_totalDiffStatus.bTextAEqB=false;
+
+      g_pProgressDialog->step();
+   }
+   else
+   {
+      g_pProgressDialog->setInformation(i18n("Loading C"));
+      m_sd3.readPPFile( bPreserveCarriageReturn, m_pOptionDialog->m_PreProcessorCmd, bUpCase );
+      m_sdlm3.readLMPPFile( &m_sd3, m_pOptionDialog->m_LineMatchingPreProcessorCmd, bUpCase );
+      g_pProgressDialog->step();
+
+      m_totalDiffStatus.bBinaryAEqB = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd2.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd2.m_pBuf,m_sd1.m_size)==0);
+      m_totalDiffStatus.bBinaryAEqC = (m_sd1.m_size!=0 && m_sd1.m_size==m_sd3.m_size  &&  memcmp(m_sd1.m_pBuf,m_sd3.m_pBuf,m_sd1.m_size)==0);
+      m_totalDiffStatus.bBinaryBEqC = (m_sd3.m_size!=0 && m_sd3.m_size==m_sd2.m_size  &&  memcmp(m_sd3.m_pBuf,m_sd2.m_pBuf,m_sd3.m_size)==0);
+
+      if ( !bUseLineMatchingPP )
+      {
+         g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
+         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd2.m_v[0], m_sd2.m_vSize, m_diffList12 );
+         g_pProgressDialog->step();
+         g_pProgressDialog->setInformation(i18n("Diff: B <-> C"));
+         runDiff( &m_sd2.m_v[0], m_sd2.m_vSize, &m_sd3.m_v[0], m_sd3.m_vSize, m_diffList23 );
+         g_pProgressDialog->step();
+         g_pProgressDialog->setInformation(i18n("Diff: A <-> C"));
+         runDiff( &m_sd1.m_v[0], m_sd1.m_vSize, &m_sd3.m_v[0], m_sd3.m_vSize, m_diffList13 );
+         g_pProgressDialog->step();
+      }
+      else
+      {
+         g_pProgressDialog->setInformation(i18n("Diff: A <-> B"));
+         runDiff( &m_sdlm1.m_v[0], m_sd1.m_vSize, &m_sdlm2.m_v[0], m_sd2.m_vSize, m_diffList12 );
+         g_pProgressDialog->step();
+         g_pProgressDialog->setInformation(i18n("Diff: B <-> C"));
+         runDiff( &m_sdlm2.m_v[0], m_sd2.m_vSize, &m_sdlm3.m_v[0], m_sd3.m_vSize, m_diffList23 );
+         g_pProgressDialog->step();
+         g_pProgressDialog->setInformation(i18n("Diff: A <-> C"));
+         runDiff( &m_sdlm1.m_v[0], m_sd1.m_vSize, &m_sdlm3.m_v[0], m_sd3.m_vSize, m_diffList13 );
+         g_pProgressDialog->step();
+      }
+
+      calcDiff3LineListUsingAB( &m_diffList12, m_diff3LineList );
+      calcDiff3LineListUsingAC( &m_diffList13, m_diff3LineList );
+      calcDiff3LineListTrim( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
+
+      calcDiff3LineListUsingBC( &m_diffList23, m_diff3LineList );
+      calcDiff3LineListTrim( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
+      debugLineCheck( m_diff3LineList, m_sd1.m_vSize, 1 );
+      debugLineCheck( m_diff3LineList, m_sd2.m_vSize, 2 );
+      debugLineCheck( m_diff3LineList, m_sd3.m_vSize, 3 );
+
+      g_pProgressDialog->setInformation(i18n("Linediff: A <-> B"));
+      fineDiff( m_diff3LineList, 1, &m_sd1.m_v[0], &m_sd2.m_v[0], maxSearchLength, m_totalDiffStatus.bTextAEqB );
+      g_pProgressDialog->step();
+      g_pProgressDialog->setInformation(i18n("Linediff: B <-> C"));
+      fineDiff( m_diff3LineList, 2, &m_sd2.m_v[0], &m_sd3.m_v[0], maxSearchLength, m_totalDiffStatus.bTextBEqC );
+      g_pProgressDialog->step();
+      g_pProgressDialog->setInformation(i18n("Linediff: A <-> C"));
+      fineDiff( m_diff3LineList, 3, &m_sd3.m_v[0], &m_sd1.m_v[0], maxSearchLength, m_totalDiffStatus.bTextAEqC );
+      g_pProgressDialog->step();
+      if ( m_sd1.m_size==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextAEqC=false; }
+      if ( m_sd2.m_size==0 ) { m_totalDiffStatus.bTextAEqB=false;  m_totalDiffStatus.bTextBEqC=false; }
+   }
+   calcWhiteDiff3Lines( m_diff3LineList, &m_sd1.m_v[0], &m_sd2.m_v[0], &m_sd3.m_v[0] );
+   calcDiff3LineVector( m_diff3LineList, m_diff3LineVector );
+
+   // Calc needed lines for display
+   m_neededLines = m_diff3LineList.size();
+
+   m_pDirectoryMergeWindow->allowResizeEvents(false);
+   initView();
+   m_pDirectoryMergeWindow->allowResizeEvents(true);
+
+   m_bTripleDiff = ! m_sd3.isEmpty();
+
+   m_pDiffTextWindow1->init( m_sd1.getAliasName(),
+      &m_sd1.m_v[0], m_sd1.m_vSize, &m_diff3LineVector, 1, m_bTripleDiff );
+   m_pDiffTextWindow2->init( m_sd2.getAliasName(),
+      &m_sd2.m_v[0], m_sd2.m_vSize, &m_diff3LineVector, 2, m_bTripleDiff );
+   m_pDiffTextWindow3->init( m_sd3.getAliasName(),
+      &m_sd3.m_v[0], m_sd3.m_vSize, &m_diff3LineVector, 3, m_bTripleDiff );
+
+   if (m_bTripleDiff) m_pDiffTextWindow3->show();
+   else               m_pDiffTextWindow3->hide();
+
+   m_bOutputModified = bVisibleMergeResultWindow;
+
+   m_pMergeResultWindow->init(
+      &m_sd1.m_v[0],
+      &m_sd2.m_v[0],
+      m_bTripleDiff ? &m_sd3.m_v[0] : 0,
+      &m_diff3LineList,
+      &m_totalDiffStatus,
+      m_outputFilename.isEmpty() ? QString("unnamed.txt") : m_outputFilename
+      );
+
+   m_pOverview->init(&m_diff3LineList, m_bTripleDiff );
+   m_pDiffVScrollBar->setValue( 0 );
+   m_pHScrollBar->setValue( 0 );
+
+   g_pProgressDialog->hide();
+   m_pDiffTextWindow1->setPaintingAllowed( true );
+   m_pDiffTextWindow2->setPaintingAllowed( true );
+   m_pDiffTextWindow3->setPaintingAllowed( true );
+   m_pOverview->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;
+
+   if ( bVisibleMergeResultWindow && !bAuto )
+      m_pMergeResultWindow->showNrOfConflicts();
+   else if ( !bAuto )
+   {
+      QString totalInfo;
+      if ( m_totalDiffStatus.bBinaryAEqB && m_totalDiffStatus.bBinaryAEqC )
+         totalInfo += i18n("All input files are binary equal.");
+      else  if ( m_totalDiffStatus.bTextAEqB && m_totalDiffStatus.bTextAEqC )
+         totalInfo += i18n("All input files contain the same text.");
+      else {
+         if    ( m_totalDiffStatus.bBinaryAEqB ) totalInfo += i18n("Files A and B are binary equal.\n");
+         else if ( m_totalDiffStatus.bTextAEqB ) totalInfo += i18n("Files A and B have equal text. \n");
+         if    ( m_totalDiffStatus.bBinaryAEqC ) totalInfo += i18n("Files A and C are binary equal.\n");
+         else if ( m_totalDiffStatus.bTextAEqC ) totalInfo += i18n("Files A and C have equal text. \n");
+         if    ( m_totalDiffStatus.bBinaryBEqC ) totalInfo += i18n("Files B and C are binary equal.\n");
+         else if ( m_totalDiffStatus.bTextBEqC ) totalInfo += i18n("Files B and C have equal text. \n");
+      }
+
+      if ( !totalInfo.isEmpty() )
+         KMessageBox::information( this, totalInfo );
+   }
+
+   if ( bVisibleMergeResultWindow && (!m_sd1.m_bIsText || !m_sd2.m_bIsText || !m_sd3.m_bIsText) )
+   {
+      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.") );
+/*      QDialog d(this);
+      QVBoxLayout* l = new QVBoxLayout(&d);
+      QVButtonGroup* bg = new QVButtonGroup(i18n("Some file(s) don't seem to be text files:"),&d);
+      l->addWidget(bg);
+      new QRadioButton("A: " + m_sd1.getAliasName(), bg);
+      new QRadioButton("B: " + m_sd2.getAliasName(), bg);
+      if (!m_sd3.isEmpty()) new QRadioButton("C: " + m_sd3.getAliasName(), bg);
+      bg->setButton(0);
+      QHBoxLayout* hbl = new QHBoxLayout(l);
+      QPushButton* pSaveButton = new QPushButton( i18n("Save Selection"), &d );
+      connect( pSaveButton, SIGNAL(clicked()), &d, SLOT(accept()));
+      hbl->addWidget( pSaveButton );
+      QPushButton* pProceedButton = new QPushButton( i18n("Proceed with text-merge"), &d );
+      connect( pProceedButton, SIGNAL(clicked()), &d, SLOT(reject()));
+      hbl->addWidget( pProceedButton );
+
+      int result = d.exec();
+      if( result == QDialog::Accepted )
+      {
+         if      ( bg->find(0)->isOn() ) saveBuffer( m_sd1.m_pBuf, m_sd1.m_size, m_outputFilename );
+         else if ( bg->find(1)->isOn() ) saveBuffer( m_sd2.m_pBuf, m_sd2.m_size, m_outputFilename );
+         else                            saveBuffer( m_sd3.m_pBuf, m_sd3.m_size, m_outputFilename );
+      }*/
+   }
+
+   QTimer::singleShot( 10, this, SLOT(slotAfterFirstPaint()) );
+}
+
+
+void KDiff3App::resizeDiffTextWindow(int newWidth, int newHeight)
+{
+   m_DTWHeight = newHeight;
+   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->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 QFrame(m_pMainSplitter);
+   m_pMainWidget->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+   m_pMainWidget->setLineWidth(1);
+
+
+   QVBoxLayout* pVLayout = new QVBoxLayout(m_pMainWidget);
+
+   QSplitter* pVSplitter = new QSplitter( m_pMainWidget );
+   pVSplitter->setOrientation( Vertical );
+   pVLayout->addWidget( pVSplitter );
+
+   QWidget* pDiffWindowFrame = new QFrame( pVSplitter );
+   QHBoxLayout* pDiffHLayout = new QHBoxLayout( pDiffWindowFrame );
+
+   m_pDiffWindowSplitter = new QSplitter( pDiffWindowFrame );
+   m_pDiffWindowSplitter->setOrientation( m_pOptionDialog->m_bHorizDiffWindowSplitting ?  Horizontal : 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( Vertical, pDiffWindowFrame );
+   pDiffHLayout->addWidget( m_pDiffVScrollBar );
+
+   m_pDiffTextWindow1 = new DiffTextWindow( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog );
+   m_pDiffTextWindow2 = new DiffTextWindow( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog );
+   m_pDiffTextWindow3 = new DiffTextWindow( m_pDiffWindowSplitter, statusBar(), m_pOptionDialog );
+
+   // Merge window
+   m_pMergeWindowFrame = new QFrame( pVSplitter );
+   QHBoxLayout* pMergeHLayout = new QHBoxLayout( m_pMergeWindowFrame );
+
+   m_pMergeResultWindow = new MergeResultWindow( m_pMergeWindowFrame, m_pOptionDialog );
+   pMergeHLayout->addWidget( m_pMergeResultWindow );
+
+   m_pMergeVScrollBar = new QScrollBar( 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
+
+   QHBoxLayout* pHScrollBarLayout = new QHBoxLayout( pVLayout );
+   m_pHScrollBar = new QScrollBar( Horizontal, m_pMainWidget );
+   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(valueChanged(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(valueChanged(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(valueChanged(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(valueChanged(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( modified() ), this, SLOT( slotOutputModified() ) );
+   connect( p, SIGNAL( updateAvailabilities() ), this, SLOT( slotUpdateAvailabilities() ) );
+   connect( p, SIGNAL( showPopupMenu(const QPoint&) ), this, SLOT(showPopupMenu(const QPoint&)));
+   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( resizeSignal(int,int) ),this, SLOT(resizeDiffTextWindow(int,int)));
+
+   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 );
+}
+
+void KDiff3App::slotAfterFirstPaint()
+{
+   int newHeight = m_pDiffTextWindow1->getNofVisibleLines();
+   int newWidth  = m_pDiffTextWindow1->getNofVisibleColumns();
+   m_DTWHeight = newHeight;
+   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 );
+
+   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 Key_Down:   ++deltaY; break;
+       case Key_Up:     --deltaY; break;
+       case Key_PageDown: if (!bCtrl) deltaY+=pageSize; break;
+       case Key_PageUp:   if (!bCtrl) deltaY-=pageSize; break;
+       case Key_Left:     --deltaX;  break;
+       case Key_Right:    ++deltaX;  break;
+       case Key_Home: if ( bCtrl )  m_pDiffVScrollBar->setValue( 0 );
+                      else          m_pHScrollBar->setValue( 0 );
+                      break;
+       case 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();
+            bool bUpCase = m_pOptionDialog->m_bUpCase;
+            if      ( o == m_pDiffTextWindow1 ) m_sd1.setData(text, bUpCase);
+            else if ( o == m_pDiffTextWindow2 ) m_sd2.setData(text, bUpCase);
+            else if ( o == m_pDiffTextWindow3 ) m_sd3.setData(text, bUpCase);
+            init();
+         }
+      }
+
+      return true;
+   }
+   return QSplitter::eventFilter( o, e );    // standard event processing
+}
+
+
+
+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( "A (Base):", this );
+
+   m_lineA = new QComboBox( true, this );
+   m_lineA->insertStringList( m_pOptions->m_recentAFiles );
+   m_lineA->setEditText( KURL(n1).prettyURL() );
+   m_lineA->setMinimumSize( 200, m_lineA->size().height() );
+   QPushButton * button = new QPushButton( "File...", this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileA() ) );
+   QPushButton * button2 = new QPushButton( "Dir...", this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirA() ) );
+
+   h->addWidget( label,    0, 0 );
+   h->addWidget( m_lineA,  0, 1 );
+   h->addWidget( button,   0, 2 );
+   h->addWidget( button2,  0, 3 );
+
+   label    = new QLabel( "B:", this );
+   m_lineB  = new QComboBox( true, this );
+   m_lineB->insertStringList( m_pOptions->m_recentBFiles );
+   m_lineB->setEditText( KURL(n2).prettyURL() );
+   m_lineB->setMinimumSize( 200, m_lineB->size().height() );
+   button   = new QPushButton( "File...", this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileB() ) );
+   button2   = new QPushButton( "Dir...", this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirB() ) );
+
+   h->addWidget( label,     1, 0 );
+   h->addWidget( m_lineB,   1, 1 );
+   h->addWidget( button,    1, 2 );
+   h->addWidget( button2,   1, 3 );
+
+   label  = new QLabel( "C (Optional):", this );
+   m_lineC= new QComboBox( true, this );
+   m_lineC->insertStringList( m_pOptions->m_recentCFiles );
+   m_lineC->setEditText( KURL(n3).prettyURL() );
+   m_lineC->setMinimumSize( 200, m_lineC->size().height() );
+   button = new QPushButton( "File...", this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectFileC() ) );
+   button2   = new QPushButton( "Dir...", this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectDirC() ) );
+
+   h->addWidget( label,     2, 0 );
+   h->addWidget( m_lineC,   2, 1 );
+   h->addWidget( button,    2, 2 );
+   h->addWidget( button2,   2, 3 );
+
+   m_pMerge = new QCheckBox( "Merge", this );
+   h->addWidget( m_pMerge, 3, 0 );
+
+   label  = new QLabel( "Output (Optional):", this );
+   m_lineOut = new QComboBox( true, this );
+   m_lineOut->insertStringList( m_pOptions->m_recentOutputFiles );
+   m_lineOut->setEditText( KURL(outputName).prettyURL() );
+   m_lineOut->setMinimumSize( 200, m_lineOut->size().height() );
+   button = new QPushButton( "File...", this );
+   connect( button, SIGNAL(clicked()), this, SLOT( selectOutputName() ) );
+   button2   = new QPushButton( "Dir...", this );
+   connect( button2, SIGNAL(clicked()), this, SLOT( selectOutputDir() ) );
+   connect( m_pMerge, SIGNAL(stateChanged(int)), this, SLOT(internalSlot(int)) );
+   connect( this, SIGNAL(internalSignal(bool)), m_lineOut, SLOT(setEnabled(bool)) );
+   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_lineOutput->setEnabled( bMerge );
+
+//   button->setEnabled( bMerge );
+
+   h->addWidget( label,          4, 0 );
+   h->addWidget( m_lineOut,      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( "Ok", this );
+   button->setDefault( true );
+   connect( button, SIGNAL(clicked()), this, SLOT( accept() ) );
+   l->addWidget( button );
+
+   button = new QPushButton( "Cancel", this );
+   connect( button, SIGNAL(clicked()), this, SLOT( reject() ) );
+   l->addWidget( button );
+
+   button = new QPushButton( "Configure...", this );
+   connect( button, SIGNAL(clicked()), pParent, slotConfigure );
+   l->addWidget( button );
+
+   QSize sh = sizeHint();
+   setFixedHeight( sh.height() );
+}
+
+void OpenDialog::selectURL( QComboBox* pLine, bool bDir, int i, bool bSave )
+{
+   QString current = pLine->currentText();
+   if (current.isEmpty() && i>3 ){  current = m_lineC->currentText(); }
+   if (current.isEmpty()        ){  current = m_lineB->currentText(); }
+   if (current.isEmpty()        ){  current = m_lineA->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_lineA,    false, 1, false );  }
+void OpenDialog::selectFileB()     {  selectURL( m_lineB,    false, 2, false );  }
+void OpenDialog::selectFileC()     {  selectURL( m_lineC,    false, 3, false );  }
+void OpenDialog::selectOutputName(){  selectURL( m_lineOut,  false, 4, true );  }
+void OpenDialog::selectDirA()      {  selectURL( m_lineA,    true,  1, false );  }
+void OpenDialog::selectDirB()      {  selectURL( m_lineB,    true,  2, false );  }
+void OpenDialog::selectDirC()      {  selectURL( m_lineC,    true,  3, false );  }
+void OpenDialog::selectOutputDir() {  selectURL( m_lineOut,  true,  4, true );  }
+
+void OpenDialog::internalSlot(int i)
+{
+   emit internalSignal(i!=0);
+}
+
+void OpenDialog::accept()
+{
+   unsigned int maxNofRecentFiles = 10;
+
+   QString s = m_lineA->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() );
+
+   s = m_lineB->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() );
+
+   s = m_lineC->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() );
+
+   s = m_lineOut->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 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("Yes - Abort"), i18n("No - Continue merging") );
+      if ( result!=KMessageBox::Yes )
+         return;
+   }
+
+
+   slotStatusMsg(i18n("Opening files..."));
+
+   for(;;)
+   {
+      OpenDialog d(this,
+         m_sd1.m_bPreserve ? QString("") : m_sd1.getAliasName(),
+         m_sd2.m_bPreserve ? QString("") : m_sd2.getAliasName(),
+         m_sd3.m_bPreserve ? QString("") : m_sd3.getAliasName(),
+         !m_outputFilename.isEmpty(),
+         m_bDefaultFilename ? QString("") : m_outputFilename,
+         SLOT(slotConfigure()), m_pOptionDialog );
+      int status = d.exec();
+      if ( status == QDialog::Accepted )
+      {
+         m_sd1.setFilename( d.m_lineA->currentText() );
+         m_sd2.setFilename( d.m_lineB->currentText() );
+         m_sd3.setFilename( d.m_lineC->currentText() );
+
+         if( d.m_pMerge->isChecked() )
+         {
+            if ( d.m_lineOut->currentText().isEmpty() )
+            {
+               m_outputFilename = "unnamed.txt";
+               m_bDefaultFilename = true;
+            }
+            else
+            {
+               m_outputFilename = d.m_lineOut->currentText();
+               m_bDefaultFilename = false;
+            }
+         }
+         else
+            m_outputFilename = "";
+
+         m_bDirCompare = improveFilenames();
+         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.m_pBuf==0  ||
+                 ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
+                 ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+            {
+               QString text( i18n("Opening of these files failed:") );
+               text += "\n\n";
+               if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+                  text += " - " + m_sd1.getAliasName() + "\n";
+               if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+                  text += " - " + m_sd2.getAliasName() + "\n";
+               if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+                  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 )
+{
+   if ( !canContinue() ) 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 = improveFilenames();  // Using local bDirCompare is intended, because
+                                           // this method is called from the directory-merge-window.
+
+   if( bDirCompare )
+   {
+   }
+   else
+   {
+      init();
+
+      if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0  ||
+           ! m_sd2.isEmpty() && m_sd2.m_pBuf==0  ||
+           ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+      {
+         QString text( i18n("Opening of these files failed:") );
+         text += "\n\n";
+         if ( ! m_sd1.isEmpty() && m_sd1.m_pBuf==0 )
+            text += " - " + m_sd1.getAliasName() + "\n";
+         if ( ! m_sd2.isEmpty() && m_sd2.m_pBuf==0 )
+            text += " - " + m_sd2.getAliasName() + "\n";
+         if ( ! m_sd3.isEmpty() && m_sd3.m_pBuf==0 )
+            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::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 );
+   }
+
+   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 );
+   }
+
+   slotStatusMsg(i18n("Ready."));
+}
+
+void KDiff3App::slotEditPaste()
+{
+   slotStatusMsg(i18n("Inserting clipboard contents..."));
+
+   if ( m_pMergeResultWindow!=0 && m_pMergeResultWindow->isVisible() )
+   {
+      m_pMergeResultWindow->pasteClipboard();
+   }
+   else if ( canContinue() )
+   {
+      bool bUpCase = m_pOptionDialog->m_bUpCase;
+      if ( m_pDiffTextWindow1->hasFocus() )
+      {
+         m_sd1.setData( QApplication::clipboard()->text(), bUpCase );
+         init();
+      }
+      else if ( m_pDiffTextWindow2->hasFocus() )
+      {
+         m_sd2.setData( QApplication::clipboard()->text(), bUpCase );
+         init();
+      }
+      else if ( m_pDiffTextWindow3->hasFocus() )
+      {
+         m_sd3.setData( QApplication::clipboard()->text(), bUpCase );
+         init();
+      }
+   }
+
+   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::slotChooseA()
+{
+   if (m_pMergeResultWindow && ! m_bTimerBlock )  
+   {
+      m_pMergeResultWindow->slotChooseA();
+      if ( autoAdvance->isChecked() )
+      {
+         m_bTimerBlock = true;                  
+         QTimer::singleShot( m_pOptionDialog->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) );
+      }
+   }
+}
+void KDiff3App::slotChooseB()
+{
+   if ( m_pMergeResultWindow && ! m_bTimerBlock )
+   {
+      m_pMergeResultWindow->slotChooseB();
+      if ( autoAdvance->isChecked()  )
+      {
+         m_bTimerBlock = true;
+         QTimer::singleShot( m_pOptionDialog->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) );
+      }
+   }
+}
+void KDiff3App::slotChooseC()
+{
+   if ( m_pMergeResultWindow && ! m_bTimerBlock )  
+   {
+      m_pMergeResultWindow->slotChooseC();
+      if ( autoAdvance->isChecked() )
+      {
+         m_bTimerBlock = true;
+         QTimer::singleShot( m_pOptionDialog->m_autoAdvanceDelay, this, SLOT( slotGoNextUnsolvedConflict() ) );
+      }
+   }
+}
+void KDiff3App::slotChooseAEverywhere()
+{
+   if (m_pMergeResultWindow )
+   {
+      slotGoTop();
+      m_pMergeResultWindow->slotChooseAEverywhere();
+   }
+}
+void KDiff3App::slotChooseBEverywhere()
+{
+   if (m_pMergeResultWindow )
+   {
+      slotGoTop();
+      m_pMergeResultWindow->slotChooseBEverywhere();
+   }
+}
+
+void KDiff3App::slotChooseCEverywhere()
+{
+   if (m_pMergeResultWindow )
+   {
+      slotGoTop();
+      m_pMergeResultWindow->slotChooseCEverywhere();
+   }
+}
+
+void KDiff3App::slotAutoSolve()
+{
+   if (m_pMergeResultWindow )
+   {
+      slotGoTop();
+      m_pMergeResultWindow->slotAutoSolve();
+      // m_pMergeWindowFrame->show(); incompatible with bPreserveCarriageReturn
+      m_pMergeResultWindow->showNrOfConflicts();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotUnsolve()
+{
+   if (m_pMergeResultWindow )
+   {
+      slotGoTop();
+      m_pMergeResultWindow->slotUnsolve();
+   }
+}
+
+
+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()
+{
+   g_tabSize = m_pOptionDialog->m_tabSize;
+   if (m_pDiffTextWindow1!=0)   m_pDiffTextWindow1->update();
+   if (m_pDiffTextWindow2!=0)   m_pDiffTextWindow2->update();
+   if (m_pDiffTextWindow3!=0)   m_pDiffTextWindow3->update();
+   if (m_pMergeResultWindow!=0) m_pMergeResultWindow->update();
+
+   autoAdvance->setChecked( m_pOptionDialog->m_bAutoAdvance );
+   showWhiteSpace->setChecked( m_pOptionDialog->m_bShowWhiteSpace );
+   showLineNumbers->setChecked( m_pOptionDialog->m_bShowLineNumbers );
+
+   if ( m_pDiffWindowSplitter!=0 )
+   {
+       m_pDiffWindowSplitter->setOrientation( m_pOptionDialog->m_bHorizDiffWindowSplitting ? Horizontal : Vertical );
+   }
+}
+
+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();
+   }
+}
+
+void KDiff3App::slotClipboardChanged()
+{
+   QString s = QApplication::clipboard()->text();
+   //editPaste->setEnabled(!s.isEmpty());
+}
+
+void KDiff3App::slotOutputModified()
+{
+   if ( !m_bOutputModified )
+   {
+      m_bOutputModified=true;
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotAutoAdvanceToggled()
+{
+   m_pOptionDialog->m_bAutoAdvance = autoAdvance->isChecked();
+}
+
+void KDiff3App::slotShowWhiteSpaceToggled()
+{
+   m_pOptionDialog->m_bShowWhiteSpace = showWhiteSpace->isChecked();
+   if ( m_pDiffTextWindow1!=0 )
+      m_pDiffTextWindow1->update();
+   if ( m_pDiffTextWindow2!=0 )
+      m_pDiffTextWindow2->update();
+   if ( m_pDiffTextWindow3!=0 )
+      m_pDiffTextWindow3->update();
+}
+
+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 directory compare, else false
+bool KDiff3App::improveFilenames()
+{
+   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() )
+   {
+      FileAccess destDir;
+      if (!m_bDefaultFilename) destDir = f4;
+      m_pDirectoryMergeSplitter->show();
+      m_pDirectoryMergeWindow->init(
+         f1, f2, f3,
+         destDir,  // Destdirname
+         !m_outputFilename.isEmpty()
+         );
+
+      if (m_pMainWidget!=0) m_pMainWidget->hide();
+      m_sd1.reset();
+      if (m_pDiffTextWindow1!=0) m_pDiffTextWindow1->init(0,0,0,0,1,false);
+      m_sd2.reset();
+      if (m_pDiffTextWindow2!=0) m_pDiffTextWindow2->init(0,0,0,0,2,false);
+      m_sd3.reset();
+      if (m_pDiffTextWindow3!=0) m_pDiffTextWindow3->init(0,0,0,0,3,false);
+      slotUpdateAvailabilities();
+      return true;
+   }
+   return false;
+}
+
+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 and 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_pDiffTextWindow1->show();
+      else                            m_pDiffTextWindow1->hide();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotShowWindowBToggled()
+{
+   if ( m_pDiffTextWindow2!=0 )
+   {
+      if ( showWindowB->isChecked() ) m_pDiffTextWindow2->show();
+      else                            m_pDiffTextWindow2->hide();
+      slotUpdateAvailabilities();
+   }
+}
+
+void KDiff3App::slotShowWindowCToggled()
+{
+   if ( m_pDiffTextWindow3!=0 )
+   {
+      if ( showWindowC->isChecked() ) m_pDiffTextWindow3->show();
+      else                            m_pDiffTextWindow3->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()
+{
+   QCString s = m_pFindDialog->m_pSearchString->text().utf8();
+   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;
+   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() );
+         m_pDiffVScrollBar->setValue(d3vLine-m_pDiffVScrollBar->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 = 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() );
+         m_pDiffVScrollBar->setValue(d3vLine-m_pDiffVScrollBar->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 = 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() );
+         m_pDiffVScrollBar->setValue(d3vLine-m_pDiffVScrollBar->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 = 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("KDiff3: 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.m_bPreserve )
+         {
+            m_outputFilename =  m_sd3.getFilename();
+         }
+         else if ( !m_sd2.isEmpty() && !m_sd2.m_bPreserve )
+         {
+            m_outputFilename =  m_sd2.getFilename();
+         }
+         else if ( !m_sd1.isEmpty() && !m_sd1.m_bPreserve )
+         {
+            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->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1);
+   if ( m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2);
+   if ( m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3);
+   if ( 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;   // if at end goto begin of list
+   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->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow1);
+   if ( m_pDiffTextWindow2->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow2);
+   if ( m_pDiffTextWindow3->isVisible() ) visibleWidgetList.push_back(m_pDiffTextWindow3);
+   if ( 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;
+   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()==Vertical ? Horizontal : Vertical
+         );
+   }
+}
+
+void KDiff3App::slotUpdateAvailabilities()
+{
+   bool bTextDataAvailable = (m_sd1.m_pBuf != 0 || m_sd2.m_pBuf != 0 || m_sd3.m_pBuf != 0 );
+   if( dirShowBoth->isChecked() )
+   {
+      if ( m_bDirCompare )
+         m_pDirectoryMergeSplitter->show();
+      else
+         m_pDirectoryMergeSplitter->hide();
+
+      if ( m_pMainWidget!=0 && !m_pMainWidget->isVisible() &&
+           bTextDataAvailable
+         )
+         m_pMainWidget->show();
+   }
+
+   bool bDiffWindowVisible = m_pMainWidget != 0 && m_pMainWidget->isVisible();
+   bool bMergeEditorVisible = m_pMergeWindowFrame !=0  &&  m_pMergeWindowFrame->isVisible();
+
+   dirStartOperation->setEnabled( m_bDirCompare );
+   dirFoldAll->setEnabled( m_bDirCompare );
+   dirUnfoldAll->setEnabled( m_bDirCompare );
+
+   dirCompareCurrent->setEnabled( m_bDirCompare  &&  m_pDirectoryMergeWindow->isVisible()  &&  m_pDirectoryMergeWindow->isFileSelected() );
+
+   dirMergeCurrent->setEnabled( m_bDirCompare  &&  m_pDirectoryMergeWindow->isVisible()  &&  m_pDirectoryMergeWindow->isFileSelected()
+                                || bDiffWindowVisible );
+
+   dirShowBoth->setEnabled( m_bDirCompare );
+
+   dirRescan->setEnabled( m_bDirCompare );
+
+   dirViewToggle->setEnabled(
+      m_bDirCompare &&
+      (!m_pDirectoryMergeSplitter->isVisible()  &&  m_pMainWidget!=0 && m_pMainWidget->isVisible() ||
+        m_pDirectoryMergeSplitter->isVisible()  &&  m_pMainWidget!=0 && !m_pMainWidget->isVisible() && bTextDataAvailable )
+      );
+
+   dirAutoChoiceEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
+   dirDoNothingEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
+   dirChooseAEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
+   dirChooseBEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
+   dirChooseCEverywhere->setEnabled( m_bDirCompare &&  m_pDirectoryMergeWindow->isVisible() );
+
+   showWhiteSpace->setEnabled( bDiffWindowVisible );
+   autoAdvance->setEnabled( bMergeEditorVisible );
+   autoSolve->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   unsolve->setEnabled( bMergeEditorVisible );
+   chooseA->setEnabled( bMergeEditorVisible );
+   chooseB->setEnabled( bMergeEditorVisible );
+   chooseC->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   chooseAEverywhere->setEnabled( bMergeEditorVisible );
+   chooseBEverywhere->setEnabled( bMergeEditorVisible );
+   chooseCEverywhere->setEnabled( bMergeEditorVisible  &&  m_bTripleDiff );
+   showWindowA->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow2->isVisible() || m_pDiffTextWindow3->isVisible() ) );
+   showWindowB->setEnabled( bDiffWindowVisible && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow3->isVisible() ));
+   showWindowC->setEnabled( bDiffWindowVisible &&  m_bTripleDiff && ( m_pDiffTextWindow1->isVisible() || m_pDiffTextWindow2->isVisible() ) );
+   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() );
+
+   winToggleSplitOrientation->setEnabled( bDiffWindowVisible && m_pDiffWindowSplitter!=0 );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/autoadvance.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *autoadvance[] = {
+/* 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/currentpos.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *currentpos[]={
+"16 16 2 1",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+".#............#.",
+".##..........##.",
+".###........###.",
+".####..##..####.",
+".##############.",
+".##############.",
+".####..##..####.",
+".###........###.",
+".##..........##.",
+".#............#.",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/down1arrow.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *down1arrow[] = {
+/* 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/down2arrow.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *down2arrow[] = {
+/* 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/downend.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *downend[]={
+"16 16 2 1",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+"................",
+"................",
+"..############..",
+"...##########...",
+"....########....",
+".....######.....",
+"......####......",
+".......##.......",
+"..############..",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/equal.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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/filesave.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *iconA[]={
+"16 16 2 1",
+". c None",
+"# c #000000",
+"................",
+"................",
+"................",
+"......####......",
+".....######.....",
+"....##....##....",
+"....##....##....",
+"....##....##....",
+"....##....##....",
+"....########....",
+"....########....",
+"....##....##....",
+"....##....##....",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/iconB.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *iconB[]={
+"16 16 2 1",
+". c None",
+"# c #000000",
+"................",
+"................",
+"................",
+"....#######.....",
+"....########....",
+"....##....##....",
+"....##....##....",
+"....#######.....",
+"....#######.....",
+"....##....##....",
+"....##....##....",
+"....########....",
+"....#######.....",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/iconC.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *iconC[]={
+"16 16 2 1",
+". c None",
+"# c #000000",
+"................",
+"................",
+"................",
+"......####......",
+".....######.....",
+"....###...#.....",
+"....##..........",
+"....##..........",
+"....##..........",
+"....##..........",
+"....###...#.....",
+".....######.....",
+"......####......",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/left1arrow.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *nextunsolved[]={
+"16 16 3 1",
+". c None",
+"# c #000000",
+"a c #ff0000",
+"..############..",
+"...##########...",
+"....########....",
+".....######.....",
+"......####......",
+"..############..",
+"...##########...",
+"....########....",
+".....######.....",
+"......####......",
+"..aaaaaaaaaaaa..",
+"...aaaaaaaaaa...",
+"....aaaaaaaa....",
+".....aaaaaa.....",
+"......aaaa......",
+".......aa......."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/not_equal.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,22 @@
+/* XPM */
+static const char *prevunsolved[]={
+"16 16 3 1",
+". c None",
+"a c #000000",
+"# c #ff0000",
+".......##.......",
+"......####......",
+".....######.....",
+"....########....",
+"...##########...",
+"..############..",
+"......aaaa......",
+".....aaaaaa.....",
+"....aaaaaaaa....",
+"...aaaaaaaaaa...",
+"..aaaaaaaaaaaa..",
+"......aaaa......",
+".....aaaaaa.....",
+"....aaaaaaaa....",
+"...aaaaaaaaaa...",
+"..aaaaaaaaaaaa.."};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/reload.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +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/showlinenumbers.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *showwhitespace[]={
+"16 16 2 1",
+". c None",
+"# c #000040",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+"................",
+".####.####.####.",
+".####.####.####.",
+"................",
+"................",
+"................",
+"................"};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kdiff3/src/xpm/startmerge.xpm	Mon Oct 06 18:50:45 2003 +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	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *up1arrow[] = {
+/* 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/up2arrow.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,24 @@
+/* XPM */
+static const char *up2arrow[] = {
+/* 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/upend.xpm	Mon Oct 06 18:50:45 2003 +0000
@@ -0,0 +1,21 @@
+/* XPM */
+static const char *upend[]={
+"16 16 2 1",
+"# c #000000",
+". c None",
+"................",
+"................",
+"................",
+"................",
+"..############..",
+".......##.......",
+"......####......",
+".....######.....",
+"....########....",
+"...##########...",
+"..############..",
+"................",
+"................",
+"................",
+"................",
+"................"};