# HG changeset patch # User joachim99 # Date 1065466245 0 # Node ID 86d21651c8db50e1b524ad6677c26be9cc074595 # Parent ff98a43bbfeadd096cbe6c003892989180aab326 KDiff3 version 0.9.70 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/.cvsignore --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/Makefile.am --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/Makefile.qt --- /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 + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/Makefile.win_qt230 --- /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 + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/common.h --- /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 +T max2( T x, T y ) +{ + return x>y ? x : y; +} + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; + + +template +T min3( T d1, T d2, T d3 ) +{ + if ( d1 < d2 && d1 < d3 ) return d1; + if ( d2 < d3 ) return d2; + return d3; +} + +template +T max3( T d1, T d2, T d3 ) +{ + + if ( d1 > d2 && d1 > d3 ) return d1; + + + if ( d2 > d3 ) return d2; + return d3; + +} + +template +T minMaxLimiter( T d, T minimum, T maximum ) +{ + assert(minimum<=maximum); + if ( d < minimum ) return minimum; + if ( d > maximum ) return maximum; + return d; +} + +#endif diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/diff.cpp --- /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 +#include + +#include "diff.h" +#include "fileaccess.h" + +#include +#include +#include +#include + +#include +#include +#include +//using namespace std; + + +int LineData::width() +{ + int w=0; + int j=0; + for( int i=0; i=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( i1m_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 occurancesMap; + int i; + for( i=0; ibegin(); + 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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/diff.h --- /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 +#include +#include +#include +#include +#include +#include +#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 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 Diff3LineList; +typedef std::vector 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 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 + { // I want to know the size immediately! + private: + typedef std::list BASE; + int m_size; + public: + typedef std::list::iterator iterator; + typedef std::list::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 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 +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=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 + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/difftextwindow.cpp --- /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 +#include "diff.h" +#include "merger.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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( pos2button() == 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=p1; + if ( l==l2 ) + return pl2 ){ 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 charChanged( pld->size ); + if ( pLineDiff1!=0 || pLineDiff2 != 0 ) + { + Merger merger( pLineDiff1, pLineDiff2 ); + while( ! merger.isEndReached() && isize ) + { + if ( i < pld->size ) + { + charChanged[i] = merger.whatChanged(); + ++i; + } + merger.next(); + } + } + + QCString s=" "; + // Convert tabs + int outPos = 0; + for( i=0; isize; ++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 ( y1topLineYOffset ) + { + 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; linepLine, 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; isize() : -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(); +} diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/directorymergewindow.cpp --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 buf1(100000); + std::vector 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(img1.scanLine(y)); + Q_UINT32 *line2 = reinterpret_cast(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(img1.scanLine(y)); + Q_UINT32 *line2 = reinterpret_cast(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(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 <filePath()<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( 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(pParent); + if (pSplitter!=0) + { + QValueList 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(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( p ); + calcSuggestedOperation( *pDMI->m_pMFI, eDefaultOperation ); + } + } +} + + +void DirectoryMergeWindow::compareFilesAndCalcAges( MergeFileInfos& mfi ) +{ + std::map 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::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::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(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(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(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( p ); + DirectoryMergeWindow* pDMW = static_cast( 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( 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( 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( 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(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( 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(pNextItem)->m_pMFI->m_bOperationComplete || + ( bSim && static_cast(pNextItem)->m_pMFI->m_bSimOpComplete ) ) ) + { + pNextItem = pNextItem->nextSibling(); + } + + if ( pNextItem == 0 ) + { + pCurrentItem = pCurrentItem->parent(); + if ( pCurrentItem!=0 ) + { + if (bSim) + static_cast(pCurrentItem)->m_pMFI->m_bSimOpComplete = true; + else + { + pCurrentItem->setText( s_OpStatusCol, "Done." ); + static_cast(pCurrentItem)->m_pMFI->m_bOperationComplete = true; + } + } + } + } + m_pCurrentItemForOperation = static_cast(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(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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/directorymergewindow.h --- /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 +#include +#include +#include +#include +#include +#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(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 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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/fileaccess.cpp --- /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 +#include +#include +#include "optiondialog.h" +#include +#include +#include +#if QT_VERSION==230 +#else +#include +#endif +#include "common.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef _WIN32 +#include +#include +#else +#include // Needed for creating symbolic links via symlink(). +#include +#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( isetSubCurrent( 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( isetSubCurrent( 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(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 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 +// with elements from class StringMatcher +// Copyright (c) 2003 André Wöbbeking +// 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(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::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 +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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/fileaccess.h --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +{}; + + +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 + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/hi16-app-kdiff3.png Binary file kdiff3/src/hi16-app-kdiff3.png has changed diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/hi32-app-kdiff3.png Binary file kdiff3/src/hi32-app-kdiff3.png has changed diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3.cpp --- /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 + +// include files for QT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// include files for KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +// 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(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()<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()<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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3.desktop --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3.h --- /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 +#endif + +// include files for Qt +#include +#include + +// include files for KDE +#include +#include +#include +#include +#include +#include + + +// 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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3.pro --- /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 +} diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3.rc --- /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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_part.cpp --- /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 + */ + +#include "kdiff3_part.h" + +#include +#include +#include +#include + +#include +#include +#include "kdiff3.h" +#include "fileaccess.h" + +#include +#include +#include +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(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 +#include + +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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_part.h --- /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 + */ + +#ifndef _KDIFF3PART_H_ +#define _KDIFF3PART_H_ + +#include +#include + +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 + */ +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_ diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_part.rc --- /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 @@ + + + + &KDiff3 + + + + + + + + Configure KDiff3 + + +KDiff3 + + + + + + + + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_shell.cpp --- /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 + */ + +#include "kdiff3_shell.h" +#include "kdiff3.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +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(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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_shell.h --- /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 + */ + +#ifndef _KDIFF3SHELL_H_ +#define _KDIFF3SHELL_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +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 + */ +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_ diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_shell.rc --- /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 @@ + + + + &File + + + &Directory + + + + + + + + + + + + &Movement + + + + + + + + + + + &Merge + + + + + + + + + + + + + + &Window + + + + + + + + + + +Main Toolbar + + + + + + + + + + + + + + + + + + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3_tmake.pro --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kdiff3part.desktop --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/README --- /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) diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kaboutdata.h --- /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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kaccel.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kaction.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kapplication.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kcmdlineargs.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kcolorbtn.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kconfig.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kdialogbase.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kedittoolbar.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kfiledialog.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kfontdialog.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kiconloader.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kinstance.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kio/global.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kio/job.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kio/jobclasses.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kkeydialog.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/klibloader.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/klocale.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kmainwindow.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kmenubar.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kmessagebox.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kparts/factory.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kparts/mainwindow.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kparts/part.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kpopupmenu.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kprogress.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kreplacements.cpp --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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 +#include +#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; + 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::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::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::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::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::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::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::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::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::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 s_vOption; +static std::vector 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; i0 && ( 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<(this); + if (f!=0) + return f->createPartObject( (QWidget*)pParent, name, + pParent, name, + classname, QStringList() ); + else + return 0; +} + + + +#include "kreplacements.moc" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kreplacements.h --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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* memberList; +public slots: + void quit(); + void slotHelp(); + void slotAbout(); +}; + +class KConfig +{ + QString m_fileName; + std::map 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 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 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 + + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kstatusbar.h --- /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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kstdaction.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/ktempfile.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kunload.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kurl.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/kreplacements/kurldrag.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" + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/lo16-app-kdiff3.png Binary file kdiff3/src/lo16-app-kdiff3.png has changed diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/lo32-app-kdiff3.png Binary file kdiff3/src/lo32-app-kdiff3.png has changed diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/main.cpp --- /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 +#include +#include + +#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 +// This command checks the comm +static bool isOptionUsed(const QString& s, int argc, char* argv[]) +{ + for(int j=0; j +#include +#include + +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(); +} diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/merger.h --- /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 diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/mergeresultwindow.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; jlineA : + 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; jlineA : + 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=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 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; i0) 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("") ); + 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("") ); + 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 ( yisEditableText() ) + { + 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; imergeEditLineList.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 ( xstr, 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 && ytext(); + 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 + getNofVisibleLines() ) + newFirstLine = y - getNofVisibleLines(); + + if (bYMoveKey) + x=convertToPosInText( ps, stringLength, m_cursorOldXPos ); + + int xOnScreen = convertToPosOnScreen( ps, x ); + 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; igetString( 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 ); +} + + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/optiondialog.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include // For KFontChooser +#include +#include +#include +#include +//#include + +#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(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::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::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::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::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::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" diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/optiondialog.h --- /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 +#include +#include + +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 m_optionItemList; + + // FontConfigDlg + KFontChooser *m_fontChooser; + +private: + void setupFontPage(); + void setupColorPage(); + void setupEditPage(); + void setupDiffPage(); + void setupDirectoryMergePage(); + void setupKeysPage(); +}; + + + +#endif + + + + + + + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/pdiff.cpp --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdiff3.h" +#include "optiondialog.h" +#include "fileaccess.h" +#ifdef _WIN32 +#include +#else +#include +#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; lm_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' || 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 +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 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 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(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 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::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 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::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 ); +} diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/autoadvance.xpm --- /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 */ +" ## # # ### # ", +"# # # # # # #", +"# # # # # # #", +"#### # # # # #", +"# # ### # # ", +" ", +" ", +" ######## ", +" ###### ", +" #### ", +" ## ", +" ######## ", +" ###### ", +" #### ", +" ## ", +" " +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/currentpos.xpm --- /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", +"................", +"................", +"................", +".#............#.", +".##..........##.", +".###........###.", +".####..##..####.", +".##############.", +".##############.", +".####..##..####.", +".###........###.", +".##..........##.", +".#............#.", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/down1arrow.xpm --- /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 */ +"................", +"................", +"................", +"................", +"................", +".. ..", +"... ...", +".... ....", +"..... .....", +"...... ......", +"....... .......", +"................", +"................", +"................", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/down2arrow.xpm --- /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 */ +"................", +"................", +".. ..", +"... ...", +".... ....", +"..... .....", +"...... ......", +"....... .......", +".. ..", +"... ...", +".... ....", +"..... .....", +"...... ......", +"....... .......", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/downend.xpm --- /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", +"................", +"................", +"................", +"................", +"................", +"..############..", +"...##########...", +"....########....", +".....######.....", +"......####......", +".......##.......", +"..############..", +"................", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/equal.xpm --- /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#", +"################"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/file.xpm --- /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#..", +"..############.."}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/filenew.xpm --- /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", +"....... ", +".++++@@. ", +".++++#+@. ", +".++++#++@.", +".++++#....", +".+++++###.", +".++++++++.", +".++++++++.", +".++++++++.", +".++++++++.", +".++++++++.", +".++++++++.", +".++++++++.", +".........."}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/fileopen.xpm --- /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" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/filesave.xpm --- /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............." +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/folder.xpm --- /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#....", +"###########.....", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/iconA.xpm --- /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", +"................", +"................", +"................", +"......####......", +".....######.....", +"....##....##....", +"....##....##....", +"....##....##....", +"....##....##....", +"....########....", +"....########....", +"....##....##....", +"....##....##....", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/iconB.xpm --- /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", +"................", +"................", +"................", +"....#######.....", +"....########....", +"....##....##....", +"....##....##....", +"....#######.....", +"....#######.....", +"....##....##....", +"....##....##....", +"....########....", +"....#######.....", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/iconC.xpm --- /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", +"................", +"................", +"................", +"......####......", +".....######.....", +"....###...#.....", +"....##..........", +"....##..........", +"....##..........", +"....##..........", +"....###...#.....", +".....######.....", +"......####......", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/left1arrow.xpm --- /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 */ +"................", +"................", +".......... .....", +"......... .....", +"........ .....", +"....... .....", +"...... .....", +"..... .....", +"..... .....", +"...... .....", +"....... .....", +"........ .....", +"......... .....", +".......... .....", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/left2arrow.xpm --- /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 */ +"................", +"................", +"....... ..... ..", +"...... .... ..", +"..... ... ..", +".... .. ..", +"... . ..", +".. ..", +".. ..", +"... . ..", +".... .. ..", +"..... ... ..", +"...... .... ..", +"....... ..... ..", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/leftend.xpm --- /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", +"................", +"................", +"....#.....#.....", +"....#....##.....", +"....#...###.....", +"....#..####.....", +"....#.#####.....", +"....#######.....", +"....#######.....", +"....#.#####.....", +"....#..####.....", +"....#...###.....", +"....#....##.....", +"....#.....#.....", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/link_arrow.xpm --- /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........"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/nextunsolved.xpm --- /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......."}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/not_equal.xpm --- /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#", +"################"}; + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/not_everywhere.xpm --- /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#", +"################"}; + diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/not_there.xpm --- /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#", +"################"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/prevunsolved.xpm --- /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.."}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/reload.xpm --- /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....", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/right1arrow.xpm --- /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 */ +"................", +"................", +"..... ..........", +"..... .........", +"..... ........", +"..... .......", +"..... ......", +"..... .....", +"..... .....", +"..... ......", +"..... .......", +"..... ........", +"..... .........", +"..... ..........", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/right2arrow.xpm --- /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 */ +"................", +"................", +".. ..... .......", +".. .... ......", +".. ... .....", +".. .. ....", +".. . ...", +".. ..", +".. ..", +".. . ...", +".. .. ....", +".. ... .....", +".. .... ......", +".. ..... .......", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/rightend.xpm --- /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", +"................", +"................", +".....#.....#....", +".....##....#....", +".....###...#....", +".....####..#....", +".....#####.#....", +".....#######....", +".....#######....", +".....#####.#....", +".....####..#....", +".....###...#....", +".....##....#....", +".....#.....#....", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/showlinenumbers.xpm --- /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", +"................", +"................", +"................", +"................", +"...#...##..###..", +"..##..#..#....#.", +"...#.....#....#.", +"...#....#...##..", +"...#...#......#.", +"...#..#.......#.", +"..###.####.###..", +"................", +"................", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/showwhitespace.xpm --- /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", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +"................", +".####.####.####.", +".####.####.####.", +"................", +"................", +"................", +"................"}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/startmerge.xpm --- /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#......", +".......##......."}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/up1arrow.xpm --- /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 */ +"................", +"................", +"................", +"................", +"................", +"....... .......", +"...... ......", +"..... .....", +".... ....", +"... ...", +".. ..", +"................", +"................", +"................", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/up2arrow.xpm --- /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 */ +"................", +"................", +"....... .......", +"...... ......", +"..... .....", +".... ....", +"... ...", +".. ..", +"....... .......", +"...... ......", +"..... .....", +".... ....", +"... ...", +".. ..", +"................", +"................" +}; diff -r ff98a43bbfea -r 86d21651c8db kdiff3/src/xpm/upend.xpm --- /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", +"................", +"................", +"................", +"................", +"..############..", +".......##.......", +"......####......", +".....######.....", +"....########....", +"...##########...", +"..############..", +"................", +"................", +"................", +"................", +"................"};